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)
378 -- find normal interfaces
379 uci_r:foreach("network", "interface",
381 for iface in utl.imatch(s.ifname) do
382 if not _iface_ignore(iface) and not _wifi_iface(iface) then
384 nfs[iface] = interface(iface)
389 for iface in utl.kspairs(ifs) do
390 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
391 nfs[iface] = interface(iface)
395 for iface in utl.kspairs(nfs) do
396 ifaces[#ifaces+1] = nfs[iface]
399 -- find wifi interfaces
402 uci_r:foreach("wireless", "wifi-iface",
405 num[s.device] = num[s.device] and num[s.device] + 1 or 1
406 local i = "%s.network%d" %{ s.device, num[s.device] }
407 wfs[i] = interface(i)
411 for iface in utl.kspairs(wfs) do
412 ifaces[#ifaces+1] = wfs[iface]
418 function ignore_interface(self, x)
419 return _iface_ignore(x)
422 function get_wifidev(self, dev)
423 if uci_r:get("wireless", dev) == "wifi-device" then
428 function get_wifidevs(self)
432 uci_r:foreach("wireless", "wifi-device",
433 function(s) wfd[#wfd+1] = s['.name'] end)
436 for _, dev in utl.vspairs(wfd) do
437 devs[#devs+1] = wifidev(dev)
443 function get_wifinet(self, net)
444 local wnet = _wifi_lookup(net)
450 function add_wifinet(self, net, options)
451 if type(options) == "table" and options.device and
452 uci_r:get("wireless", options.device) == "wifi-device"
454 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
459 function del_wifinet(self, net)
460 local wnet = _wifi_lookup(net)
462 uci_r:delete("wireless", wnet)
469 network = utl.class()
471 function network.__init__(self, name)
475 function network._get(self, opt)
476 local v = uci_r:get("network", self.sid, opt)
477 if type(v) == "table" then
478 return table.concat(v, " ")
483 function network.get(self, opt)
484 return _get("network", self.sid, opt)
487 function network.set(self, opt, val)
488 return _set("network", self.sid, opt, val)
491 function network.ifname(self)
492 local p = self:proto()
493 if self:is_bridge() then
494 return "br-" .. self.sid
495 elseif self:is_virtual() then
496 return p .. "-" .. self.sid
498 local dev = self:_get("ifname") or
499 uci_r:get("network", self.sid, "ifname")
501 dev = dev and dev:match("%S+")
504 uci_r:foreach("wireless", "wifi-iface",
507 num[s.device] = num[s.device]
508 and num[s.device] + 1 or 1
510 if s.network == self.sid then
511 dev = "%s.network%d" %{ s.device, num[s.device] }
522 function network.device(self)
523 local dev = self:_get("device")
524 if not dev or dev:match("[^%w%-%.%s]") then
525 dev = uci_r:get("network", self.sid, "ifname")
530 function network.proto(self)
531 return self:_get("proto") or "none"
534 function network.type(self)
535 return self:_get("type")
538 function network.name(self)
542 function network.is_bridge(self)
543 return (self:type() == "bridge")
546 function network.is_virtual(self)
547 local p = self:proto()
549 p == "3g" or p == "6in4" or p == "ppp" or
550 p == "pppoe" or p == "pppoa"
554 function network.is_empty(self)
555 if self:is_virtual() then
560 if (self:_get("ifname") or ""):match("%S+") then
564 uci_r:foreach("wireless", "wifi-iface",
566 if s.network == self.sid then
576 function network.add_interface(self, ifname)
577 if not self:is_virtual() then
578 if type(ifname) ~= "string" then
579 ifname = ifname:name()
581 ifname = ifname:match("[^%s:]+")
584 -- remove the interface from all ifaces
585 uci_r:foreach("network", "interface",
587 _list_del("network", s['.name'], "ifname", ifname)
590 -- if its a wifi interface, change its network option
591 local wif = _wifi_lookup(ifname)
593 uci_r:set("wireless", wif, "network", self.sid)
595 -- add iface to our iface list
597 _list_add("network", self.sid, "ifname", ifname)
602 function network.del_interface(self, ifname)
603 if not self:is_virtual() then
604 if utl.instanceof(ifname, interface) then
605 ifname = ifname:name()
607 ifname = ifname:match("[^%s:]+")
610 -- if its a wireless interface, clear its network option
611 local wif = _wifi_lookup(ifname)
612 if wif then uci_r:delete("wireless", wif, "network") end
614 -- remove the interface
615 _list_del("network", self.sid, "ifname", ifname)
619 function network.get_interfaces(self)
623 if self:is_virtual() then
624 ifn = self:proto() .. "-" .. self.sid
625 ifaces = { interface(ifn) }
628 for ifn in utl.imatch(self:get("ifname")) do
629 ifn = ifn:match("[^:]+")
630 nfs[ifn] = interface(ifn)
633 for ifn in utl.kspairs(nfs) do
634 ifaces[#ifaces+1] = nfs[ifn]
639 uci_r:foreach("wireless", "wifi-iface",
642 num[s.device] = num[s.device] and num[s.device] + 1 or 1
643 if s.network == self.sid then
644 ifn = "%s.network%d" %{ s.device, num[s.device] }
645 wfs[ifn] = interface(ifn)
650 for ifn in utl.kspairs(wfs) do
651 ifaces[#ifaces+1] = wfs[ifn]
658 function network.contains_interface(self, ifname)
659 if type(ifname) ~= "string" then
660 ifname = ifname:name()
662 ifname = ifname:match("[^%s:]+")
666 if self:is_virtual() then
667 ifn = self:proto() .. "-" .. self.sid
670 for ifn in utl.imatch(self:get("ifname")) do
671 ifn = ifn:match("[^:]+")
672 if ifn == ifname then
677 local wif = _wifi_lookup(ifname)
679 return (uci_r:get("wireless", wif, "network") == self.sid)
686 function network.adminlink(self)
687 return dsp.build_url("admin", "network", "network", self.sid)
691 interface = utl.class()
692 function interface.__init__(self, ifname)
693 local wif = _wifi_lookup(ifname)
694 if wif then self.wif = wifinet(wif) end
696 self.ifname = self.ifname or ifname
697 self.dev = ifs[self.ifname]
700 function interface.name(self)
701 return self.wif and self.wif:ifname() or self.ifname
704 function interface.mac(self)
705 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
708 function interface.ipaddrs(self)
709 return self.dev and self.dev.ipaddrs or { }
712 function interface.ip6addrs(self)
713 return self.dev and self.dev.ip6addrs or { }
716 function interface.type(self)
717 if self.wif or _wifi_iface(self.ifname) then
719 elseif brs[self.ifname] then
721 elseif sws[self.ifname] or self.ifname:match("%.") then
728 function interface.shortname(self)
731 self.wif:active_mode(),
732 self.wif:active_ssid() or self.wif:active_bssid()
739 function interface.get_i18n(self)
741 return "%s: %s %q" %{
742 i18n.translate("Wireless Network"),
743 self.wif:active_mode(),
744 self.wif:active_ssid() or self.wif:active_bssid()
747 return "%s: %q" %{ self:get_type_i18n(), self:name() }
751 function interface.get_type_i18n(self)
752 local x = self:type()
754 return i18n.translate("Wireless Adapter")
755 elseif x == "bridge" then
756 return i18n.translate("Bridge")
757 elseif x == "switch" then
758 return i18n.translate("Ethernet Switch")
760 return i18n.translate("Ethernet Adapter")
764 function interface.adminlink(self)
766 return self.wif:adminlink()
770 function interface.ports(self)
774 for _, iface in ipairs(self.br.ifnames) do
775 ifaces[#ifaces+1] = interface(iface.name)
781 function interface.bridge_id(self)
789 function interface.bridge_stp(self)
797 function interface.is_up(self)
799 return self.wif:is_up()
801 return self.dev and self.dev.flags and self.dev.flags.up or false
805 function interface.is_bridge(self)
806 return (self:type() == "bridge")
809 function interface.is_bridgeport(self)
810 return self.dev and self.dev.bridge and true or false
813 function interface.tx_bytes(self)
814 return self.dev and self.dev.stats
815 and self.dev.stats.tx_bytes or 0
818 function interface.rx_bytes(self)
819 return self.dev and self.dev.stats
820 and self.dev.stats.rx_bytes or 0
823 function interface.tx_packets(self)
824 return self.dev and self.dev.stats
825 and self.dev.stats.tx_packets or 0
828 function interface.rx_packets(self)
829 return self.dev and self.dev.stats
830 and self.dev.stats.rx_packets or 0
833 function interface.get_network(self)
834 if self.dev and self.dev.network then
835 self.network = _M:get_network(self.dev.network)
838 if not self.network then
840 for _, net in ipairs(_M:get_networks()) do
841 if net:contains_interface(self.ifname) then
851 function interface.get_wifinet(self)
856 wifidev = utl.class()
857 function wifidev.__init__(self, dev)
861 function wifidev.get(self, opt)
862 return _get("wireless", self.sid, opt)
865 function wifidev.set(self, opt, val)
866 return _set("wireless", self.sid, opt, val)
869 function wifidev.name(self)
873 function wifidev.is_up(self)
876 uci_s:foreach("wireless", "wifi-iface",
878 if s.device == self.sid then
889 function wifidev.get_wifinet(self, net)
890 if uci_r:get("wireless", net) == "wifi-iface" then
893 local wnet = _wifi_lookup(net)
900 function wifidev.get_wifinets(self)
903 uci_r:foreach("wireless", "wifi-iface",
905 if s.device == self.sid then
906 nets[#nets+1] = wifinet(s['.name'])
913 function wifidev.add_wifinet(self, options)
914 options = options or { }
915 options.device = self.sid
917 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
919 return wifinet(wnet, options)
923 function wifidev.del_wifinet(self, net)
924 if utl.instanceof(net, wifinet) then
926 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
927 net = _wifi_lookup(net)
930 if net and uci_r:get("wireless", net, "device") == self.sid then
931 uci_r:delete("wireless", net)
939 wifinet = utl.class()
940 function wifinet.__init__(self, net, data)
943 local dev = uci_s:get("wireless", self.sid, "ifname")
946 uci_r:foreach("wireless", "wifi-iface",
949 num[s.device] = num[s.device] and num[s.device] + 1 or 1
950 if s['.name'] == self.sid then
951 dev = "%s.network%d" %{ s.device, num[s.device] }
959 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
960 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
961 uci_r:get_all("wireless", self.sid) or { }
964 function wifinet.get(self, opt)
965 return _get("wireless", self.sid, opt)
968 function wifinet.set(self, opt, val)
969 return _set("wireless", self.sid, opt, val)
972 function wifinet.mode(self)
973 return uci_s:get("wireless", self.sid, "mode") or "ap"
976 function wifinet.ssid(self)
977 return uci_s:get("wireless", self.sid, "ssid")
980 function wifinet.bssid(self)
981 return uci_s:get("wireless", self.sid, "bssid")
984 function wifinet.network(self)
985 return uci_s:get("wifinet", self.sid, "network")
988 function wifinet.name(self)
992 function wifinet.ifname(self)
993 return self.iwinfo.ifname or self.wdev
996 function wifinet.get_device(self)
997 if self.iwdata.device then
998 return wifidev(self.iwdata.device)
1002 function wifinet.is_up(self)
1003 return (self.iwdata.up == "1")
1006 function wifinet.active_mode(self)
1007 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1009 if m == "ap" then m = "AP"
1010 elseif m == "sta" then m = "Client"
1011 elseif m == "adhoc" then m = "Ad-Hoc"
1012 elseif m == "mesh" then m = "Mesh"
1013 elseif m == "monitor" then m = "Monitor"
1019 function wifinet.active_mode_i18n(self)
1020 return i18n.translate(self:active_mode())
1023 function wifinet.active_ssid(self)
1024 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1027 function wifinet.active_bssid(self)
1028 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1031 function wifinet.active_encryption(self)
1032 local enc = self.iwinfo and self.iwinfo.encryption
1033 return enc and enc.description or "-"
1036 function wifinet.assoclist(self)
1037 return self.iwinfo.assoclist or { }
1040 function wifinet.frequency(self)
1041 local freq = self.iwinfo.frequency
1042 if freq and freq > 0 then
1043 return "%.03f" % (freq / 1000)
1047 function wifinet.bitrate(self)
1048 local rate = self.iwinfo.bitrate
1049 if rate and rate > 0 then
1050 return (rate / 1000)
1054 function wifinet.channel(self)
1055 return self.iwinfo.channel or
1056 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1059 function wifinet.signal(self)
1060 return self.iwinfo.signal or 0
1063 function wifinet.noise(self)
1064 return self.iwinfo.noise or 0
1067 function wifinet.signal_level(self, s, n)
1068 if self:active_bssid() ~= "00:00:00:00:00:00" then
1069 local signal = s or self:signal()
1070 local noise = n or self:noise()
1072 if signal < 0 and noise < 0 then
1073 local snr = -1 * (noise - signal)
1074 return math.floor(snr / 5)
1083 function wifinet.signal_percent(self)
1084 local qc = self.iwinfo.quality or 0
1085 local qm = self.iwinfo.quality_max or 0
1087 if qc > 0 and qm > 0 then
1088 return math.floor((100 / qm) * qc)
1094 function wifinet.shortname(self)
1096 i18n.translate(self:active_mode()),
1097 self:active_ssid() or self:active_bssid()
1101 function wifinet.get_i18n(self)
1102 return "%s: %s %q (%s)" %{
1103 i18n.translate("Wireless Network"),
1104 i18n.translate(self:active_mode()),
1105 self:active_ssid() or self:active_bssid(),
1110 function wifinet.adminlink(self)
1111 return dsp.build_url("admin", "network", "wireless",
1112 self.iwdata.device, self.wdev)
1115 function wifinet.get_network(self)
1116 if uci_r:get("network", self.iwdata.network) == "interface" then
1117 return network(self.iwdata.network)
1121 function wifinet.get_interface(self)
1122 return interface(self:ifname())