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 == "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
484 local dev = self:_get("ifname") or
485 uci_r:get("network", self.sid, "ifname")
487 dev = dev and dev:match("%S+")
490 uci_r:foreach("wireless", "wifi-iface",
493 num[s.device] = num[s.device]
494 and num[s.device] + 1 or 1
496 if s.network == self.sid then
497 dev = "%s.network%d" %{ s.device, num[s.device] }
508 function network.device(self)
509 local dev = self:_get("device")
510 if not dev or dev:match("[^%w%-%.%s]") then
511 dev = uci_r:get("network", self.sid, "ifname")
516 function network.proto(self)
517 return self:_get("proto") or "none"
520 function network.type(self)
521 return self:_get("type")
524 function network.name(self)
528 function network.is_bridge(self)
529 return (self:type() == "bridge")
532 function network.is_virtual(self)
533 local p = self:proto()
535 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
536 p == "pppoe" or p == "pppoa"
540 function network.is_empty(self)
541 if self:is_virtual() then
546 if (self:_get("ifname") or ""):match("%S+") then
550 uci_r:foreach("wireless", "wifi-iface",
552 if s.network == self.sid then
562 function network.add_interface(self, ifname)
563 if not self:is_virtual() then
564 if type(ifname) ~= "string" then
565 ifname = ifname:name()
567 ifname = ifname:match("[^%s:]+")
570 -- remove the interface from all ifaces
571 uci_r:foreach("network", "interface",
573 _list_del("network", s['.name'], "ifname", ifname)
576 -- if its a wifi interface, change its network option
577 local wif = _wifi_lookup(ifname)
579 uci_r:set("wireless", wif, "network", self.sid)
581 -- add iface to our iface list
583 _list_add("network", self.sid, "ifname", ifname)
588 function network.del_interface(self, ifname)
589 if not self:is_virtual() then
590 if utl.instanceof(ifname, interface) then
591 ifname = ifname:name()
593 ifname = ifname:match("[^%s:]+")
596 -- if its a wireless interface, clear its network option
597 local wif = _wifi_lookup(ifname)
598 if wif then uci_r:delete("wireless", wif, "network") end
600 -- remove the interface
601 _list_del("network", self.sid, "ifname", ifname)
605 function network.get_interfaces(self)
609 if self:is_virtual() then
610 ifn = self:proto() .. "-" .. self.sid
611 ifaces = { interface(ifn) }
614 for ifn in utl.imatch(self:get("ifname")) do
615 ifn = ifn:match("[^:]+")
616 nfs[ifn] = interface(ifn)
619 for ifn in utl.kspairs(nfs) do
620 ifaces[#ifaces+1] = nfs[ifn]
625 uci_r:foreach("wireless", "wifi-iface",
628 num[s.device] = num[s.device] and num[s.device] + 1 or 1
629 if s.network == self.sid then
630 ifn = "%s.network%d" %{ s.device, num[s.device] }
631 wfs[ifn] = interface(ifn)
636 for ifn in utl.kspairs(wfs) do
637 ifaces[#ifaces+1] = wfs[ifn]
644 function network.contains_interface(self, ifname)
645 if type(ifname) ~= "string" then
646 ifname = ifname:name()
648 ifname = ifname:match("[^%s:]+")
652 if self:is_virtual() then
653 ifn = self:proto() .. "-" .. self.sid
656 for ifn in utl.imatch(self:get("ifname")) do
657 ifn = ifn:match("[^:]+")
658 if ifn == ifname then
663 local wif = _wifi_lookup(ifname)
665 return (uci_r:get("wireless", wif, "network") == self.sid)
672 function network.adminlink(self)
673 return dsp.build_url("admin", "network", "network", self.sid)
677 interface = utl.class()
678 function interface.__init__(self, ifname)
679 local wif = _wifi_lookup(ifname)
680 if wif then self.wif = wifinet(wif) end
682 self.ifname = self.ifname or ifname
683 self.dev = ifs[self.ifname]
686 function interface.name(self)
687 return self.wif and self.wif:ifname() or self.ifname
690 function interface.mac(self)
691 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
694 function interface.ipaddrs(self)
695 return self.dev and self.dev.ipaddrs or { }
698 function interface.ip6addrs(self)
699 return self.dev and self.dev.ip6addrs or { }
702 function interface.type(self)
703 if self.wif or _wifi_iface(self.ifname) then
705 elseif brs[self.ifname] then
707 elseif sws[self.ifname] or self.ifname:match("%.") then
714 function interface.shortname(self)
717 self.wif:active_mode(),
718 self.wif:active_ssid() or self.wif:active_bssid()
725 function interface.get_i18n(self)
727 return "%s: %s %q" %{
728 i18n.translate("Wireless Network"),
729 self.wif:active_mode(),
730 self.wif:active_ssid() or self.wif:active_bssid()
733 return "%s: %q" %{ self:get_type_i18n(), self:name() }
737 function interface.get_type_i18n(self)
738 local x = self:type()
740 return i18n.translate("Wireless Adapter")
741 elseif x == "bridge" then
742 return i18n.translate("Bridge")
743 elseif x == "switch" then
744 return i18n.translate("Ethernet Switch")
746 return i18n.translate("Ethernet Adapter")
750 function interface.adminlink(self)
752 return self.wif:adminlink()
756 function interface.ports(self)
760 for _, iface in ipairs(self.br.ifnames) do
761 ifaces[#ifaces+1] = interface(iface.name)
767 function interface.bridge_id(self)
775 function interface.bridge_stp(self)
783 function interface.is_up(self)
785 return self.wif:is_up()
787 return self.dev and self.dev.flags and self.dev.flags.up or false
791 function interface.is_bridge(self)
792 return (self:type() == "bridge")
795 function interface.is_bridgeport(self)
796 return self.dev and self.dev.bridge and true or false
799 function interface.tx_bytes(self)
800 return self.dev and self.dev.stats
801 and self.dev.stats.tx_bytes or 0
804 function interface.rx_bytes(self)
805 return self.dev and self.dev.stats
806 and self.dev.stats.rx_bytes or 0
809 function interface.tx_packets(self)
810 return self.dev and self.dev.stats
811 and self.dev.stats.tx_packets or 0
814 function interface.rx_packets(self)
815 return self.dev and self.dev.stats
816 and self.dev.stats.rx_packets or 0
819 function interface.get_network(self)
820 if self.dev and self.dev.network then
821 self.network = _M:get_network(self.dev.network)
824 if not self.network then
826 for _, net in ipairs(_M:get_networks()) do
827 if net:contains_interface(self.ifname) then
837 function interface.get_wifinet(self)
842 wifidev = utl.class()
843 function wifidev.__init__(self, dev)
847 function wifidev.get(self, opt)
848 return _get("wireless", self.sid, opt)
851 function wifidev.set(self, opt, val)
852 return _set("wireless", self.sid, opt, val)
855 function wifidev.name(self)
859 function wifidev.is_up(self)
862 uci_s:foreach("wireless", "wifi-iface",
864 if s.device == self.sid then
875 function wifidev.get_wifinet(self, net)
876 if uci_r:get("wireless", net) == "wifi-iface" then
879 local wnet = _wifi_lookup(net)
886 function wifidev.get_wifinets(self)
889 uci_r:foreach("wireless", "wifi-iface",
891 if s.device == self.sid then
892 nets[#nets+1] = wifinet(s['.name'])
899 function wifidev.add_wifinet(self, options)
900 options = options or { }
901 options.device = self.sid
903 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
905 return wifinet(wnet, options)
909 function wifidev.del_wifinet(self, net)
910 if utl.instanceof(net, wifinet) then
912 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
913 net = _wifi_lookup(net)
916 if net and uci_r:get("wireless", net, "device") == self.sid then
917 uci_r:delete("wireless", net)
925 wifinet = utl.class()
926 function wifinet.__init__(self, net, data)
929 local dev = uci_s:get("wireless", self.sid, "ifname")
932 uci_r:foreach("wireless", "wifi-iface",
935 num[s.device] = num[s.device] and num[s.device] + 1 or 1
936 if s['.name'] == self.sid then
937 dev = "%s.network%d" %{ s.device, num[s.device] }
945 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
946 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
947 uci_r:get_all("wireless", self.sid) or { }
950 function wifinet.get(self, opt)
951 return _get("wireless", self.sid, opt)
954 function wifinet.set(self, opt, val)
955 return _set("wireless", self.sid, opt, val)
958 function wifinet.mode(self)
959 return uci_s:get("wireless", self.sid, "mode") or "ap"
962 function wifinet.ssid(self)
963 return uci_s:get("wireless", self.sid, "ssid")
966 function wifinet.bssid(self)
967 return uci_s:get("wireless", self.sid, "bssid")
970 function wifinet.network(self)
971 return uci_s:get("wifinet", self.sid, "network")
974 function wifinet.name(self)
978 function wifinet.ifname(self)
979 local ifname = self.iwinfo.ifname
980 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
986 function wifinet.get_device(self)
987 if self.iwdata.device then
988 return wifidev(self.iwdata.device)
992 function wifinet.is_up(self)
993 return (self.iwdata.up == "1")
996 function wifinet.active_mode(self)
997 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
999 if m == "ap" then m = "AP"
1000 elseif m == "sta" then m = "Client"
1001 elseif m == "adhoc" then m = "Ad-Hoc"
1002 elseif m == "mesh" then m = "Mesh"
1003 elseif m == "monitor" then m = "Monitor"
1009 function wifinet.active_mode_i18n(self)
1010 return i18n.translate(self:active_mode())
1013 function wifinet.active_ssid(self)
1014 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1017 function wifinet.active_bssid(self)
1018 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1021 function wifinet.active_encryption(self)
1022 local enc = self.iwinfo and self.iwinfo.encryption
1023 return enc and enc.description or "-"
1026 function wifinet.assoclist(self)
1027 return self.iwinfo.assoclist or { }
1030 function wifinet.frequency(self)
1031 local freq = self.iwinfo.frequency
1032 if freq and freq > 0 then
1033 return "%.03f" % (freq / 1000)
1037 function wifinet.bitrate(self)
1038 local rate = self.iwinfo.bitrate
1039 if rate and rate > 0 then
1040 return (rate / 1000)
1044 function wifinet.channel(self)
1045 return self.iwinfo.channel or
1046 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1049 function wifinet.signal(self)
1050 return self.iwinfo.signal or 0
1053 function wifinet.noise(self)
1054 return self.iwinfo.noise or 0
1057 function wifinet.signal_level(self, s, n)
1058 if self:active_bssid() ~= "00:00:00:00:00:00" then
1059 local signal = s or self:signal()
1060 local noise = n or self:noise()
1062 if signal < 0 and noise < 0 then
1063 local snr = -1 * (noise - signal)
1064 return math.floor(snr / 5)
1073 function wifinet.signal_percent(self)
1074 local qc = self.iwinfo.quality or 0
1075 local qm = self.iwinfo.quality_max or 0
1077 if qc > 0 and qm > 0 then
1078 return math.floor((100 / qm) * qc)
1084 function wifinet.shortname(self)
1086 i18n.translate(self:active_mode()),
1087 self:active_ssid() or self:active_bssid()
1091 function wifinet.get_i18n(self)
1092 return "%s: %s %q (%s)" %{
1093 i18n.translate("Wireless Network"),
1094 i18n.translate(self:active_mode()),
1095 self:active_ssid() or self:active_bssid(),
1100 function wifinet.adminlink(self)
1101 return dsp.build_url("admin", "network", "wireless",
1102 self.iwdata.device, self.wdev)
1105 function wifinet.get_network(self)
1106 if uci_r:get("network", self.iwdata.network) == "interface" then
1107 return network(self.iwdata.network)
1111 function wifinet.get_interface(self)
1112 return interface(self:ifname())