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 return addrs and #addrs > 0
817 and "%s/%d" %{ addrs[1].address, addrs[1].mask }
820 function protocol.gw6addr(self)
822 for _, route in ipairs(self:_ubus("route") or { }) do
823 if route.target == "::" and route.mask == 0 then
824 return ipc.IPv6(route.nexthop):string()
829 function protocol.dns6addrs(self)
832 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
833 if addr:match(":") then
840 function protocol.is_bridge(self)
841 return (not self:is_virtual() and self:type() == "bridge")
844 function protocol.opkg_package(self)
848 function protocol.is_installed(self)
852 function protocol.is_virtual(self)
856 function protocol.is_floating(self)
860 function protocol.is_empty(self)
861 if self:is_floating() then
866 if (self:_get("ifname") or ""):match("%S+") then
870 _uci_real:foreach("wireless", "wifi-iface",
873 for n in utl.imatch(s.network) do
874 if n == self.sid then
885 function protocol.add_interface(self, ifname)
886 ifname = _M:ifnameof(ifname)
887 if ifname and not self:is_floating() then
888 -- if its a wifi interface, change its network option
889 local wif = _wifi_lookup(ifname)
891 _append("wireless", wif, "network", self.sid)
893 -- add iface to our iface list
895 _append("network", self.sid, "ifname", ifname)
900 function protocol.del_interface(self, ifname)
901 ifname = _M:ifnameof(ifname)
902 if ifname and not self:is_floating() then
903 -- if its a wireless interface, clear its network option
904 local wif = _wifi_lookup(ifname)
905 if wif then _filter("wireless", wif, "network", self.sid) end
907 -- remove the interface
908 _filter("network", self.sid, "ifname", ifname)
912 function protocol.get_interface(self)
913 if self:is_virtual() then
914 _tunnel[self:proto() .. "-" .. self.sid] = true
915 return interface(self:proto() .. "-" .. self.sid, self)
916 elseif self:is_bridge() then
917 _bridge["br-" .. self.sid] = true
918 return interface("br-" .. self.sid, self)
922 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
923 ifn = ifn:match("^[^:/]+")
924 return ifn and interface(ifn, self)
927 _uci_real:foreach("wireless", "wifi-iface",
930 num[s.device] = num[s.device] and num[s.device] + 1 or 1
933 for net in utl.imatch(s.network) do
934 if net == self.sid then
935 ifn = "%s.network%d" %{ s.device, num[s.device] }
941 return ifn and interface(ifn, self)
945 function protocol.get_interfaces(self)
946 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
951 for ifn in utl.imatch(self:get("ifname")) do
952 ifn = ifn:match("^[^:/]+")
953 nfs[ifn] = interface(ifn, self)
956 for ifn in utl.kspairs(nfs) do
957 ifaces[#ifaces+1] = nfs[ifn]
962 _uci_real:foreach("wireless", "wifi-iface",
965 num[s.device] = num[s.device] and num[s.device] + 1 or 1
968 for net in utl.imatch(s.network) do
969 if net == self.sid then
970 ifn = "%s.network%d" %{ s.device, num[s.device] }
971 wfs[ifn] = interface(ifn, self)
977 for ifn in utl.kspairs(wfs) do
978 ifaces[#ifaces+1] = wfs[ifn]
985 function protocol.contains_interface(self, ifname)
986 ifname = _M:ifnameof(ifname)
989 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
991 elseif self:is_bridge() and "br-" .. self.sid == ifname then
995 for ifn in utl.imatch(self:get("ifname")) do
996 ifn = ifn:match("[^:]+")
997 if ifn == ifname then
1002 local wif = _wifi_lookup(ifname)
1005 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
1006 if n == self.sid then
1016 function protocol.adminlink(self)
1017 return dsp.build_url("admin", "network", "network", self.sid)
1021 interface = utl.class()
1023 function interface.__init__(self, ifname, network)
1024 local wif = _wifi_lookup(ifname)
1026 self.wif = wifinet(wif)
1027 self.ifname = _uci_state:get("wireless", wif, "ifname")
1030 self.ifname = self.ifname or ifname
1031 self.dev = _interfaces[self.ifname]
1032 self.network = network
1035 function interface._ubus(self, field)
1036 if not _ubusdevcache[self.ifname] then
1037 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
1038 { name = self.ifname })
1040 if _ubusdevcache[self.ifname] and field then
1041 return _ubusdevcache[self.ifname][field]
1043 return _ubusdevcache[self.ifname]
1046 function interface.name(self)
1047 return self.wif and self.wif:ifname() or self.ifname
1050 function interface.mac(self)
1051 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
1054 function interface.ipaddrs(self)
1055 return self.dev and self.dev.ipaddrs or { }
1058 function interface.ip6addrs(self)
1059 return self.dev and self.dev.ip6addrs or { }
1062 function interface.type(self)
1063 if self.wif or _wifi_iface(self.ifname) then
1065 elseif _bridge[self.ifname] then
1067 elseif _tunnel[self.ifname] then
1069 elseif self.ifname:match("%.") then
1071 elseif _switch[self.ifname] then
1078 function interface.shortname(self)
1081 self.wif:active_mode(),
1082 self.wif:active_ssid() or self.wif:active_bssid()
1089 function interface.get_i18n(self)
1091 return "%s: %s %q" %{
1092 lng.translate("Wireless Network"),
1093 self.wif:active_mode(),
1094 self.wif:active_ssid() or self.wif:active_bssid()
1097 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1101 function interface.get_type_i18n(self)
1102 local x = self:type()
1104 return lng.translate("Wireless Adapter")
1105 elseif x == "bridge" then
1106 return lng.translate("Bridge")
1107 elseif x == "switch" then
1108 return lng.translate("Ethernet Switch")
1109 elseif x == "vlan" then
1110 return lng.translate("VLAN Interface")
1111 elseif x == "tunnel" then
1112 return lng.translate("Tunnel Interface")
1114 return lng.translate("Ethernet Adapter")
1118 function interface.adminlink(self)
1120 return self.wif:adminlink()
1124 function interface.ports(self)
1125 local members = self:_ubus("bridge-members")
1129 for _, iface in ipairs(members) do
1130 ifaces[#ifaces+1] = interface(iface)
1135 function interface.bridge_id(self)
1143 function interface.bridge_stp(self)
1151 function interface.is_up(self)
1153 return self.wif:is_up()
1155 return self:_ubus("up") or false
1159 function interface.is_bridge(self)
1160 return (self:type() == "bridge")
1163 function interface.is_bridgeport(self)
1164 return self.dev and self.dev.bridge and true or false
1167 local function uint(x)
1169 return (x < 0) and ((2^32) + x) or x
1174 function interface.tx_bytes(self)
1175 local stat = self:_ubus("statistics")
1176 return stat and uint(stat.tx_bytes) or 0
1179 function interface.rx_bytes(self)
1180 local stat = self:_ubus("statistics")
1181 return stat and uint(stat.rx_bytes) or 0
1184 function interface.tx_packets(self)
1185 local stat = self:_ubus("statistics")
1186 return stat and uint(stat.tx_packets) or 0
1189 function interface.rx_packets(self)
1190 local stat = self:_ubus("statistics")
1191 return stat and uint(stat.rx_packets) or 0
1194 function interface.get_network(self)
1195 return self:get_networks()[1]
1198 function interface.get_networks(self)
1199 if not self.networks then
1202 for _, net in ipairs(_M:get_networks()) do
1203 if net:contains_interface(self.ifname) or
1204 net:ifname() == self.ifname
1209 table.sort(nets, function(a, b) return a.sid < b.sid end)
1210 self.networks = nets
1213 return self.networks
1217 function interface.get_wifinet(self)
1222 wifidev = utl.class()
1224 function wifidev.__init__(self, dev)
1226 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1229 function wifidev.get(self, opt)
1230 return _get("wireless", self.sid, opt)
1233 function wifidev.set(self, opt, val)
1234 return _set("wireless", self.sid, opt, val)
1237 function wifidev.name(self)
1241 function wifidev.hwmodes(self)
1242 local l = self.iwinfo.hwmodelist
1243 if l and next(l) then
1246 return { b = true, g = true }
1250 function wifidev.get_i18n(self)
1252 if self.iwinfo.type == "wl" then
1254 elseif self.iwinfo.type == "madwifi" then
1259 local l = self:hwmodes()
1260 if l.a then m = m .. "a" end
1261 if l.b then m = m .. "b" end
1262 if l.g then m = m .. "g" end
1263 if l.n then m = m .. "n" end
1265 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1268 function wifidev.is_up(self)
1271 _uci_state:foreach("wireless", "wifi-iface",
1273 if s.device == self.sid then
1284 function wifidev.get_wifinet(self, net)
1285 if _uci_real:get("wireless", net) == "wifi-iface" then
1288 local wnet = _wifi_lookup(net)
1290 return wifinet(wnet)
1295 function wifidev.get_wifinets(self)
1298 _uci_real:foreach("wireless", "wifi-iface",
1300 if s.device == self.sid then
1301 nets[#nets+1] = wifinet(s['.name'])
1308 function wifidev.add_wifinet(self, options)
1309 options = options or { }
1310 options.device = self.sid
1312 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1314 return wifinet(wnet, options)
1318 function wifidev.del_wifinet(self, net)
1319 if utl.instanceof(net, wifinet) then
1321 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1322 net = _wifi_lookup(net)
1325 if net and _uci_real:get("wireless", net, "device") == self.sid then
1326 _uci_real:delete("wireless", net)
1334 wifinet = utl.class()
1336 function wifinet.__init__(self, net, data)
1341 _uci_real:foreach("wireless", "wifi-iface",
1344 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1345 if s['.name'] == self.sid then
1346 netid = "%s.network%d" %{ s.device, num[s.device] }
1352 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1356 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1357 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1358 _uci_real:get_all("wireless", self.sid) or { }
1361 function wifinet.get(self, opt)
1362 return _get("wireless", self.sid, opt)
1365 function wifinet.set(self, opt, val)
1366 return _set("wireless", self.sid, opt, val)
1369 function wifinet.mode(self)
1370 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1373 function wifinet.ssid(self)
1374 return _uci_state:get("wireless", self.sid, "ssid")
1377 function wifinet.bssid(self)
1378 return _uci_state:get("wireless", self.sid, "bssid")
1381 function wifinet.network(self)
1382 return _uci_state:get("wifinet", self.sid, "network")
1385 function wifinet.id(self)
1389 function wifinet.name(self)
1393 function wifinet.ifname(self)
1394 local ifname = self.iwinfo.ifname
1395 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1401 function wifinet.get_device(self)
1402 if self.iwdata.device then
1403 return wifidev(self.iwdata.device)
1407 function wifinet.is_up(self)
1408 return (self.iwdata.up == "1")
1411 function wifinet.active_mode(self)
1412 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1414 if m == "ap" then m = "Master"
1415 elseif m == "sta" then m = "Client"
1416 elseif m == "adhoc" then m = "Ad-Hoc"
1417 elseif m == "mesh" then m = "Mesh"
1418 elseif m == "monitor" then m = "Monitor"
1424 function wifinet.active_mode_i18n(self)
1425 return lng.translate(self:active_mode())
1428 function wifinet.active_ssid(self)
1429 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1432 function wifinet.active_bssid(self)
1433 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1436 function wifinet.active_encryption(self)
1437 local enc = self.iwinfo and self.iwinfo.encryption
1438 return enc and enc.description or "-"
1441 function wifinet.assoclist(self)
1442 return self.iwinfo.assoclist or { }
1445 function wifinet.frequency(self)
1446 local freq = self.iwinfo.frequency
1447 if freq and freq > 0 then
1448 return "%.03f" % (freq / 1000)
1452 function wifinet.bitrate(self)
1453 local rate = self.iwinfo.bitrate
1454 if rate and rate > 0 then
1455 return (rate / 1000)
1459 function wifinet.channel(self)
1460 return self.iwinfo.channel or
1461 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1464 function wifinet.signal(self)
1465 return self.iwinfo.signal or 0
1468 function wifinet.noise(self)
1469 return self.iwinfo.noise or 0
1472 function wifinet.country(self)
1473 return self.iwinfo.country or "00"
1476 function wifinet.txpower(self)
1477 local pwr = (self.iwinfo.txpower or 0)
1478 return pwr + self:txpower_offset()
1481 function wifinet.txpower_offset(self)
1482 return self.iwinfo.txpower_offset or 0
1485 function wifinet.signal_level(self, s, n)
1486 if self:active_bssid() ~= "00:00:00:00:00:00" then
1487 local signal = s or self:signal()
1488 local noise = n or self:noise()
1490 if signal < 0 and noise < 0 then
1491 local snr = -1 * (noise - signal)
1492 return math.floor(snr / 5)
1501 function wifinet.signal_percent(self)
1502 local qc = self.iwinfo.quality or 0
1503 local qm = self.iwinfo.quality_max or 0
1505 if qc > 0 and qm > 0 then
1506 return math.floor((100 / qm) * qc)
1512 function wifinet.shortname(self)
1514 lng.translate(self:active_mode()),
1515 self:active_ssid() or self:active_bssid()
1519 function wifinet.get_i18n(self)
1520 return "%s: %s %q (%s)" %{
1521 lng.translate("Wireless Network"),
1522 lng.translate(self:active_mode()),
1523 self:active_ssid() or self:active_bssid(),
1528 function wifinet.adminlink(self)
1529 return dsp.build_url("admin", "network", "wireless", self.netid)
1532 function wifinet.get_network(self)
1533 return self:get_networks()[1]
1536 function wifinet.get_networks(self)
1539 for net in utl.imatch(tostring(self.iwdata.network)) do
1540 if _uci_real:get("network", net) == "interface" then
1541 nets[#nets+1] = network(net)
1544 table.sort(nets, function(a, b) return a.sid < b.sid end)
1548 function wifinet.get_interface(self)
1549 return interface(self:ifname())
1553 -- setup base protocols
1554 _M:register_protocol("static")
1555 _M:register_protocol("dhcp")
1556 _M:register_protocol("none")
1558 -- load protocol extensions
1559 local exts = nfs.dir(utl.libpath() .. "/model/network")
1563 if ext:match("%.lua$") then
1564 require("luci.model.network." .. ext:gsub("%.lua$", ""))