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, i18n
24 = tonumber, tostring, math, luci.i18n
26 local require = require
28 local bus = require "ubus"
29 local nxo = require "nixio"
30 local nfs = require "nixio.fs"
31 local ipc = require "luci.ip"
32 local sys = require "luci.sys"
33 local utl = require "luci.util"
34 local dsp = require "luci.dispatcher"
35 local uci = require "luci.model.uci"
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", "^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",
387 if s.network == n then
388 _uci_real:delete("wireless", s['.name'], "network")
395 function rename_network(self, old, new)
397 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
398 r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
401 _uci_real:foreach("network", "alias",
403 if s.interface == old then
404 _uci_real:set("network", s['.name'], "interface", new)
408 _uci_real:foreach("network", "route",
410 if s.interface == old then
411 _uci_real:set("network", s['.name'], "interface", new)
415 _uci_real:foreach("network", "route6",
417 if s.interface == old then
418 _uci_real:set("network", s['.name'], "interface", new)
422 _uci_real:foreach("wireless", "wifi-iface",
424 if s.network == old then
425 _uci_real:set("wireless", s['.name'], "network", new)
429 _uci_real:delete("network", old)
435 function get_interface(self, i)
436 if _interfaces[i] or _wifi_iface(i) then
441 _uci_real:foreach("wireless", "wifi-iface",
444 num[s.device] = num[s.device] and num[s.device] + 1 or 1
445 if s['.name'] == i then
447 "%s.network%d" %{s.device, num[s.device] })
456 function get_interfaces(self)
463 -- find normal interfaces
464 _uci_real:foreach("network", "interface",
466 for iface in utl.imatch(s.ifname) do
467 if not _iface_ignore(iface) and not _wifi_iface(iface) then
469 nfs[iface] = interface(iface)
474 for iface in utl.kspairs(_interfaces) do
475 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
476 nfs[iface] = interface(iface)
480 -- find vlan interfaces
481 _uci_real:foreach("network", "switch_vlan",
487 local base = baseof[s.device]
489 if not s.device:match("^eth%d") then
491 for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
493 base = l:match("^%w+: (%w+)")
496 if not base or not base:match("^eth%d") then
502 baseof[s.device] = base
505 local vid = tonumber(s.vid or s.vlan)
506 if vid ~= nil and vid >= 0 and vid <= 4095 then
507 local iface = "%s.%d" %{ base, vid }
508 if not seen[iface] then
510 nfs[iface] = interface(iface)
515 for iface in utl.kspairs(nfs) do
516 ifaces[#ifaces+1] = nfs[iface]
519 -- find wifi interfaces
522 _uci_real:foreach("wireless", "wifi-iface",
525 num[s.device] = num[s.device] and num[s.device] + 1 or 1
526 local i = "%s.network%d" %{ s.device, num[s.device] }
527 wfs[i] = interface(i)
531 for iface in utl.kspairs(wfs) do
532 ifaces[#ifaces+1] = wfs[iface]
538 function ignore_interface(self, x)
539 return _iface_ignore(x)
542 function get_wifidev(self, dev)
543 if _uci_real:get("wireless", dev) == "wifi-device" then
548 function get_wifidevs(self)
552 _uci_real:foreach("wireless", "wifi-device",
553 function(s) wfd[#wfd+1] = s['.name'] end)
556 for _, dev in utl.vspairs(wfd) do
557 devs[#devs+1] = wifidev(dev)
563 function get_wifinet(self, net)
564 local wnet = _wifi_lookup(net)
570 function add_wifinet(self, net, options)
571 if type(options) == "table" and options.device and
572 _uci_real:get("wireless", options.device) == "wifi-device"
574 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
579 function del_wifinet(self, net)
580 local wnet = _wifi_lookup(net)
582 _uci_real:delete("wireless", wnet)
588 function get_status_by_route(self, addr, mask)
590 for _, object in ipairs(_ubus:objects()) do
591 local net = object:match("^network%.interface%.(.+)")
593 local s = _ubus:call(object, "status", {})
594 if s and s.route then
596 for _, rt in ipairs(s.route) do
597 if rt.target == addr and rt.mask == mask then
606 function get_wannet(self)
607 local net = self:get_status_by_route("0.0.0.0", 0)
608 return net and network(net)
611 function get_wandev(self)
612 local _, stat = self:get_status_by_route("0.0.0.0", 0)
613 return stat and interface(stat.l3_device or stat.device)
616 function get_wan6net(self)
617 local net = self:get_status_by_route("::", 0)
618 return net and network(net)
621 function get_wan6dev(self)
622 local _, stat = self:get_status_by_route("::", 0)
623 return stat and interface(stat.l3_device or stat.device)
627 function network(name, proto)
629 local p = proto or _uci_real:get("network", name, "proto")
630 local c = p and _protocols[p] or protocol
635 function protocol.__init__(self, name)
639 function protocol._get(self, opt)
640 local v = _uci_real:get("network", self.sid, opt)
641 if type(v) == "table" then
642 return table.concat(v, " ")
647 function protocol._ubus(self, field)
648 if not _ubusnetcache[self.sid] then
649 _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
652 if _ubusnetcache[self.sid] and field then
653 return _ubusnetcache[self.sid][field]
655 return _ubusnetcache[self.sid]
658 function protocol.get(self, opt)
659 return _get("network", self.sid, opt)
662 function protocol.set(self, opt, val)
663 return _set("network", self.sid, opt, val)
666 function protocol.ifname(self)
668 if self:is_floating() then
669 ifname = self:_ubus("l3_device")
671 ifname = self:_ubus("device")
675 _uci_real:foreach("wireless", "wifi-iface",
678 num[s.device] = num[s.device]
679 and num[s.device] + 1 or 1
681 if s.network == self.sid then
682 ifname = "%s.network%d" %{ s.device, num[s.device] }
691 function protocol.proto(self)
695 function protocol.get_i18n(self)
696 local p = self:proto()
698 return i18n.translate("Unmanaged")
699 elseif p == "static" then
700 return i18n.translate("Static address")
701 elseif p == "dhcp" then
702 return i18n.translate("DHCP client")
704 return i18n.translate("Unknown")
708 function protocol.type(self)
709 return self:_get("type")
712 function protocol.name(self)
716 function protocol.uptime(self)
717 return self:_ubus("uptime") or 0
720 function protocol.expires(self)
721 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
722 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
724 l = l - (nxo.sysinfo().uptime - a)
725 return l > 0 and l or 0
730 function protocol.metric(self)
731 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
734 function protocol.ipaddr(self)
735 local addrs = self:_ubus("ipv4-address")
736 return addrs and #addrs > 0 and addrs[1].address
739 function protocol.netmask(self)
740 local addrs = self:_ubus("ipv4-address")
741 return addrs and #addrs > 0 and
742 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
745 function protocol.gwaddr(self)
747 for _, route in ipairs(self:_ubus("route") or { }) do
748 if route.target == "0.0.0.0" and route.mask == 0 then
754 function protocol.dnsaddrs(self)
757 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
758 if not addr:match(":") then
765 function protocol.ip6addr(self)
766 local addrs = self:_ubus("ipv6-address")
767 return addrs and #addrs > 0
768 and "%s/%d" %{ addrs[1].address, addrs[1].mask }
771 function protocol.gw6addr(self)
773 for _, route in ipairs(self:_ubus("route") or { }) do
774 if route.target == "::" and route.mask == 0 then
775 return ipc.IPv6(route.nexthop):string()
780 function protocol.dns6addrs(self)
783 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
784 if addr:match(":") then
791 function protocol.is_bridge(self)
792 return (not self:is_virtual() and self:type() == "bridge")
795 function protocol.opkg_package(self)
799 function protocol.is_installed(self)
803 function protocol.is_virtual(self)
807 function protocol.is_floating(self)
811 function protocol.is_empty(self)
812 if self:is_floating() then
817 if (self:_get("ifname") or ""):match("%S+") then
821 _uci_real:foreach("wireless", "wifi-iface",
824 for n in utl.imatch(s.network) do
825 if n == self.sid then
836 function protocol.add_interface(self, ifname)
837 ifname = _M:ifnameof(ifname)
838 if ifname and not self:is_floating() then
839 -- if its a wifi interface, change its network option
840 local wif = _wifi_lookup(ifname)
842 _append("wireless", wif, "network", self.sid)
844 -- add iface to our iface list
846 _append("network", self.sid, "ifname", ifname)
851 function protocol.del_interface(self, ifname)
852 ifname = _M:ifnameof(ifname)
853 if ifname and not self:is_floating() then
854 -- if its a wireless interface, clear its network option
855 local wif = _wifi_lookup(ifname)
856 if wif then _filter("wireless", wif, "network", self.sid) end
858 -- remove the interface
859 _filter("network", self.sid, "ifname", ifname)
863 function protocol.get_interface(self)
864 if self:is_virtual() then
865 _tunnel[self:proto() .. "-" .. self.sid] = true
866 return interface(self:proto() .. "-" .. self.sid, self)
867 elseif self:is_bridge() then
868 _bridge["br-" .. self.sid] = true
869 return interface("br-" .. self.sid, self)
873 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
874 ifn = ifn:match("^[^:/]+")
875 return ifn and interface(ifn, self)
878 _uci_real:foreach("wireless", "wifi-iface",
881 num[s.device] = num[s.device] and num[s.device] + 1 or 1
882 if s.network == self.sid then
883 ifn = "%s.network%d" %{ s.device, num[s.device] }
888 return ifn and interface(ifn, self)
892 function protocol.get_interfaces(self)
893 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
898 for ifn in utl.imatch(self:get("ifname")) do
899 ifn = ifn:match("^[^:/]+")
900 nfs[ifn] = interface(ifn, self)
903 for ifn in utl.kspairs(nfs) do
904 ifaces[#ifaces+1] = nfs[ifn]
909 _uci_real:foreach("wireless", "wifi-iface",
912 num[s.device] = num[s.device] and num[s.device] + 1 or 1
913 if s.network == self.sid then
914 ifn = "%s.network%d" %{ s.device, num[s.device] }
915 wfs[ifn] = interface(ifn, self)
920 for ifn in utl.kspairs(wfs) do
921 ifaces[#ifaces+1] = wfs[ifn]
928 function protocol.contains_interface(self, ifname)
929 ifname = _M:ifnameof(ifname)
932 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
934 elseif self:is_bridge() and "br-" .. self.sid == ifname then
938 for ifn in utl.imatch(self:get("ifname")) do
939 ifn = ifn:match("[^:]+")
940 if ifn == ifname then
945 local wif = _wifi_lookup(ifname)
948 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
949 if n == self.sid then
959 function protocol.adminlink(self)
960 return dsp.build_url("admin", "network", "network", self.sid)
964 interface = utl.class()
966 function interface.__init__(self, ifname, network)
967 local wif = _wifi_lookup(ifname)
969 self.wif = wifinet(wif)
970 self.ifname = _uci_state:get("wireless", wif, "ifname")
973 self.ifname = self.ifname or ifname
974 self.dev = _interfaces[self.ifname]
975 self.network = network
978 function interface._ubus(self, field)
979 if not _ubusdevcache[self.ifname] then
980 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
981 { name = self.ifname })
983 if _ubusdevcache[self.ifname] and field then
984 return _ubusdevcache[self.ifname][field]
986 return _ubusdevcache[self.ifname]
989 function interface.name(self)
990 return self.wif and self.wif:ifname() or self.ifname
993 function interface.mac(self)
994 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
997 function interface.ipaddrs(self)
998 return self.dev and self.dev.ipaddrs or { }
1001 function interface.ip6addrs(self)
1002 return self.dev and self.dev.ip6addrs or { }
1005 function interface.type(self)
1006 if self.wif or _wifi_iface(self.ifname) then
1008 elseif _bridge[self.ifname] then
1010 elseif _tunnel[self.ifname] then
1012 elseif self.ifname:match("%.") then
1014 elseif _switch[self.ifname] then
1021 function interface.shortname(self)
1024 self.wif:active_mode(),
1025 self.wif:active_ssid() or self.wif:active_bssid()
1032 function interface.get_i18n(self)
1034 return "%s: %s %q" %{
1035 i18n.translate("Wireless Network"),
1036 self.wif:active_mode(),
1037 self.wif:active_ssid() or self.wif:active_bssid()
1040 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1044 function interface.get_type_i18n(self)
1045 local x = self:type()
1047 return i18n.translate("Wireless Adapter")
1048 elseif x == "bridge" then
1049 return i18n.translate("Bridge")
1050 elseif x == "switch" then
1051 return i18n.translate("Ethernet Switch")
1052 elseif x == "vlan" then
1053 return i18n.translate("VLAN Interface")
1054 elseif x == "tunnel" then
1055 return i18n.translate("Tunnel Interface")
1057 return i18n.translate("Ethernet Adapter")
1061 function interface.adminlink(self)
1063 return self.wif:adminlink()
1067 function interface.ports(self)
1068 local members = self:_ubus("bridge-members")
1072 for _, iface in ipairs(members) do
1073 ifaces[#ifaces+1] = interface(iface)
1078 function interface.bridge_id(self)
1086 function interface.bridge_stp(self)
1094 function interface.is_up(self)
1096 return self.wif:is_up()
1098 return self:_ubus("up") or false
1102 function interface.is_bridge(self)
1103 return (self:type() == "bridge")
1106 function interface.is_bridgeport(self)
1107 return self.dev and self.dev.bridge and true or false
1110 local function uint(x)
1112 return (x < 0) and ((2^32) + x) or x
1117 function interface.tx_bytes(self)
1118 local stat = self:_ubus("statistics")
1119 return stat and uint(stat.tx_bytes) or 0
1122 function interface.rx_bytes(self)
1123 local stat = self:_ubus("statistics")
1124 return stat and uint(stat.rx_bytes) or 0
1127 function interface.tx_packets(self)
1128 local stat = self:_ubus("statistics")
1129 return stat and uint(stat.tx_packets) or 0
1132 function interface.rx_packets(self)
1133 local stat = self:_ubus("statistics")
1134 return stat and uint(stat.rx_packets) or 0
1137 function interface.get_network(self)
1138 return self:get_networks()[1]
1141 function interface.get_networks(self)
1142 if not self.networks then
1145 for _, net in ipairs(_M:get_networks()) do
1146 if net:contains_interface(self.ifname) or
1147 net:ifname() == self.ifname
1152 table.sort(nets, function(a, b) return a.sid < b.sid end)
1153 self.networks = nets
1156 return self.networks
1160 function interface.get_wifinet(self)
1165 wifidev = utl.class()
1167 function wifidev.__init__(self, dev)
1169 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1172 function wifidev.get(self, opt)
1173 return _get("wireless", self.sid, opt)
1176 function wifidev.set(self, opt, val)
1177 return _set("wireless", self.sid, opt, val)
1180 function wifidev.name(self)
1184 function wifidev.hwmodes(self)
1185 local l = self.iwinfo.hwmodelist
1186 if l and next(l) then
1189 return { b = true, g = true }
1193 function wifidev.get_i18n(self)
1195 if self.iwinfo.type == "wl" then
1197 elseif self.iwinfo.type == "madwifi" then
1202 local l = self:hwmodes()
1203 if l.a then m = m .. "a" end
1204 if l.b then m = m .. "b" end
1205 if l.g then m = m .. "g" end
1206 if l.n then m = m .. "n" end
1208 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1211 function wifidev.is_up(self)
1214 _uci_state:foreach("wireless", "wifi-iface",
1216 if s.device == self.sid then
1227 function wifidev.get_wifinet(self, net)
1228 if _uci_real:get("wireless", net) == "wifi-iface" then
1231 local wnet = _wifi_lookup(net)
1233 return wifinet(wnet)
1238 function wifidev.get_wifinets(self)
1241 _uci_real:foreach("wireless", "wifi-iface",
1243 if s.device == self.sid then
1244 nets[#nets+1] = wifinet(s['.name'])
1251 function wifidev.add_wifinet(self, options)
1252 options = options or { }
1253 options.device = self.sid
1255 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1257 return wifinet(wnet, options)
1261 function wifidev.del_wifinet(self, net)
1262 if utl.instanceof(net, wifinet) then
1264 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1265 net = _wifi_lookup(net)
1268 if net and _uci_real:get("wireless", net, "device") == self.sid then
1269 _uci_real:delete("wireless", net)
1277 wifinet = utl.class()
1279 function wifinet.__init__(self, net, data)
1284 _uci_real:foreach("wireless", "wifi-iface",
1287 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1288 if s['.name'] == self.sid then
1289 netid = "%s.network%d" %{ s.device, num[s.device] }
1295 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1299 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1300 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1301 _uci_real:get_all("wireless", self.sid) or { }
1304 function wifinet.get(self, opt)
1305 return _get("wireless", self.sid, opt)
1308 function wifinet.set(self, opt, val)
1309 return _set("wireless", self.sid, opt, val)
1312 function wifinet.mode(self)
1313 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1316 function wifinet.ssid(self)
1317 return _uci_state:get("wireless", self.sid, "ssid")
1320 function wifinet.bssid(self)
1321 return _uci_state:get("wireless", self.sid, "bssid")
1324 function wifinet.network(self)
1325 return _uci_state:get("wifinet", self.sid, "network")
1328 function wifinet.id(self)
1332 function wifinet.name(self)
1336 function wifinet.ifname(self)
1337 local ifname = self.iwinfo.ifname
1338 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1344 function wifinet.get_device(self)
1345 if self.iwdata.device then
1346 return wifidev(self.iwdata.device)
1350 function wifinet.is_up(self)
1351 return (self.iwdata.up == "1")
1354 function wifinet.active_mode(self)
1355 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1357 if m == "ap" then m = "Master"
1358 elseif m == "sta" then m = "Client"
1359 elseif m == "adhoc" then m = "Ad-Hoc"
1360 elseif m == "mesh" then m = "Mesh"
1361 elseif m == "monitor" then m = "Monitor"
1367 function wifinet.active_mode_i18n(self)
1368 return i18n.translate(self:active_mode())
1371 function wifinet.active_ssid(self)
1372 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1375 function wifinet.active_bssid(self)
1376 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1379 function wifinet.active_encryption(self)
1380 local enc = self.iwinfo and self.iwinfo.encryption
1381 return enc and enc.description or "-"
1384 function wifinet.assoclist(self)
1385 return self.iwinfo.assoclist or { }
1388 function wifinet.frequency(self)
1389 local freq = self.iwinfo.frequency
1390 if freq and freq > 0 then
1391 return "%.03f" % (freq / 1000)
1395 function wifinet.bitrate(self)
1396 local rate = self.iwinfo.bitrate
1397 if rate and rate > 0 then
1398 return (rate / 1000)
1402 function wifinet.channel(self)
1403 return self.iwinfo.channel or
1404 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1407 function wifinet.signal(self)
1408 return self.iwinfo.signal or 0
1411 function wifinet.noise(self)
1412 return self.iwinfo.noise or 0
1415 function wifinet.country(self)
1416 return self.iwinfo.country or "00"
1419 function wifinet.txpower(self)
1420 local pwr = (self.iwinfo.txpower or 0)
1421 return pwr + self:txpower_offset()
1424 function wifinet.txpower_offset(self)
1425 return self.iwinfo.txpower_offset or 0
1428 function wifinet.signal_level(self, s, n)
1429 if self:active_bssid() ~= "00:00:00:00:00:00" then
1430 local signal = s or self:signal()
1431 local noise = n or self:noise()
1433 if signal < 0 and noise < 0 then
1434 local snr = -1 * (noise - signal)
1435 return math.floor(snr / 5)
1444 function wifinet.signal_percent(self)
1445 local qc = self.iwinfo.quality or 0
1446 local qm = self.iwinfo.quality_max or 0
1448 if qc > 0 and qm > 0 then
1449 return math.floor((100 / qm) * qc)
1455 function wifinet.shortname(self)
1457 i18n.translate(self:active_mode()),
1458 self:active_ssid() or self:active_bssid()
1462 function wifinet.get_i18n(self)
1463 return "%s: %s %q (%s)" %{
1464 i18n.translate("Wireless Network"),
1465 i18n.translate(self:active_mode()),
1466 self:active_ssid() or self:active_bssid(),
1471 function wifinet.adminlink(self)
1472 return dsp.build_url("admin", "network", "wireless", self.netid)
1475 function wifinet.get_network(self)
1476 return self:get_networks()[1]
1479 function wifinet.get_networks(self)
1482 for net in utl.imatch(tostring(self.iwdata.network)) do
1483 if _uci_real:get("network", net) == "interface" then
1484 nets[#nets+1] = network(net)
1487 table.sort(nets, function(a, b) return a.sid < b.sid end)
1491 function wifinet.get_interface(self)
1492 return interface(self:ifname())
1496 -- setup base protocols
1497 _M:register_protocol("static")
1498 _M:register_protocol("dhcp")
1499 _M:register_protocol("none")
1501 -- load protocol extensions
1502 local exts = nfs.dir(utl.libpath() .. "/model/network")
1506 if ext:match("%.lua$") then
1507 require("luci.model.network." .. ext:gsub("%.lua$", ""))