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 local oldnet = self:get_network(n)
246 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
247 if uci_r:section("network", "interface", n, options) then
250 elseif oldnet and oldnet:is_empty() then
253 for k, v in pairs(options) do
261 function get_network(self, n)
262 if n and uci_r:get("network", n) == "interface" then
267 function get_networks(self)
271 uci_r:foreach("network", "interface",
273 nls[s['.name']] = network(s['.name'])
277 for n in utl.kspairs(nls) do
278 nets[#nets+1] = nls[n]
284 function del_network(self, n)
285 local r = uci_r:delete("network", n)
287 uci_r:delete_all("network", "alias",
288 function(s) return (s.interface == n) end)
290 uci_r:delete_all("network", "route",
291 function(s) return (s.interface == n) end)
293 uci_r:delete_all("network", "route6",
294 function(s) return (s.interface == n) end)
296 uci_r:foreach("wireless", "wifi-iface",
298 if s.network == n then
299 uci_r:delete("wireless", s['.name'], "network")
306 function rename_network(self, old, new)
308 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
309 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
312 uci_r:foreach("network", "alias",
314 if s.interface == old then
315 uci_r:set("network", s['.name'], "interface", new)
319 uci_r:foreach("network", "route",
321 if s.interface == old then
322 uci_r:set("network", s['.name'], "interface", new)
326 uci_r:foreach("network", "route6",
328 if s.interface == old then
329 uci_r:set("network", s['.name'], "interface", new)
333 uci_r:foreach("wireless", "wifi-iface",
335 if s.network == old then
336 uci_r:set("wireless", s['.name'], "network", new)
340 uci_r:delete("network", old)
346 function get_interface(self, i)
347 if ifs[i] or _wifi_iface(i) then
352 uci_r:foreach("wireless", "wifi-iface",
355 num[s.device] = num[s.device] and num[s.device] + 1 or 1
356 if s['.name'] == i then
358 "%s.network%d" %{s.device, num[s.device] })
367 function get_interfaces(self)
373 -- find normal interfaces
374 uci_r:foreach("network", "interface",
376 for iface in utl.imatch(s.ifname) do
377 if not _iface_ignore(iface) and not _wifi_iface(iface) then
379 nfs[iface] = interface(iface)
384 for iface in utl.kspairs(ifs) do
385 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
386 nfs[iface] = interface(iface)
390 for iface in utl.kspairs(nfs) do
391 ifaces[#ifaces+1] = nfs[iface]
394 -- find wifi interfaces
397 uci_r:foreach("wireless", "wifi-iface",
400 num[s.device] = num[s.device] and num[s.device] + 1 or 1
401 local i = "%s.network%d" %{ s.device, num[s.device] }
402 wfs[i] = interface(i)
406 for iface in utl.kspairs(wfs) do
407 ifaces[#ifaces+1] = wfs[iface]
413 function ignore_interface(self, x)
414 return _iface_ignore(x)
417 function get_wifidev(self, dev)
418 if uci_r:get("wireless", dev) == "wifi-device" then
423 function get_wifidevs(self)
427 uci_r:foreach("wireless", "wifi-device",
428 function(s) wfd[#wfd+1] = s['.name'] end)
431 for _, dev in utl.vspairs(wfd) do
432 devs[#devs+1] = wifidev(dev)
438 function get_wifinet(self, net)
439 local wnet = _wifi_lookup(net)
445 function add_wifinet(self, net, options)
446 if type(options) == "table" and options.device and
447 uci_r:get("wireless", options.device) == "wifi-device"
449 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
454 function del_wifinet(self, net)
455 local wnet = _wifi_lookup(net)
457 uci_r:delete("wireless", wnet)
464 network = utl.class()
466 function network.__init__(self, name)
470 function network._get(self, opt)
471 local v = uci_r:get("network", self.sid, opt)
472 if type(v) == "table" then
473 return table.concat(v, " ")
478 function network._ip(self, opt, family, list)
479 local ip = uci_s:get("network", self.sid, opt)
480 local fc = (family == 6) and ipc.IPv6 or ipc.IPv4
484 for ip in utl.imatch(ip) do
486 if ip then l[#l+1] = ip:string() end
491 return ip and ip:string()
496 function network.get(self, opt)
497 return _get("network", self.sid, opt)
500 function network.set(self, opt, val)
501 return _set("network", self.sid, opt, val)
504 function network.ifname(self)
505 local p = self:proto()
506 if self:is_bridge() then
507 return "br-" .. self.sid
508 elseif self:is_virtual() then
509 return p .. "-" .. self.sid
512 local dev = uci_r:get("network", self.sid, "ifname") or
513 uci_s:get("network", self.sid, "ifname")
515 dev = (type(dev) == "table") and dev[1] or dev
516 dev = (dev ~= nil) and dev:match("%S+")
519 uci_r:foreach("wireless", "wifi-iface",
522 num[s.device] = num[s.device]
523 and num[s.device] + 1 or 1
525 if s.network == self.sid then
526 dev = "%s.network%d" %{ s.device, num[s.device] }
537 function network.device(self)
538 local dev = uci_r:get("network", self.sid, "device") or
539 uci_s:get("network", self.sid, "device")
541 dev = (type(dev) == "table") and dev[1] or dev
543 if not dev or dev:match("[^%w%-%.%s]") then
544 dev = uci_r:get("network", self.sid, "ifname") or
545 uci_s:get("network", self.sid, "ifname")
547 dev = (type(dev) == "table") and dev[1] or dev
553 function network.proto(self)
554 return self:_get("proto") or "none"
557 function network.type(self)
558 return self:_get("type")
561 function network.name(self)
565 function network.uptime(self)
566 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
568 return nxo.sysinfo().uptime - cnt
574 function network.expires(self)
575 local a = tonumber(uci_s:get("network", self.sid, "lease_acquired"))
576 local l = tonumber(uci_s:get("network", self.sid, "lease_lifetime"))
578 l = l - (nxo.sysinfo().uptime - a)
579 return l > 0 and l or 0
584 function network.metric(self)
585 return tonumber(uci_s:get("network", self.sid, "metric")) or 0
588 function network.ipaddr(self)
589 return self:_ip("ipaddr", 4)
592 function network.netmask(self)
593 return self:_ip("netmask", 4)
596 function network.gwaddr(self)
597 return self:_ip("gateway", 4)
600 function network.dnsaddrs(self)
601 return self:_ip("dns", 4, true)
604 function network.ip6addr(self)
605 local ip6 = self:_ip("ip6addr", 6)
607 local ifc = ifs[self:ifname()]
608 local llr = ipc.IPv6("fe80::/10")
609 if ifc and ifc.ip6addrs then
611 for _, a in ipairs(ifc.ip6addrs) do
612 if not llr:contains(a) then
622 function network.gw6addr(self)
623 local ip6 = self:_ip("ip6gw", 6)
625 local dr6 = sys.net.defaultroute6()
626 if dr6 and dr6.device == self:ifname() then
627 return dr6.nexthop:string()
633 function network.dns6addrs(self)
634 return self:_ip("dns", 6, true)
637 function network.is_bridge(self)
638 return (self:type() == "bridge")
641 function network.is_virtual(self)
642 local p = self:proto()
644 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
645 p == "pppoe" or p == "pppoa"
649 function network.is_empty(self)
650 if self:is_virtual() then
655 if (self:_get("ifname") or ""):match("%S+") then
659 uci_r:foreach("wireless", "wifi-iface",
661 if s.network == self.sid then
671 function network.add_interface(self, ifname)
672 if not self:is_virtual() then
673 if type(ifname) ~= "string" then
674 ifname = ifname:name()
676 ifname = ifname:match("[^%s:]+")
679 -- remove the interface from all ifaces
680 uci_r:foreach("network", "interface",
682 _list_del("network", s['.name'], "ifname", ifname)
685 -- if its a wifi interface, change its network option
686 local wif = _wifi_lookup(ifname)
688 uci_r:set("wireless", wif, "network", self.sid)
690 -- add iface to our iface list
692 _list_add("network", self.sid, "ifname", ifname)
697 function network.del_interface(self, ifname)
698 if not self:is_virtual() then
699 if utl.instanceof(ifname, interface) then
700 ifname = ifname:name()
702 ifname = ifname:match("[^%s:]+")
705 -- if its a wireless interface, clear its network option
706 local wif = _wifi_lookup(ifname)
707 if wif then uci_r:delete("wireless", wif, "network") end
709 -- remove the interface
710 _list_del("network", self.sid, "ifname", ifname)
714 function network.get_interfaces(self)
718 if self:is_virtual() then
719 ifn = self:proto() .. "-" .. self.sid
720 ifaces = { interface(ifn) }
723 for ifn in utl.imatch(self:get("ifname")) do
724 ifn = ifn:match("[^:]+")
725 nfs[ifn] = interface(ifn)
728 for ifn in utl.kspairs(nfs) do
729 ifaces[#ifaces+1] = nfs[ifn]
734 uci_r:foreach("wireless", "wifi-iface",
737 num[s.device] = num[s.device] and num[s.device] + 1 or 1
738 if s.network == self.sid then
739 ifn = "%s.network%d" %{ s.device, num[s.device] }
740 wfs[ifn] = interface(ifn)
745 for ifn in utl.kspairs(wfs) do
746 ifaces[#ifaces+1] = wfs[ifn]
753 function network.contains_interface(self, ifname)
754 if type(ifname) ~= "string" then
755 ifname = ifname:name()
757 ifname = ifname:match("[^%s:]+")
761 if self:is_virtual() then
762 ifn = self:proto() .. "-" .. self.sid
765 for ifn in utl.imatch(self:get("ifname")) do
766 ifn = ifn:match("[^:]+")
767 if ifn == ifname then
772 local wif = _wifi_lookup(ifname)
774 return (uci_r:get("wireless", wif, "network") == self.sid)
781 function network.adminlink(self)
782 return dsp.build_url("admin", "network", "network", self.sid)
786 interface = utl.class()
787 function interface.__init__(self, ifname)
788 local wif = _wifi_lookup(ifname)
789 if wif then self.wif = wifinet(wif) end
791 self.ifname = self.ifname or ifname
792 self.dev = ifs[self.ifname]
795 function interface.name(self)
796 return self.wif and self.wif:ifname() or self.ifname
799 function interface.mac(self)
800 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
803 function interface.ipaddrs(self)
804 return self.dev and self.dev.ipaddrs or { }
807 function interface.ip6addrs(self)
808 return self.dev and self.dev.ip6addrs or { }
811 function interface.type(self)
812 if self.wif or _wifi_iface(self.ifname) then
814 elseif brs[self.ifname] then
816 elseif sws[self.ifname] or self.ifname:match("%.") then
823 function interface.shortname(self)
826 self.wif:active_mode(),
827 self.wif:active_ssid() or self.wif:active_bssid()
834 function interface.get_i18n(self)
836 return "%s: %s %q" %{
837 i18n.translate("Wireless Network"),
838 self.wif:active_mode(),
839 self.wif:active_ssid() or self.wif:active_bssid()
842 return "%s: %q" %{ self:get_type_i18n(), self:name() }
846 function interface.get_type_i18n(self)
847 local x = self:type()
849 return i18n.translate("Wireless Adapter")
850 elseif x == "bridge" then
851 return i18n.translate("Bridge")
852 elseif x == "switch" then
853 return i18n.translate("Ethernet Switch")
855 return i18n.translate("Ethernet Adapter")
859 function interface.adminlink(self)
861 return self.wif:adminlink()
865 function interface.ports(self)
869 for _, iface in ipairs(self.br.ifnames) do
870 ifaces[#ifaces+1] = interface(iface.name)
876 function interface.bridge_id(self)
884 function interface.bridge_stp(self)
892 function interface.is_up(self)
894 return self.wif:is_up()
896 return self.dev and self.dev.flags and self.dev.flags.up or false
900 function interface.is_bridge(self)
901 return (self:type() == "bridge")
904 function interface.is_bridgeport(self)
905 return self.dev and self.dev.bridge and true or false
908 function interface.tx_bytes(self)
909 return self.dev and self.dev.stats
910 and self.dev.stats.tx_bytes or 0
913 function interface.rx_bytes(self)
914 return self.dev and self.dev.stats
915 and self.dev.stats.rx_bytes or 0
918 function interface.tx_packets(self)
919 return self.dev and self.dev.stats
920 and self.dev.stats.tx_packets or 0
923 function interface.rx_packets(self)
924 return self.dev and self.dev.stats
925 and self.dev.stats.rx_packets or 0
928 function interface.get_network(self)
929 if self.dev and self.dev.network then
930 self.network = _M:get_network(self.dev.network)
933 if not self.network then
935 for _, net in ipairs(_M:get_networks()) do
936 if net:contains_interface(self.ifname) or
937 net:ifname() == self.ifname
948 function interface.get_wifinet(self)
953 wifidev = utl.class()
954 function wifidev.__init__(self, dev)
958 function wifidev.get(self, opt)
959 return _get("wireless", self.sid, opt)
962 function wifidev.set(self, opt, val)
963 return _set("wireless", self.sid, opt, val)
966 function wifidev.name(self)
970 function wifidev.is_up(self)
973 uci_s:foreach("wireless", "wifi-iface",
975 if s.device == self.sid then
986 function wifidev.get_wifinet(self, net)
987 if uci_r:get("wireless", net) == "wifi-iface" then
990 local wnet = _wifi_lookup(net)
997 function wifidev.get_wifinets(self)
1000 uci_r:foreach("wireless", "wifi-iface",
1002 if s.device == self.sid then
1003 nets[#nets+1] = wifinet(s['.name'])
1010 function wifidev.add_wifinet(self, options)
1011 options = options or { }
1012 options.device = self.sid
1014 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1016 return wifinet(wnet, options)
1020 function wifidev.del_wifinet(self, net)
1021 if utl.instanceof(net, wifinet) then
1023 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1024 net = _wifi_lookup(net)
1027 if net and uci_r:get("wireless", net, "device") == self.sid then
1028 uci_r:delete("wireless", net)
1036 wifinet = utl.class()
1037 function wifinet.__init__(self, net, data)
1042 uci_r:foreach("wireless", "wifi-iface",
1045 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1046 if s['.name'] == self.sid then
1047 netid = "%s.network%d" %{ s.device, num[s.device] }
1053 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1057 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1058 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1059 uci_r:get_all("wireless", self.sid) or { }
1062 function wifinet.get(self, opt)
1063 return _get("wireless", self.sid, opt)
1066 function wifinet.set(self, opt, val)
1067 return _set("wireless", self.sid, opt, val)
1070 function wifinet.mode(self)
1071 return uci_s:get("wireless", self.sid, "mode") or "ap"
1074 function wifinet.ssid(self)
1075 return uci_s:get("wireless", self.sid, "ssid")
1078 function wifinet.bssid(self)
1079 return uci_s:get("wireless", self.sid, "bssid")
1082 function wifinet.network(self)
1083 return uci_s:get("wifinet", self.sid, "network")
1086 function wifinet.name(self)
1090 function wifinet.ifname(self)
1091 local ifname = self.iwinfo.ifname
1092 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1098 function wifinet.get_device(self)
1099 if self.iwdata.device then
1100 return wifidev(self.iwdata.device)
1104 function wifinet.is_up(self)
1105 return (self.iwdata.up == "1")
1108 function wifinet.active_mode(self)
1109 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1111 if m == "ap" then m = "Master"
1112 elseif m == "sta" then m = "Client"
1113 elseif m == "adhoc" then m = "Ad-Hoc"
1114 elseif m == "mesh" then m = "Mesh"
1115 elseif m == "monitor" then m = "Monitor"
1121 function wifinet.active_mode_i18n(self)
1122 return i18n.translate(self:active_mode())
1125 function wifinet.active_ssid(self)
1126 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1129 function wifinet.active_bssid(self)
1130 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1133 function wifinet.active_encryption(self)
1134 local enc = self.iwinfo and self.iwinfo.encryption
1135 return enc and enc.description or "-"
1138 function wifinet.assoclist(self)
1139 return self.iwinfo.assoclist or { }
1142 function wifinet.frequency(self)
1143 local freq = self.iwinfo.frequency
1144 if freq and freq > 0 then
1145 return "%.03f" % (freq / 1000)
1149 function wifinet.bitrate(self)
1150 local rate = self.iwinfo.bitrate
1151 if rate and rate > 0 then
1152 return (rate / 1000)
1156 function wifinet.channel(self)
1157 return self.iwinfo.channel or
1158 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1161 function wifinet.signal(self)
1162 return self.iwinfo.signal or 0
1165 function wifinet.noise(self)
1166 return self.iwinfo.noise or 0
1169 function wifinet.signal_level(self, s, n)
1170 if self:active_bssid() ~= "00:00:00:00:00:00" then
1171 local signal = s or self:signal()
1172 local noise = n or self:noise()
1174 if signal < 0 and noise < 0 then
1175 local snr = -1 * (noise - signal)
1176 return math.floor(snr / 5)
1185 function wifinet.signal_percent(self)
1186 local qc = self.iwinfo.quality or 0
1187 local qm = self.iwinfo.quality_max or 0
1189 if qc > 0 and qm > 0 then
1190 return math.floor((100 / qm) * qc)
1196 function wifinet.shortname(self)
1198 i18n.translate(self:active_mode()),
1199 self:active_ssid() or self:active_bssid()
1203 function wifinet.get_i18n(self)
1204 return "%s: %s %q (%s)" %{
1205 i18n.translate("Wireless Network"),
1206 i18n.translate(self:active_mode()),
1207 self:active_ssid() or self:active_bssid(),
1212 function wifinet.adminlink(self)
1213 return dsp.build_url("admin", "network", "wireless", self.netid)
1216 function wifinet.get_network(self)
1217 if uci_r:get("network", self.iwdata.network) == "interface" then
1218 return network(self.iwdata.network)
1222 function wifinet.get_interface(self)
1223 return interface(self:ifname())