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) or
856 net:ifname() == self.ifname
867 function interface.get_wifinet(self)
872 wifidev = utl.class()
873 function wifidev.__init__(self, dev)
877 function wifidev.get(self, opt)
878 return _get("wireless", self.sid, opt)
881 function wifidev.set(self, opt, val)
882 return _set("wireless", self.sid, opt, val)
885 function wifidev.name(self)
889 function wifidev.is_up(self)
892 uci_s:foreach("wireless", "wifi-iface",
894 if s.device == self.sid then
905 function wifidev.get_wifinet(self, net)
906 if uci_r:get("wireless", net) == "wifi-iface" then
909 local wnet = _wifi_lookup(net)
916 function wifidev.get_wifinets(self)
919 uci_r:foreach("wireless", "wifi-iface",
921 if s.device == self.sid then
922 nets[#nets+1] = wifinet(s['.name'])
929 function wifidev.add_wifinet(self, options)
930 options = options or { }
931 options.device = self.sid
933 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
935 return wifinet(wnet, options)
939 function wifidev.del_wifinet(self, net)
940 if utl.instanceof(net, wifinet) then
942 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
943 net = _wifi_lookup(net)
946 if net and uci_r:get("wireless", net, "device") == self.sid then
947 uci_r:delete("wireless", net)
955 wifinet = utl.class()
956 function wifinet.__init__(self, net, data)
961 uci_r:foreach("wireless", "wifi-iface",
964 num[s.device] = num[s.device] and num[s.device] + 1 or 1
965 if s['.name'] == self.sid then
966 netid = "%s.network%d" %{ s.device, num[s.device] }
972 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
976 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
977 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
978 uci_r:get_all("wireless", self.sid) or { }
981 function wifinet.get(self, opt)
982 return _get("wireless", self.sid, opt)
985 function wifinet.set(self, opt, val)
986 return _set("wireless", self.sid, opt, val)
989 function wifinet.mode(self)
990 return uci_s:get("wireless", self.sid, "mode") or "ap"
993 function wifinet.ssid(self)
994 return uci_s:get("wireless", self.sid, "ssid")
997 function wifinet.bssid(self)
998 return uci_s:get("wireless", self.sid, "bssid")
1001 function wifinet.network(self)
1002 return uci_s:get("wifinet", self.sid, "network")
1005 function wifinet.name(self)
1009 function wifinet.ifname(self)
1010 local ifname = self.iwinfo.ifname
1011 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1017 function wifinet.get_device(self)
1018 if self.iwdata.device then
1019 return wifidev(self.iwdata.device)
1023 function wifinet.is_up(self)
1024 return (self.iwdata.up == "1")
1027 function wifinet.active_mode(self)
1028 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1030 if m == "ap" then m = "Master"
1031 elseif m == "sta" then m = "Client"
1032 elseif m == "adhoc" then m = "Ad-Hoc"
1033 elseif m == "mesh" then m = "Mesh"
1034 elseif m == "monitor" then m = "Monitor"
1040 function wifinet.active_mode_i18n(self)
1041 return i18n.translate(self:active_mode())
1044 function wifinet.active_ssid(self)
1045 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1048 function wifinet.active_bssid(self)
1049 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1052 function wifinet.active_encryption(self)
1053 local enc = self.iwinfo and self.iwinfo.encryption
1054 return enc and enc.description or "-"
1057 function wifinet.assoclist(self)
1058 return self.iwinfo.assoclist or { }
1061 function wifinet.frequency(self)
1062 local freq = self.iwinfo.frequency
1063 if freq and freq > 0 then
1064 return "%.03f" % (freq / 1000)
1068 function wifinet.bitrate(self)
1069 local rate = self.iwinfo.bitrate
1070 if rate and rate > 0 then
1071 return (rate / 1000)
1075 function wifinet.channel(self)
1076 return self.iwinfo.channel or
1077 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1080 function wifinet.signal(self)
1081 return self.iwinfo.signal or 0
1084 function wifinet.noise(self)
1085 return self.iwinfo.noise or 0
1088 function wifinet.signal_level(self, s, n)
1089 if self:active_bssid() ~= "00:00:00:00:00:00" then
1090 local signal = s or self:signal()
1091 local noise = n or self:noise()
1093 if signal < 0 and noise < 0 then
1094 local snr = -1 * (noise - signal)
1095 return math.floor(snr / 5)
1104 function wifinet.signal_percent(self)
1105 local qc = self.iwinfo.quality or 0
1106 local qm = self.iwinfo.quality_max or 0
1108 if qc > 0 and qm > 0 then
1109 return math.floor((100 / qm) * qc)
1115 function wifinet.shortname(self)
1117 i18n.translate(self:active_mode()),
1118 self:active_ssid() or self:active_bssid()
1122 function wifinet.get_i18n(self)
1123 return "%s: %s %q (%s)" %{
1124 i18n.translate("Wireless Network"),
1125 i18n.translate(self:active_mode()),
1126 self:active_ssid() or self:active_bssid(),
1131 function wifinet.adminlink(self)
1132 return dsp.build_url("admin", "network", "wireless", self.netid)
1135 function wifinet.get_network(self)
1136 if uci_r:get("network", self.iwdata.network) == "interface" then
1137 return network(self.iwdata.network)
1141 function wifinet.get_interface(self)
1142 return interface(self:ifname())