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, next, pairs, ipairs, loadfile, table, tonumber, math, i18n
21 = type, next, pairs, ipairs, loadfile, table, tonumber, math, luci.i18n
23 local require = require
25 local nxo = require "nixio"
26 local nfs = require "nixio.fs"
27 local ipc = require "luci.ip"
28 local sys = require "luci.sys"
29 local utl = require "luci.util"
30 local dsp = require "luci.dispatcher"
31 local uci = require "luci.model.uci"
33 module "luci.model.network"
36 IFACE_PATTERNS_VIRTUAL = { }
37 IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^lo$" }
38 IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
42 proto.generic = utl.class()
44 local _interfaces, _bridge, _switch, _tunnel
45 local _uci_real, _uci_state
47 function _filter(c, s, o, r)
48 local val = _uci_real:get(c, s, o)
51 if type(val) == "string" then
52 for val in val:gmatch("%S+") do
58 _uci_real:set(c, s, o, table.concat(l, " "))
60 _uci_real:delete(c, s, o)
62 elseif type(val) == "table" then
63 for _, val in ipairs(val) do
69 _uci_real:set(c, s, o, l)
71 _uci_real:delete(c, s, o)
77 function _append(c, s, o, a)
78 local val = _uci_real:get(c, s, o) or ""
79 if type(val) == "string" then
81 for val in val:gmatch("%S+") do
87 _uci_real:set(c, s, o, table.concat(l, " "))
88 elseif type(val) == "table" then
90 for _, val in ipairs(val) do
96 _uci_real:set(c, s, o, l)
100 function _stror(s1, s2)
101 if not s1 or #s1 == 0 then
102 return s2 and #s2 > 0 and s2
108 function _get(c, s, o)
109 return _uci_real:get(c, s, o)
112 function _set(c, s, o, v)
114 if type(v) == "boolean" then v = v and "1" or "0" end
115 return _uci_real:set(c, s, o, v)
117 return _uci_real:delete(c, s, o)
121 function _wifi_iface(x)
123 for _, p in ipairs(IFACE_PATTERNS_WIRELESS) do
131 function _wifi_lookup(ifn)
132 -- got a radio#.network# pseudo iface, locate the corresponding section
133 local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
134 if radio and ifnidx then
138 ifnidx = tonumber(ifnidx)
139 _uci_real:foreach("wireless", "wifi-iface",
141 if s.device == radio then
143 if num == ifnidx then
152 -- looks like wifi, try to locate the section via state vars
153 elseif _wifi_iface(ifn) then
156 _uci_state:foreach("wireless", "wifi-iface",
158 if s.ifname == ifn then
168 function _iface_virtual(x)
170 for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do
178 function _iface_ignore(x)
180 for _, p in ipairs(IFACE_PATTERNS_IGNORE) do
185 return _iface_virtual(x)
189 function init(cursor)
190 _uci_real = cursor or _uci_real or uci.cursor()
191 _uci_state = _uci_real:substate()
198 -- read interface information
200 for n, i in ipairs(nxo.getifaddrs()) do
201 local name = i.name:match("[^:]+")
202 local prnt = name:match("^([^%.]+)%.")
204 if _iface_virtual(name) then
208 if _tunnel[name] or not _iface_ignore(name) then
209 _interfaces[name] = _interfaces[name] or {
210 idx = i.ifindex or n,
223 if i.family == "packet" then
224 _interfaces[name].flags = i.flags
225 _interfaces[name].stats = i.data
226 _interfaces[name].macaddr = i.addr
227 elseif i.family == "inet" then
228 _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
229 elseif i.family == "inet6" then
230 _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
235 -- read bridge informaton
237 for l in utl.execi("brctl show") do
238 if not l:match("STP") then
239 local r = utl.split(l, "%s+", nil, true)
245 ifnames = { _interfaces[r[4]] }
248 b.ifnames[1].bridge = b
252 b.ifnames[#b.ifnames+1] = _interfaces[r[2]]
253 b.ifnames[#b.ifnames].bridge = b
261 function save(self, ...)
266 function commit(self, ...)
267 _uci_real:commit(...)
271 function ifnameof(self, x)
272 if utl.instanceof(x, interface) then
274 elseif utl.instanceof(x, proto.generic) then
276 elseif type(x) == "string" then
277 return x:match("^[^:]+")
281 function has_ipv6(self)
282 return nfs.access("/proc/net/ipv6_route")
285 function add_network(self, n, options)
286 local oldnet = self:get_network(n)
287 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
288 if _uci_real:section("network", "interface", n, options) then
291 elseif oldnet and oldnet:is_empty() then
294 for k, v in pairs(options) do
302 function get_network(self, n)
303 if n and _uci_real:get("network", n) == "interface" then
308 function get_networks(self)
312 _uci_real:foreach("network", "interface",
314 nls[s['.name']] = network(s['.name'])
318 for n in utl.kspairs(nls) do
319 nets[#nets+1] = nls[n]
325 function del_network(self, n)
326 local r = _uci_real:delete("network", n)
328 _uci_real:delete_all("network", "alias",
329 function(s) return (s.interface == n) end)
331 _uci_real:delete_all("network", "route",
332 function(s) return (s.interface == n) end)
334 _uci_real:delete_all("network", "route6",
335 function(s) return (s.interface == n) end)
337 _uci_real:foreach("wireless", "wifi-iface",
339 if s.network == n then
340 _uci_real:delete("wireless", s['.name'], "network")
347 function rename_network(self, old, new)
349 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
350 r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
353 _uci_real:foreach("network", "alias",
355 if s.interface == old then
356 _uci_real:set("network", s['.name'], "interface", new)
360 _uci_real:foreach("network", "route",
362 if s.interface == old then
363 _uci_real:set("network", s['.name'], "interface", new)
367 _uci_real:foreach("network", "route6",
369 if s.interface == old then
370 _uci_real:set("network", s['.name'], "interface", new)
374 _uci_real:foreach("wireless", "wifi-iface",
376 if s.network == old then
377 _uci_real:set("wireless", s['.name'], "network", new)
381 _uci_real:delete("network", old)
387 function get_interface(self, i)
388 if _interfaces[i] or _wifi_iface(i) then
393 _uci_real:foreach("wireless", "wifi-iface",
396 num[s.device] = num[s.device] and num[s.device] + 1 or 1
397 if s['.name'] == i then
399 "%s.network%d" %{s.device, num[s.device] })
408 function get_interfaces(self)
414 -- find normal interfaces
415 _uci_real:foreach("network", "interface",
417 for iface in utl.imatch(s.ifname) do
418 if not _iface_ignore(iface) and not _wifi_iface(iface) then
420 nfs[iface] = interface(iface)
425 for iface in utl.kspairs(_interfaces) do
426 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
427 nfs[iface] = interface(iface)
431 -- find vlan interfaces
432 _uci_real:foreach("network", "switch_vlan",
434 local base = s.device or "-"
435 if not base:match("^eth%d") then
439 local vid = tonumber(s.vid or s.vlan)
440 if vid ~= nil and vid >= 0 and vid <= 4095 then
441 local iface = "%s.%d" %{ base, vid }
442 if not seen[iface] then
444 nfs[iface] = interface(iface)
449 for iface in utl.kspairs(nfs) do
450 ifaces[#ifaces+1] = nfs[iface]
453 -- find wifi interfaces
456 _uci_real:foreach("wireless", "wifi-iface",
459 num[s.device] = num[s.device] and num[s.device] + 1 or 1
460 local i = "%s.network%d" %{ s.device, num[s.device] }
461 wfs[i] = interface(i)
465 for iface in utl.kspairs(wfs) do
466 ifaces[#ifaces+1] = wfs[iface]
472 function ignore_interface(self, x)
473 return _iface_ignore(x)
476 function get_wifidev(self, dev)
477 if _uci_real:get("wireless", dev) == "wifi-device" then
482 function get_wifidevs(self)
486 _uci_real:foreach("wireless", "wifi-device",
487 function(s) wfd[#wfd+1] = s['.name'] end)
490 for _, dev in utl.vspairs(wfd) do
491 devs[#devs+1] = wifidev(dev)
497 function get_wifinet(self, net)
498 local wnet = _wifi_lookup(net)
504 function add_wifinet(self, net, options)
505 if type(options) == "table" and options.device and
506 _uci_real:get("wireless", options.device) == "wifi-device"
508 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
513 function del_wifinet(self, net)
514 local wnet = _wifi_lookup(net)
516 _uci_real:delete("wireless", wnet)
523 function network(name)
525 local p = _uci_real:get("network", name, "proto")
526 local c = p and proto[p] or proto.generic
531 function proto.generic.__init__(self, name)
535 function proto.generic._get(self, opt)
536 local v = _uci_real:get("network", self.sid, opt)
537 if type(v) == "table" then
538 return table.concat(v, " ")
543 function proto.generic._ip(self, opt, family, list)
544 local ip = _uci_state:get("network", self.sid, opt)
545 local fc = (family == 6) and ipc.IPv6 or ipc.IPv4
549 for ip in utl.imatch(ip) do
551 if ip then l[#l+1] = ip:string() end
556 return ip and ip:string()
561 function proto.generic.get(self, opt)
562 return _get("network", self.sid, opt)
565 function proto.generic.set(self, opt, val)
566 return _set("network", self.sid, opt, val)
569 function proto.generic.ifname(self)
570 local p = self:proto()
571 if self:is_bridge() then
572 return "br-" .. self.sid
573 elseif self:is_virtual() then
574 return p .. "-" .. self.sid
577 local dev = _uci_real:get("network", self.sid, "ifname") or
578 _uci_state:get("network", self.sid, "ifname")
580 dev = (type(dev) == "table") and dev[1] or dev
581 dev = (dev ~= nil) and dev:match("%S+")
584 _uci_real:foreach("wireless", "wifi-iface",
587 num[s.device] = num[s.device]
588 and num[s.device] + 1 or 1
590 if s.network == self.sid then
591 dev = "%s.network%d" %{ s.device, num[s.device] }
602 function proto.generic.proto(self)
603 return self:_get("proto") or "none"
606 function proto.generic.type(self)
607 return self:_get("type")
610 function proto.generic.name(self)
614 function proto.generic.uptime(self)
615 local cnt = tonumber(_uci_state:get("network", self.sid, "connect_time"))
617 return nxo.sysinfo().uptime - cnt
623 function proto.generic.expires(self)
624 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
625 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
627 l = l - (nxo.sysinfo().uptime - a)
628 return l > 0 and l or 0
633 function proto.generic.metric(self)
634 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
637 function proto.generic.ipaddr(self)
638 return self:_ip("ipaddr", 4)
641 function proto.generic.netmask(self)
642 return self:_ip("netmask", 4)
645 function proto.generic.gwaddr(self)
646 return self:_ip("gateway", 4)
649 function proto.generic.dnsaddrs(self)
650 return self:_ip("dns", 4, true)
653 function proto.generic.ip6addr(self)
654 local ip6 = self:_ip("ip6addr", 6)
656 local ifc = _interfaces[self:ifname()]
657 if ifc and ifc.ip6addrs then
659 for _, a in ipairs(ifc.ip6addrs) do
660 if not a:is6linklocal() then
670 function proto.generic.gw6addr(self)
671 local ip6 = self:_ip("ip6gw", 6)
673 local dr6 = sys.net.defaultroute6()
674 if dr6 and dr6.device == self:ifname() then
675 return dr6.nexthop:string()
681 function proto.generic.dns6addrs(self)
682 return self:_ip("dns", 6, true)
685 function proto.generic.is_bridge(self)
686 return (self:type() == "bridge")
689 function proto.generic.is_virtual(self)
693 function proto.generic.is_floating(self)
697 function proto.generic.is_empty(self)
698 if self:is_virtual() then
703 if (self:_get("ifname") or ""):match("%S+") then
707 _uci_real:foreach("wireless", "wifi-iface",
709 if s.network == self.sid then
719 function proto.generic.add_interface(self, ifname)
720 ifname = _M:ifnameof(ifname)
721 if ifname and not self:is_floating() then
722 -- remove the interface from all ifaces
723 _uci_real:foreach("network", "interface",
725 _filter("network", s['.name'], "ifname", ifname)
728 -- if its a wifi interface, change its network option
729 local wif = _wifi_lookup(ifname)
731 _uci_real:set("wireless", wif, "network", self.sid)
733 -- add iface to our iface list
735 _append("network", self.sid, "ifname", ifname)
740 function proto.generic.del_interface(self, ifname)
741 ifname = _M:ifnameof(ifname)
742 if ifname and not self:is_floating() then
743 -- if its a wireless interface, clear its network option
744 local wif = _wifi_lookup(ifname)
745 if wif then _uci_real:delete("wireless", wif, "network") end
747 -- remove the interface
748 _filter("network", self.sid, "ifname", ifname)
752 function proto.generic.get_interface(self)
753 if self:is_virtual() then
754 _tunnel[self:proto() .. "-" .. self.sid] = true
755 return interface(self:proto() .. "-" .. self.sid, self)
756 elseif self:is_bridge() then
757 _bridge["br-" .. self.sid] = true
758 return interface("br-" .. self.sid, self)
762 for ifn in utl.imatch(_uci_state:get("network", self.sid, "ifname")) do
763 ifn = ifn:match("^[^:/]+")
764 return ifn and interface(ifn, self)
767 _uci_state:foreach("wireless", "wifi-iface",
770 num[s.device] = num[s.device] and num[s.device] + 1 or 1
771 if s.network == self.sid then
772 ifn = s.ifname or "%s.network%d" %{ s.device, num[s.device] }
777 return ifn and interface(ifn, self)
781 function proto.generic.get_interfaces(self)
782 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
787 for ifn in utl.imatch(self:get("ifname")) do
788 ifn = ifn:match("^[^:/]+")
789 nfs[ifn] = interface(ifn, self)
792 for ifn in utl.kspairs(nfs) do
793 ifaces[#ifaces+1] = nfs[ifn]
798 _uci_real:foreach("wireless", "wifi-iface",
801 num[s.device] = num[s.device] and num[s.device] + 1 or 1
802 if s.network == self.sid then
803 ifn = "%s.network%d" %{ s.device, num[s.device] }
804 wfs[ifn] = interface(ifn, self)
809 for ifn in utl.kspairs(wfs) do
810 ifaces[#ifaces+1] = wfs[ifn]
817 function proto.generic.contains_interface(self, ifname)
818 ifname = _M:ifnameof(ifname)
821 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
823 elseif self:is_bridge() and "br-" .. self.sid == ifname then
827 for ifn in utl.imatch(self:get("ifname")) do
828 ifn = ifn:match("[^:]+")
829 if ifn == ifname then
834 local wif = _wifi_lookup(ifname)
836 return (_uci_real:get("wireless", wif, "network") == self.sid)
843 function proto.generic.adminlink(self)
844 return dsp.build_url("admin", "network", "network", self.sid)
848 interface = utl.class()
850 function interface.__init__(self, ifname, network)
851 local wif = _wifi_lookup(ifname)
852 if wif then self.wif = wifinet(wif) end
854 self.ifname = self.ifname or ifname
855 self.dev = _interfaces[self.ifname]
856 self.network = network
859 function interface.name(self)
860 return self.wif and self.wif:ifname() or self.ifname
863 function interface.mac(self)
864 return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper()
867 function interface.ipaddrs(self)
868 return self.dev and self.dev.ipaddrs or { }
871 function interface.ip6addrs(self)
872 return self.dev and self.dev.ip6addrs or { }
875 function interface.type(self)
876 if self.wif or _wifi_iface(self.ifname) then
878 elseif _bridge[self.ifname] then
880 elseif _tunnel[self.ifname] then
882 elseif self.ifname:match("%.") then
884 elseif _switch[self.ifname] then
891 function interface.shortname(self)
894 self.wif:active_mode(),
895 self.wif:active_ssid() or self.wif:active_bssid()
902 function interface.get_i18n(self)
904 return "%s: %s %q" %{
905 i18n.translate("Wireless Network"),
906 self.wif:active_mode(),
907 self.wif:active_ssid() or self.wif:active_bssid()
910 return "%s: %q" %{ self:get_type_i18n(), self:name() }
914 function interface.get_type_i18n(self)
915 local x = self:type()
917 return i18n.translate("Wireless Adapter")
918 elseif x == "bridge" then
919 return i18n.translate("Bridge")
920 elseif x == "switch" then
921 return i18n.translate("Ethernet Switch")
922 elseif x == "vlan" then
923 return i18n.translate("VLAN Interface")
924 elseif x == "tunnel" then
925 return i18n.translate("Tunnel Interface")
927 return i18n.translate("Ethernet Adapter")
931 function interface.adminlink(self)
933 return self.wif:adminlink()
937 function interface.ports(self)
941 for _, iface in ipairs(self.br.ifnames) do
942 ifaces[#ifaces+1] = interface(iface.name)
948 function interface.bridge_id(self)
956 function interface.bridge_stp(self)
964 function interface.is_up(self)
966 return self.wif:is_up()
968 return self.dev and self.dev.flags and self.dev.flags.up or false
972 function interface.is_bridge(self)
973 return (self:type() == "bridge")
976 function interface.is_bridgeport(self)
977 return self.dev and self.dev.bridge and true or false
980 function interface.tx_bytes(self)
981 return self.dev and self.dev.stats
982 and self.dev.stats.tx_bytes or 0
985 function interface.rx_bytes(self)
986 return self.dev and self.dev.stats
987 and self.dev.stats.rx_bytes or 0
990 function interface.tx_packets(self)
991 return self.dev and self.dev.stats
992 and self.dev.stats.tx_packets or 0
995 function interface.rx_packets(self)
996 return self.dev and self.dev.stats
997 and self.dev.stats.rx_packets or 0
1000 function interface.get_network(self)
1001 if not self.network then
1002 if self.dev and self.dev.network then
1003 self.network = _M:get_network(self.dev.network)
1007 if not self.network then
1009 for _, net in ipairs(_M:get_networks()) do
1010 if net:contains_interface(self.ifname) or
1011 net:ifname() == self.ifname
1022 function interface.get_wifinet(self)
1027 wifidev = utl.class()
1029 function wifidev.__init__(self, dev)
1031 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1034 function wifidev.get(self, opt)
1035 return _get("wireless", self.sid, opt)
1038 function wifidev.set(self, opt, val)
1039 return _set("wireless", self.sid, opt, val)
1042 function wifidev.name(self)
1046 function wifidev.hwmodes(self)
1047 local l = self.iwinfo.hwmodelist
1048 if l and next(l) then
1051 return { b = true, g = true }
1055 function wifidev.get_i18n(self)
1057 if self.iwinfo.type == "wl" then
1059 elseif self.iwinfo.type == "madwifi" then
1064 local l = self:hwmodes()
1065 if l.a then m = m .. "a" end
1066 if l.b then m = m .. "b" end
1067 if l.g then m = m .. "g" end
1068 if l.n then m = m .. "n" end
1070 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1073 function wifidev.is_up(self)
1076 _uci_state:foreach("wireless", "wifi-iface",
1078 if s.device == self.sid then
1089 function wifidev.get_wifinet(self, net)
1090 if _uci_real:get("wireless", net) == "wifi-iface" then
1093 local wnet = _wifi_lookup(net)
1095 return wifinet(wnet)
1100 function wifidev.get_wifinets(self)
1103 _uci_real:foreach("wireless", "wifi-iface",
1105 if s.device == self.sid then
1106 nets[#nets+1] = wifinet(s['.name'])
1113 function wifidev.add_wifinet(self, options)
1114 options = options or { }
1115 options.device = self.sid
1117 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1119 return wifinet(wnet, options)
1123 function wifidev.del_wifinet(self, net)
1124 if utl.instanceof(net, wifinet) then
1126 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1127 net = _wifi_lookup(net)
1130 if net and _uci_real:get("wireless", net, "device") == self.sid then
1131 _uci_real:delete("wireless", net)
1139 wifinet = utl.class()
1141 function wifinet.__init__(self, net, data)
1146 _uci_real:foreach("wireless", "wifi-iface",
1149 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1150 if s['.name'] == self.sid then
1151 netid = "%s.network%d" %{ s.device, num[s.device] }
1157 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1161 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1162 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1163 _uci_real:get_all("wireless", self.sid) or { }
1166 function wifinet.get(self, opt)
1167 return _get("wireless", self.sid, opt)
1170 function wifinet.set(self, opt, val)
1171 return _set("wireless", self.sid, opt, val)
1174 function wifinet.mode(self)
1175 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1178 function wifinet.ssid(self)
1179 return _uci_state:get("wireless", self.sid, "ssid")
1182 function wifinet.bssid(self)
1183 return _uci_state:get("wireless", self.sid, "bssid")
1186 function wifinet.network(self)
1187 return _uci_state:get("wifinet", self.sid, "network")
1190 function wifinet.id(self)
1194 function wifinet.name(self)
1198 function wifinet.ifname(self)
1199 local ifname = self.iwinfo.ifname
1200 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1206 function wifinet.get_device(self)
1207 if self.iwdata.device then
1208 return wifidev(self.iwdata.device)
1212 function wifinet.is_up(self)
1213 return (self.iwdata.up == "1")
1216 function wifinet.active_mode(self)
1217 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1219 if m == "ap" then m = "Master"
1220 elseif m == "sta" then m = "Client"
1221 elseif m == "adhoc" then m = "Ad-Hoc"
1222 elseif m == "mesh" then m = "Mesh"
1223 elseif m == "monitor" then m = "Monitor"
1229 function wifinet.active_mode_i18n(self)
1230 return i18n.translate(self:active_mode())
1233 function wifinet.active_ssid(self)
1234 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1237 function wifinet.active_bssid(self)
1238 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1241 function wifinet.active_encryption(self)
1242 local enc = self.iwinfo and self.iwinfo.encryption
1243 return enc and enc.description or "-"
1246 function wifinet.assoclist(self)
1247 return self.iwinfo.assoclist or { }
1250 function wifinet.frequency(self)
1251 local freq = self.iwinfo.frequency
1252 if freq and freq > 0 then
1253 return "%.03f" % (freq / 1000)
1257 function wifinet.bitrate(self)
1258 local rate = self.iwinfo.bitrate
1259 if rate and rate > 0 then
1260 return (rate / 1000)
1264 function wifinet.channel(self)
1265 return self.iwinfo.channel or
1266 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1269 function wifinet.signal(self)
1270 return self.iwinfo.signal or 0
1273 function wifinet.noise(self)
1274 return self.iwinfo.noise or 0
1277 function wifinet.country(self)
1278 return self.iwinfo.country or "00"
1281 function wifinet.txpower(self)
1282 return self.iwinfo.txpower or 0
1285 function wifinet.signal_level(self, s, n)
1286 if self:active_bssid() ~= "00:00:00:00:00:00" then
1287 local signal = s or self:signal()
1288 local noise = n or self:noise()
1290 if signal < 0 and noise < 0 then
1291 local snr = -1 * (noise - signal)
1292 return math.floor(snr / 5)
1301 function wifinet.signal_percent(self)
1302 local qc = self.iwinfo.quality or 0
1303 local qm = self.iwinfo.quality_max or 0
1305 if qc > 0 and qm > 0 then
1306 return math.floor((100 / qm) * qc)
1312 function wifinet.shortname(self)
1314 i18n.translate(self:active_mode()),
1315 self:active_ssid() or self:active_bssid()
1319 function wifinet.get_i18n(self)
1320 return "%s: %s %q (%s)" %{
1321 i18n.translate("Wireless Network"),
1322 i18n.translate(self:active_mode()),
1323 self:active_ssid() or self:active_bssid(),
1328 function wifinet.adminlink(self)
1329 return dsp.build_url("admin", "network", "wireless", self.netid)
1332 function wifinet.get_network(self)
1333 if _uci_real:get("network", self.iwdata.network) == "interface" then
1334 return network(self.iwdata.network)
1338 function wifinet.get_interface(self)
1339 return interface(self:ifname())
1343 -- load protocol extensions
1344 local exts = nfs.dir(utl.libpath() .. "/model/network")
1348 if ext:match("%.lua$") then
1349 require("luci.model.network." .. ext:gsub("%.lua$", ""))