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:del(c, s, o, v)
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 luci.model.uci.cursor()
165 uci_s = cursor: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)
376 -- find normal interfaces
377 for iface in utl.kspairs(ifs) do
378 if not _iface_ignore(iface) and not _wifi_iface(iface) then
379 ifaces[#ifaces+1] = interface(iface)
383 -- find wifi interfaces
386 uci_r:foreach("wireless", "wifi-iface",
389 num[s.device] = num[s.device] and num[s.device] + 1 or 1
390 local i = "%s.network%d" %{ s.device, num[s.device] }
391 wfs[i] = interface(i)
395 for iface in utl.kspairs(wfs) do
396 ifaces[#ifaces+1] = wfs[iface]
402 function ignore_interface(self, x)
403 return _iface_ignore(x)
406 function get_wifidev(self, dev)
407 if uci_r:get("wireless", dev) == "wifi-device" then
412 function get_wifidevs(self)
416 uci_r:foreach("wireless", "wifi-device",
417 function(s) wfd[#wfd+1] = s['.name'] end)
420 for _, dev in utl.vspairs(wfd) do
421 devs[#devs+1] = wifidev(dev)
427 function get_wifinet(self, net)
428 local wnet = _wifi_lookup(net)
434 function add_wifinet(self, net, options)
435 if type(options) == "table" and options.device and
436 uci_r:get("wireless", options.device) == "wifi-device"
438 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
443 function del_wifinet(self, net)
444 local wnet = _wifi_lookup(net)
446 uci_r:delete("wireless", wnet)
453 network = utl.class()
455 function network.__init__(self, name)
459 function network._get(self, opt)
460 local v = uci_r:get("network", self.sid, opt)
461 if type(v) == "table" then
462 return table.concat(v, " ")
467 function network.get(self, opt)
468 return _get("network", self.sid, opt)
471 function network.set(self, opt, val)
472 return _set("network", self.sid, opt, val)
475 function network.ifname(self)
476 local p = self:proto()
477 if self:is_bridge() then
478 return "br-" .. self.sid
479 elseif self:is_virtual() then
480 return p .. "-" .. self.sid
482 local dev = self:_get("ifname") or
483 uci_r:get("network", self.sid, "ifname")
485 dev = dev and dev:match("%S+")
488 uci_r:foreach("wireless", "wifi-iface",
491 num[s.device] = num[s.device]
492 and num[s.device] + 1 or 1
494 if s.network == self.sid then
495 dev = "%s.network%d" %{ s.device, num[s.device] }
506 function network.device(self)
507 local dev = self:_get("device")
508 if not dev or dev:match("[^%w%-%.%s]") then
509 dev = uci_r:get("network", self.sid, "ifname")
514 function network.proto(self)
515 return self:_get("proto") or "none"
518 function network.type(self)
519 return self:_get("type")
522 function network.name(self)
526 function network.is_bridge(self)
527 return (self:type() == "bridge")
530 function network.is_virtual(self)
531 local p = self:proto()
533 p == "3g" or p == "6in4" or p == "ppp" or
534 p == "pppoe" or p == "pppoa"
538 function network.is_empty(self)
539 if self:is_virtual() then
544 if (self:_get("ifname") or ""):match("%S+") then
548 uci_r:foreach("wireless", "wifi-iface",
550 if s.network == self.sid then
560 function network.add_interface(self, ifname)
561 if not self:is_virtual() then
562 if type(ifname) ~= "string" then
563 ifname = ifname:name()
565 ifname = ifname:match("[^%s:]+")
568 -- remove the interface from all ifaces
569 uci_r:foreach("network", "interface",
571 _list_del("network", s['.name'], "ifname", ifname)
574 -- if its a wifi interface, change its network option
575 local wif = _wifi_lookup(ifname)
577 uci_r:set("wireless", wif, "network", self.sid)
579 -- add iface to our iface list
581 _list_add("network", self.sid, "ifname", ifname)
586 function network.del_interface(self, ifname)
587 if not self:is_virtual() then
588 if utl.instanceof(ifname, interface) then
589 ifname = ifname:name()
591 ifname = ifname:match("[^%s:]+")
594 -- if its a wireless interface, clear its network option
595 local wif = _wifi_lookup(ifname)
596 if wif then uci_r:delete("wireless", wif, "network") end
598 -- remove the interface
599 _list_del("network", self.sid, "ifname", ifname)
603 function network.get_interfaces(self)
607 if self:is_virtual() then
608 ifn = self:proto() .. "-" .. self.sid
609 ifaces = { interface(ifn) }
612 for ifn in self:_get("ifname"):gmatch("%S+") do
613 ifn = ifn:match("[^:]+")
614 nfs[ifn] = interface(ifn)
617 for ifn in utl.kspairs(nfs) do
618 ifaces[#ifaces+1] = nfs[ifn]
623 uci_r:foreach("wireless", "wifi-iface",
626 num[s.device] = num[s.device] and num[s.device] + 1 or 1
627 if s.network == self.sid then
628 ifn = "%s.network%d" %{ s.device, num[s.device] }
629 wfs[ifn] = interface(ifn)
634 for ifn in utl.kspairs(wfs) do
635 ifaces[#ifaces+1] = wfs[ifn]
642 function network.contains_interface(self, ifname)
643 if type(ifname) ~= "string" then
644 ifname = ifname:name()
646 ifname = ifname:match("[^%s:]+")
650 if self:is_virtual() then
651 ifn = self:proto() .. "-" .. self.sid
654 for ifn in self:_get("ifname"):gmatch("%S+") do
655 ifn = ifn:match("[^:]+")
656 if ifn == ifname then
661 local wif = _wifi_lookup(ifname)
663 return (uci_r:get("wireless", wif, "network") == self.sid)
670 function network.adminlink(self)
671 return dsp.build_url("admin", "network", "network", self.sid)
675 interface = utl.class()
676 function interface.__init__(self, ifname)
677 local wif = _wifi_lookup(ifname)
678 if wif then self.wif = wifinet(wif) end
680 self.ifname = self.ifname or ifname
681 self.dev = ifs[self.ifname]
684 function interface.name(self)
685 return self.wif and self.wif:ifname() or self.ifname
688 function interface.mac(self)
689 return self.dev and self.dev or "00:00:00:00:00:00"
692 function interface.ipaddrs(self)
693 return self.dev and self.dev.ipaddrs or { }
696 function interface.ip6addrs(self)
697 return self.dev and self.dev.ip6addrs or { }
700 function interface.type(self)
701 if self.wif or _wifi_iface(self.ifname) then
703 elseif brs[self.ifname] then
705 elseif sws[self.ifname] or self.ifname:match("%.") then
712 function interface.shortname(self)
715 self.wif:active_mode(),
716 self.wif:active_ssid() or self.wif:active_bssid()
723 function interface.get_i18n(self)
725 return "%s: %s %q" %{
726 i18n.translate("Wireless Network"),
727 self.wif:active_mode(),
728 self.wif:active_ssid() or self.wif:active_bssid()
731 return "%s: %q" %{ self:get_type_i18n(), self:name() }
735 function interface.get_type_i18n(self)
736 local x = self:type()
738 return i18n.translate("Wireless Adapter")
739 elseif x == "bridge" then
740 return i18n.translate("Bridge")
741 elseif x == "switch" then
742 return i18n.translate("Ethernet Switch")
744 return i18n.translate("Ethernet Adapter")
748 function interface.adminlink(self)
750 return self.wif:adminlink()
754 function interface.ports(self)
758 for _, iface in ipairs(self.br.ifnames) do
759 ifaces[#ifaces+1] = interface(iface.name)
765 function interface.bridge_id(self)
773 function interface.bridge_stp(self)
781 function interface.is_up(self)
783 return self.wif:is_up()
785 return self.dev and self.dev.flags and self.dev.flags.up or false
789 function interface.is_bridge(self)
790 return (self:type() == "bridge")
793 function interface.is_bridgeport(self)
794 return self.dev and self.dev.bridge and true or false
797 function interface.tx_bytes(self)
798 return self.dev and self.dev.stats
799 and self.dev.stats.tx_bytes or 0
802 function interface.rx_bytes(self)
803 return self.dev and self.dev.stats
804 and self.dev.stats.rx_bytes or 0
807 function interface.tx_packets(self)
808 return self.dev and self.dev.stats
809 and self.dev.stats.tx_packets or 0
812 function interface.rx_packets(self)
813 return self.dev and self.dev.stats
814 and self.dev.stats.rx_packets or 0
817 function interface.get_network(self)
818 if self.dev and self.dev.network then
819 self.network = _M:get_network(self.dev.network)
822 if not self.network then
824 for _, net in ipairs(_M:get_networks()) do
825 if net:contains_interface(self.ifname) then
835 function interface.get_wifinet(self)
840 wifidev = utl.class()
841 function wifidev.__init__(self, dev)
845 function wifidev.get(self, opt)
846 return _get("wireless", self.sid, opt)
849 function wifidev.set(self, opt, val)
850 return _set("wireless", self.sid, opt, val)
853 function wifidev.name(self)
857 function wifidev.is_up(self)
860 uci_s:foreach("wireless", "wifi-iface",
862 if s.device == self.sid then
873 function wifidev.get_wifinet(self, net)
874 if uci_r:get("wireless", net) == "wifi-iface" then
877 local wnet = _wifi_lookup(net)
884 function wifidev.get_wifinets(self)
887 uci_r:foreach("wireless", "wifi-iface",
889 if s.device == self.sid then
890 nets[#nets+1] = wifinet(s['.name'])
897 function wifidev.add_wifinet(self, options)
898 options = options or { }
899 options.device = self.sid
901 local wnet = uci_r:section("wifidev", "wifi-iface", nil, options)
907 function wifidev.del_wifinet(self, net)
908 if utl.instanceof(net, wifinet) then
910 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
911 net = _wifi_lookup(net)
914 if net and uci_r:get("wireless", net, "device") == self.sid then
915 uci_r:delete("wireless", net)
923 wifinet = utl.class()
924 function wifinet.__init__(self, net)
927 local dev = uci_s:get("wireless", self.sid, "ifname")
930 uci_r:foreach("wireless", "wifi-iface",
933 num[s.device] = num[s.device] and num[s.device] + 1 or 1
934 if s['.name'] == self.sid then
935 dev = "%s.network%d" %{ s.device, num[s.device] }
943 self.iwdata = uci_s:get_all("wireless", self.sid) or { }
944 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
947 function wifinet.get(self, opt)
948 return _get("wireless", self.sid, opt)
951 function wifinet.set(self, opt, val)
952 return _set("wireless", self.sid, opt, val)
955 function wifinet.mode(self)
956 return uci_s:get("wireless", self.sid, "mode") or "ap"
959 function wifinet.ssid(self)
960 return uci_s:get("wireless", self.sid, "ssid")
963 function wifinet.bssid(self)
964 return uci_s:get("wireless", self.sid, "bssid")
967 function wifinet.network(self)
968 return uci_s:get("wifinet", self.sid, "network")
971 function wifinet.name(self)
975 function wifinet.ifname(self)
976 return self.iwinfo.ifname or self.wdev
979 function wifinet.get_device(self)
980 if self.iwdata.device then
981 return wifidev(self.iwdata.device)
985 function wifinet.is_up(self)
986 return (self.iwdata.up == "1")
989 function wifinet.active_mode(self)
990 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
992 if m == "ap" then m = "AP"
993 elseif m == "sta" then m = "Client"
994 elseif m == "adhoc" then m = "Ad-Hoc"
995 elseif m == "mesh" then m = "Mesh"
996 elseif m == "monitor" then m = "Monitor"
1002 function wifinet.active_mode_i18n(self)
1003 return i18n.translate(self:active_mode())
1006 function wifinet.active_ssid(self)
1007 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1010 function wifinet.active_bssid(self)
1011 return _stror(self.iwinfo.bssid, self.iwinfo.bssid) or "00:00:00:00:00:00"
1014 function wifinet.active_encryption(self)
1015 local enc = self.iwinfo and self.iwinfo.encryption
1016 return enc and enc.description or "-"
1019 function wifinet.assoclist(self)
1020 return self.iwinfo.assoclist or { }
1023 function wifinet.frequency(self)
1024 local freq = self.iwinfo.frequency
1025 if freq and freq > 0 then
1026 return "%.03f" % (freq / 1000)
1030 function wifinet.bitrate(self)
1031 local rate = self.iwinfo.bitrate
1032 if rate and rate > 0 then
1033 return (rate / 1000)
1037 function wifinet.channel(self)
1038 return self.iwinfo.channel or
1039 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1042 function wifinet.signal(self)
1043 return self.iwinfo.signal or 0
1046 function wifinet.noise(self)
1047 return self.iwinfo.noise or 0
1050 function wifinet.signal_level(self, s, n)
1051 if self:active_bssid() ~= "00:00:00:00:00:00" then
1052 local signal = s or self:signal()
1053 local noise = n or self:noise()
1055 if signal < 0 and noise < 0 then
1056 local snr = -1 * (noise - signal)
1057 return math.floor(snr / 5)
1066 function wifinet.signal_percent(self)
1067 local qc = self.iwinfo.quality or 0
1068 local qm = self.iwinfo.quality_max or 0
1070 if qc > 0 and qm > 0 then
1071 return math.floor((100 / qm) * qc)
1077 function wifinet.shortname(self)
1079 i18n.translate(self:active_mode()),
1080 self:active_ssid() or self:active_bssid()
1084 function wifinet.get_i18n(self)
1085 return "%s: %s %q (%s)" %{
1086 i18n.translate("Wireless Network"),
1087 i18n.translate(self:active_mode()),
1088 self:active_ssid() or self:active_bssid(),
1093 function wifinet.adminlink(self)
1094 return dsp.build_url("admin", "network", "wireless",
1095 self.iwdata.device, self.wdev)
1098 function wifinet.get_network(self)
1099 if uci_r:get("network", self.iwdata.network) == "interface" then
1100 return network(self.iwdata.network)
1104 function wifinet.get_interface(self)
1105 return interface(self:ifname())