4 Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
20 local type, pairs, ipairs, loadfile, table, tonumber, math, i18n
21 = type, pairs, ipairs, loadfile, table, tonumber, math, luci.i18n
23 local nxo = require "nixio"
24 local ipc = require "luci.ip"
25 local sys = require "luci.sys"
26 local utl = require "luci.util"
27 local dsp = require "luci.dispatcher"
28 local uci = require "luci.model.uci"
30 module "luci.model.network"
33 local ifs, brs, sws, uci_r, uci_s
35 function _list_del(c, s, o, r)
36 local val = uci_r:get(c, s, o)
39 if type(val) == "string" then
40 for val in val:gmatch("%S+") do
46 uci_r:set(c, s, o, table.concat(l, " "))
50 elseif type(val) == "table" then
51 for _, val in ipairs(val) do
65 function _list_add(c, s, o, a)
66 local val = uci_r:get(c, s, o) or ""
67 if type(val) == "string" then
69 for val in val:gmatch("%S+") do
75 uci_r:set(c, s, o, table.concat(l, " "))
76 elseif type(val) == "table" then
78 for _, val in ipairs(val) do
88 function _stror(s1, s2)
89 if not s1 or #s1 == 0 then
90 return s2 and #s2 > 0 and s2
96 function _get(c, s, o)
97 return uci_r:get(c, s, o)
100 function _set(c, s, o, v)
102 if type(v) == "boolean" then v = v and "1" or "0" end
103 return uci_r:set(c, s, o, v)
105 return uci_r:delete(c, s, o)
109 function _wifi_iface(x)
111 x:match("^wlan%d") or x:match("^wl%d") or x:match("^ath%d") or
112 x:match("^%w+%.network%d")
116 function _wifi_lookup(ifn)
117 -- got a radio#.network# pseudo iface, locate the corresponding section
118 local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
119 if radio and ifnidx then
123 ifnidx = tonumber(ifnidx)
124 uci_r:foreach("wireless", "wifi-iface",
126 if s.device == radio then
128 if num == ifnidx then
137 -- looks like wifi, try to locate the section via state vars
138 elseif _wifi_iface(ifn) then
141 uci_s:foreach("wireless", "wifi-iface",
143 if s.ifname == ifn then
153 function _iface_ignore(x)
155 x:match("^wmaster%d") or x:match("^wifi%d") or x:match("^hwsim%d") or
156 x:match("^imq%d") or x:match("^mon.wlan%d") or x:match("^6in4-%w") or
157 x:match("^6to4-%w") or x:match("^3g-%w") or x:match("^ppp-%w") or
158 x:match("^pppoe-%w") or x:match("^pppoa-%w") or x == "sit0" or x == "lo"
163 function init(cursor)
164 uci_r = cursor or uci_r or uci.cursor()
165 uci_s = uci_r:substate()
171 -- read interface information
173 for n, i in ipairs(nxo.getifaddrs()) do
174 local name = i.name:match("[^:]+")
175 local prnt = name:match("^([^%.]+)%.")
177 if not _iface_ignore(name) then
178 ifs[name] = ifs[name] or {
179 idx = i.ifindex or n,
192 if i.family == "packet" then
193 ifs[name].flags = i.flags
194 ifs[name].stats = i.data
195 ifs[name].macaddr = i.addr
196 elseif i.family == "inet" then
197 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
198 elseif i.family == "inet6" then
199 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
204 -- read bridge informaton
206 for l in utl.execi("brctl show") do
207 if not l:match("STP") then
208 local r = utl.split(l, "%s+", nil, true)
214 ifnames = { ifs[r[4]] }
217 b.ifnames[1].bridge = b
221 b.ifnames[#b.ifnames+1] = ifs[r[2]]
222 b.ifnames[#b.ifnames].bridge = b
230 function save(self, ...)
235 function commit(self, ...)
240 function has_ipv6(self)
241 return nfs.access("/proc/net/ipv6_route")
244 function add_network(self, n, options)
245 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
246 if uci_r:section("network", "interface", n, options) then
252 function get_network(self, n)
253 if n and uci_r:get("network", n) == "interface" then
258 function get_networks(self)
262 uci_r:foreach("network", "interface",
264 nls[s['.name']] = network(s['.name'])
268 for n in utl.kspairs(nls) do
269 nets[#nets+1] = nls[n]
275 function del_network(self, n)
276 local r = uci_r:delete("network", n)
278 uci_r:delete_all("network", "alias",
279 function(s) return (s.interface == n) end)
281 uci_r:delete_all("network", "route",
282 function(s) return (s.interface == n) end)
284 uci_r:delete_all("network", "route6",
285 function(s) return (s.interface == n) end)
287 uci_r:foreach("wireless", "wifi-iface",
289 if s.network == n then
290 uci_r:delete("wireless", s['.name'], "network")
297 function rename_network(self, old, new)
299 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
300 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
303 uci_r:foreach("network", "alias",
305 if s.interface == old then
306 uci_r:set("network", s['.name'], "interface", new)
310 uci_r:foreach("network", "route",
312 if s.interface == old then
313 uci_r:set("network", s['.name'], "interface", new)
317 uci_r:foreach("network", "route6",
319 if s.interface == old then
320 uci_r:set("network", s['.name'], "interface", new)
324 uci_r:foreach("wireless", "wifi-iface",
326 if s.network == old then
327 uci_r:set("wireless", s['.name'], "network", new)
331 uci_r:delete("network", old)
337 function get_interface(self, i)
338 if ifs[i] or _wifi_iface(i) then
343 uci_r:foreach("wireless", "wifi-iface",
346 num[s.device] = num[s.device] and num[s.device] + 1 or 1
347 if s['.name'] == i then
349 "%s.network%d" %{s.device, num[s.device] })
358 function get_interfaces(self)
364 -- find normal interfaces
365 uci_r:foreach("network", "interface",
367 for iface in utl.imatch(s.ifname) do
368 if not _iface_ignore(iface) and not _wifi_iface(iface) then
370 nfs[iface] = interface(iface)
375 for iface in utl.kspairs(ifs) do
376 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
377 nfs[iface] = interface(iface)
381 for iface in utl.kspairs(nfs) do
382 ifaces[#ifaces+1] = nfs[iface]
385 -- find wifi interfaces
388 uci_r:foreach("wireless", "wifi-iface",
391 num[s.device] = num[s.device] and num[s.device] + 1 or 1
392 local i = "%s.network%d" %{ s.device, num[s.device] }
393 wfs[i] = interface(i)
397 for iface in utl.kspairs(wfs) do
398 ifaces[#ifaces+1] = wfs[iface]
404 function ignore_interface(self, x)
405 return _iface_ignore(x)
408 function get_wifidev(self, dev)
409 if uci_r:get("wireless", dev) == "wifi-device" then
414 function get_wifidevs(self)
418 uci_r:foreach("wireless", "wifi-device",
419 function(s) wfd[#wfd+1] = s['.name'] end)
422 for _, dev in utl.vspairs(wfd) do
423 devs[#devs+1] = wifidev(dev)
429 function get_wifinet(self, net)
430 local wnet = _wifi_lookup(net)
436 function add_wifinet(self, net, options)
437 if type(options) == "table" and options.device and
438 uci_r:get("wireless", options.device) == "wifi-device"
440 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
445 function del_wifinet(self, net)
446 local wnet = _wifi_lookup(net)
448 uci_r:delete("wireless", wnet)
455 network = utl.class()
457 function network.__init__(self, name)
461 function network._get(self, opt)
462 local v = uci_r:get("network", self.sid, opt)
463 if type(v) == "table" then
464 return table.concat(v, " ")
469 function network.get(self, opt)
470 return _get("network", self.sid, opt)
473 function network.set(self, opt, val)
474 return _set("network", self.sid, opt, val)
477 function network.ifname(self)
478 local p = self:proto()
479 if self:is_bridge() then
480 return "br-" .. self.sid
481 elseif self:is_virtual() then
482 return p .. "-" .. self.sid
485 local dev = self:_get("ifname") or
486 uci_r:get("network", self.sid, "ifname")
488 dev = dev and dev:match("%S+")
491 uci_r:foreach("wireless", "wifi-iface",
494 num[s.device] = num[s.device]
495 and num[s.device] + 1 or 1
497 if s.network == self.sid then
498 dev = "%s.network%d" %{ s.device, num[s.device] }
509 function network.device(self)
510 local dev = self:_get("device")
511 if not dev or dev:match("[^%w%-%.%s]") then
512 dev = uci_r:get("network", self.sid, "ifname")
517 function network.proto(self)
518 return self:_get("proto") or "none"
521 function network.type(self)
522 return self:_get("type")
525 function network.name(self)
529 function network.uptime(self)
530 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
532 return nxo.sysinfo().uptime - cnt
538 function network.is_bridge(self)
539 return (self:type() == "bridge")
542 function network.is_virtual(self)
543 local p = self:proto()
545 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
546 p == "pppoe" or p == "pppoa"
550 function network.is_empty(self)
551 if self:is_virtual() then
556 if (self:_get("ifname") or ""):match("%S+") then
560 uci_r:foreach("wireless", "wifi-iface",
562 if s.network == self.sid then
572 function network.add_interface(self, ifname)
573 if not self:is_virtual() then
574 if type(ifname) ~= "string" then
575 ifname = ifname:name()
577 ifname = ifname:match("[^%s:]+")
580 -- remove the interface from all ifaces
581 uci_r:foreach("network", "interface",
583 _list_del("network", s['.name'], "ifname", ifname)
586 -- if its a wifi interface, change its network option
587 local wif = _wifi_lookup(ifname)
589 uci_r:set("wireless", wif, "network", self.sid)
591 -- add iface to our iface list
593 _list_add("network", self.sid, "ifname", ifname)
598 function network.del_interface(self, ifname)
599 if not self:is_virtual() then
600 if utl.instanceof(ifname, interface) then
601 ifname = ifname:name()
603 ifname = ifname:match("[^%s:]+")
606 -- if its a wireless interface, clear its network option
607 local wif = _wifi_lookup(ifname)
608 if wif then uci_r:delete("wireless", wif, "network") end
610 -- remove the interface
611 _list_del("network", self.sid, "ifname", ifname)
615 function network.get_interfaces(self)
619 if self:is_virtual() then
620 ifn = self:proto() .. "-" .. self.sid
621 ifaces = { interface(ifn) }
624 for ifn in utl.imatch(self:get("ifname")) do
625 ifn = ifn:match("[^:]+")
626 nfs[ifn] = interface(ifn)
629 for ifn in utl.kspairs(nfs) do
630 ifaces[#ifaces+1] = nfs[ifn]
635 uci_r:foreach("wireless", "wifi-iface",
638 num[s.device] = num[s.device] and num[s.device] + 1 or 1
639 if s.network == self.sid then
640 ifn = "%s.network%d" %{ s.device, num[s.device] }
641 wfs[ifn] = interface(ifn)
646 for ifn in utl.kspairs(wfs) do
647 ifaces[#ifaces+1] = wfs[ifn]
654 function network.contains_interface(self, ifname)
655 if type(ifname) ~= "string" then
656 ifname = ifname:name()
658 ifname = ifname:match("[^%s:]+")
662 if self:is_virtual() then
663 ifn = self:proto() .. "-" .. self.sid
666 for ifn in utl.imatch(self:get("ifname")) do
667 ifn = ifn:match("[^:]+")
668 if ifn == ifname then
673 local wif = _wifi_lookup(ifname)
675 return (uci_r:get("wireless", wif, "network") == self.sid)
682 function network.adminlink(self)
683 return dsp.build_url("admin", "network", "network", self.sid)
687 interface = utl.class()
688 function interface.__init__(self, ifname)
689 local wif = _wifi_lookup(ifname)
690 if wif then self.wif = wifinet(wif) end
692 self.ifname = self.ifname or ifname
693 self.dev = ifs[self.ifname]
696 function interface.name(self)
697 return self.wif and self.wif:ifname() or self.ifname
700 function interface.mac(self)
701 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
704 function interface.ipaddrs(self)
705 return self.dev and self.dev.ipaddrs or { }
708 function interface.ip6addrs(self)
709 return self.dev and self.dev.ip6addrs or { }
712 function interface.type(self)
713 if self.wif or _wifi_iface(self.ifname) then
715 elseif brs[self.ifname] then
717 elseif sws[self.ifname] or self.ifname:match("%.") then
724 function interface.shortname(self)
727 self.wif:active_mode(),
728 self.wif:active_ssid() or self.wif:active_bssid()
735 function interface.get_i18n(self)
737 return "%s: %s %q" %{
738 i18n.translate("Wireless Network"),
739 self.wif:active_mode(),
740 self.wif:active_ssid() or self.wif:active_bssid()
743 return "%s: %q" %{ self:get_type_i18n(), self:name() }
747 function interface.get_type_i18n(self)
748 local x = self:type()
750 return i18n.translate("Wireless Adapter")
751 elseif x == "bridge" then
752 return i18n.translate("Bridge")
753 elseif x == "switch" then
754 return i18n.translate("Ethernet Switch")
756 return i18n.translate("Ethernet Adapter")
760 function interface.adminlink(self)
762 return self.wif:adminlink()
766 function interface.ports(self)
770 for _, iface in ipairs(self.br.ifnames) do
771 ifaces[#ifaces+1] = interface(iface.name)
777 function interface.bridge_id(self)
785 function interface.bridge_stp(self)
793 function interface.is_up(self)
795 return self.wif:is_up()
797 return self.dev and self.dev.flags and self.dev.flags.up or false
801 function interface.is_bridge(self)
802 return (self:type() == "bridge")
805 function interface.is_bridgeport(self)
806 return self.dev and self.dev.bridge and true or false
809 function interface.tx_bytes(self)
810 return self.dev and self.dev.stats
811 and self.dev.stats.tx_bytes or 0
814 function interface.rx_bytes(self)
815 return self.dev and self.dev.stats
816 and self.dev.stats.rx_bytes or 0
819 function interface.tx_packets(self)
820 return self.dev and self.dev.stats
821 and self.dev.stats.tx_packets or 0
824 function interface.rx_packets(self)
825 return self.dev and self.dev.stats
826 and self.dev.stats.rx_packets or 0
829 function interface.get_network(self)
830 if self.dev and self.dev.network then
831 self.network = _M:get_network(self.dev.network)
834 if not self.network then
836 for _, net in ipairs(_M:get_networks()) do
837 if net:contains_interface(self.ifname) then
847 function interface.get_wifinet(self)
852 wifidev = utl.class()
853 function wifidev.__init__(self, dev)
857 function wifidev.get(self, opt)
858 return _get("wireless", self.sid, opt)
861 function wifidev.set(self, opt, val)
862 return _set("wireless", self.sid, opt, val)
865 function wifidev.name(self)
869 function wifidev.is_up(self)
872 uci_s:foreach("wireless", "wifi-iface",
874 if s.device == self.sid then
885 function wifidev.get_wifinet(self, net)
886 if uci_r:get("wireless", net) == "wifi-iface" then
889 local wnet = _wifi_lookup(net)
896 function wifidev.get_wifinets(self)
899 uci_r:foreach("wireless", "wifi-iface",
901 if s.device == self.sid then
902 nets[#nets+1] = wifinet(s['.name'])
909 function wifidev.add_wifinet(self, options)
910 options = options or { }
911 options.device = self.sid
913 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
915 return wifinet(wnet, options)
919 function wifidev.del_wifinet(self, net)
920 if utl.instanceof(net, wifinet) then
922 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
923 net = _wifi_lookup(net)
926 if net and uci_r:get("wireless", net, "device") == self.sid then
927 uci_r:delete("wireless", net)
935 wifinet = utl.class()
936 function wifinet.__init__(self, net, data)
941 uci_r:foreach("wireless", "wifi-iface",
944 num[s.device] = num[s.device] and num[s.device] + 1 or 1
945 if s['.name'] == self.sid then
946 netid = "%s.network%d" %{ s.device, num[s.device] }
952 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
956 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
957 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
958 uci_r:get_all("wireless", self.sid) or { }
961 function wifinet.get(self, opt)
962 return _get("wireless", self.sid, opt)
965 function wifinet.set(self, opt, val)
966 return _set("wireless", self.sid, opt, val)
969 function wifinet.mode(self)
970 return uci_s:get("wireless", self.sid, "mode") or "ap"
973 function wifinet.ssid(self)
974 return uci_s:get("wireless", self.sid, "ssid")
977 function wifinet.bssid(self)
978 return uci_s:get("wireless", self.sid, "bssid")
981 function wifinet.network(self)
982 return uci_s:get("wifinet", self.sid, "network")
985 function wifinet.name(self)
989 function wifinet.ifname(self)
990 local ifname = self.iwinfo.ifname
991 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
997 function wifinet.get_device(self)
998 if self.iwdata.device then
999 return wifidev(self.iwdata.device)
1003 function wifinet.is_up(self)
1004 return (self.iwdata.up == "1")
1007 function wifinet.active_mode(self)
1008 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1010 if m == "ap" then m = "AP"
1011 elseif m == "sta" then m = "Client"
1012 elseif m == "adhoc" then m = "Ad-Hoc"
1013 elseif m == "mesh" then m = "Mesh"
1014 elseif m == "monitor" then m = "Monitor"
1020 function wifinet.active_mode_i18n(self)
1021 return i18n.translate(self:active_mode())
1024 function wifinet.active_ssid(self)
1025 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1028 function wifinet.active_bssid(self)
1029 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1032 function wifinet.active_encryption(self)
1033 local enc = self.iwinfo and self.iwinfo.encryption
1034 return enc and enc.description or "-"
1037 function wifinet.assoclist(self)
1038 return self.iwinfo.assoclist or { }
1041 function wifinet.frequency(self)
1042 local freq = self.iwinfo.frequency
1043 if freq and freq > 0 then
1044 return "%.03f" % (freq / 1000)
1048 function wifinet.bitrate(self)
1049 local rate = self.iwinfo.bitrate
1050 if rate and rate > 0 then
1051 return (rate / 1000)
1055 function wifinet.channel(self)
1056 return self.iwinfo.channel or
1057 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1060 function wifinet.signal(self)
1061 return self.iwinfo.signal or 0
1064 function wifinet.noise(self)
1065 return self.iwinfo.noise or 0
1068 function wifinet.signal_level(self, s, n)
1069 if self:active_bssid() ~= "00:00:00:00:00:00" then
1070 local signal = s or self:signal()
1071 local noise = n or self:noise()
1073 if signal < 0 and noise < 0 then
1074 local snr = -1 * (noise - signal)
1075 return math.floor(snr / 5)
1084 function wifinet.signal_percent(self)
1085 local qc = self.iwinfo.quality or 0
1086 local qm = self.iwinfo.quality_max or 0
1088 if qc > 0 and qm > 0 then
1089 return math.floor((100 / qm) * qc)
1095 function wifinet.shortname(self)
1097 i18n.translate(self:active_mode()),
1098 self:active_ssid() or self:active_bssid()
1102 function wifinet.get_i18n(self)
1103 return "%s: %s %q (%s)" %{
1104 i18n.translate("Wireless Network"),
1105 i18n.translate(self:active_mode()),
1106 self:active_ssid() or self:active_bssid(),
1111 function wifinet.adminlink(self)
1112 return dsp.build_url("admin", "network", "wireless",
1113 self.iwdata.device, self.netid)
1116 function wifinet.get_network(self)
1117 if uci_r:get("network", self.iwdata.network) == "interface" then
1118 return network(self.iwdata.network)
1122 function wifinet.get_interface(self)
1123 return interface(self:ifname())