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, next, pairs, ipairs, loadfile, table, tonumber, math, i18n
21 = type, next, 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:match("^relay-%w") or
159 x == "sit0" or x == "lo"
164 function init(cursor)
165 uci_r = cursor or uci_r or uci.cursor()
166 uci_s = uci_r:substate()
172 -- read interface information
174 for n, i in ipairs(nxo.getifaddrs()) do
175 local name = i.name:match("[^:]+")
176 local prnt = name:match("^([^%.]+)%.")
178 if not _iface_ignore(name) then
179 ifs[name] = ifs[name] or {
180 idx = i.ifindex or n,
193 if i.family == "packet" then
194 ifs[name].flags = i.flags
195 ifs[name].stats = i.data
196 ifs[name].macaddr = i.addr
197 elseif i.family == "inet" then
198 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
199 elseif i.family == "inet6" then
200 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
205 -- read bridge informaton
207 for l in utl.execi("brctl show") do
208 if not l:match("STP") then
209 local r = utl.split(l, "%s+", nil, true)
215 ifnames = { ifs[r[4]] }
218 b.ifnames[1].bridge = b
222 b.ifnames[#b.ifnames+1] = ifs[r[2]]
223 b.ifnames[#b.ifnames].bridge = b
231 function save(self, ...)
236 function commit(self, ...)
241 function has_ipv6(self)
242 return nfs.access("/proc/net/ipv6_route")
245 function add_network(self, n, options)
246 local oldnet = self:get_network(n)
247 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
248 if uci_r:section("network", "interface", n, options) then
251 elseif oldnet and oldnet:is_empty() then
254 for k, v in pairs(options) do
262 function get_network(self, n)
263 if n and uci_r:get("network", n) == "interface" then
268 function get_networks(self)
272 uci_r:foreach("network", "interface",
274 nls[s['.name']] = network(s['.name'])
278 for n in utl.kspairs(nls) do
279 nets[#nets+1] = nls[n]
285 function del_network(self, n)
286 local r = uci_r:delete("network", n)
288 uci_r:delete_all("network", "alias",
289 function(s) return (s.interface == n) end)
291 uci_r:delete_all("network", "route",
292 function(s) return (s.interface == n) end)
294 uci_r:delete_all("network", "route6",
295 function(s) return (s.interface == n) end)
297 uci_r:foreach("wireless", "wifi-iface",
299 if s.network == n then
300 uci_r:delete("wireless", s['.name'], "network")
307 function rename_network(self, old, new)
309 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
310 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
313 uci_r:foreach("network", "alias",
315 if s.interface == old then
316 uci_r:set("network", s['.name'], "interface", new)
320 uci_r:foreach("network", "route",
322 if s.interface == old then
323 uci_r:set("network", s['.name'], "interface", new)
327 uci_r:foreach("network", "route6",
329 if s.interface == old then
330 uci_r:set("network", s['.name'], "interface", new)
334 uci_r:foreach("wireless", "wifi-iface",
336 if s.network == old then
337 uci_r:set("wireless", s['.name'], "network", new)
341 uci_r:delete("network", old)
347 function get_interface(self, i)
348 if ifs[i] or _wifi_iface(i) then
353 uci_r:foreach("wireless", "wifi-iface",
356 num[s.device] = num[s.device] and num[s.device] + 1 or 1
357 if s['.name'] == i then
359 "%s.network%d" %{s.device, num[s.device] })
368 function get_interfaces(self)
374 -- find normal interfaces
375 uci_r:foreach("network", "interface",
377 for iface in utl.imatch(s.ifname) do
378 if not _iface_ignore(iface) and not _wifi_iface(iface) then
380 nfs[iface] = interface(iface)
385 for iface in utl.kspairs(ifs) do
386 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
387 nfs[iface] = interface(iface)
391 for iface in utl.kspairs(nfs) do
392 ifaces[#ifaces+1] = nfs[iface]
395 -- find wifi interfaces
398 uci_r:foreach("wireless", "wifi-iface",
401 num[s.device] = num[s.device] and num[s.device] + 1 or 1
402 local i = "%s.network%d" %{ s.device, num[s.device] }
403 wfs[i] = interface(i)
407 for iface in utl.kspairs(wfs) do
408 ifaces[#ifaces+1] = wfs[iface]
414 function ignore_interface(self, x)
415 return _iface_ignore(x)
418 function get_wifidev(self, dev)
419 if uci_r:get("wireless", dev) == "wifi-device" then
424 function get_wifidevs(self)
428 uci_r:foreach("wireless", "wifi-device",
429 function(s) wfd[#wfd+1] = s['.name'] end)
432 for _, dev in utl.vspairs(wfd) do
433 devs[#devs+1] = wifidev(dev)
439 function get_wifinet(self, net)
440 local wnet = _wifi_lookup(net)
446 function add_wifinet(self, net, options)
447 if type(options) == "table" and options.device and
448 uci_r:get("wireless", options.device) == "wifi-device"
450 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
455 function del_wifinet(self, net)
456 local wnet = _wifi_lookup(net)
458 uci_r:delete("wireless", wnet)
465 network = utl.class()
467 function network.__init__(self, name)
471 function network._get(self, opt)
472 local v = uci_r:get("network", self.sid, opt)
473 if type(v) == "table" then
474 return table.concat(v, " ")
479 function network._ip(self, opt, family, list)
480 local ip = uci_s:get("network", self.sid, opt)
481 local fc = (family == 6) and ipc.IPv6 or ipc.IPv4
485 for ip in utl.imatch(ip) do
487 if ip then l[#l+1] = ip:string() end
492 return ip and ip:string()
497 function network.get(self, opt)
498 return _get("network", self.sid, opt)
501 function network.set(self, opt, val)
502 return _set("network", self.sid, opt, val)
505 function network.ifname(self)
506 local p = self:proto()
507 if self:is_bridge() then
508 return "br-" .. self.sid
509 elseif self:proto() == "relay" then
510 return uci_s:get("network", self.sid, "up") == "1" and "lo" or nil
511 elseif self:is_virtual() then
512 return p .. "-" .. self.sid
515 local dev = uci_r:get("network", self.sid, "ifname") or
516 uci_s:get("network", self.sid, "ifname")
518 dev = (type(dev) == "table") and dev[1] or dev
519 dev = (dev ~= nil) and dev:match("%S+")
522 uci_r:foreach("wireless", "wifi-iface",
525 num[s.device] = num[s.device]
526 and num[s.device] + 1 or 1
528 if s.network == self.sid then
529 dev = "%s.network%d" %{ s.device, num[s.device] }
540 function network.device(self)
541 local dev = uci_r:get("network", self.sid, "device") or
542 uci_s:get("network", self.sid, "device")
544 dev = (type(dev) == "table") and dev[1] or dev
546 if not dev or dev:match("[^%w%-%.%s]") then
547 dev = uci_r:get("network", self.sid, "ifname") or
548 uci_s:get("network", self.sid, "ifname")
550 dev = (type(dev) == "table") and dev[1] or dev
553 for dev in utl.imatch(dev) do
558 function network.proto(self)
559 return self:_get("proto") or "none"
562 function network.type(self)
563 return self:_get("type")
566 function network.name(self)
570 function network.uptime(self)
571 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
573 return nxo.sysinfo().uptime - cnt
579 function network.expires(self)
580 local a = tonumber(uci_s:get("network", self.sid, "lease_acquired"))
581 local l = tonumber(uci_s:get("network", self.sid, "lease_lifetime"))
583 l = l - (nxo.sysinfo().uptime - a)
584 return l > 0 and l or 0
589 function network.metric(self)
590 return tonumber(uci_s:get("network", self.sid, "metric")) or 0
593 function network.ipaddr(self)
594 return self:_ip("ipaddr", 4)
597 function network.netmask(self)
598 return self:_ip("netmask", 4)
601 function network.gwaddr(self)
602 return self:_ip("gateway", 4)
605 function network.dnsaddrs(self)
606 return self:_ip("dns", 4, true)
609 function network.ip6addr(self)
610 local ip6 = self:_ip("ip6addr", 6)
612 local ifc = ifs[self:ifname()]
613 if ifc and ifc.ip6addrs then
615 for _, a in ipairs(ifc.ip6addrs) do
616 if not a:is6linklocal() then
626 function network.gw6addr(self)
627 local ip6 = self:_ip("ip6gw", 6)
629 local dr6 = sys.net.defaultroute6()
630 if dr6 and dr6.device == self:ifname() then
631 return dr6.nexthop:string()
637 function network.dns6addrs(self)
638 return self:_ip("dns", 6, true)
641 function network.is_bridge(self)
642 return (self:type() == "bridge")
645 function network.is_virtual(self)
646 local p = self:proto()
648 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
649 p == "pppoe" or p == "pppoa" or p == "relay"
653 function network.is_empty(self)
654 if self:is_virtual() then
659 if (self:_get("ifname") or ""):match("%S+") then
663 uci_r:foreach("wireless", "wifi-iface",
665 if s.network == self.sid then
675 function network.add_interface(self, ifname)
676 if not self:is_virtual() then
677 if type(ifname) ~= "string" then
678 ifname = ifname:name()
680 ifname = ifname:match("[^%s:]+")
683 -- remove the interface from all ifaces
684 uci_r:foreach("network", "interface",
686 _list_del("network", s['.name'], "ifname", ifname)
689 -- if its a wifi interface, change its network option
690 local wif = _wifi_lookup(ifname)
692 uci_r:set("wireless", wif, "network", self.sid)
694 -- add iface to our iface list
696 _list_add("network", self.sid, "ifname", ifname)
701 function network.del_interface(self, ifname)
702 if not self:is_virtual() then
703 if utl.instanceof(ifname, interface) then
704 ifname = ifname:name()
706 ifname = ifname:match("[^%s:]+")
709 -- if its a wireless interface, clear its network option
710 local wif = _wifi_lookup(ifname)
711 if wif then uci_r:delete("wireless", wif, "network") end
713 -- remove the interface
714 _list_del("network", self.sid, "ifname", ifname)
718 function network.get_interfaces(self)
722 if self:is_virtual() then
723 ifn = self:proto() .. "-" .. self.sid
724 ifaces = { interface(ifn) }
727 for ifn in utl.imatch(self:get("ifname")) do
728 ifn = ifn:match("[^:]+")
729 nfs[ifn] = interface(ifn)
732 for ifn in utl.kspairs(nfs) do
733 ifaces[#ifaces+1] = nfs[ifn]
738 uci_r:foreach("wireless", "wifi-iface",
741 num[s.device] = num[s.device] and num[s.device] + 1 or 1
742 if s.network == self.sid then
743 ifn = "%s.network%d" %{ s.device, num[s.device] }
744 wfs[ifn] = interface(ifn)
749 for ifn in utl.kspairs(wfs) do
750 ifaces[#ifaces+1] = wfs[ifn]
757 function network.contains_interface(self, ifname)
758 if type(ifname) ~= "string" then
759 ifname = ifname:name()
761 ifname = ifname:match("[^%s:]+")
765 if self:is_virtual() then
766 ifn = self:proto() .. "-" .. self.sid
769 for ifn in utl.imatch(self:get("ifname")) do
770 ifn = ifn:match("[^:]+")
771 if ifn == ifname then
776 local wif = _wifi_lookup(ifname)
778 return (uci_r:get("wireless", wif, "network") == self.sid)
785 function network.adminlink(self)
786 return dsp.build_url("admin", "network", "network", self.sid)
790 interface = utl.class()
791 function interface.__init__(self, ifname)
792 local wif = _wifi_lookup(ifname)
793 if wif then self.wif = wifinet(wif) end
795 self.ifname = self.ifname or ifname
796 self.dev = ifs[self.ifname]
799 function interface.name(self)
800 return self.wif and self.wif:ifname() or self.ifname
803 function interface.mac(self)
804 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
807 function interface.ipaddrs(self)
808 return self.dev and self.dev.ipaddrs or { }
811 function interface.ip6addrs(self)
812 return self.dev and self.dev.ip6addrs or { }
815 function interface.type(self)
816 if self.wif or _wifi_iface(self.ifname) then
818 elseif brs[self.ifname] then
820 elseif sws[self.ifname] or self.ifname:match("%.") then
827 function interface.shortname(self)
830 self.wif:active_mode(),
831 self.wif:active_ssid() or self.wif:active_bssid()
838 function interface.get_i18n(self)
840 return "%s: %s %q" %{
841 i18n.translate("Wireless Network"),
842 self.wif:active_mode(),
843 self.wif:active_ssid() or self.wif:active_bssid()
846 return "%s: %q" %{ self:get_type_i18n(), self:name() }
850 function interface.get_type_i18n(self)
851 local x = self:type()
853 return i18n.translate("Wireless Adapter")
854 elseif x == "bridge" then
855 return i18n.translate("Bridge")
856 elseif x == "switch" then
857 return i18n.translate("Ethernet Switch")
859 return i18n.translate("Ethernet Adapter")
863 function interface.adminlink(self)
865 return self.wif:adminlink()
869 function interface.ports(self)
873 for _, iface in ipairs(self.br.ifnames) do
874 ifaces[#ifaces+1] = interface(iface.name)
880 function interface.bridge_id(self)
888 function interface.bridge_stp(self)
896 function interface.is_up(self)
898 return self.wif:is_up()
900 return self.dev and self.dev.flags and self.dev.flags.up or false
904 function interface.is_bridge(self)
905 return (self:type() == "bridge")
908 function interface.is_bridgeport(self)
909 return self.dev and self.dev.bridge and true or false
912 function interface.tx_bytes(self)
913 return self.dev and self.dev.stats
914 and self.dev.stats.tx_bytes or 0
917 function interface.rx_bytes(self)
918 return self.dev and self.dev.stats
919 and self.dev.stats.rx_bytes or 0
922 function interface.tx_packets(self)
923 return self.dev and self.dev.stats
924 and self.dev.stats.tx_packets or 0
927 function interface.rx_packets(self)
928 return self.dev and self.dev.stats
929 and self.dev.stats.rx_packets or 0
932 function interface.get_network(self)
933 if self.dev and self.dev.network then
934 self.network = _M:get_network(self.dev.network)
937 if not self.network then
939 for _, net in ipairs(_M:get_networks()) do
940 if net:contains_interface(self.ifname) or
941 net:ifname() == self.ifname
952 function interface.get_wifinet(self)
957 wifidev = utl.class()
958 function wifidev.__init__(self, dev)
960 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
963 function wifidev.get(self, opt)
964 return _get("wireless", self.sid, opt)
967 function wifidev.set(self, opt, val)
968 return _set("wireless", self.sid, opt, val)
971 function wifidev.name(self)
975 function wifidev.hwmodes(self)
976 local l = self.iwinfo.hwmodelist
977 if l and next(l) then
980 return { b = true, g = true }
984 function wifidev.get_i18n(self)
986 if self.iwinfo.type == "wl" then
988 elseif self.iwinfo.type == "madwifi" then
993 local l = self:hwmodes()
994 if l.a then m = m .. "a" end
995 if l.b then m = m .. "b" end
996 if l.g then m = m .. "g" end
997 if l.n then m = m .. "n" end
999 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1002 function wifidev.is_up(self)
1005 uci_s:foreach("wireless", "wifi-iface",
1007 if s.device == self.sid then
1018 function wifidev.get_wifinet(self, net)
1019 if uci_r:get("wireless", net) == "wifi-iface" then
1022 local wnet = _wifi_lookup(net)
1024 return wifinet(wnet)
1029 function wifidev.get_wifinets(self)
1032 uci_r:foreach("wireless", "wifi-iface",
1034 if s.device == self.sid then
1035 nets[#nets+1] = wifinet(s['.name'])
1042 function wifidev.add_wifinet(self, options)
1043 options = options or { }
1044 options.device = self.sid
1046 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1048 return wifinet(wnet, options)
1052 function wifidev.del_wifinet(self, net)
1053 if utl.instanceof(net, wifinet) then
1055 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1056 net = _wifi_lookup(net)
1059 if net and uci_r:get("wireless", net, "device") == self.sid then
1060 uci_r:delete("wireless", net)
1068 wifinet = utl.class()
1069 function wifinet.__init__(self, net, data)
1074 uci_r:foreach("wireless", "wifi-iface",
1077 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1078 if s['.name'] == self.sid then
1079 netid = "%s.network%d" %{ s.device, num[s.device] }
1085 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1089 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1090 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1091 uci_r:get_all("wireless", self.sid) or { }
1094 function wifinet.get(self, opt)
1095 return _get("wireless", self.sid, opt)
1098 function wifinet.set(self, opt, val)
1099 return _set("wireless", self.sid, opt, val)
1102 function wifinet.mode(self)
1103 return uci_s:get("wireless", self.sid, "mode") or "ap"
1106 function wifinet.ssid(self)
1107 return uci_s:get("wireless", self.sid, "ssid")
1110 function wifinet.bssid(self)
1111 return uci_s:get("wireless", self.sid, "bssid")
1114 function wifinet.network(self)
1115 return uci_s:get("wifinet", self.sid, "network")
1118 function wifinet.name(self)
1122 function wifinet.ifname(self)
1123 local ifname = self.iwinfo.ifname
1124 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1130 function wifinet.get_device(self)
1131 if self.iwdata.device then
1132 return wifidev(self.iwdata.device)
1136 function wifinet.is_up(self)
1137 return (self.iwdata.up == "1")
1140 function wifinet.active_mode(self)
1141 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1143 if m == "ap" then m = "Master"
1144 elseif m == "sta" then m = "Client"
1145 elseif m == "adhoc" then m = "Ad-Hoc"
1146 elseif m == "mesh" then m = "Mesh"
1147 elseif m == "monitor" then m = "Monitor"
1153 function wifinet.active_mode_i18n(self)
1154 return i18n.translate(self:active_mode())
1157 function wifinet.active_ssid(self)
1158 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1161 function wifinet.active_bssid(self)
1162 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1165 function wifinet.active_encryption(self)
1166 local enc = self.iwinfo and self.iwinfo.encryption
1167 return enc and enc.description or "-"
1170 function wifinet.assoclist(self)
1171 return self.iwinfo.assoclist or { }
1174 function wifinet.frequency(self)
1175 local freq = self.iwinfo.frequency
1176 if freq and freq > 0 then
1177 return "%.03f" % (freq / 1000)
1181 function wifinet.bitrate(self)
1182 local rate = self.iwinfo.bitrate
1183 if rate and rate > 0 then
1184 return (rate / 1000)
1188 function wifinet.channel(self)
1189 return self.iwinfo.channel or
1190 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1193 function wifinet.signal(self)
1194 return self.iwinfo.signal or 0
1197 function wifinet.noise(self)
1198 return self.iwinfo.noise or 0
1201 function wifinet.signal_level(self, s, n)
1202 if self:active_bssid() ~= "00:00:00:00:00:00" then
1203 local signal = s or self:signal()
1204 local noise = n or self:noise()
1206 if signal < 0 and noise < 0 then
1207 local snr = -1 * (noise - signal)
1208 return math.floor(snr / 5)
1217 function wifinet.signal_percent(self)
1218 local qc = self.iwinfo.quality or 0
1219 local qm = self.iwinfo.quality_max or 0
1221 if qc > 0 and qm > 0 then
1222 return math.floor((100 / qm) * qc)
1228 function wifinet.shortname(self)
1230 i18n.translate(self:active_mode()),
1231 self:active_ssid() or self:active_bssid()
1235 function wifinet.get_i18n(self)
1236 return "%s: %s %q (%s)" %{
1237 i18n.translate("Wireless Network"),
1238 i18n.translate(self:active_mode()),
1239 self:active_ssid() or self:active_bssid(),
1244 function wifinet.adminlink(self)
1245 return dsp.build_url("admin", "network", "wireless", self.netid)
1248 function wifinet.get_network(self)
1249 if uci_r:get("network", self.iwdata.network) == "interface" then
1250 return network(self.iwdata.network)
1254 function wifinet.get_interface(self)
1255 return interface(self:ifname())