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.get(self, opt)
479 return _get("network", self.sid, opt)
482 function network.set(self, opt, val)
483 return _set("network", self.sid, opt, val)
486 function network.ifname(self)
487 local p = self:proto()
488 if self:is_bridge() then
489 return "br-" .. self.sid
490 elseif self:is_virtual() then
491 return p .. "-" .. self.sid
494 local dev = uci_r:get("network", self.sid, "ifname") or
495 uci_s:get("network", self.sid, "ifname")
497 dev = (type(dev) == "table") and dev[1] or dev
498 dev = (dev ~= nil) and dev:match("%S+")
501 uci_r:foreach("wireless", "wifi-iface",
504 num[s.device] = num[s.device]
505 and num[s.device] + 1 or 1
507 if s.network == self.sid then
508 dev = "%s.network%d" %{ s.device, num[s.device] }
519 function network.device(self)
520 local dev = uci_r:get("network", self.sid, "device") or
521 uci_s:get("network", self.sid, "device")
523 dev = (type(dev) == "table") and dev[1] or dev
525 if not dev or dev:match("[^%w%-%.%s]") then
526 dev = uci_r:get("network", self.sid, "ifname") or
527 uci_s:get("network", self.sid, "ifname")
529 dev = (type(dev) == "table") and dev[1] or dev
535 function network.proto(self)
536 return self:_get("proto") or "none"
539 function network.type(self)
540 return self:_get("type")
543 function network.name(self)
547 function network.uptime(self)
548 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
550 return nxo.sysinfo().uptime - cnt
556 function network.is_bridge(self)
557 return (self:type() == "bridge")
560 function network.is_virtual(self)
561 local p = self:proto()
563 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
564 p == "pppoe" or p == "pppoa"
568 function network.is_empty(self)
569 if self:is_virtual() then
574 if (self:_get("ifname") or ""):match("%S+") then
578 uci_r:foreach("wireless", "wifi-iface",
580 if s.network == self.sid then
590 function network.add_interface(self, ifname)
591 if not self:is_virtual() then
592 if type(ifname) ~= "string" then
593 ifname = ifname:name()
595 ifname = ifname:match("[^%s:]+")
598 -- remove the interface from all ifaces
599 uci_r:foreach("network", "interface",
601 _list_del("network", s['.name'], "ifname", ifname)
604 -- if its a wifi interface, change its network option
605 local wif = _wifi_lookup(ifname)
607 uci_r:set("wireless", wif, "network", self.sid)
609 -- add iface to our iface list
611 _list_add("network", self.sid, "ifname", ifname)
616 function network.del_interface(self, ifname)
617 if not self:is_virtual() then
618 if utl.instanceof(ifname, interface) then
619 ifname = ifname:name()
621 ifname = ifname:match("[^%s:]+")
624 -- if its a wireless interface, clear its network option
625 local wif = _wifi_lookup(ifname)
626 if wif then uci_r:delete("wireless", wif, "network") end
628 -- remove the interface
629 _list_del("network", self.sid, "ifname", ifname)
633 function network.get_interfaces(self)
637 if self:is_virtual() then
638 ifn = self:proto() .. "-" .. self.sid
639 ifaces = { interface(ifn) }
642 for ifn in utl.imatch(self:get("ifname")) do
643 ifn = ifn:match("[^:]+")
644 nfs[ifn] = interface(ifn)
647 for ifn in utl.kspairs(nfs) do
648 ifaces[#ifaces+1] = nfs[ifn]
653 uci_r:foreach("wireless", "wifi-iface",
656 num[s.device] = num[s.device] and num[s.device] + 1 or 1
657 if s.network == self.sid then
658 ifn = "%s.network%d" %{ s.device, num[s.device] }
659 wfs[ifn] = interface(ifn)
664 for ifn in utl.kspairs(wfs) do
665 ifaces[#ifaces+1] = wfs[ifn]
672 function network.contains_interface(self, ifname)
673 if type(ifname) ~= "string" then
674 ifname = ifname:name()
676 ifname = ifname:match("[^%s:]+")
680 if self:is_virtual() then
681 ifn = self:proto() .. "-" .. self.sid
684 for ifn in utl.imatch(self:get("ifname")) do
685 ifn = ifn:match("[^:]+")
686 if ifn == ifname then
691 local wif = _wifi_lookup(ifname)
693 return (uci_r:get("wireless", wif, "network") == self.sid)
700 function network.adminlink(self)
701 return dsp.build_url("admin", "network", "network", self.sid)
705 interface = utl.class()
706 function interface.__init__(self, ifname)
707 local wif = _wifi_lookup(ifname)
708 if wif then self.wif = wifinet(wif) end
710 self.ifname = self.ifname or ifname
711 self.dev = ifs[self.ifname]
714 function interface.name(self)
715 return self.wif and self.wif:ifname() or self.ifname
718 function interface.mac(self)
719 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
722 function interface.ipaddrs(self)
723 return self.dev and self.dev.ipaddrs or { }
726 function interface.ip6addrs(self)
727 return self.dev and self.dev.ip6addrs or { }
730 function interface.type(self)
731 if self.wif or _wifi_iface(self.ifname) then
733 elseif brs[self.ifname] then
735 elseif sws[self.ifname] or self.ifname:match("%.") then
742 function interface.shortname(self)
745 self.wif:active_mode(),
746 self.wif:active_ssid() or self.wif:active_bssid()
753 function interface.get_i18n(self)
755 return "%s: %s %q" %{
756 i18n.translate("Wireless Network"),
757 self.wif:active_mode(),
758 self.wif:active_ssid() or self.wif:active_bssid()
761 return "%s: %q" %{ self:get_type_i18n(), self:name() }
765 function interface.get_type_i18n(self)
766 local x = self:type()
768 return i18n.translate("Wireless Adapter")
769 elseif x == "bridge" then
770 return i18n.translate("Bridge")
771 elseif x == "switch" then
772 return i18n.translate("Ethernet Switch")
774 return i18n.translate("Ethernet Adapter")
778 function interface.adminlink(self)
780 return self.wif:adminlink()
784 function interface.ports(self)
788 for _, iface in ipairs(self.br.ifnames) do
789 ifaces[#ifaces+1] = interface(iface.name)
795 function interface.bridge_id(self)
803 function interface.bridge_stp(self)
811 function interface.is_up(self)
813 return self.wif:is_up()
815 return self.dev and self.dev.flags and self.dev.flags.up or false
819 function interface.is_bridge(self)
820 return (self:type() == "bridge")
823 function interface.is_bridgeport(self)
824 return self.dev and self.dev.bridge and true or false
827 function interface.tx_bytes(self)
828 return self.dev and self.dev.stats
829 and self.dev.stats.tx_bytes or 0
832 function interface.rx_bytes(self)
833 return self.dev and self.dev.stats
834 and self.dev.stats.rx_bytes or 0
837 function interface.tx_packets(self)
838 return self.dev and self.dev.stats
839 and self.dev.stats.tx_packets or 0
842 function interface.rx_packets(self)
843 return self.dev and self.dev.stats
844 and self.dev.stats.rx_packets or 0
847 function interface.get_network(self)
848 if self.dev and self.dev.network then
849 self.network = _M:get_network(self.dev.network)
852 if not self.network then
854 for _, net in ipairs(_M:get_networks()) do
855 if net:contains_interface(self.ifname) then
865 function interface.get_wifinet(self)
870 wifidev = utl.class()
871 function wifidev.__init__(self, dev)
875 function wifidev.get(self, opt)
876 return _get("wireless", self.sid, opt)
879 function wifidev.set(self, opt, val)
880 return _set("wireless", self.sid, opt, val)
883 function wifidev.name(self)
887 function wifidev.is_up(self)
890 uci_s:foreach("wireless", "wifi-iface",
892 if s.device == self.sid then
903 function wifidev.get_wifinet(self, net)
904 if uci_r:get("wireless", net) == "wifi-iface" then
907 local wnet = _wifi_lookup(net)
914 function wifidev.get_wifinets(self)
917 uci_r:foreach("wireless", "wifi-iface",
919 if s.device == self.sid then
920 nets[#nets+1] = wifinet(s['.name'])
927 function wifidev.add_wifinet(self, options)
928 options = options or { }
929 options.device = self.sid
931 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
933 return wifinet(wnet, options)
937 function wifidev.del_wifinet(self, net)
938 if utl.instanceof(net, wifinet) then
940 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
941 net = _wifi_lookup(net)
944 if net and uci_r:get("wireless", net, "device") == self.sid then
945 uci_r:delete("wireless", net)
953 wifinet = utl.class()
954 function wifinet.__init__(self, net, data)
959 uci_r:foreach("wireless", "wifi-iface",
962 num[s.device] = num[s.device] and num[s.device] + 1 or 1
963 if s['.name'] == self.sid then
964 netid = "%s.network%d" %{ s.device, num[s.device] }
970 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
974 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
975 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
976 uci_r:get_all("wireless", self.sid) or { }
979 function wifinet.get(self, opt)
980 return _get("wireless", self.sid, opt)
983 function wifinet.set(self, opt, val)
984 return _set("wireless", self.sid, opt, val)
987 function wifinet.mode(self)
988 return uci_s:get("wireless", self.sid, "mode") or "ap"
991 function wifinet.ssid(self)
992 return uci_s:get("wireless", self.sid, "ssid")
995 function wifinet.bssid(self)
996 return uci_s:get("wireless", self.sid, "bssid")
999 function wifinet.network(self)
1000 return uci_s:get("wifinet", self.sid, "network")
1003 function wifinet.name(self)
1007 function wifinet.ifname(self)
1008 local ifname = self.iwinfo.ifname
1009 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1015 function wifinet.get_device(self)
1016 if self.iwdata.device then
1017 return wifidev(self.iwdata.device)
1021 function wifinet.is_up(self)
1022 return (self.iwdata.up == "1")
1025 function wifinet.active_mode(self)
1026 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1028 if m == "ap" then m = "Master"
1029 elseif m == "sta" then m = "Client"
1030 elseif m == "adhoc" then m = "Ad-Hoc"
1031 elseif m == "mesh" then m = "Mesh"
1032 elseif m == "monitor" then m = "Monitor"
1038 function wifinet.active_mode_i18n(self)
1039 return i18n.translate(self:active_mode())
1042 function wifinet.active_ssid(self)
1043 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1046 function wifinet.active_bssid(self)
1047 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1050 function wifinet.active_encryption(self)
1051 local enc = self.iwinfo and self.iwinfo.encryption
1052 return enc and enc.description or "-"
1055 function wifinet.assoclist(self)
1056 return self.iwinfo.assoclist or { }
1059 function wifinet.frequency(self)
1060 local freq = self.iwinfo.frequency
1061 if freq and freq > 0 then
1062 return "%.03f" % (freq / 1000)
1066 function wifinet.bitrate(self)
1067 local rate = self.iwinfo.bitrate
1068 if rate and rate > 0 then
1069 return (rate / 1000)
1073 function wifinet.channel(self)
1074 return self.iwinfo.channel or
1075 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1078 function wifinet.signal(self)
1079 return self.iwinfo.signal or 0
1082 function wifinet.noise(self)
1083 return self.iwinfo.noise or 0
1086 function wifinet.signal_level(self, s, n)
1087 if self:active_bssid() ~= "00:00:00:00:00:00" then
1088 local signal = s or self:signal()
1089 local noise = n or self:noise()
1091 if signal < 0 and noise < 0 then
1092 local snr = -1 * (noise - signal)
1093 return math.floor(snr / 5)
1102 function wifinet.signal_percent(self)
1103 local qc = self.iwinfo.quality or 0
1104 local qm = self.iwinfo.quality_max or 0
1106 if qc > 0 and qm > 0 then
1107 return math.floor((100 / qm) * qc)
1113 function wifinet.shortname(self)
1115 i18n.translate(self:active_mode()),
1116 self:active_ssid() or self:active_bssid()
1120 function wifinet.get_i18n(self)
1121 return "%s: %s %q (%s)" %{
1122 i18n.translate("Wireless Network"),
1123 i18n.translate(self:active_mode()),
1124 self:active_ssid() or self:active_bssid(),
1129 function wifinet.adminlink(self)
1130 return dsp.build_url("admin", "network", "wireless", self.netid)
1133 function wifinet.get_network(self)
1134 if uci_r:get("network", self.iwdata.network) == "interface" then
1135 return network(self.iwdata.network)
1139 function wifinet.get_interface(self)
1140 return interface(self:ifname())