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 if not next(_ubuswificache) then
139 _ubuswificache = _ubus:call("network.wireless", "status", {}) or {}
142 local radio, radiostate
143 for radio, radiostate in pairs(_ubuswificache) do
145 for ifc, ifcstate in pairs(radiostate.interfaces) do
146 if ifcstate[key] == val then
147 return ifcstate[field]
153 function _wifi_lookup(ifn)
154 -- got a radio#.network# pseudo iface, locate the corresponding section
155 local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
156 if radio and ifnidx then
160 ifnidx = tonumber(ifnidx)
161 _uci_real:foreach("wireless", "wifi-iface",
163 if s.device == radio then
165 if num == ifnidx then
174 -- looks like wifi, try to locate the section via state vars
175 elseif _wifi_iface(ifn) then
176 local sid = _wifi_state("ifname", ifn, "section")
178 _uci_state:foreach("wireless", "wifi-iface",
180 if s.ifname == ifn then
191 function _iface_virtual(x)
193 for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do
201 function _iface_ignore(x)
203 for _, p in ipairs(IFACE_PATTERNS_IGNORE) do
208 return _iface_virtual(x)
212 function init(cursor)
213 _uci_real = cursor or _uci_real or uci.cursor()
214 _uci_state = _uci_real:substate()
221 _ubus = bus.connect()
226 -- read interface information
228 for n, i in ipairs(nxo.getifaddrs()) do
229 local name = i.name:match("[^:]+")
230 local prnt = name:match("^([^%.]+)%.")
232 if _iface_virtual(name) then
236 if _tunnel[name] or not _iface_ignore(name) then
237 _interfaces[name] = _interfaces[name] or {
238 idx = i.ifindex or n,
251 if i.family == "packet" then
252 _interfaces[name].flags = i.flags
253 _interfaces[name].stats = i.data
254 _interfaces[name].macaddr = i.addr
255 elseif i.family == "inet" then
256 _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
257 elseif i.family == "inet6" then
258 _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
263 -- read bridge informaton
265 for l in utl.execi("brctl show") do
266 if not l:match("STP") then
267 local r = utl.split(l, "%s+", nil, true)
273 ifnames = { _interfaces[r[4]] }
276 b.ifnames[1].bridge = b
280 b.ifnames[#b.ifnames+1] = _interfaces[r[2]]
281 b.ifnames[#b.ifnames].bridge = b
289 function save(self, ...)
294 function commit(self, ...)
295 _uci_real:commit(...)
299 function ifnameof(self, x)
300 if utl.instanceof(x, interface) then
302 elseif utl.instanceof(x, protocol) then
304 elseif type(x) == "string" then
305 return x:match("^[^:]+")
309 function get_protocol(self, protoname, netname)
310 local v = _protocols[protoname]
312 return v(netname or "__dummy__")
316 function get_protocols(self)
319 for _, v in ipairs(_protocols) do
320 p[#p+1] = v("__dummy__")
325 function register_protocol(self, protoname)
326 local proto = utl.class(protocol)
328 function proto.__init__(self, name)
332 function proto.proto(self)
336 _protocols[#_protocols+1] = proto
337 _protocols[protoname] = proto
342 function register_pattern_virtual(self, pat)
343 IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
347 function has_ipv6(self)
348 return nfs.access("/proc/net/ipv6_route")
351 function add_network(self, n, options)
352 local oldnet = self:get_network(n)
353 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
354 if _uci_real:section("network", "interface", n, options) then
357 elseif oldnet and oldnet:is_empty() then
360 for k, v in pairs(options) do
368 function get_network(self, n)
369 if n and _uci_real:get("network", n) == "interface" then
374 function get_networks(self)
378 _uci_real:foreach("network", "interface",
380 nls[s['.name']] = network(s['.name'])
384 for n in utl.kspairs(nls) do
385 nets[#nets+1] = nls[n]
391 function del_network(self, n)
392 local r = _uci_real:delete("network", n)
394 _uci_real:delete_all("network", "alias",
395 function(s) return (s.interface == n) end)
397 _uci_real:delete_all("network", "route",
398 function(s) return (s.interface == n) end)
400 _uci_real:delete_all("network", "route6",
401 function(s) return (s.interface == n) end)
403 _uci_real:foreach("wireless", "wifi-iface",
407 for net in utl.imatch(s.network) do
413 _uci_real:set("wireless", s['.name'], "network",
414 table.concat(rest, " "))
416 _uci_real:delete("wireless", s['.name'], "network")
423 function rename_network(self, old, new)
425 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
426 r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
429 _uci_real:foreach("network", "alias",
431 if s.interface == old then
432 _uci_real:set("network", s['.name'], "interface", new)
436 _uci_real:foreach("network", "route",
438 if s.interface == old then
439 _uci_real:set("network", s['.name'], "interface", new)
443 _uci_real:foreach("network", "route6",
445 if s.interface == old then
446 _uci_real:set("network", s['.name'], "interface", new)
450 _uci_real:foreach("wireless", "wifi-iface",
454 for net in utl.imatch(s.network) do
462 _uci_real:set("wireless", s['.name'], "network",
463 table.concat(list, " "))
467 _uci_real:delete("network", old)
473 function get_interface(self, i)
474 if _interfaces[i] or _wifi_iface(i) then
479 _uci_real:foreach("wireless", "wifi-iface",
482 num[s.device] = num[s.device] and num[s.device] + 1 or 1
483 if s['.name'] == i then
485 "%s.network%d" %{s.device, num[s.device] })
494 function get_interfaces(self)
501 -- find normal interfaces
502 _uci_real:foreach("network", "interface",
504 for iface in utl.imatch(s.ifname) do
505 if not _iface_ignore(iface) and not _wifi_iface(iface) then
507 nfs[iface] = interface(iface)
512 for iface in utl.kspairs(_interfaces) do
513 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
514 nfs[iface] = interface(iface)
518 -- find vlan interfaces
519 _uci_real:foreach("network", "switch_vlan",
525 local base = baseof[s.device]
527 if not s.device:match("^eth%d") then
529 for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
531 base = l:match("^%w+: (%w+)")
534 if not base or not base:match("^eth%d") then
540 baseof[s.device] = base
543 local vid = tonumber(s.vid or s.vlan)
544 if vid ~= nil and vid >= 0 and vid <= 4095 then
545 local iface = "%s.%d" %{ base, vid }
546 if not seen[iface] then
548 nfs[iface] = interface(iface)
553 for iface in utl.kspairs(nfs) do
554 ifaces[#ifaces+1] = nfs[iface]
557 -- find wifi interfaces
560 _uci_real:foreach("wireless", "wifi-iface",
563 num[s.device] = num[s.device] and num[s.device] + 1 or 1
564 local i = "%s.network%d" %{ s.device, num[s.device] }
565 wfs[i] = interface(i)
569 for iface in utl.kspairs(wfs) do
570 ifaces[#ifaces+1] = wfs[iface]
576 function ignore_interface(self, x)
577 return _iface_ignore(x)
580 function get_wifidev(self, dev)
581 if _uci_real:get("wireless", dev) == "wifi-device" then
586 function get_wifidevs(self)
590 _uci_real:foreach("wireless", "wifi-device",
591 function(s) wfd[#wfd+1] = s['.name'] end)
594 for _, dev in utl.vspairs(wfd) do
595 devs[#devs+1] = wifidev(dev)
601 function get_wifinet(self, net)
602 local wnet = _wifi_lookup(net)
608 function add_wifinet(self, net, options)
609 if type(options) == "table" and options.device and
610 _uci_real:get("wireless", options.device) == "wifi-device"
612 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
617 function del_wifinet(self, net)
618 local wnet = _wifi_lookup(net)
620 _uci_real:delete("wireless", wnet)
626 function get_status_by_route(self, addr, mask)
628 for _, object in ipairs(_ubus:objects()) do
629 local net = object:match("^network%.interface%.(.+)")
631 local s = _ubus:call(object, "status", {})
632 if s and s.route then
634 for _, rt in ipairs(s.route) do
635 if not rt.table and rt.target == addr and rt.mask == mask then
644 function get_status_by_address(self, addr)
646 for _, object in ipairs(_ubus:objects()) do
647 local net = object:match("^network%.interface%.(.+)")
649 local s = _ubus:call(object, "status", {})
650 if s and s['ipv4-address'] then
652 for _, a in ipairs(s['ipv4-address']) do
653 if a.address == addr then
658 if s and s['ipv6-address'] then
660 for _, a in ipairs(s['ipv6-address']) do
661 if a.address == addr then
670 function get_wannet(self)
671 local net = self:get_status_by_route("0.0.0.0", 0)
672 return net and network(net)
675 function get_wandev(self)
676 local _, stat = self:get_status_by_route("0.0.0.0", 0)
677 return stat and interface(stat.l3_device or stat.device)
680 function get_wan6net(self)
681 local net = self:get_status_by_route("::", 0)
682 return net and network(net)
685 function get_wan6dev(self)
686 local _, stat = self:get_status_by_route("::", 0)
687 return stat and interface(stat.l3_device or stat.device)
691 function network(name, proto)
693 local p = proto or _uci_real:get("network", name, "proto")
694 local c = p and _protocols[p] or protocol
699 function protocol.__init__(self, name)
703 function protocol._get(self, opt)
704 local v = _uci_real:get("network", self.sid, opt)
705 if type(v) == "table" then
706 return table.concat(v, " ")
711 function protocol._ubus(self, field)
712 if not _ubusnetcache[self.sid] then
713 _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
716 if _ubusnetcache[self.sid] and field then
717 return _ubusnetcache[self.sid][field]
719 return _ubusnetcache[self.sid]
722 function protocol.get(self, opt)
723 return _get("network", self.sid, opt)
726 function protocol.set(self, opt, val)
727 return _set("network", self.sid, opt, val)
730 function protocol.ifname(self)
732 if self:is_floating() then
733 ifname = self:_ubus("l3_device")
735 ifname = self:_ubus("device")
739 _uci_real:foreach("wireless", "wifi-iface",
742 num[s.device] = num[s.device]
743 and num[s.device] + 1 or 1
746 for net in utl.imatch(s.network) do
747 if net == self.sid then
748 ifname = "%s.network%d" %{ s.device, num[s.device] }
758 function protocol.proto(self)
762 function protocol.get_i18n(self)
763 local p = self:proto()
765 return lng.translate("Unmanaged")
766 elseif p == "static" then
767 return lng.translate("Static address")
768 elseif p == "dhcp" then
769 return lng.translate("DHCP client")
771 return lng.translate("Unknown")
775 function protocol.type(self)
776 return self:_get("type")
779 function protocol.name(self)
783 function protocol.uptime(self)
784 return self:_ubus("uptime") or 0
787 function protocol.expires(self)
788 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
789 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
791 l = l - (nxo.sysinfo().uptime - a)
792 return l > 0 and l or 0
797 function protocol.metric(self)
798 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
801 function protocol.ipaddr(self)
802 local addrs = self:_ubus("ipv4-address")
803 return addrs and #addrs > 0 and addrs[1].address
806 function protocol.netmask(self)
807 local addrs = self:_ubus("ipv4-address")
808 return addrs and #addrs > 0 and
809 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
812 function protocol.gwaddr(self)
814 for _, route in ipairs(self:_ubus("route") or { }) do
815 if route.target == "0.0.0.0" and route.mask == 0 then
821 function protocol.dnsaddrs(self)
824 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
825 if not addr:match(":") then
832 function protocol.ip6addr(self)
833 local addrs = self:_ubus("ipv6-address")
834 if addrs and #addrs > 0 then
835 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
837 addrs = self:_ubus("ipv6-prefix-assignment")
838 if addrs and #addrs > 0 then
839 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
844 function protocol.gw6addr(self)
846 for _, route in ipairs(self:_ubus("route") or { }) do
847 if route.target == "::" and route.mask == 0 then
848 return ipc.IPv6(route.nexthop):string()
853 function protocol.dns6addrs(self)
856 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
857 if addr:match(":") then
864 function protocol.is_bridge(self)
865 return (not self:is_virtual() and self:type() == "bridge")
868 function protocol.opkg_package(self)
872 function protocol.is_installed(self)
876 function protocol.is_virtual(self)
880 function protocol.is_floating(self)
884 function protocol.is_empty(self)
885 if self:is_floating() then
890 if (self:_get("ifname") or ""):match("%S+") then
894 _uci_real:foreach("wireless", "wifi-iface",
897 for n in utl.imatch(s.network) do
898 if n == self.sid then
909 function protocol.add_interface(self, ifname)
910 ifname = _M:ifnameof(ifname)
911 if ifname and not self:is_floating() then
912 -- if its a wifi interface, change its network option
913 local wif = _wifi_lookup(ifname)
915 _append("wireless", wif, "network", self.sid)
917 -- add iface to our iface list
919 _append("network", self.sid, "ifname", ifname)
924 function protocol.del_interface(self, ifname)
925 ifname = _M:ifnameof(ifname)
926 if ifname and not self:is_floating() then
927 -- if its a wireless interface, clear its network option
928 local wif = _wifi_lookup(ifname)
929 if wif then _filter("wireless", wif, "network", self.sid) end
931 -- remove the interface
932 _filter("network", self.sid, "ifname", ifname)
936 function protocol.get_interface(self)
937 if self:is_virtual() then
938 _tunnel[self:proto() .. "-" .. self.sid] = true
939 return interface(self:proto() .. "-" .. self.sid, self)
940 elseif self:is_bridge() then
941 _bridge["br-" .. self.sid] = true
942 return interface("br-" .. self.sid, self)
946 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
947 ifn = ifn:match("^[^:/]+")
948 return ifn and interface(ifn, self)
951 _uci_real:foreach("wireless", "wifi-iface",
954 num[s.device] = num[s.device] and num[s.device] + 1 or 1
957 for net in utl.imatch(s.network) do
958 if net == self.sid then
959 ifn = "%s.network%d" %{ s.device, num[s.device] }
965 return ifn and interface(ifn, self)
969 function protocol.get_interfaces(self)
970 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
975 for ifn in utl.imatch(self:get("ifname")) do
976 ifn = ifn:match("^[^:/]+")
977 nfs[ifn] = interface(ifn, self)
980 for ifn in utl.kspairs(nfs) do
981 ifaces[#ifaces+1] = nfs[ifn]
986 _uci_real:foreach("wireless", "wifi-iface",
989 num[s.device] = num[s.device] and num[s.device] + 1 or 1
992 for net in utl.imatch(s.network) do
993 if net == self.sid then
994 ifn = "%s.network%d" %{ s.device, num[s.device] }
995 wfs[ifn] = interface(ifn, self)
1001 for ifn in utl.kspairs(wfs) do
1002 ifaces[#ifaces+1] = wfs[ifn]
1009 function protocol.contains_interface(self, ifname)
1010 ifname = _M:ifnameof(ifname)
1013 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
1015 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1019 for ifn in utl.imatch(self:get("ifname")) do
1020 ifn = ifn:match("[^:]+")
1021 if ifn == ifname then
1026 local wif = _wifi_lookup(ifname)
1029 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
1030 if n == self.sid then
1040 function protocol.adminlink(self)
1041 return dsp.build_url("admin", "network", "network", self.sid)
1045 interface = utl.class()
1047 function interface.__init__(self, ifname, network)
1048 local wif = _wifi_lookup(ifname)
1050 self.wif = wifinet(wif)
1051 self.ifname = _wifi_state("section", wif, "ifname")
1054 self.ifname = self.ifname or ifname
1055 self.dev = _interfaces[self.ifname]
1056 self.network = network
1059 function interface._ubus(self, field)
1060 if not _ubusdevcache[self.ifname] then
1061 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
1062 { name = self.ifname })
1064 if _ubusdevcache[self.ifname] and field then
1065 return _ubusdevcache[self.ifname][field]
1067 return _ubusdevcache[self.ifname]
1070 function interface.name(self)
1071 return self.wif and self.wif:ifname() or self.ifname
1074 function interface.mac(self)
1075 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
1078 function interface.ipaddrs(self)
1079 return self.dev and self.dev.ipaddrs or { }
1082 function interface.ip6addrs(self)
1083 return self.dev and self.dev.ip6addrs or { }
1086 function interface.type(self)
1087 if self.wif or _wifi_iface(self.ifname) then
1089 elseif _bridge[self.ifname] then
1091 elseif _tunnel[self.ifname] then
1093 elseif self.ifname:match("%.") then
1095 elseif _switch[self.ifname] then
1102 function interface.shortname(self)
1105 self.wif:active_mode(),
1106 self.wif:active_ssid() or self.wif:active_bssid()
1113 function interface.get_i18n(self)
1115 return "%s: %s %q" %{
1116 lng.translate("Wireless Network"),
1117 self.wif:active_mode(),
1118 self.wif:active_ssid() or self.wif:active_bssid()
1121 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1125 function interface.get_type_i18n(self)
1126 local x = self:type()
1128 return lng.translate("Wireless Adapter")
1129 elseif x == "bridge" then
1130 return lng.translate("Bridge")
1131 elseif x == "switch" then
1132 return lng.translate("Ethernet Switch")
1133 elseif x == "vlan" then
1134 return lng.translate("VLAN Interface")
1135 elseif x == "tunnel" then
1136 return lng.translate("Tunnel Interface")
1138 return lng.translate("Ethernet Adapter")
1142 function interface.adminlink(self)
1144 return self.wif:adminlink()
1148 function interface.ports(self)
1149 local members = self:_ubus("bridge-members")
1153 for _, iface in ipairs(members) do
1154 ifaces[#ifaces+1] = interface(iface)
1159 function interface.bridge_id(self)
1167 function interface.bridge_stp(self)
1175 function interface.is_up(self)
1177 return self.wif:is_up()
1179 return self:_ubus("up") or false
1183 function interface.is_bridge(self)
1184 return (self:type() == "bridge")
1187 function interface.is_bridgeport(self)
1188 return self.dev and self.dev.bridge and true or false
1191 function interface.tx_bytes(self)
1192 local stat = self:_ubus("statistics")
1193 return stat and stat.tx_bytes or 0
1196 function interface.rx_bytes(self)
1197 local stat = self:_ubus("statistics")
1198 return stat and stat.rx_bytes or 0
1201 function interface.tx_packets(self)
1202 local stat = self:_ubus("statistics")
1203 return stat and stat.tx_packets or 0
1206 function interface.rx_packets(self)
1207 local stat = self:_ubus("statistics")
1208 return stat and stat.rx_packets or 0
1211 function interface.get_network(self)
1212 return self:get_networks()[1]
1215 function interface.get_networks(self)
1216 if not self.networks then
1219 for _, net in ipairs(_M:get_networks()) do
1220 if net:contains_interface(self.ifname) or
1221 net:ifname() == self.ifname
1226 table.sort(nets, function(a, b) return a.sid < b.sid end)
1227 self.networks = nets
1230 return self.networks
1234 function interface.get_wifinet(self)
1239 wifidev = utl.class()
1241 function wifidev.__init__(self, dev)
1243 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1246 function wifidev.get(self, opt)
1247 return _get("wireless", self.sid, opt)
1250 function wifidev.set(self, opt, val)
1251 return _set("wireless", self.sid, opt, val)
1254 function wifidev.name(self)
1258 function wifidev.hwmodes(self)
1259 local l = self.iwinfo.hwmodelist
1260 if l and next(l) then
1263 return { b = true, g = true }
1267 function wifidev.get_i18n(self)
1269 if self.iwinfo.type == "wl" then
1271 elseif self.iwinfo.type == "madwifi" then
1276 local l = self:hwmodes()
1277 if l.a then m = m .. "a" end
1278 if l.b then m = m .. "b" end
1279 if l.g then m = m .. "g" end
1280 if l.n then m = m .. "n" end
1282 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1285 function wifidev.is_up(self)
1286 if _ubuswificache[self.sid] then
1287 return (_ubuswificache[self.sid].up == true)
1291 _uci_state:foreach("wireless", "wifi-iface",
1293 if s.device == self.sid then
1304 function wifidev.get_wifinet(self, net)
1305 if _uci_real:get("wireless", net) == "wifi-iface" then
1308 local wnet = _wifi_lookup(net)
1310 return wifinet(wnet)
1315 function wifidev.get_wifinets(self)
1318 _uci_real:foreach("wireless", "wifi-iface",
1320 if s.device == self.sid then
1321 nets[#nets+1] = wifinet(s['.name'])
1328 function wifidev.add_wifinet(self, options)
1329 options = options or { }
1330 options.device = self.sid
1332 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1334 return wifinet(wnet, options)
1338 function wifidev.del_wifinet(self, net)
1339 if utl.instanceof(net, wifinet) then
1341 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1342 net = _wifi_lookup(net)
1345 if net and _uci_real:get("wireless", net, "device") == self.sid then
1346 _uci_real:delete("wireless", net)
1354 wifinet = utl.class()
1356 function wifinet.__init__(self, net, data)
1361 _uci_real:foreach("wireless", "wifi-iface",
1364 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1365 if s['.name'] == self.sid then
1366 netid = "%s.network%d" %{ s.device, num[s.device] }
1372 local dev = _wifi_state("section", self.sid, "ifname") or netid
1376 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1377 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1378 _uci_real:get_all("wireless", self.sid) or { }
1381 function wifinet.get(self, opt)
1382 return _get("wireless", self.sid, opt)
1385 function wifinet.set(self, opt, val)
1386 return _set("wireless", self.sid, opt, val)
1389 function wifinet.mode(self)
1390 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1393 function wifinet.ssid(self)
1394 return _uci_state:get("wireless", self.sid, "ssid")
1397 function wifinet.bssid(self)
1398 return _uci_state:get("wireless", self.sid, "bssid")
1401 function wifinet.network(self)
1402 return _uci_state:get("wifinet", self.sid, "network")
1405 function wifinet.id(self)
1409 function wifinet.name(self)
1413 function wifinet.ifname(self)
1414 local ifname = self.iwinfo.ifname
1415 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1421 function wifinet.get_device(self)
1422 if self.iwdata.device then
1423 return wifidev(self.iwdata.device)
1427 function wifinet.is_up(self)
1428 return (_wifi_state("section", self.sid, "up") == true)
1431 function wifinet.active_mode(self)
1432 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1434 if m == "ap" then m = "Master"
1435 elseif m == "sta" then m = "Client"
1436 elseif m == "adhoc" then m = "Ad-Hoc"
1437 elseif m == "mesh" then m = "Mesh"
1438 elseif m == "monitor" then m = "Monitor"
1444 function wifinet.active_mode_i18n(self)
1445 return lng.translate(self:active_mode())
1448 function wifinet.active_ssid(self)
1449 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1452 function wifinet.active_bssid(self)
1453 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1456 function wifinet.active_encryption(self)
1457 local enc = self.iwinfo and self.iwinfo.encryption
1458 return enc and enc.description or "-"
1461 function wifinet.assoclist(self)
1462 return self.iwinfo.assoclist or { }
1465 function wifinet.frequency(self)
1466 local freq = self.iwinfo.frequency
1467 if freq and freq > 0 then
1468 return "%.03f" % (freq / 1000)
1472 function wifinet.bitrate(self)
1473 local rate = self.iwinfo.bitrate
1474 if rate and rate > 0 then
1475 return (rate / 1000)
1479 function wifinet.channel(self)
1480 return self.iwinfo.channel or
1481 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1484 function wifinet.signal(self)
1485 return self.iwinfo.signal or 0
1488 function wifinet.noise(self)
1489 return self.iwinfo.noise or 0
1492 function wifinet.country(self)
1493 return self.iwinfo.country or "00"
1496 function wifinet.txpower(self)
1497 local pwr = (self.iwinfo.txpower or 0)
1498 return pwr + self:txpower_offset()
1501 function wifinet.txpower_offset(self)
1502 return self.iwinfo.txpower_offset or 0
1505 function wifinet.signal_level(self, s, n)
1506 if self:active_bssid() ~= "00:00:00:00:00:00" then
1507 local signal = s or self:signal()
1508 local noise = n or self:noise()
1510 if signal < 0 and noise < 0 then
1511 local snr = -1 * (noise - signal)
1512 return math.floor(snr / 5)
1521 function wifinet.signal_percent(self)
1522 local qc = self.iwinfo.quality or 0
1523 local qm = self.iwinfo.quality_max or 0
1525 if qc > 0 and qm > 0 then
1526 return math.floor((100 / qm) * qc)
1532 function wifinet.shortname(self)
1534 lng.translate(self:active_mode()),
1535 self:active_ssid() or self:active_bssid()
1539 function wifinet.get_i18n(self)
1540 return "%s: %s %q (%s)" %{
1541 lng.translate("Wireless Network"),
1542 lng.translate(self:active_mode()),
1543 self:active_ssid() or self:active_bssid(),
1548 function wifinet.adminlink(self)
1549 return dsp.build_url("admin", "network", "wireless", self.netid)
1552 function wifinet.get_network(self)
1553 return self:get_networks()[1]
1556 function wifinet.get_networks(self)
1559 for net in utl.imatch(tostring(self.iwdata.network)) do
1560 if _uci_real:get("network", net) == "interface" then
1561 nets[#nets+1] = network(net)
1564 table.sort(nets, function(a, b) return a.sid < b.sid end)
1568 function wifinet.get_interface(self)
1569 return interface(self:ifname())
1573 -- setup base protocols
1574 _M:register_protocol("static")
1575 _M:register_protocol("dhcp")
1576 _M:register_protocol("none")
1578 -- load protocol extensions
1579 local exts = nfs.dir(utl.libpath() .. "/model/network")
1583 if ext:match("%.lua$") then
1584 require("luci.model.network." .. ext:gsub("%.lua$", ""))