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("^3g-%w") or x:match("^ppp-%w") or x:match("^pppoe-%w") or
158 x:match("^pppoa-%w") 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:foreach("network", "alias",
280 if s.interface == n then
281 uci_r:delete("network", s['.name'])
285 uci_r:foreach("network", "route",
287 if s.interface == n then
288 uci_r:delete("network", s['.name'])
292 uci_r:foreach("network", "route6",
294 if s.interface == n then
295 uci_r:delete("network", s['.name'])
299 uci_r:foreach("wireless", "wifi-iface",
301 if s.network == n then
302 uci_r:delete("wireless", s['.name'], "network")
306 uci_r:delete("network", n)
311 function rename_network(self, old, new)
313 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
314 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
317 uci_r:foreach("network", "alias",
319 if s.interface == old then
320 uci_r:set("network", s['.name'], "interface", new)
324 uci_r:foreach("network", "route",
326 if s.interface == old then
327 uci_r:set("network", s['.name'], "interface", new)
331 uci_r:foreach("network", "route6",
333 if s.interface == old then
334 uci_r:set("network", s['.name'], "interface", new)
338 uci_r:foreach("wireless", "wifi-iface",
340 if s.network == old then
341 uci_r:set("wireless", s['.name'], "network", new)
345 uci_r:delete("network", old)
351 function get_interface(self, i)
352 if ifs[i] or _wifi_iface(i) then
357 uci_r:foreach("wireless", "wifi-iface",
360 num[s.device] = num[s.device] and num[s.device] + 1 or 1
361 if s['.name'] == i then
363 "%s.network%d" %{s.device, num[s.device] })
372 function get_interfaces(self)
377 -- find normal interfaces
378 uci_r:foreach("network", "interface",
380 for iface in utl.imatch(s.ifname) do
381 if not _iface_ignore(iface) and not _wifi_iface(iface) then
383 ifaces[#ifaces+1] = interface(iface)
388 for iface in utl.kspairs(ifs) do
389 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
390 ifaces[#ifaces+1] = interface(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
493 local dev = self:_get("ifname") or
494 uci_r:get("network", self.sid, "ifname")
496 dev = dev and dev:match("%S+")
499 uci_r:foreach("wireless", "wifi-iface",
502 num[s.device] = num[s.device]
503 and num[s.device] + 1 or 1
505 if s.network == self.sid then
506 dev = "%s.network%d" %{ s.device, num[s.device] }
517 function network.device(self)
518 local dev = self:_get("device")
519 if not dev or dev:match("[^%w%-%.%s]") then
520 dev = uci_r:get("network", self.sid, "ifname")
525 function network.proto(self)
526 return self:_get("proto") or "none"
529 function network.type(self)
530 return self:_get("type")
533 function network.name(self)
537 function network.is_bridge(self)
538 return (self:type() == "bridge")
541 function network.is_virtual(self)
542 local p = self:proto()
544 p == "3g" or p == "6in4" or p == "ppp" or
545 p == "pppoe" or p == "pppoa"
549 function network.is_empty(self)
550 if self:is_virtual() then
555 if (self:_get("ifname") or ""):match("%S+") then
559 uci_r:foreach("wireless", "wifi-iface",
561 if s.network == self.sid then
571 function network.add_interface(self, ifname)
572 if not self:is_virtual() then
573 if type(ifname) ~= "string" then
574 ifname = ifname:name()
576 ifname = ifname:match("[^%s:]+")
579 -- remove the interface from all ifaces
580 uci_r:foreach("network", "interface",
582 _list_del("network", s['.name'], "ifname", ifname)
585 -- if its a wifi interface, change its network option
586 local wif = _wifi_lookup(ifname)
588 uci_r:set("wireless", wif, "network", self.sid)
590 -- add iface to our iface list
592 _list_add("network", self.sid, "ifname", ifname)
597 function network.del_interface(self, ifname)
598 if not self:is_virtual() then
599 if utl.instanceof(ifname, interface) then
600 ifname = ifname:name()
602 ifname = ifname:match("[^%s:]+")
605 -- if its a wireless interface, clear its network option
606 local wif = _wifi_lookup(ifname)
607 if wif then uci_r:delete("wireless", wif, "network") end
609 -- remove the interface
610 _list_del("network", self.sid, "ifname", ifname)
614 function network.get_interfaces(self)
618 if self:is_virtual() then
619 ifn = self:proto() .. "-" .. self.sid
620 ifaces = { interface(ifn) }
623 for ifn in utl.imatch(self:get("ifname")) do
624 ifn = ifn:match("[^:]+")
625 nfs[ifn] = interface(ifn)
628 for ifn in utl.kspairs(nfs) do
629 ifaces[#ifaces+1] = nfs[ifn]
634 uci_r:foreach("wireless", "wifi-iface",
637 num[s.device] = num[s.device] and num[s.device] + 1 or 1
638 if s.network == self.sid then
639 ifn = "%s.network%d" %{ s.device, num[s.device] }
640 wfs[ifn] = interface(ifn)
645 for ifn in utl.kspairs(wfs) do
646 ifaces[#ifaces+1] = wfs[ifn]
653 function network.contains_interface(self, ifname)
654 if type(ifname) ~= "string" then
655 ifname = ifname:name()
657 ifname = ifname:match("[^%s:]+")
661 if self:is_virtual() then
662 ifn = self:proto() .. "-" .. self.sid
665 for ifn in utl.imatch(self:get("ifname")) do
666 ifn = ifn:match("[^:]+")
667 if ifn == ifname then
672 local wif = _wifi_lookup(ifname)
674 return (uci_r:get("wireless", wif, "network") == self.sid)
681 function network.adminlink(self)
682 return dsp.build_url("admin", "network", "network", self.sid)
686 interface = utl.class()
687 function interface.__init__(self, ifname)
688 local wif = _wifi_lookup(ifname)
689 if wif then self.wif = wifinet(wif) end
691 self.ifname = self.ifname or ifname
692 self.dev = ifs[self.ifname]
695 function interface.name(self)
696 return self.wif and self.wif:ifname() or self.ifname
699 function interface.mac(self)
700 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
703 function interface.ipaddrs(self)
704 return self.dev and self.dev.ipaddrs or { }
707 function interface.ip6addrs(self)
708 return self.dev and self.dev.ip6addrs or { }
711 function interface.type(self)
712 if self.wif or _wifi_iface(self.ifname) then
714 elseif brs[self.ifname] then
716 elseif sws[self.ifname] or self.ifname:match("%.") then
723 function interface.shortname(self)
726 self.wif:active_mode(),
727 self.wif:active_ssid() or self.wif:active_bssid()
734 function interface.get_i18n(self)
736 return "%s: %s %q" %{
737 i18n.translate("Wireless Network"),
738 self.wif:active_mode(),
739 self.wif:active_ssid() or self.wif:active_bssid()
742 return "%s: %q" %{ self:get_type_i18n(), self:name() }
746 function interface.get_type_i18n(self)
747 local x = self:type()
749 return i18n.translate("Wireless Adapter")
750 elseif x == "bridge" then
751 return i18n.translate("Bridge")
752 elseif x == "switch" then
753 return i18n.translate("Ethernet Switch")
755 return i18n.translate("Ethernet Adapter")
759 function interface.adminlink(self)
761 return self.wif:adminlink()
765 function interface.ports(self)
769 for _, iface in ipairs(self.br.ifnames) do
770 ifaces[#ifaces+1] = interface(iface.name)
776 function interface.bridge_id(self)
784 function interface.bridge_stp(self)
792 function interface.is_up(self)
794 return self.wif:is_up()
796 return self.dev and self.dev.flags and self.dev.flags.up or false
800 function interface.is_bridge(self)
801 return (self:type() == "bridge")
804 function interface.is_bridgeport(self)
805 return self.dev and self.dev.bridge and true or false
808 function interface.tx_bytes(self)
809 return self.dev and self.dev.stats
810 and self.dev.stats.tx_bytes or 0
813 function interface.rx_bytes(self)
814 return self.dev and self.dev.stats
815 and self.dev.stats.rx_bytes or 0
818 function interface.tx_packets(self)
819 return self.dev and self.dev.stats
820 and self.dev.stats.tx_packets or 0
823 function interface.rx_packets(self)
824 return self.dev and self.dev.stats
825 and self.dev.stats.rx_packets or 0
828 function interface.get_network(self)
829 if self.dev and self.dev.network then
830 self.network = _M:get_network(self.dev.network)
833 if not self.network then
835 for _, net in ipairs(_M:get_networks()) do
836 if net:contains_interface(self.ifname) then
846 function interface.get_wifinet(self)
851 wifidev = utl.class()
852 function wifidev.__init__(self, dev)
856 function wifidev.get(self, opt)
857 return _get("wireless", self.sid, opt)
860 function wifidev.set(self, opt, val)
861 return _set("wireless", self.sid, opt, val)
864 function wifidev.name(self)
868 function wifidev.is_up(self)
871 uci_s:foreach("wireless", "wifi-iface",
873 if s.device == self.sid then
884 function wifidev.get_wifinet(self, net)
885 if uci_r:get("wireless", net) == "wifi-iface" then
888 local wnet = _wifi_lookup(net)
895 function wifidev.get_wifinets(self)
898 uci_r:foreach("wireless", "wifi-iface",
900 if s.device == self.sid then
901 nets[#nets+1] = wifinet(s['.name'])
908 function wifidev.add_wifinet(self, options)
909 options = options or { }
910 options.device = self.sid
912 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
914 return wifinet(wnet, options)
918 function wifidev.del_wifinet(self, net)
919 if utl.instanceof(net, wifinet) then
921 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
922 net = _wifi_lookup(net)
925 if net and uci_r:get("wireless", net, "device") == self.sid then
926 uci_r:delete("wireless", net)
934 wifinet = utl.class()
935 function wifinet.__init__(self, net, data)
938 local dev = uci_s:get("wireless", self.sid, "ifname")
941 uci_r:foreach("wireless", "wifi-iface",
944 num[s.device] = num[s.device] and num[s.device] + 1 or 1
945 if s['.name'] == self.sid then
946 dev = "%s.network%d" %{ s.device, num[s.device] }
954 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
955 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
956 uci_r:get_all("wireless", self.sid) or { }
959 function wifinet.get(self, opt)
960 return _get("wireless", self.sid, opt)
963 function wifinet.set(self, opt, val)
964 return _set("wireless", self.sid, opt, val)
967 function wifinet.mode(self)
968 return uci_s:get("wireless", self.sid, "mode") or "ap"
971 function wifinet.ssid(self)
972 return uci_s:get("wireless", self.sid, "ssid")
975 function wifinet.bssid(self)
976 return uci_s:get("wireless", self.sid, "bssid")
979 function wifinet.network(self)
980 return uci_s:get("wifinet", self.sid, "network")
983 function wifinet.name(self)
987 function wifinet.ifname(self)
988 return self.iwinfo.ifname or self.wdev
991 function wifinet.get_device(self)
992 if self.iwdata.device then
993 return wifidev(self.iwdata.device)
997 function wifinet.is_up(self)
998 return (self.iwdata.up == "1")
1001 function wifinet.active_mode(self)
1002 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1004 if m == "ap" then m = "AP"
1005 elseif m == "sta" then m = "Client"
1006 elseif m == "adhoc" then m = "Ad-Hoc"
1007 elseif m == "mesh" then m = "Mesh"
1008 elseif m == "monitor" then m = "Monitor"
1014 function wifinet.active_mode_i18n(self)
1015 return i18n.translate(self:active_mode())
1018 function wifinet.active_ssid(self)
1019 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1022 function wifinet.active_bssid(self)
1023 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1026 function wifinet.active_encryption(self)
1027 local enc = self.iwinfo and self.iwinfo.encryption
1028 return enc and enc.description or "-"
1031 function wifinet.assoclist(self)
1032 return self.iwinfo.assoclist or { }
1035 function wifinet.frequency(self)
1036 local freq = self.iwinfo.frequency
1037 if freq and freq > 0 then
1038 return "%.03f" % (freq / 1000)
1042 function wifinet.bitrate(self)
1043 local rate = self.iwinfo.bitrate
1044 if rate and rate > 0 then
1045 return (rate / 1000)
1049 function wifinet.channel(self)
1050 return self.iwinfo.channel or
1051 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1054 function wifinet.signal(self)
1055 return self.iwinfo.signal or 0
1058 function wifinet.noise(self)
1059 return self.iwinfo.noise or 0
1062 function wifinet.signal_level(self, s, n)
1063 if self:active_bssid() ~= "00:00:00:00:00:00" then
1064 local signal = s or self:signal()
1065 local noise = n or self:noise()
1067 if signal < 0 and noise < 0 then
1068 local snr = -1 * (noise - signal)
1069 return math.floor(snr / 5)
1078 function wifinet.signal_percent(self)
1079 local qc = self.iwinfo.quality or 0
1080 local qm = self.iwinfo.quality_max or 0
1082 if qc > 0 and qm > 0 then
1083 return math.floor((100 / qm) * qc)
1089 function wifinet.shortname(self)
1091 i18n.translate(self:active_mode()),
1092 self:active_ssid() or self:active_bssid()
1096 function wifinet.get_i18n(self)
1097 return "%s: %s %q (%s)" %{
1098 i18n.translate("Wireless Network"),
1099 i18n.translate(self:active_mode()),
1100 self:active_ssid() or self:active_bssid(),
1105 function wifinet.adminlink(self)
1106 return dsp.build_url("admin", "network", "wireless",
1107 self.iwdata.device, self.wdev)
1110 function wifinet.get_network(self)
1111 if uci_r:get("network", self.iwdata.network) == "interface" then
1112 return network(self.iwdata.network)
1116 function wifinet.get_interface(self)
1117 return interface(self:ifname())