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 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
246 if uci_r:section("network", "interface", n, options) then
252 function get_network(self, n)
253 if n and uci_r:get("network", n) == "interface" then
258 function get_networks(self)
262 uci_r:foreach("network", "interface",
264 nls[s['.name']] = network(s['.name'])
268 for n in utl.kspairs(nls) do
269 nets[#nets+1] = nls[n]
275 function del_network(self, n)
276 local r = uci_r:delete("network", n)
278 uci_r:delete_all("network", "alias",
279 function(s) return (s.interface == n) end)
281 uci_r:delete_all("network", "route",
282 function(s) return (s.interface == n) end)
284 uci_r:delete_all("network", "route6",
285 function(s) return (s.interface == n) end)
287 uci_r:foreach("wireless", "wifi-iface",
289 if s.network == n then
290 uci_r:delete("wireless", s['.name'], "network")
297 function rename_network(self, old, new)
299 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
300 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
303 uci_r:foreach("network", "alias",
305 if s.interface == old then
306 uci_r:set("network", s['.name'], "interface", new)
310 uci_r:foreach("network", "route",
312 if s.interface == old then
313 uci_r:set("network", s['.name'], "interface", new)
317 uci_r:foreach("network", "route6",
319 if s.interface == old then
320 uci_r:set("network", s['.name'], "interface", new)
324 uci_r:foreach("wireless", "wifi-iface",
326 if s.network == old then
327 uci_r:set("wireless", s['.name'], "network", new)
331 uci_r:delete("network", old)
337 function get_interface(self, i)
338 if ifs[i] or _wifi_iface(i) then
343 uci_r:foreach("wireless", "wifi-iface",
346 num[s.device] = num[s.device] and num[s.device] + 1 or 1
347 if s['.name'] == i then
349 "%s.network%d" %{s.device, num[s.device] })
358 function get_interfaces(self)
364 -- find normal interfaces
365 uci_r:foreach("network", "interface",
367 for iface in utl.imatch(s.ifname) do
368 if not _iface_ignore(iface) and not _wifi_iface(iface) then
370 nfs[iface] = interface(iface)
375 for iface in utl.kspairs(ifs) do
376 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
377 nfs[iface] = interface(iface)
381 for iface in utl.kspairs(nfs) do
382 ifaces[#ifaces+1] = nfs[iface]
385 -- find wifi interfaces
388 uci_r:foreach("wireless", "wifi-iface",
391 num[s.device] = num[s.device] and num[s.device] + 1 or 1
392 local i = "%s.network%d" %{ s.device, num[s.device] }
393 wfs[i] = interface(i)
397 for iface in utl.kspairs(wfs) do
398 ifaces[#ifaces+1] = wfs[iface]
404 function ignore_interface(self, x)
405 return _iface_ignore(x)
408 function get_wifidev(self, dev)
409 if uci_r:get("wireless", dev) == "wifi-device" then
414 function get_wifidevs(self)
418 uci_r:foreach("wireless", "wifi-device",
419 function(s) wfd[#wfd+1] = s['.name'] end)
422 for _, dev in utl.vspairs(wfd) do
423 devs[#devs+1] = wifidev(dev)
429 function get_wifinet(self, net)
430 local wnet = _wifi_lookup(net)
436 function add_wifinet(self, net, options)
437 if type(options) == "table" and options.device and
438 uci_r:get("wireless", options.device) == "wifi-device"
440 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
445 function del_wifinet(self, net)
446 local wnet = _wifi_lookup(net)
448 uci_r:delete("wireless", wnet)
455 network = utl.class()
457 function network.__init__(self, name)
461 function network._get(self, opt)
462 local v = uci_r:get("network", self.sid, opt)
463 if type(v) == "table" then
464 return table.concat(v, " ")
469 function network.get(self, opt)
470 return _get("network", self.sid, opt)
473 function network.set(self, opt, val)
474 return _set("network", self.sid, opt, val)
477 function network.ifname(self)
478 local p = self:proto()
479 if self:is_bridge() then
480 return "br-" .. self.sid
481 elseif self:is_virtual() then
482 return p .. "-" .. self.sid
485 local dev = uci_r:get("network", self.sid, "ifname") or
486 uci_s:get("network", self.sid, "ifname")
488 dev = (type(dev) == "table") and dev[1] or dev
489 dev = (dev ~= nil) and dev:match("%S+")
492 uci_r:foreach("wireless", "wifi-iface",
495 num[s.device] = num[s.device]
496 and num[s.device] + 1 or 1
498 if s.network == self.sid then
499 dev = "%s.network%d" %{ s.device, num[s.device] }
510 function network.device(self)
511 local dev = uci_r:get("network", self.sid, "device") or
512 uci_s:get("network", self.sid, "device")
514 dev = (type(dev) == "table") and dev[1] or dev
516 if not dev or dev:match("[^%w%-%.%s]") then
517 dev = uci_r:get("network", self.sid, "ifname") or
518 uci_s:get("network", self.sid, "ifname")
520 dev = (type(dev) == "table") and dev[1] or dev
526 function network.proto(self)
527 return self:_get("proto") or "none"
530 function network.type(self)
531 return self:_get("type")
534 function network.name(self)
538 function network.uptime(self)
539 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
541 return nxo.sysinfo().uptime - cnt
547 function network.is_bridge(self)
548 return (self:type() == "bridge")
551 function network.is_virtual(self)
552 local p = self:proto()
554 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
555 p == "pppoe" or p == "pppoa"
559 function network.is_empty(self)
560 if self:is_virtual() then
565 if (self:_get("ifname") or ""):match("%S+") then
569 uci_r:foreach("wireless", "wifi-iface",
571 if s.network == self.sid then
581 function network.add_interface(self, ifname)
582 if not self:is_virtual() then
583 if type(ifname) ~= "string" then
584 ifname = ifname:name()
586 ifname = ifname:match("[^%s:]+")
589 -- remove the interface from all ifaces
590 uci_r:foreach("network", "interface",
592 _list_del("network", s['.name'], "ifname", ifname)
595 -- if its a wifi interface, change its network option
596 local wif = _wifi_lookup(ifname)
598 uci_r:set("wireless", wif, "network", self.sid)
600 -- add iface to our iface list
602 _list_add("network", self.sid, "ifname", ifname)
607 function network.del_interface(self, ifname)
608 if not self:is_virtual() then
609 if utl.instanceof(ifname, interface) then
610 ifname = ifname:name()
612 ifname = ifname:match("[^%s:]+")
615 -- if its a wireless interface, clear its network option
616 local wif = _wifi_lookup(ifname)
617 if wif then uci_r:delete("wireless", wif, "network") end
619 -- remove the interface
620 _list_del("network", self.sid, "ifname", ifname)
624 function network.get_interfaces(self)
628 if self:is_virtual() then
629 ifn = self:proto() .. "-" .. self.sid
630 ifaces = { interface(ifn) }
633 for ifn in utl.imatch(self:get("ifname")) do
634 ifn = ifn:match("[^:]+")
635 nfs[ifn] = interface(ifn)
638 for ifn in utl.kspairs(nfs) do
639 ifaces[#ifaces+1] = nfs[ifn]
644 uci_r:foreach("wireless", "wifi-iface",
647 num[s.device] = num[s.device] and num[s.device] + 1 or 1
648 if s.network == self.sid then
649 ifn = "%s.network%d" %{ s.device, num[s.device] }
650 wfs[ifn] = interface(ifn)
655 for ifn in utl.kspairs(wfs) do
656 ifaces[#ifaces+1] = wfs[ifn]
663 function network.contains_interface(self, ifname)
664 if type(ifname) ~= "string" then
665 ifname = ifname:name()
667 ifname = ifname:match("[^%s:]+")
671 if self:is_virtual() then
672 ifn = self:proto() .. "-" .. self.sid
675 for ifn in utl.imatch(self:get("ifname")) do
676 ifn = ifn:match("[^:]+")
677 if ifn == ifname then
682 local wif = _wifi_lookup(ifname)
684 return (uci_r:get("wireless", wif, "network") == self.sid)
691 function network.adminlink(self)
692 return dsp.build_url("admin", "network", "network", self.sid)
696 interface = utl.class()
697 function interface.__init__(self, ifname)
698 local wif = _wifi_lookup(ifname)
699 if wif then self.wif = wifinet(wif) end
701 self.ifname = self.ifname or ifname
702 self.dev = ifs[self.ifname]
705 function interface.name(self)
706 return self.wif and self.wif:ifname() or self.ifname
709 function interface.mac(self)
710 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
713 function interface.ipaddrs(self)
714 return self.dev and self.dev.ipaddrs or { }
717 function interface.ip6addrs(self)
718 return self.dev and self.dev.ip6addrs or { }
721 function interface.type(self)
722 if self.wif or _wifi_iface(self.ifname) then
724 elseif brs[self.ifname] then
726 elseif sws[self.ifname] or self.ifname:match("%.") then
733 function interface.shortname(self)
736 self.wif:active_mode(),
737 self.wif:active_ssid() or self.wif:active_bssid()
744 function interface.get_i18n(self)
746 return "%s: %s %q" %{
747 i18n.translate("Wireless Network"),
748 self.wif:active_mode(),
749 self.wif:active_ssid() or self.wif:active_bssid()
752 return "%s: %q" %{ self:get_type_i18n(), self:name() }
756 function interface.get_type_i18n(self)
757 local x = self:type()
759 return i18n.translate("Wireless Adapter")
760 elseif x == "bridge" then
761 return i18n.translate("Bridge")
762 elseif x == "switch" then
763 return i18n.translate("Ethernet Switch")
765 return i18n.translate("Ethernet Adapter")
769 function interface.adminlink(self)
771 return self.wif:adminlink()
775 function interface.ports(self)
779 for _, iface in ipairs(self.br.ifnames) do
780 ifaces[#ifaces+1] = interface(iface.name)
786 function interface.bridge_id(self)
794 function interface.bridge_stp(self)
802 function interface.is_up(self)
804 return self.wif:is_up()
806 return self.dev and self.dev.flags and self.dev.flags.up or false
810 function interface.is_bridge(self)
811 return (self:type() == "bridge")
814 function interface.is_bridgeport(self)
815 return self.dev and self.dev.bridge and true or false
818 function interface.tx_bytes(self)
819 return self.dev and self.dev.stats
820 and self.dev.stats.tx_bytes or 0
823 function interface.rx_bytes(self)
824 return self.dev and self.dev.stats
825 and self.dev.stats.rx_bytes or 0
828 function interface.tx_packets(self)
829 return self.dev and self.dev.stats
830 and self.dev.stats.tx_packets or 0
833 function interface.rx_packets(self)
834 return self.dev and self.dev.stats
835 and self.dev.stats.rx_packets or 0
838 function interface.get_network(self)
839 if self.dev and self.dev.network then
840 self.network = _M:get_network(self.dev.network)
843 if not self.network then
845 for _, net in ipairs(_M:get_networks()) do
846 if net:contains_interface(self.ifname) then
856 function interface.get_wifinet(self)
861 wifidev = utl.class()
862 function wifidev.__init__(self, dev)
866 function wifidev.get(self, opt)
867 return _get("wireless", self.sid, opt)
870 function wifidev.set(self, opt, val)
871 return _set("wireless", self.sid, opt, val)
874 function wifidev.name(self)
878 function wifidev.is_up(self)
881 uci_s:foreach("wireless", "wifi-iface",
883 if s.device == self.sid then
894 function wifidev.get_wifinet(self, net)
895 if uci_r:get("wireless", net) == "wifi-iface" then
898 local wnet = _wifi_lookup(net)
905 function wifidev.get_wifinets(self)
908 uci_r:foreach("wireless", "wifi-iface",
910 if s.device == self.sid then
911 nets[#nets+1] = wifinet(s['.name'])
918 function wifidev.add_wifinet(self, options)
919 options = options or { }
920 options.device = self.sid
922 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
924 return wifinet(wnet, options)
928 function wifidev.del_wifinet(self, net)
929 if utl.instanceof(net, wifinet) then
931 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
932 net = _wifi_lookup(net)
935 if net and uci_r:get("wireless", net, "device") == self.sid then
936 uci_r:delete("wireless", net)
944 wifinet = utl.class()
945 function wifinet.__init__(self, net, data)
950 uci_r:foreach("wireless", "wifi-iface",
953 num[s.device] = num[s.device] and num[s.device] + 1 or 1
954 if s['.name'] == self.sid then
955 netid = "%s.network%d" %{ s.device, num[s.device] }
961 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
965 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
966 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
967 uci_r:get_all("wireless", self.sid) or { }
970 function wifinet.get(self, opt)
971 return _get("wireless", self.sid, opt)
974 function wifinet.set(self, opt, val)
975 return _set("wireless", self.sid, opt, val)
978 function wifinet.mode(self)
979 return uci_s:get("wireless", self.sid, "mode") or "ap"
982 function wifinet.ssid(self)
983 return uci_s:get("wireless", self.sid, "ssid")
986 function wifinet.bssid(self)
987 return uci_s:get("wireless", self.sid, "bssid")
990 function wifinet.network(self)
991 return uci_s:get("wifinet", self.sid, "network")
994 function wifinet.name(self)
998 function wifinet.ifname(self)
999 local ifname = self.iwinfo.ifname
1000 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1006 function wifinet.get_device(self)
1007 if self.iwdata.device then
1008 return wifidev(self.iwdata.device)
1012 function wifinet.is_up(self)
1013 return (self.iwdata.up == "1")
1016 function wifinet.active_mode(self)
1017 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1019 if m == "ap" then m = "AP"
1020 elseif m == "sta" then m = "Client"
1021 elseif m == "adhoc" then m = "Ad-Hoc"
1022 elseif m == "mesh" then m = "Mesh"
1023 elseif m == "monitor" then m = "Monitor"
1029 function wifinet.active_mode_i18n(self)
1030 return i18n.translate(self:active_mode())
1033 function wifinet.active_ssid(self)
1034 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1037 function wifinet.active_bssid(self)
1038 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1041 function wifinet.active_encryption(self)
1042 local enc = self.iwinfo and self.iwinfo.encryption
1043 return enc and enc.description or "-"
1046 function wifinet.assoclist(self)
1047 return self.iwinfo.assoclist or { }
1050 function wifinet.frequency(self)
1051 local freq = self.iwinfo.frequency
1052 if freq and freq > 0 then
1053 return "%.03f" % (freq / 1000)
1057 function wifinet.bitrate(self)
1058 local rate = self.iwinfo.bitrate
1059 if rate and rate > 0 then
1060 return (rate / 1000)
1064 function wifinet.channel(self)
1065 return self.iwinfo.channel or
1066 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1069 function wifinet.signal(self)
1070 return self.iwinfo.signal or 0
1073 function wifinet.noise(self)
1074 return self.iwinfo.noise or 0
1077 function wifinet.signal_level(self, s, n)
1078 if self:active_bssid() ~= "00:00:00:00:00:00" then
1079 local signal = s or self:signal()
1080 local noise = n or self:noise()
1082 if signal < 0 and noise < 0 then
1083 local snr = -1 * (noise - signal)
1084 return math.floor(snr / 5)
1093 function wifinet.signal_percent(self)
1094 local qc = self.iwinfo.quality or 0
1095 local qm = self.iwinfo.quality_max or 0
1097 if qc > 0 and qm > 0 then
1098 return math.floor((100 / qm) * qc)
1104 function wifinet.shortname(self)
1106 i18n.translate(self:active_mode()),
1107 self:active_ssid() or self:active_bssid()
1111 function wifinet.get_i18n(self)
1112 return "%s: %s %q (%s)" %{
1113 i18n.translate("Wireless Network"),
1114 i18n.translate(self:active_mode()),
1115 self:active_ssid() or self:active_bssid(),
1120 function wifinet.adminlink(self)
1121 return dsp.build_url("admin", "network", "wireless",
1122 self.iwdata.device, self.netid)
1125 function wifinet.get_network(self)
1126 if uci_r:get("network", self.iwdata.network) == "interface" then
1127 return network(self.iwdata.network)
1131 function wifinet.get_interface(self)
1132 return interface(self:ifname())