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
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_lookup(ifn)
138 -- got a radio#.network# pseudo iface, locate the corresponding section
139 local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
140 if radio and ifnidx then
144 ifnidx = tonumber(ifnidx)
145 _uci_real:foreach("wireless", "wifi-iface",
147 if s.device == radio then
149 if num == ifnidx then
158 -- looks like wifi, try to locate the section via state vars
159 elseif _wifi_iface(ifn) then
162 _uci_state:foreach("wireless", "wifi-iface",
164 if s.ifname == ifn then
174 function _iface_virtual(x)
176 for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do
184 function _iface_ignore(x)
186 for _, p in ipairs(IFACE_PATTERNS_IGNORE) do
191 return _iface_virtual(x)
195 function init(cursor)
196 _uci_real = cursor or _uci_real or uci.cursor()
197 _uci_state = _uci_real:substate()
204 _ubus = bus.connect()
208 -- read interface information
210 for n, i in ipairs(nxo.getifaddrs()) do
211 local name = i.name:match("[^:]+")
212 local prnt = name:match("^([^%.]+)%.")
214 if _iface_virtual(name) then
218 if _tunnel[name] or not _iface_ignore(name) then
219 _interfaces[name] = _interfaces[name] or {
220 idx = i.ifindex or n,
233 if i.family == "packet" then
234 _interfaces[name].flags = i.flags
235 _interfaces[name].stats = i.data
236 _interfaces[name].macaddr = i.addr
237 elseif i.family == "inet" then
238 _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
239 elseif i.family == "inet6" then
240 _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
245 -- read bridge informaton
247 for l in utl.execi("brctl show") do
248 if not l:match("STP") then
249 local r = utl.split(l, "%s+", nil, true)
255 ifnames = { _interfaces[r[4]] }
258 b.ifnames[1].bridge = b
262 b.ifnames[#b.ifnames+1] = _interfaces[r[2]]
263 b.ifnames[#b.ifnames].bridge = b
271 function save(self, ...)
276 function commit(self, ...)
277 _uci_real:commit(...)
281 function ifnameof(self, x)
282 if utl.instanceof(x, interface) then
284 elseif utl.instanceof(x, protocol) then
286 elseif type(x) == "string" then
287 return x:match("^[^:]+")
291 function get_protocol(self, protoname, netname)
292 local v = _protocols[protoname]
294 return v(netname or "__dummy__")
298 function get_protocols(self)
301 for _, v in ipairs(_protocols) do
302 p[#p+1] = v("__dummy__")
307 function register_protocol(self, protoname)
308 local proto = utl.class(protocol)
310 function proto.__init__(self, name)
314 function proto.proto(self)
318 _protocols[#_protocols+1] = proto
319 _protocols[protoname] = proto
324 function register_pattern_virtual(self, pat)
325 IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
329 function has_ipv6(self)
330 return nfs.access("/proc/net/ipv6_route")
333 function add_network(self, n, options)
334 local oldnet = self:get_network(n)
335 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
336 if _uci_real:section("network", "interface", n, options) then
339 elseif oldnet and oldnet:is_empty() then
342 for k, v in pairs(options) do
350 function get_network(self, n)
351 if n and _uci_real:get("network", n) == "interface" then
356 function get_networks(self)
360 _uci_real:foreach("network", "interface",
362 nls[s['.name']] = network(s['.name'])
366 for n in utl.kspairs(nls) do
367 nets[#nets+1] = nls[n]
373 function del_network(self, n)
374 local r = _uci_real:delete("network", n)
376 _uci_real:delete_all("network", "alias",
377 function(s) return (s.interface == n) end)
379 _uci_real:delete_all("network", "route",
380 function(s) return (s.interface == n) end)
382 _uci_real:delete_all("network", "route6",
383 function(s) return (s.interface == n) end)
385 _uci_real:foreach("wireless", "wifi-iface",
389 for net in utl.imatch(s.network) do
395 _uci_real:set("wireless", s['.name'], "network",
396 table.concat(rest, " "))
398 _uci_real:delete("wireless", s['.name'], "network")
405 function rename_network(self, old, new)
407 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
408 r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
411 _uci_real:foreach("network", "alias",
413 if s.interface == old then
414 _uci_real:set("network", s['.name'], "interface", new)
418 _uci_real:foreach("network", "route",
420 if s.interface == old then
421 _uci_real:set("network", s['.name'], "interface", new)
425 _uci_real:foreach("network", "route6",
427 if s.interface == old then
428 _uci_real:set("network", s['.name'], "interface", new)
432 _uci_real:foreach("wireless", "wifi-iface",
436 for net in utl.imatch(s.network) do
444 _uci_real:set("wireless", s['.name'], "network",
445 table.concat(list, " "))
449 _uci_real:delete("network", old)
455 function get_interface(self, i)
456 if _interfaces[i] or _wifi_iface(i) then
461 _uci_real:foreach("wireless", "wifi-iface",
464 num[s.device] = num[s.device] and num[s.device] + 1 or 1
465 if s['.name'] == i then
467 "%s.network%d" %{s.device, num[s.device] })
476 function get_interfaces(self)
483 -- find normal interfaces
484 _uci_real:foreach("network", "interface",
486 for iface in utl.imatch(s.ifname) do
487 if not _iface_ignore(iface) and not _wifi_iface(iface) then
489 nfs[iface] = interface(iface)
494 for iface in utl.kspairs(_interfaces) do
495 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
496 nfs[iface] = interface(iface)
500 -- find vlan interfaces
501 _uci_real:foreach("network", "switch_vlan",
507 local base = baseof[s.device]
509 if not s.device:match("^eth%d") then
511 for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
513 base = l:match("^%w+: (%w+)")
516 if not base or not base:match("^eth%d") then
522 baseof[s.device] = base
525 local vid = tonumber(s.vid or s.vlan)
526 if vid ~= nil and vid >= 0 and vid <= 4095 then
527 local iface = "%s.%d" %{ base, vid }
528 if not seen[iface] then
530 nfs[iface] = interface(iface)
535 for iface in utl.kspairs(nfs) do
536 ifaces[#ifaces+1] = nfs[iface]
539 -- find wifi interfaces
542 _uci_real:foreach("wireless", "wifi-iface",
545 num[s.device] = num[s.device] and num[s.device] + 1 or 1
546 local i = "%s.network%d" %{ s.device, num[s.device] }
547 wfs[i] = interface(i)
551 for iface in utl.kspairs(wfs) do
552 ifaces[#ifaces+1] = wfs[iface]
558 function ignore_interface(self, x)
559 return _iface_ignore(x)
562 function get_wifidev(self, dev)
563 if _uci_real:get("wireless", dev) == "wifi-device" then
568 function get_wifidevs(self)
572 _uci_real:foreach("wireless", "wifi-device",
573 function(s) wfd[#wfd+1] = s['.name'] end)
576 for _, dev in utl.vspairs(wfd) do
577 devs[#devs+1] = wifidev(dev)
583 function get_wifinet(self, net)
584 local wnet = _wifi_lookup(net)
590 function add_wifinet(self, net, options)
591 if type(options) == "table" and options.device and
592 _uci_real:get("wireless", options.device) == "wifi-device"
594 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
599 function del_wifinet(self, net)
600 local wnet = _wifi_lookup(net)
602 _uci_real:delete("wireless", wnet)
608 function get_status_by_route(self, addr, mask)
610 for _, object in ipairs(_ubus:objects()) do
611 local net = object:match("^network%.interface%.(.+)")
613 local s = _ubus:call(object, "status", {})
614 if s and s.route then
616 for _, rt in ipairs(s.route) do
617 if rt.target == addr and rt.mask == mask then
626 function get_status_by_address(self, addr)
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['ipv4-address'] then
634 for _, a in ipairs(s['ipv4-address']) do
635 if a.address == addr then
640 if s and s['ipv6-address'] then
642 for _, a in ipairs(s['ipv6-address']) do
643 if a.address == addr then
652 function get_wannet(self)
653 local net = self:get_status_by_route("0.0.0.0", 0)
654 return net and network(net)
657 function get_wandev(self)
658 local _, stat = self:get_status_by_route("0.0.0.0", 0)
659 return stat and interface(stat.l3_device or stat.device)
662 function get_wan6net(self)
663 local net = self:get_status_by_route("::", 0)
664 return net and network(net)
667 function get_wan6dev(self)
668 local _, stat = self:get_status_by_route("::", 0)
669 return stat and interface(stat.l3_device or stat.device)
673 function network(name, proto)
675 local p = proto or _uci_real:get("network", name, "proto")
676 local c = p and _protocols[p] or protocol
681 function protocol.__init__(self, name)
685 function protocol._get(self, opt)
686 local v = _uci_real:get("network", self.sid, opt)
687 if type(v) == "table" then
688 return table.concat(v, " ")
693 function protocol._ubus(self, field)
694 if not _ubusnetcache[self.sid] then
695 _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
698 if _ubusnetcache[self.sid] and field then
699 return _ubusnetcache[self.sid][field]
701 return _ubusnetcache[self.sid]
704 function protocol.get(self, opt)
705 return _get("network", self.sid, opt)
708 function protocol.set(self, opt, val)
709 return _set("network", self.sid, opt, val)
712 function protocol.ifname(self)
714 if self:is_floating() then
715 ifname = self:_ubus("l3_device")
717 ifname = self:_ubus("device")
721 _uci_real:foreach("wireless", "wifi-iface",
724 num[s.device] = num[s.device]
725 and num[s.device] + 1 or 1
728 for net in utl.imatch(s.network) do
729 if net == self.sid then
730 ifname = "%s.network%d" %{ s.device, num[s.device] }
740 function protocol.proto(self)
744 function protocol.get_i18n(self)
745 local p = self:proto()
747 return lng.translate("Unmanaged")
748 elseif p == "static" then
749 return lng.translate("Static address")
750 elseif p == "dhcp" then
751 return lng.translate("DHCP client")
753 return lng.translate("Unknown")
757 function protocol.type(self)
758 return self:_get("type")
761 function protocol.name(self)
765 function protocol.uptime(self)
766 return self:_ubus("uptime") or 0
769 function protocol.expires(self)
770 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
771 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
773 l = l - (nxo.sysinfo().uptime - a)
774 return l > 0 and l or 0
779 function protocol.metric(self)
780 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
783 function protocol.ipaddr(self)
784 local addrs = self:_ubus("ipv4-address")
785 return addrs and #addrs > 0 and addrs[1].address
788 function protocol.netmask(self)
789 local addrs = self:_ubus("ipv4-address")
790 return addrs and #addrs > 0 and
791 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
794 function protocol.gwaddr(self)
796 for _, route in ipairs(self:_ubus("route") or { }) do
797 if route.target == "0.0.0.0" and route.mask == 0 then
803 function protocol.dnsaddrs(self)
806 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
807 if not addr:match(":") then
814 function protocol.ip6addr(self)
815 local addrs = self:_ubus("ipv6-address")
816 if addrs and #addrs > 0 then
817 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
819 addrs = self:_ubus("ipv6-prefix-assignment")
820 if addrs and #addrs > 0 then
821 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
826 function protocol.gw6addr(self)
828 for _, route in ipairs(self:_ubus("route") or { }) do
829 if route.target == "::" and route.mask == 0 then
830 return ipc.IPv6(route.nexthop):string()
835 function protocol.dns6addrs(self)
838 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
839 if addr:match(":") then
846 function protocol.is_bridge(self)
847 return (not self:is_virtual() and self:type() == "bridge")
850 function protocol.opkg_package(self)
854 function protocol.is_installed(self)
858 function protocol.is_virtual(self)
862 function protocol.is_floating(self)
866 function protocol.is_empty(self)
867 if self:is_floating() then
872 if (self:_get("ifname") or ""):match("%S+") then
876 _uci_real:foreach("wireless", "wifi-iface",
879 for n in utl.imatch(s.network) do
880 if n == self.sid then
891 function protocol.add_interface(self, ifname)
892 ifname = _M:ifnameof(ifname)
893 if ifname and not self:is_floating() then
894 -- if its a wifi interface, change its network option
895 local wif = _wifi_lookup(ifname)
897 _append("wireless", wif, "network", self.sid)
899 -- add iface to our iface list
901 _append("network", self.sid, "ifname", ifname)
906 function protocol.del_interface(self, ifname)
907 ifname = _M:ifnameof(ifname)
908 if ifname and not self:is_floating() then
909 -- if its a wireless interface, clear its network option
910 local wif = _wifi_lookup(ifname)
911 if wif then _filter("wireless", wif, "network", self.sid) end
913 -- remove the interface
914 _filter("network", self.sid, "ifname", ifname)
918 function protocol.get_interface(self)
919 if self:is_virtual() then
920 _tunnel[self:proto() .. "-" .. self.sid] = true
921 return interface(self:proto() .. "-" .. self.sid, self)
922 elseif self:is_bridge() then
923 _bridge["br-" .. self.sid] = true
924 return interface("br-" .. self.sid, self)
928 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
929 ifn = ifn:match("^[^:/]+")
930 return ifn and interface(ifn, self)
933 _uci_real:foreach("wireless", "wifi-iface",
936 num[s.device] = num[s.device] and num[s.device] + 1 or 1
939 for net in utl.imatch(s.network) do
940 if net == self.sid then
941 ifn = "%s.network%d" %{ s.device, num[s.device] }
947 return ifn and interface(ifn, self)
951 function protocol.get_interfaces(self)
952 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
957 for ifn in utl.imatch(self:get("ifname")) do
958 ifn = ifn:match("^[^:/]+")
959 nfs[ifn] = interface(ifn, self)
962 for ifn in utl.kspairs(nfs) do
963 ifaces[#ifaces+1] = nfs[ifn]
968 _uci_real:foreach("wireless", "wifi-iface",
971 num[s.device] = num[s.device] and num[s.device] + 1 or 1
974 for net in utl.imatch(s.network) do
975 if net == self.sid then
976 ifn = "%s.network%d" %{ s.device, num[s.device] }
977 wfs[ifn] = interface(ifn, self)
983 for ifn in utl.kspairs(wfs) do
984 ifaces[#ifaces+1] = wfs[ifn]
991 function protocol.contains_interface(self, ifname)
992 ifname = _M:ifnameof(ifname)
995 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
997 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1001 for ifn in utl.imatch(self:get("ifname")) do
1002 ifn = ifn:match("[^:]+")
1003 if ifn == ifname then
1008 local wif = _wifi_lookup(ifname)
1011 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
1012 if n == self.sid then
1022 function protocol.adminlink(self)
1023 return dsp.build_url("admin", "network", "network", self.sid)
1027 interface = utl.class()
1029 function interface.__init__(self, ifname, network)
1030 local wif = _wifi_lookup(ifname)
1032 self.wif = wifinet(wif)
1033 self.ifname = _uci_state:get("wireless", wif, "ifname")
1036 self.ifname = self.ifname or ifname
1037 self.dev = _interfaces[self.ifname]
1038 self.network = network
1041 function interface._ubus(self, field)
1042 if not _ubusdevcache[self.ifname] then
1043 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
1044 { name = self.ifname })
1046 if _ubusdevcache[self.ifname] and field then
1047 return _ubusdevcache[self.ifname][field]
1049 return _ubusdevcache[self.ifname]
1052 function interface.name(self)
1053 return self.wif and self.wif:ifname() or self.ifname
1056 function interface.mac(self)
1057 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
1060 function interface.ipaddrs(self)
1061 return self.dev and self.dev.ipaddrs or { }
1064 function interface.ip6addrs(self)
1065 return self.dev and self.dev.ip6addrs or { }
1068 function interface.type(self)
1069 if self.wif or _wifi_iface(self.ifname) then
1071 elseif _bridge[self.ifname] then
1073 elseif _tunnel[self.ifname] then
1075 elseif self.ifname:match("%.") then
1077 elseif _switch[self.ifname] then
1084 function interface.shortname(self)
1087 self.wif:active_mode(),
1088 self.wif:active_ssid() or self.wif:active_bssid()
1095 function interface.get_i18n(self)
1097 return "%s: %s %q" %{
1098 lng.translate("Wireless Network"),
1099 self.wif:active_mode(),
1100 self.wif:active_ssid() or self.wif:active_bssid()
1103 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1107 function interface.get_type_i18n(self)
1108 local x = self:type()
1110 return lng.translate("Wireless Adapter")
1111 elseif x == "bridge" then
1112 return lng.translate("Bridge")
1113 elseif x == "switch" then
1114 return lng.translate("Ethernet Switch")
1115 elseif x == "vlan" then
1116 return lng.translate("VLAN Interface")
1117 elseif x == "tunnel" then
1118 return lng.translate("Tunnel Interface")
1120 return lng.translate("Ethernet Adapter")
1124 function interface.adminlink(self)
1126 return self.wif:adminlink()
1130 function interface.ports(self)
1131 local members = self:_ubus("bridge-members")
1135 for _, iface in ipairs(members) do
1136 ifaces[#ifaces+1] = interface(iface)
1141 function interface.bridge_id(self)
1149 function interface.bridge_stp(self)
1157 function interface.is_up(self)
1159 return self.wif:is_up()
1161 return self:_ubus("up") or false
1165 function interface.is_bridge(self)
1166 return (self:type() == "bridge")
1169 function interface.is_bridgeport(self)
1170 return self.dev and self.dev.bridge and true or false
1173 function interface.tx_bytes(self)
1174 local stat = self:_ubus("statistics")
1175 return stat and stat.tx_bytes or 0
1178 function interface.rx_bytes(self)
1179 local stat = self:_ubus("statistics")
1180 return stat and stat.rx_bytes or 0
1183 function interface.tx_packets(self)
1184 local stat = self:_ubus("statistics")
1185 return stat and stat.tx_packets or 0
1188 function interface.rx_packets(self)
1189 local stat = self:_ubus("statistics")
1190 return stat and stat.rx_packets or 0
1193 function interface.get_network(self)
1194 return self:get_networks()[1]
1197 function interface.get_networks(self)
1198 if not self.networks then
1201 for _, net in ipairs(_M:get_networks()) do
1202 if net:contains_interface(self.ifname) or
1203 net:ifname() == self.ifname
1208 table.sort(nets, function(a, b) return a.sid < b.sid end)
1209 self.networks = nets
1212 return self.networks
1216 function interface.get_wifinet(self)
1221 wifidev = utl.class()
1223 function wifidev.__init__(self, dev)
1225 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1228 function wifidev.get(self, opt)
1229 return _get("wireless", self.sid, opt)
1232 function wifidev.set(self, opt, val)
1233 return _set("wireless", self.sid, opt, val)
1236 function wifidev.name(self)
1240 function wifidev.hwmodes(self)
1241 local l = self.iwinfo.hwmodelist
1242 if l and next(l) then
1245 return { b = true, g = true }
1249 function wifidev.get_i18n(self)
1251 if self.iwinfo.type == "wl" then
1253 elseif self.iwinfo.type == "madwifi" then
1258 local l = self:hwmodes()
1259 if l.a then m = m .. "a" end
1260 if l.b then m = m .. "b" end
1261 if l.g then m = m .. "g" end
1262 if l.n then m = m .. "n" end
1264 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1267 function wifidev.is_up(self)
1270 _uci_state:foreach("wireless", "wifi-iface",
1272 if s.device == self.sid then
1283 function wifidev.get_wifinet(self, net)
1284 if _uci_real:get("wireless", net) == "wifi-iface" then
1287 local wnet = _wifi_lookup(net)
1289 return wifinet(wnet)
1294 function wifidev.get_wifinets(self)
1297 _uci_real:foreach("wireless", "wifi-iface",
1299 if s.device == self.sid then
1300 nets[#nets+1] = wifinet(s['.name'])
1307 function wifidev.add_wifinet(self, options)
1308 options = options or { }
1309 options.device = self.sid
1311 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1313 return wifinet(wnet, options)
1317 function wifidev.del_wifinet(self, net)
1318 if utl.instanceof(net, wifinet) then
1320 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1321 net = _wifi_lookup(net)
1324 if net and _uci_real:get("wireless", net, "device") == self.sid then
1325 _uci_real:delete("wireless", net)
1333 wifinet = utl.class()
1335 function wifinet.__init__(self, net, data)
1340 _uci_real:foreach("wireless", "wifi-iface",
1343 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1344 if s['.name'] == self.sid then
1345 netid = "%s.network%d" %{ s.device, num[s.device] }
1351 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1355 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1356 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1357 _uci_real:get_all("wireless", self.sid) or { }
1360 function wifinet.get(self, opt)
1361 return _get("wireless", self.sid, opt)
1364 function wifinet.set(self, opt, val)
1365 return _set("wireless", self.sid, opt, val)
1368 function wifinet.mode(self)
1369 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1372 function wifinet.ssid(self)
1373 return _uci_state:get("wireless", self.sid, "ssid")
1376 function wifinet.bssid(self)
1377 return _uci_state:get("wireless", self.sid, "bssid")
1380 function wifinet.network(self)
1381 return _uci_state:get("wifinet", self.sid, "network")
1384 function wifinet.id(self)
1388 function wifinet.name(self)
1392 function wifinet.ifname(self)
1393 local ifname = self.iwinfo.ifname
1394 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1400 function wifinet.get_device(self)
1401 if self.iwdata.device then
1402 return wifidev(self.iwdata.device)
1406 function wifinet.is_up(self)
1407 return (self.iwdata.up == "1")
1410 function wifinet.active_mode(self)
1411 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1413 if m == "ap" then m = "Master"
1414 elseif m == "sta" then m = "Client"
1415 elseif m == "adhoc" then m = "Ad-Hoc"
1416 elseif m == "mesh" then m = "Mesh"
1417 elseif m == "monitor" then m = "Monitor"
1423 function wifinet.active_mode_i18n(self)
1424 return lng.translate(self:active_mode())
1427 function wifinet.active_ssid(self)
1428 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1431 function wifinet.active_bssid(self)
1432 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1435 function wifinet.active_encryption(self)
1436 local enc = self.iwinfo and self.iwinfo.encryption
1437 return enc and enc.description or "-"
1440 function wifinet.assoclist(self)
1441 return self.iwinfo.assoclist or { }
1444 function wifinet.frequency(self)
1445 local freq = self.iwinfo.frequency
1446 if freq and freq > 0 then
1447 return "%.03f" % (freq / 1000)
1451 function wifinet.bitrate(self)
1452 local rate = self.iwinfo.bitrate
1453 if rate and rate > 0 then
1454 return (rate / 1000)
1458 function wifinet.channel(self)
1459 return self.iwinfo.channel or
1460 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1463 function wifinet.signal(self)
1464 return self.iwinfo.signal or 0
1467 function wifinet.noise(self)
1468 return self.iwinfo.noise or 0
1471 function wifinet.country(self)
1472 return self.iwinfo.country or "00"
1475 function wifinet.txpower(self)
1476 local pwr = (self.iwinfo.txpower or 0)
1477 return pwr + self:txpower_offset()
1480 function wifinet.txpower_offset(self)
1481 return self.iwinfo.txpower_offset or 0
1484 function wifinet.signal_level(self, s, n)
1485 if self:active_bssid() ~= "00:00:00:00:00:00" then
1486 local signal = s or self:signal()
1487 local noise = n or self:noise()
1489 if signal < 0 and noise < 0 then
1490 local snr = -1 * (noise - signal)
1491 return math.floor(snr / 5)
1500 function wifinet.signal_percent(self)
1501 local qc = self.iwinfo.quality or 0
1502 local qm = self.iwinfo.quality_max or 0
1504 if qc > 0 and qm > 0 then
1505 return math.floor((100 / qm) * qc)
1511 function wifinet.shortname(self)
1513 lng.translate(self:active_mode()),
1514 self:active_ssid() or self:active_bssid()
1518 function wifinet.get_i18n(self)
1519 return "%s: %s %q (%s)" %{
1520 lng.translate("Wireless Network"),
1521 lng.translate(self:active_mode()),
1522 self:active_ssid() or self:active_bssid(),
1527 function wifinet.adminlink(self)
1528 return dsp.build_url("admin", "network", "wireless", self.netid)
1531 function wifinet.get_network(self)
1532 return self:get_networks()[1]
1535 function wifinet.get_networks(self)
1538 for net in utl.imatch(tostring(self.iwdata.network)) do
1539 if _uci_real:get("network", net) == "interface" then
1540 nets[#nets+1] = network(net)
1543 table.sort(nets, function(a, b) return a.sid < b.sid end)
1547 function wifinet.get_interface(self)
1548 return interface(self:ifname())
1552 -- setup base protocols
1553 _M:register_protocol("static")
1554 _M:register_protocol("dhcp")
1555 _M:register_protocol("none")
1557 -- load protocol extensions
1558 local exts = nfs.dir(utl.libpath() .. "/model/network")
1562 if ext:match("%.lua$") then
1563 require("luci.model.network." .. ext:gsub("%.lua$", ""))