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 if ifc and ifc.ip6addrs then
610 for _, a in ipairs(ifc.ip6addrs) do
611 if not a:is6linklocal() then
621 function network.gw6addr(self)
622 local ip6 = self:_ip("ip6gw", 6)
624 local dr6 = sys.net.defaultroute6()
625 if dr6 and dr6.device == self:ifname() then
626 return dr6.nexthop:string()
632 function network.dns6addrs(self)
633 return self:_ip("dns", 6, true)
636 function network.is_bridge(self)
637 return (self:type() == "bridge")
640 function network.is_virtual(self)
641 local p = self:proto()
643 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
644 p == "pppoe" or p == "pppoa"
648 function network.is_empty(self)
649 if self:is_virtual() then
654 if (self:_get("ifname") or ""):match("%S+") then
658 uci_r:foreach("wireless", "wifi-iface",
660 if s.network == self.sid then
670 function network.add_interface(self, ifname)
671 if not self:is_virtual() then
672 if type(ifname) ~= "string" then
673 ifname = ifname:name()
675 ifname = ifname:match("[^%s:]+")
678 -- remove the interface from all ifaces
679 uci_r:foreach("network", "interface",
681 _list_del("network", s['.name'], "ifname", ifname)
684 -- if its a wifi interface, change its network option
685 local wif = _wifi_lookup(ifname)
687 uci_r:set("wireless", wif, "network", self.sid)
689 -- add iface to our iface list
691 _list_add("network", self.sid, "ifname", ifname)
696 function network.del_interface(self, ifname)
697 if not self:is_virtual() then
698 if utl.instanceof(ifname, interface) then
699 ifname = ifname:name()
701 ifname = ifname:match("[^%s:]+")
704 -- if its a wireless interface, clear its network option
705 local wif = _wifi_lookup(ifname)
706 if wif then uci_r:delete("wireless", wif, "network") end
708 -- remove the interface
709 _list_del("network", self.sid, "ifname", ifname)
713 function network.get_interfaces(self)
717 if self:is_virtual() then
718 ifn = self:proto() .. "-" .. self.sid
719 ifaces = { interface(ifn) }
722 for ifn in utl.imatch(self:get("ifname")) do
723 ifn = ifn:match("[^:]+")
724 nfs[ifn] = interface(ifn)
727 for ifn in utl.kspairs(nfs) do
728 ifaces[#ifaces+1] = nfs[ifn]
733 uci_r:foreach("wireless", "wifi-iface",
736 num[s.device] = num[s.device] and num[s.device] + 1 or 1
737 if s.network == self.sid then
738 ifn = "%s.network%d" %{ s.device, num[s.device] }
739 wfs[ifn] = interface(ifn)
744 for ifn in utl.kspairs(wfs) do
745 ifaces[#ifaces+1] = wfs[ifn]
752 function network.contains_interface(self, ifname)
753 if type(ifname) ~= "string" then
754 ifname = ifname:name()
756 ifname = ifname:match("[^%s:]+")
760 if self:is_virtual() then
761 ifn = self:proto() .. "-" .. self.sid
764 for ifn in utl.imatch(self:get("ifname")) do
765 ifn = ifn:match("[^:]+")
766 if ifn == ifname then
771 local wif = _wifi_lookup(ifname)
773 return (uci_r:get("wireless", wif, "network") == self.sid)
780 function network.adminlink(self)
781 return dsp.build_url("admin", "network", "network", self.sid)
785 interface = utl.class()
786 function interface.__init__(self, ifname)
787 local wif = _wifi_lookup(ifname)
788 if wif then self.wif = wifinet(wif) end
790 self.ifname = self.ifname or ifname
791 self.dev = ifs[self.ifname]
794 function interface.name(self)
795 return self.wif and self.wif:ifname() or self.ifname
798 function interface.mac(self)
799 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
802 function interface.ipaddrs(self)
803 return self.dev and self.dev.ipaddrs or { }
806 function interface.ip6addrs(self)
807 return self.dev and self.dev.ip6addrs or { }
810 function interface.type(self)
811 if self.wif or _wifi_iface(self.ifname) then
813 elseif brs[self.ifname] then
815 elseif sws[self.ifname] or self.ifname:match("%.") then
822 function interface.shortname(self)
825 self.wif:active_mode(),
826 self.wif:active_ssid() or self.wif:active_bssid()
833 function interface.get_i18n(self)
835 return "%s: %s %q" %{
836 i18n.translate("Wireless Network"),
837 self.wif:active_mode(),
838 self.wif:active_ssid() or self.wif:active_bssid()
841 return "%s: %q" %{ self:get_type_i18n(), self:name() }
845 function interface.get_type_i18n(self)
846 local x = self:type()
848 return i18n.translate("Wireless Adapter")
849 elseif x == "bridge" then
850 return i18n.translate("Bridge")
851 elseif x == "switch" then
852 return i18n.translate("Ethernet Switch")
854 return i18n.translate("Ethernet Adapter")
858 function interface.adminlink(self)
860 return self.wif:adminlink()
864 function interface.ports(self)
868 for _, iface in ipairs(self.br.ifnames) do
869 ifaces[#ifaces+1] = interface(iface.name)
875 function interface.bridge_id(self)
883 function interface.bridge_stp(self)
891 function interface.is_up(self)
893 return self.wif:is_up()
895 return self.dev and self.dev.flags and self.dev.flags.up or false
899 function interface.is_bridge(self)
900 return (self:type() == "bridge")
903 function interface.is_bridgeport(self)
904 return self.dev and self.dev.bridge and true or false
907 function interface.tx_bytes(self)
908 return self.dev and self.dev.stats
909 and self.dev.stats.tx_bytes or 0
912 function interface.rx_bytes(self)
913 return self.dev and self.dev.stats
914 and self.dev.stats.rx_bytes or 0
917 function interface.tx_packets(self)
918 return self.dev and self.dev.stats
919 and self.dev.stats.tx_packets or 0
922 function interface.rx_packets(self)
923 return self.dev and self.dev.stats
924 and self.dev.stats.rx_packets or 0
927 function interface.get_network(self)
928 if self.dev and self.dev.network then
929 self.network = _M:get_network(self.dev.network)
932 if not self.network then
934 for _, net in ipairs(_M:get_networks()) do
935 if net:contains_interface(self.ifname) or
936 net:ifname() == self.ifname
947 function interface.get_wifinet(self)
952 wifidev = utl.class()
953 function wifidev.__init__(self, dev)
957 function wifidev.get(self, opt)
958 return _get("wireless", self.sid, opt)
961 function wifidev.set(self, opt, val)
962 return _set("wireless", self.sid, opt, val)
965 function wifidev.name(self)
969 function wifidev.is_up(self)
972 uci_s:foreach("wireless", "wifi-iface",
974 if s.device == self.sid then
985 function wifidev.get_wifinet(self, net)
986 if uci_r:get("wireless", net) == "wifi-iface" then
989 local wnet = _wifi_lookup(net)
996 function wifidev.get_wifinets(self)
999 uci_r:foreach("wireless", "wifi-iface",
1001 if s.device == self.sid then
1002 nets[#nets+1] = wifinet(s['.name'])
1009 function wifidev.add_wifinet(self, options)
1010 options = options or { }
1011 options.device = self.sid
1013 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1015 return wifinet(wnet, options)
1019 function wifidev.del_wifinet(self, net)
1020 if utl.instanceof(net, wifinet) then
1022 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1023 net = _wifi_lookup(net)
1026 if net and uci_r:get("wireless", net, "device") == self.sid then
1027 uci_r:delete("wireless", net)
1035 wifinet = utl.class()
1036 function wifinet.__init__(self, net, data)
1041 uci_r:foreach("wireless", "wifi-iface",
1044 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1045 if s['.name'] == self.sid then
1046 netid = "%s.network%d" %{ s.device, num[s.device] }
1052 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1056 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1057 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1058 uci_r:get_all("wireless", self.sid) or { }
1061 function wifinet.get(self, opt)
1062 return _get("wireless", self.sid, opt)
1065 function wifinet.set(self, opt, val)
1066 return _set("wireless", self.sid, opt, val)
1069 function wifinet.mode(self)
1070 return uci_s:get("wireless", self.sid, "mode") or "ap"
1073 function wifinet.ssid(self)
1074 return uci_s:get("wireless", self.sid, "ssid")
1077 function wifinet.bssid(self)
1078 return uci_s:get("wireless", self.sid, "bssid")
1081 function wifinet.network(self)
1082 return uci_s:get("wifinet", self.sid, "network")
1085 function wifinet.name(self)
1089 function wifinet.ifname(self)
1090 local ifname = self.iwinfo.ifname
1091 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1097 function wifinet.get_device(self)
1098 if self.iwdata.device then
1099 return wifidev(self.iwdata.device)
1103 function wifinet.is_up(self)
1104 return (self.iwdata.up == "1")
1107 function wifinet.active_mode(self)
1108 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1110 if m == "ap" then m = "Master"
1111 elseif m == "sta" then m = "Client"
1112 elseif m == "adhoc" then m = "Ad-Hoc"
1113 elseif m == "mesh" then m = "Mesh"
1114 elseif m == "monitor" then m = "Monitor"
1120 function wifinet.active_mode_i18n(self)
1121 return i18n.translate(self:active_mode())
1124 function wifinet.active_ssid(self)
1125 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1128 function wifinet.active_bssid(self)
1129 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1132 function wifinet.active_encryption(self)
1133 local enc = self.iwinfo and self.iwinfo.encryption
1134 return enc and enc.description or "-"
1137 function wifinet.assoclist(self)
1138 return self.iwinfo.assoclist or { }
1141 function wifinet.frequency(self)
1142 local freq = self.iwinfo.frequency
1143 if freq and freq > 0 then
1144 return "%.03f" % (freq / 1000)
1148 function wifinet.bitrate(self)
1149 local rate = self.iwinfo.bitrate
1150 if rate and rate > 0 then
1151 return (rate / 1000)
1155 function wifinet.channel(self)
1156 return self.iwinfo.channel or
1157 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1160 function wifinet.signal(self)
1161 return self.iwinfo.signal or 0
1164 function wifinet.noise(self)
1165 return self.iwinfo.noise or 0
1168 function wifinet.signal_level(self, s, n)
1169 if self:active_bssid() ~= "00:00:00:00:00:00" then
1170 local signal = s or self:signal()
1171 local noise = n or self:noise()
1173 if signal < 0 and noise < 0 then
1174 local snr = -1 * (noise - signal)
1175 return math.floor(snr / 5)
1184 function wifinet.signal_percent(self)
1185 local qc = self.iwinfo.quality or 0
1186 local qm = self.iwinfo.quality_max or 0
1188 if qc > 0 and qm > 0 then
1189 return math.floor((100 / qm) * qc)
1195 function wifinet.shortname(self)
1197 i18n.translate(self:active_mode()),
1198 self:active_ssid() or self:active_bssid()
1202 function wifinet.get_i18n(self)
1203 return "%s: %s %q (%s)" %{
1204 i18n.translate("Wireless Network"),
1205 i18n.translate(self:active_mode()),
1206 self:active_ssid() or self:active_bssid(),
1211 function wifinet.adminlink(self)
1212 return dsp.build_url("admin", "network", "wireless", self.netid)
1215 function wifinet.get_network(self)
1216 if uci_r:get("network", self.iwdata.network) == "interface" then
1217 return network(self.iwdata.network)
1221 function wifinet.get_interface(self)
1222 return interface(self:ifname())