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
21 = type, next, pairs, ipairs, loadfile, table
23 local tonumber, tostring, math = tonumber, tostring, math
25 local require = require
27 local bus = require "ubus"
28 local nxo = require "nixio"
29 local nfs = require "nixio.fs"
30 local ipc = require "luci.ip"
31 local sys = require "luci.sys"
32 local utl = require "luci.util"
33 local dsp = require "luci.dispatcher"
34 local uci = require "luci.model.uci"
35 local lng = require "luci.i18n"
37 module "luci.model.network"
40 IFACE_PATTERNS_VIRTUAL = { }
41 IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" }
42 IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
45 protocol = utl.class()
47 local _protocols = { }
49 local _interfaces, _bridge, _switch, _tunnel
50 local _ubus, _ubusnetcache, _ubusdevcache, _ubuswificache
51 local _uci_real, _uci_state
53 function _filter(c, s, o, r)
54 local val = _uci_real:get(c, s, o)
57 if type(val) == "string" then
58 for val in val:gmatch("%S+") do
64 _uci_real:set(c, s, o, table.concat(l, " "))
66 _uci_real:delete(c, s, o)
68 elseif type(val) == "table" then
69 for _, val in ipairs(val) do
75 _uci_real:set(c, s, o, l)
77 _uci_real:delete(c, s, o)
83 function _append(c, s, o, a)
84 local val = _uci_real:get(c, s, o) or ""
85 if type(val) == "string" then
87 for val in val:gmatch("%S+") do
93 _uci_real:set(c, s, o, table.concat(l, " "))
94 elseif type(val) == "table" then
96 for _, val in ipairs(val) do
102 _uci_real:set(c, s, o, l)
106 function _stror(s1, s2)
107 if not s1 or #s1 == 0 then
108 return s2 and #s2 > 0 and s2
114 function _get(c, s, o)
115 return _uci_real:get(c, s, o)
118 function _set(c, s, o, v)
120 if type(v) == "boolean" then v = v and "1" or "0" end
121 return _uci_real:set(c, s, o, v)
123 return _uci_real:delete(c, s, o)
127 function _wifi_iface(x)
129 for _, p in ipairs(IFACE_PATTERNS_WIRELESS) do
137 function _wifi_state(key, val, field)
138 local radio, radiostate, ifc, ifcstate
140 if not next(_ubuswificache) then
141 _ubuswificache = _ubus:call("network.wireless", "status", {}) or {}
143 -- workaround extended section format
144 for radio, radiostate in pairs(_ubuswificache) do
145 for ifc, ifcstate in pairs(radiostate.interfaces) do
146 if ifcstate.section and ifcstate.section:sub(1, 1) == '@' then
147 local s = _uci_real:get_all('wireless.%s' % ifcstate.section)
149 ifcstate.section = s['.name']
156 for radio, radiostate in pairs(_ubuswificache) do
157 for ifc, ifcstate in pairs(radiostate.interfaces) do
158 if ifcstate[key] == val then
159 return ifcstate[field]
165 function _wifi_lookup(ifn)
166 -- got a radio#.network# pseudo iface, locate the corresponding section
167 local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
168 if radio and ifnidx then
172 ifnidx = tonumber(ifnidx)
173 _uci_real:foreach("wireless", "wifi-iface",
175 if s.device == radio then
177 if num == ifnidx then
186 -- looks like wifi, try to locate the section via state vars
187 elseif _wifi_iface(ifn) then
188 local sid = _wifi_state("ifname", ifn, "section")
190 _uci_state:foreach("wireless", "wifi-iface",
192 if s.ifname == ifn then
203 function _iface_virtual(x)
205 for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do
213 function _iface_ignore(x)
215 for _, p in ipairs(IFACE_PATTERNS_IGNORE) do
220 return _iface_virtual(x)
224 function init(cursor)
225 _uci_real = cursor or _uci_real or uci.cursor()
226 _uci_state = _uci_real:substate()
233 _ubus = bus.connect()
238 -- read interface information
240 for n, i in ipairs(nxo.getifaddrs()) do
241 local name = i.name:match("[^:]+")
242 local prnt = name:match("^([^%.]+)%.")
244 if _iface_virtual(name) then
248 if _tunnel[name] or not _iface_ignore(name) then
249 _interfaces[name] = _interfaces[name] or {
250 idx = i.ifindex or n,
263 if i.family == "packet" then
264 _interfaces[name].flags = i.flags
265 _interfaces[name].stats = i.data
266 _interfaces[name].macaddr = i.addr
267 elseif i.family == "inet" then
268 _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
269 elseif i.family == "inet6" then
270 _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
275 -- read bridge informaton
277 for l in utl.execi("brctl show") do
278 if not l:match("STP") then
279 local r = utl.split(l, "%s+", nil, true)
285 ifnames = { _interfaces[r[4]] }
288 b.ifnames[1].bridge = b
292 b.ifnames[#b.ifnames+1] = _interfaces[r[2]]
293 b.ifnames[#b.ifnames].bridge = b
301 function save(self, ...)
306 function commit(self, ...)
307 _uci_real:commit(...)
311 function ifnameof(self, x)
312 if utl.instanceof(x, interface) then
314 elseif utl.instanceof(x, protocol) then
316 elseif type(x) == "string" then
317 return x:match("^[^:]+")
321 function get_protocol(self, protoname, netname)
322 local v = _protocols[protoname]
324 return v(netname or "__dummy__")
328 function get_protocols(self)
331 for _, v in ipairs(_protocols) do
332 p[#p+1] = v("__dummy__")
337 function register_protocol(self, protoname)
338 local proto = utl.class(protocol)
340 function proto.__init__(self, name)
344 function proto.proto(self)
348 _protocols[#_protocols+1] = proto
349 _protocols[protoname] = proto
354 function register_pattern_virtual(self, pat)
355 IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
359 function has_ipv6(self)
360 return nfs.access("/proc/net/ipv6_route")
363 function add_network(self, n, options)
364 local oldnet = self:get_network(n)
365 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
366 if _uci_real:section("network", "interface", n, options) then
369 elseif oldnet and oldnet:is_empty() then
372 for k, v in pairs(options) do
380 function get_network(self, n)
381 if n and _uci_real:get("network", n) == "interface" then
386 function get_networks(self)
390 _uci_real:foreach("network", "interface",
392 nls[s['.name']] = network(s['.name'])
396 for n in utl.kspairs(nls) do
397 nets[#nets+1] = nls[n]
403 function del_network(self, n)
404 local r = _uci_real:delete("network", n)
406 _uci_real:delete_all("network", "alias",
407 function(s) return (s.interface == n) end)
409 _uci_real:delete_all("network", "route",
410 function(s) return (s.interface == n) end)
412 _uci_real:delete_all("network", "route6",
413 function(s) return (s.interface == n) end)
415 _uci_real:foreach("wireless", "wifi-iface",
419 for net in utl.imatch(s.network) do
425 _uci_real:set("wireless", s['.name'], "network",
426 table.concat(rest, " "))
428 _uci_real:delete("wireless", s['.name'], "network")
435 function rename_network(self, old, new)
437 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
438 r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
441 _uci_real:foreach("network", "alias",
443 if s.interface == old then
444 _uci_real:set("network", s['.name'], "interface", new)
448 _uci_real:foreach("network", "route",
450 if s.interface == old then
451 _uci_real:set("network", s['.name'], "interface", new)
455 _uci_real:foreach("network", "route6",
457 if s.interface == old then
458 _uci_real:set("network", s['.name'], "interface", new)
462 _uci_real:foreach("wireless", "wifi-iface",
466 for net in utl.imatch(s.network) do
474 _uci_real:set("wireless", s['.name'], "network",
475 table.concat(list, " "))
479 _uci_real:delete("network", old)
485 function get_interface(self, i)
486 if _interfaces[i] or _wifi_iface(i) then
491 _uci_real:foreach("wireless", "wifi-iface",
494 num[s.device] = num[s.device] and num[s.device] + 1 or 1
495 if s['.name'] == i then
497 "%s.network%d" %{s.device, num[s.device] })
506 function get_interfaces(self)
513 -- find normal interfaces
514 _uci_real:foreach("network", "interface",
516 for iface in utl.imatch(s.ifname) do
517 if not _iface_ignore(iface) and not _wifi_iface(iface) then
519 nfs[iface] = interface(iface)
524 for iface in utl.kspairs(_interfaces) do
525 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
526 nfs[iface] = interface(iface)
530 -- find vlan interfaces
531 _uci_real:foreach("network", "switch_vlan",
537 local base = baseof[s.device]
539 if not s.device:match("^eth%d") then
541 for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
543 base = l:match("^%w+: (%w+)")
546 if not base or not base:match("^eth%d") then
552 baseof[s.device] = base
555 local vid = tonumber(s.vid or s.vlan)
556 if vid ~= nil and vid >= 0 and vid <= 4095 then
557 local iface = "%s.%d" %{ base, vid }
558 if not seen[iface] then
560 nfs[iface] = interface(iface)
565 for iface in utl.kspairs(nfs) do
566 ifaces[#ifaces+1] = nfs[iface]
569 -- find wifi interfaces
572 _uci_real:foreach("wireless", "wifi-iface",
575 num[s.device] = num[s.device] and num[s.device] + 1 or 1
576 local i = "%s.network%d" %{ s.device, num[s.device] }
577 wfs[i] = interface(i)
581 for iface in utl.kspairs(wfs) do
582 ifaces[#ifaces+1] = wfs[iface]
588 function ignore_interface(self, x)
589 return _iface_ignore(x)
592 function get_wifidev(self, dev)
593 if _uci_real:get("wireless", dev) == "wifi-device" then
598 function get_wifidevs(self)
602 _uci_real:foreach("wireless", "wifi-device",
603 function(s) wfd[#wfd+1] = s['.name'] end)
606 for _, dev in utl.vspairs(wfd) do
607 devs[#devs+1] = wifidev(dev)
613 function get_wifinet(self, net)
614 local wnet = _wifi_lookup(net)
620 function add_wifinet(self, net, options)
621 if type(options) == "table" and options.device and
622 _uci_real:get("wireless", options.device) == "wifi-device"
624 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
629 function del_wifinet(self, net)
630 local wnet = _wifi_lookup(net)
632 _uci_real:delete("wireless", wnet)
638 function get_status_by_route(self, addr, mask)
640 for _, object in ipairs(_ubus:objects()) do
641 local net = object:match("^network%.interface%.(.+)")
643 local s = _ubus:call(object, "status", {})
644 if s and s.route then
646 for _, rt in ipairs(s.route) do
647 if not rt.table and rt.target == addr and rt.mask == mask then
656 function get_status_by_address(self, addr)
658 for _, object in ipairs(_ubus:objects()) do
659 local net = object:match("^network%.interface%.(.+)")
661 local s = _ubus:call(object, "status", {})
662 if s and s['ipv4-address'] then
664 for _, a in ipairs(s['ipv4-address']) do
665 if a.address == addr then
670 if s and s['ipv6-address'] then
672 for _, a in ipairs(s['ipv6-address']) do
673 if a.address == addr then
682 function get_wannet(self)
683 local net = self:get_status_by_route("0.0.0.0", 0)
684 return net and network(net)
687 function get_wandev(self)
688 local _, stat = self:get_status_by_route("0.0.0.0", 0)
689 return stat and interface(stat.l3_device or stat.device)
692 function get_wan6net(self)
693 local net = self:get_status_by_route("::", 0)
694 return net and network(net)
697 function get_wan6dev(self)
698 local _, stat = self:get_status_by_route("::", 0)
699 return stat and interface(stat.l3_device or stat.device)
703 function network(name, proto)
705 local p = proto or _uci_real:get("network", name, "proto")
706 local c = p and _protocols[p] or protocol
711 function protocol.__init__(self, name)
715 function protocol._get(self, opt)
716 local v = _uci_real:get("network", self.sid, opt)
717 if type(v) == "table" then
718 return table.concat(v, " ")
723 function protocol._ubus(self, field)
724 if not _ubusnetcache[self.sid] then
725 _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
728 if _ubusnetcache[self.sid] and field then
729 return _ubusnetcache[self.sid][field]
731 return _ubusnetcache[self.sid]
734 function protocol.get(self, opt)
735 return _get("network", self.sid, opt)
738 function protocol.set(self, opt, val)
739 return _set("network", self.sid, opt, val)
742 function protocol.ifname(self)
744 if self:is_floating() then
745 ifname = self:_ubus("l3_device")
747 ifname = self:_ubus("device")
751 _uci_real:foreach("wireless", "wifi-iface",
754 num[s.device] = num[s.device]
755 and num[s.device] + 1 or 1
758 for net in utl.imatch(s.network) do
759 if net == self.sid then
760 ifname = "%s.network%d" %{ s.device, num[s.device] }
770 function protocol.proto(self)
774 function protocol.get_i18n(self)
775 local p = self:proto()
777 return lng.translate("Unmanaged")
778 elseif p == "static" then
779 return lng.translate("Static address")
780 elseif p == "dhcp" then
781 return lng.translate("DHCP client")
783 return lng.translate("Unknown")
787 function protocol.type(self)
788 return self:_get("type")
791 function protocol.name(self)
795 function protocol.uptime(self)
796 return self:_ubus("uptime") or 0
799 function protocol.expires(self)
800 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
801 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
803 l = l - (nxo.sysinfo().uptime - a)
804 return l > 0 and l or 0
809 function protocol.metric(self)
810 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
813 function protocol.ipaddr(self)
814 local addrs = self:_ubus("ipv4-address")
815 return addrs and #addrs > 0 and addrs[1].address
818 function protocol.netmask(self)
819 local addrs = self:_ubus("ipv4-address")
820 return addrs and #addrs > 0 and
821 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
824 function protocol.gwaddr(self)
826 for _, route in ipairs(self:_ubus("route") or { }) do
827 if route.target == "0.0.0.0" and route.mask == 0 then
833 function protocol.dnsaddrs(self)
836 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
837 if not addr:match(":") then
844 function protocol.ip6addr(self)
845 local addrs = self:_ubus("ipv6-address")
846 if addrs and #addrs > 0 then
847 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
849 addrs = self:_ubus("ipv6-prefix-assignment")
850 if addrs and #addrs > 0 then
851 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
856 function protocol.gw6addr(self)
858 for _, route in ipairs(self:_ubus("route") or { }) do
859 if route.target == "::" and route.mask == 0 then
860 return ipc.IPv6(route.nexthop):string()
865 function protocol.dns6addrs(self)
868 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
869 if addr:match(":") then
876 function protocol.is_bridge(self)
877 return (not self:is_virtual() and self:type() == "bridge")
880 function protocol.opkg_package(self)
884 function protocol.is_installed(self)
888 function protocol.is_virtual(self)
892 function protocol.is_floating(self)
896 function protocol.is_empty(self)
897 if self:is_floating() then
902 if (self:_get("ifname") or ""):match("%S+") then
906 _uci_real:foreach("wireless", "wifi-iface",
909 for n in utl.imatch(s.network) do
910 if n == self.sid then
921 function protocol.add_interface(self, ifname)
922 ifname = _M:ifnameof(ifname)
923 if ifname and not self:is_floating() then
924 -- if its a wifi interface, change its network option
925 local wif = _wifi_lookup(ifname)
927 _append("wireless", wif, "network", self.sid)
929 -- add iface to our iface list
931 _append("network", self.sid, "ifname", ifname)
936 function protocol.del_interface(self, ifname)
937 ifname = _M:ifnameof(ifname)
938 if ifname and not self:is_floating() then
939 -- if its a wireless interface, clear its network option
940 local wif = _wifi_lookup(ifname)
941 if wif then _filter("wireless", wif, "network", self.sid) end
943 -- remove the interface
944 _filter("network", self.sid, "ifname", ifname)
948 function protocol.get_interface(self)
949 if self:is_virtual() then
950 _tunnel[self:proto() .. "-" .. self.sid] = true
951 return interface(self:proto() .. "-" .. self.sid, self)
952 elseif self:is_bridge() then
953 _bridge["br-" .. self.sid] = true
954 return interface("br-" .. self.sid, self)
958 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
959 ifn = ifn:match("^[^:/]+")
960 return ifn and interface(ifn, self)
963 _uci_real:foreach("wireless", "wifi-iface",
966 num[s.device] = num[s.device] and num[s.device] + 1 or 1
969 for net in utl.imatch(s.network) do
970 if net == self.sid then
971 ifn = "%s.network%d" %{ s.device, num[s.device] }
977 return ifn and interface(ifn, self)
981 function protocol.get_interfaces(self)
982 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
987 for ifn in utl.imatch(self:get("ifname")) do
988 ifn = ifn:match("^[^:/]+")
989 nfs[ifn] = interface(ifn, self)
992 for ifn in utl.kspairs(nfs) do
993 ifaces[#ifaces+1] = nfs[ifn]
998 _uci_real:foreach("wireless", "wifi-iface",
1001 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1004 for net in utl.imatch(s.network) do
1005 if net == self.sid then
1006 ifn = "%s.network%d" %{ s.device, num[s.device] }
1007 wfs[ifn] = interface(ifn, self)
1013 for ifn in utl.kspairs(wfs) do
1014 ifaces[#ifaces+1] = wfs[ifn]
1021 function protocol.contains_interface(self, ifname)
1022 ifname = _M:ifnameof(ifname)
1025 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
1027 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1031 for ifn in utl.imatch(self:get("ifname")) do
1032 ifn = ifn:match("[^:]+")
1033 if ifn == ifname then
1038 local wif = _wifi_lookup(ifname)
1041 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
1042 if n == self.sid then
1052 function protocol.adminlink(self)
1053 return dsp.build_url("admin", "network", "network", self.sid)
1057 interface = utl.class()
1059 function interface.__init__(self, ifname, network)
1060 local wif = _wifi_lookup(ifname)
1062 self.wif = wifinet(wif)
1063 self.ifname = _wifi_state("section", wif, "ifname")
1066 self.ifname = self.ifname or ifname
1067 self.dev = _interfaces[self.ifname]
1068 self.network = network
1071 function interface._ubus(self, field)
1072 if not _ubusdevcache[self.ifname] then
1073 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
1074 { name = self.ifname })
1076 if _ubusdevcache[self.ifname] and field then
1077 return _ubusdevcache[self.ifname][field]
1079 return _ubusdevcache[self.ifname]
1082 function interface.name(self)
1083 return self.wif and self.wif:ifname() or self.ifname
1086 function interface.mac(self)
1087 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
1090 function interface.ipaddrs(self)
1091 return self.dev and self.dev.ipaddrs or { }
1094 function interface.ip6addrs(self)
1095 return self.dev and self.dev.ip6addrs or { }
1098 function interface.type(self)
1099 if self.wif or _wifi_iface(self.ifname) then
1101 elseif _bridge[self.ifname] then
1103 elseif _tunnel[self.ifname] then
1105 elseif self.ifname:match("%.") then
1107 elseif _switch[self.ifname] then
1114 function interface.shortname(self)
1117 self.wif:active_mode(),
1118 self.wif:active_ssid() or self.wif:active_bssid()
1125 function interface.get_i18n(self)
1127 return "%s: %s %q" %{
1128 lng.translate("Wireless Network"),
1129 self.wif:active_mode(),
1130 self.wif:active_ssid() or self.wif:active_bssid()
1133 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1137 function interface.get_type_i18n(self)
1138 local x = self:type()
1140 return lng.translate("Wireless Adapter")
1141 elseif x == "bridge" then
1142 return lng.translate("Bridge")
1143 elseif x == "switch" then
1144 return lng.translate("Ethernet Switch")
1145 elseif x == "vlan" then
1146 return lng.translate("VLAN Interface")
1147 elseif x == "tunnel" then
1148 return lng.translate("Tunnel Interface")
1150 return lng.translate("Ethernet Adapter")
1154 function interface.adminlink(self)
1156 return self.wif:adminlink()
1160 function interface.ports(self)
1161 local members = self:_ubus("bridge-members")
1165 for _, iface in ipairs(members) do
1166 ifaces[#ifaces+1] = interface(iface)
1171 function interface.bridge_id(self)
1179 function interface.bridge_stp(self)
1187 function interface.is_up(self)
1188 return self:_ubus("up") or false
1191 function interface.is_bridge(self)
1192 return (self:type() == "bridge")
1195 function interface.is_bridgeport(self)
1196 return self.dev and self.dev.bridge and true or false
1199 function interface.tx_bytes(self)
1200 local stat = self:_ubus("statistics")
1201 return stat and stat.tx_bytes or 0
1204 function interface.rx_bytes(self)
1205 local stat = self:_ubus("statistics")
1206 return stat and stat.rx_bytes or 0
1209 function interface.tx_packets(self)
1210 local stat = self:_ubus("statistics")
1211 return stat and stat.tx_packets or 0
1214 function interface.rx_packets(self)
1215 local stat = self:_ubus("statistics")
1216 return stat and stat.rx_packets or 0
1219 function interface.get_network(self)
1220 return self:get_networks()[1]
1223 function interface.get_networks(self)
1224 if not self.networks then
1227 for _, net in ipairs(_M:get_networks()) do
1228 if net:contains_interface(self.ifname) or
1229 net:ifname() == self.ifname
1234 table.sort(nets, function(a, b) return a.sid < b.sid end)
1235 self.networks = nets
1238 return self.networks
1242 function interface.get_wifinet(self)
1247 wifidev = utl.class()
1249 function wifidev.__init__(self, dev)
1251 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1254 function wifidev.get(self, opt)
1255 return _get("wireless", self.sid, opt)
1258 function wifidev.set(self, opt, val)
1259 return _set("wireless", self.sid, opt, val)
1262 function wifidev.name(self)
1266 function wifidev.hwmodes(self)
1267 local l = self.iwinfo.hwmodelist
1268 if l and next(l) then
1271 return { b = true, g = true }
1275 function wifidev.get_i18n(self)
1277 if self.iwinfo.type == "wl" then
1279 elseif self.iwinfo.type == "madwifi" then
1284 local l = self:hwmodes()
1285 if l.a then m = m .. "a" end
1286 if l.b then m = m .. "b" end
1287 if l.g then m = m .. "g" end
1288 if l.n then m = m .. "n" end
1289 if l.ac then m = "ac" end
1291 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1294 function wifidev.is_up(self)
1295 if _ubuswificache[self.sid] then
1296 return (_ubuswificache[self.sid].up == true)
1300 _uci_state:foreach("wireless", "wifi-iface",
1302 if s.device == self.sid then
1313 function wifidev.get_wifinet(self, net)
1314 if _uci_real:get("wireless", net) == "wifi-iface" then
1317 local wnet = _wifi_lookup(net)
1319 return wifinet(wnet)
1324 function wifidev.get_wifinets(self)
1327 _uci_real:foreach("wireless", "wifi-iface",
1329 if s.device == self.sid then
1330 nets[#nets+1] = wifinet(s['.name'])
1337 function wifidev.add_wifinet(self, options)
1338 options = options or { }
1339 options.device = self.sid
1341 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1343 return wifinet(wnet, options)
1347 function wifidev.del_wifinet(self, net)
1348 if utl.instanceof(net, wifinet) then
1350 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1351 net = _wifi_lookup(net)
1354 if net and _uci_real:get("wireless", net, "device") == self.sid then
1355 _uci_real:delete("wireless", net)
1363 wifinet = utl.class()
1365 function wifinet.__init__(self, net, data)
1370 _uci_real:foreach("wireless", "wifi-iface",
1373 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1374 if s['.name'] == self.sid then
1375 netid = "%s.network%d" %{ s.device, num[s.device] }
1381 local dev = _wifi_state("section", self.sid, "ifname") or netid
1385 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1386 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1387 _uci_real:get_all("wireless", self.sid) or { }
1390 function wifinet.get(self, opt)
1391 return _get("wireless", self.sid, opt)
1394 function wifinet.set(self, opt, val)
1395 return _set("wireless", self.sid, opt, val)
1398 function wifinet.mode(self)
1399 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1402 function wifinet.ssid(self)
1403 return _uci_state:get("wireless", self.sid, "ssid")
1406 function wifinet.bssid(self)
1407 return _uci_state:get("wireless", self.sid, "bssid")
1410 function wifinet.network(self)
1411 return _uci_state:get("wifinet", self.sid, "network")
1414 function wifinet.id(self)
1418 function wifinet.name(self)
1422 function wifinet.ifname(self)
1423 local ifname = self.iwinfo.ifname
1424 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1430 function wifinet.get_device(self)
1431 if self.iwdata.device then
1432 return wifidev(self.iwdata.device)
1436 function wifinet.is_up(self)
1437 local ifc = self:get_interface()
1438 return (ifc and ifc:is_up() or false)
1441 function wifinet.active_mode(self)
1442 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1444 if m == "ap" then m = "Master"
1445 elseif m == "sta" then m = "Client"
1446 elseif m == "adhoc" then m = "Ad-Hoc"
1447 elseif m == "mesh" then m = "Mesh"
1448 elseif m == "monitor" then m = "Monitor"
1454 function wifinet.active_mode_i18n(self)
1455 return lng.translate(self:active_mode())
1458 function wifinet.active_ssid(self)
1459 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1462 function wifinet.active_bssid(self)
1463 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1466 function wifinet.active_encryption(self)
1467 local enc = self.iwinfo and self.iwinfo.encryption
1468 return enc and enc.description or "-"
1471 function wifinet.assoclist(self)
1472 return self.iwinfo.assoclist or { }
1475 function wifinet.frequency(self)
1476 local freq = self.iwinfo.frequency
1477 if freq and freq > 0 then
1478 return "%.03f" % (freq / 1000)
1482 function wifinet.bitrate(self)
1483 local rate = self.iwinfo.bitrate
1484 if rate and rate > 0 then
1485 return (rate / 1000)
1489 function wifinet.channel(self)
1490 return self.iwinfo.channel or
1491 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1494 function wifinet.signal(self)
1495 return self.iwinfo.signal or 0
1498 function wifinet.noise(self)
1499 return self.iwinfo.noise or 0
1502 function wifinet.country(self)
1503 return self.iwinfo.country or "00"
1506 function wifinet.txpower(self)
1507 local pwr = (self.iwinfo.txpower or 0)
1508 return pwr + self:txpower_offset()
1511 function wifinet.txpower_offset(self)
1512 return self.iwinfo.txpower_offset or 0
1515 function wifinet.signal_level(self, s, n)
1516 if self:active_bssid() ~= "00:00:00:00:00:00" then
1517 local signal = s or self:signal()
1518 local noise = n or self:noise()
1520 if signal < 0 and noise < 0 then
1521 local snr = -1 * (noise - signal)
1522 return math.floor(snr / 5)
1531 function wifinet.signal_percent(self)
1532 local qc = self.iwinfo.quality or 0
1533 local qm = self.iwinfo.quality_max or 0
1535 if qc > 0 and qm > 0 then
1536 return math.floor((100 / qm) * qc)
1542 function wifinet.shortname(self)
1544 lng.translate(self:active_mode()),
1545 self:active_ssid() or self:active_bssid()
1549 function wifinet.get_i18n(self)
1550 return "%s: %s %q (%s)" %{
1551 lng.translate("Wireless Network"),
1552 lng.translate(self:active_mode()),
1553 self:active_ssid() or self:active_bssid(),
1558 function wifinet.adminlink(self)
1559 return dsp.build_url("admin", "network", "wireless", self.netid)
1562 function wifinet.get_network(self)
1563 return self:get_networks()[1]
1566 function wifinet.get_networks(self)
1569 for net in utl.imatch(tostring(self.iwdata.network)) do
1570 if _uci_real:get("network", net) == "interface" then
1571 nets[#nets+1] = network(net)
1574 table.sort(nets, function(a, b) return a.sid < b.sid end)
1578 function wifinet.get_interface(self)
1579 return interface(self:ifname())
1583 -- setup base protocols
1584 _M:register_protocol("static")
1585 _M:register_protocol("dhcp")
1586 _M:register_protocol("none")
1588 -- load protocol extensions
1589 local exts = nfs.dir(utl.libpath() .. "/model/network")
1593 if ext:match("%.lua$") then
1594 require("luci.model.network." .. ext:gsub("%.lua$", ""))