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")
752 elseif p == "dhcpv6" then
753 return lng.translate("DHCPv6 client")
755 return lng.translate("Unknown")
759 function protocol.type(self)
760 return self:_get("type")
763 function protocol.name(self)
767 function protocol.uptime(self)
768 return self:_ubus("uptime") or 0
771 function protocol.expires(self)
772 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
773 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
775 l = l - (nxo.sysinfo().uptime - a)
776 return l > 0 and l or 0
781 function protocol.metric(self)
782 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
785 function protocol.ipaddr(self)
786 local addrs = self:_ubus("ipv4-address")
787 return addrs and #addrs > 0 and addrs[1].address
790 function protocol.netmask(self)
791 local addrs = self:_ubus("ipv4-address")
792 return addrs and #addrs > 0 and
793 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
796 function protocol.gwaddr(self)
798 for _, route in ipairs(self:_ubus("route") or { }) do
799 if route.target == "0.0.0.0" and route.mask == 0 then
805 function protocol.dnsaddrs(self)
808 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
809 if not addr:match(":") then
816 function protocol.ip6addr(self)
817 local addrs = self:_ubus("ipv6-address")
818 return addrs and #addrs > 0
819 and "%s/%d" %{ addrs[1].address, addrs[1].mask }
822 function protocol.gw6addr(self)
824 for _, route in ipairs(self:_ubus("route") or { }) do
825 if route.target == "::" and route.mask == 0 then
826 return ipc.IPv6(route.nexthop):string()
831 function protocol.dns6addrs(self)
834 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
835 if addr:match(":") then
842 function protocol.is_bridge(self)
843 return (not self:is_virtual() and self:type() == "bridge")
846 function protocol.opkg_package(self)
850 function protocol.is_installed(self)
854 function protocol.is_virtual(self)
858 function protocol.is_floating(self)
862 function protocol.is_empty(self)
863 if self:is_floating() then
868 if (self:_get("ifname") or ""):match("%S+") then
872 _uci_real:foreach("wireless", "wifi-iface",
875 for n in utl.imatch(s.network) do
876 if n == self.sid then
887 function protocol.add_interface(self, ifname)
888 ifname = _M:ifnameof(ifname)
889 if ifname and not self:is_floating() then
890 -- if its a wifi interface, change its network option
891 local wif = _wifi_lookup(ifname)
893 _append("wireless", wif, "network", self.sid)
895 -- add iface to our iface list
897 _append("network", self.sid, "ifname", ifname)
902 function protocol.del_interface(self, ifname)
903 ifname = _M:ifnameof(ifname)
904 if ifname and not self:is_floating() then
905 -- if its a wireless interface, clear its network option
906 local wif = _wifi_lookup(ifname)
907 if wif then _filter("wireless", wif, "network", self.sid) end
909 -- remove the interface
910 _filter("network", self.sid, "ifname", ifname)
914 function protocol.get_interface(self)
915 if self:is_virtual() then
916 _tunnel[self:proto() .. "-" .. self.sid] = true
917 return interface(self:proto() .. "-" .. self.sid, self)
918 elseif self:is_bridge() then
919 _bridge["br-" .. self.sid] = true
920 return interface("br-" .. self.sid, self)
924 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
925 ifn = ifn:match("^[^:/]+")
926 return ifn and interface(ifn, self)
929 _uci_real:foreach("wireless", "wifi-iface",
932 num[s.device] = num[s.device] and num[s.device] + 1 or 1
935 for net in utl.imatch(s.network) do
936 if net == self.sid then
937 ifn = "%s.network%d" %{ s.device, num[s.device] }
943 return ifn and interface(ifn, self)
947 function protocol.get_interfaces(self)
948 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
953 for ifn in utl.imatch(self:get("ifname")) do
954 ifn = ifn:match("^[^:/]+")
955 nfs[ifn] = interface(ifn, self)
958 for ifn in utl.kspairs(nfs) do
959 ifaces[#ifaces+1] = nfs[ifn]
964 _uci_real:foreach("wireless", "wifi-iface",
967 num[s.device] = num[s.device] and num[s.device] + 1 or 1
970 for net in utl.imatch(s.network) do
971 if net == self.sid then
972 ifn = "%s.network%d" %{ s.device, num[s.device] }
973 wfs[ifn] = interface(ifn, self)
979 for ifn in utl.kspairs(wfs) do
980 ifaces[#ifaces+1] = wfs[ifn]
987 function protocol.contains_interface(self, ifname)
988 ifname = _M:ifnameof(ifname)
991 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
993 elseif self:is_bridge() and "br-" .. self.sid == ifname then
997 for ifn in utl.imatch(self:get("ifname")) do
998 ifn = ifn:match("[^:]+")
999 if ifn == ifname then
1004 local wif = _wifi_lookup(ifname)
1007 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
1008 if n == self.sid then
1018 function protocol.adminlink(self)
1019 return dsp.build_url("admin", "network", "network", self.sid)
1023 interface = utl.class()
1025 function interface.__init__(self, ifname, network)
1026 local wif = _wifi_lookup(ifname)
1028 self.wif = wifinet(wif)
1029 self.ifname = _uci_state:get("wireless", wif, "ifname")
1032 self.ifname = self.ifname or ifname
1033 self.dev = _interfaces[self.ifname]
1034 self.network = network
1037 function interface._ubus(self, field)
1038 if not _ubusdevcache[self.ifname] then
1039 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
1040 { name = self.ifname })
1042 if _ubusdevcache[self.ifname] and field then
1043 return _ubusdevcache[self.ifname][field]
1045 return _ubusdevcache[self.ifname]
1048 function interface.name(self)
1049 return self.wif and self.wif:ifname() or self.ifname
1052 function interface.mac(self)
1053 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
1056 function interface.ipaddrs(self)
1057 return self.dev and self.dev.ipaddrs or { }
1060 function interface.ip6addrs(self)
1061 return self.dev and self.dev.ip6addrs or { }
1064 function interface.type(self)
1065 if self.wif or _wifi_iface(self.ifname) then
1067 elseif _bridge[self.ifname] then
1069 elseif _tunnel[self.ifname] then
1071 elseif self.ifname:match("%.") then
1073 elseif _switch[self.ifname] then
1080 function interface.shortname(self)
1083 self.wif:active_mode(),
1084 self.wif:active_ssid() or self.wif:active_bssid()
1091 function interface.get_i18n(self)
1093 return "%s: %s %q" %{
1094 lng.translate("Wireless Network"),
1095 self.wif:active_mode(),
1096 self.wif:active_ssid() or self.wif:active_bssid()
1099 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1103 function interface.get_type_i18n(self)
1104 local x = self:type()
1106 return lng.translate("Wireless Adapter")
1107 elseif x == "bridge" then
1108 return lng.translate("Bridge")
1109 elseif x == "switch" then
1110 return lng.translate("Ethernet Switch")
1111 elseif x == "vlan" then
1112 return lng.translate("VLAN Interface")
1113 elseif x == "tunnel" then
1114 return lng.translate("Tunnel Interface")
1116 return lng.translate("Ethernet Adapter")
1120 function interface.adminlink(self)
1122 return self.wif:adminlink()
1126 function interface.ports(self)
1127 local members = self:_ubus("bridge-members")
1131 for _, iface in ipairs(members) do
1132 ifaces[#ifaces+1] = interface(iface)
1137 function interface.bridge_id(self)
1145 function interface.bridge_stp(self)
1153 function interface.is_up(self)
1155 return self.wif:is_up()
1157 return self:_ubus("up") or false
1161 function interface.is_bridge(self)
1162 return (self:type() == "bridge")
1165 function interface.is_bridgeport(self)
1166 return self.dev and self.dev.bridge and true or false
1169 function interface.tx_bytes(self)
1170 local stat = self:_ubus("statistics")
1171 return stat and stat.tx_bytes or 0
1174 function interface.rx_bytes(self)
1175 local stat = self:_ubus("statistics")
1176 return stat and stat.rx_bytes or 0
1179 function interface.tx_packets(self)
1180 local stat = self:_ubus("statistics")
1181 return stat and stat.tx_packets or 0
1184 function interface.rx_packets(self)
1185 local stat = self:_ubus("statistics")
1186 return stat and stat.rx_packets or 0
1189 function interface.get_network(self)
1190 return self:get_networks()[1]
1193 function interface.get_networks(self)
1194 if not self.networks then
1197 for _, net in ipairs(_M:get_networks()) do
1198 if net:contains_interface(self.ifname) or
1199 net:ifname() == self.ifname
1204 table.sort(nets, function(a, b) return a.sid < b.sid end)
1205 self.networks = nets
1208 return self.networks
1212 function interface.get_wifinet(self)
1217 wifidev = utl.class()
1219 function wifidev.__init__(self, dev)
1221 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1224 function wifidev.get(self, opt)
1225 return _get("wireless", self.sid, opt)
1228 function wifidev.set(self, opt, val)
1229 return _set("wireless", self.sid, opt, val)
1232 function wifidev.name(self)
1236 function wifidev.hwmodes(self)
1237 local l = self.iwinfo.hwmodelist
1238 if l and next(l) then
1241 return { b = true, g = true }
1245 function wifidev.get_i18n(self)
1247 if self.iwinfo.type == "wl" then
1249 elseif self.iwinfo.type == "madwifi" then
1254 local l = self:hwmodes()
1255 if l.a then m = m .. "a" end
1256 if l.b then m = m .. "b" end
1257 if l.g then m = m .. "g" end
1258 if l.n then m = m .. "n" end
1260 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1263 function wifidev.is_up(self)
1266 _uci_state:foreach("wireless", "wifi-iface",
1268 if s.device == self.sid then
1279 function wifidev.get_wifinet(self, net)
1280 if _uci_real:get("wireless", net) == "wifi-iface" then
1283 local wnet = _wifi_lookup(net)
1285 return wifinet(wnet)
1290 function wifidev.get_wifinets(self)
1293 _uci_real:foreach("wireless", "wifi-iface",
1295 if s.device == self.sid then
1296 nets[#nets+1] = wifinet(s['.name'])
1303 function wifidev.add_wifinet(self, options)
1304 options = options or { }
1305 options.device = self.sid
1307 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1309 return wifinet(wnet, options)
1313 function wifidev.del_wifinet(self, net)
1314 if utl.instanceof(net, wifinet) then
1316 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1317 net = _wifi_lookup(net)
1320 if net and _uci_real:get("wireless", net, "device") == self.sid then
1321 _uci_real:delete("wireless", net)
1329 wifinet = utl.class()
1331 function wifinet.__init__(self, net, data)
1336 _uci_real:foreach("wireless", "wifi-iface",
1339 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1340 if s['.name'] == self.sid then
1341 netid = "%s.network%d" %{ s.device, num[s.device] }
1347 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1351 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1352 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1353 _uci_real:get_all("wireless", self.sid) or { }
1356 function wifinet.get(self, opt)
1357 return _get("wireless", self.sid, opt)
1360 function wifinet.set(self, opt, val)
1361 return _set("wireless", self.sid, opt, val)
1364 function wifinet.mode(self)
1365 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1368 function wifinet.ssid(self)
1369 return _uci_state:get("wireless", self.sid, "ssid")
1372 function wifinet.bssid(self)
1373 return _uci_state:get("wireless", self.sid, "bssid")
1376 function wifinet.network(self)
1377 return _uci_state:get("wifinet", self.sid, "network")
1380 function wifinet.id(self)
1384 function wifinet.name(self)
1388 function wifinet.ifname(self)
1389 local ifname = self.iwinfo.ifname
1390 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1396 function wifinet.get_device(self)
1397 if self.iwdata.device then
1398 return wifidev(self.iwdata.device)
1402 function wifinet.is_up(self)
1403 return (self.iwdata.up == "1")
1406 function wifinet.active_mode(self)
1407 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1409 if m == "ap" then m = "Master"
1410 elseif m == "sta" then m = "Client"
1411 elseif m == "adhoc" then m = "Ad-Hoc"
1412 elseif m == "mesh" then m = "Mesh"
1413 elseif m == "monitor" then m = "Monitor"
1419 function wifinet.active_mode_i18n(self)
1420 return lng.translate(self:active_mode())
1423 function wifinet.active_ssid(self)
1424 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1427 function wifinet.active_bssid(self)
1428 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1431 function wifinet.active_encryption(self)
1432 local enc = self.iwinfo and self.iwinfo.encryption
1433 return enc and enc.description or "-"
1436 function wifinet.assoclist(self)
1437 return self.iwinfo.assoclist or { }
1440 function wifinet.frequency(self)
1441 local freq = self.iwinfo.frequency
1442 if freq and freq > 0 then
1443 return "%.03f" % (freq / 1000)
1447 function wifinet.bitrate(self)
1448 local rate = self.iwinfo.bitrate
1449 if rate and rate > 0 then
1450 return (rate / 1000)
1454 function wifinet.channel(self)
1455 return self.iwinfo.channel or
1456 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1459 function wifinet.signal(self)
1460 return self.iwinfo.signal or 0
1463 function wifinet.noise(self)
1464 return self.iwinfo.noise or 0
1467 function wifinet.country(self)
1468 return self.iwinfo.country or "00"
1471 function wifinet.txpower(self)
1472 local pwr = (self.iwinfo.txpower or 0)
1473 return pwr + self:txpower_offset()
1476 function wifinet.txpower_offset(self)
1477 return self.iwinfo.txpower_offset or 0
1480 function wifinet.signal_level(self, s, n)
1481 if self:active_bssid() ~= "00:00:00:00:00:00" then
1482 local signal = s or self:signal()
1483 local noise = n or self:noise()
1485 if signal < 0 and noise < 0 then
1486 local snr = -1 * (noise - signal)
1487 return math.floor(snr / 5)
1496 function wifinet.signal_percent(self)
1497 local qc = self.iwinfo.quality or 0
1498 local qm = self.iwinfo.quality_max or 0
1500 if qc > 0 and qm > 0 then
1501 return math.floor((100 / qm) * qc)
1507 function wifinet.shortname(self)
1509 lng.translate(self:active_mode()),
1510 self:active_ssid() or self:active_bssid()
1514 function wifinet.get_i18n(self)
1515 return "%s: %s %q (%s)" %{
1516 lng.translate("Wireless Network"),
1517 lng.translate(self:active_mode()),
1518 self:active_ssid() or self:active_bssid(),
1523 function wifinet.adminlink(self)
1524 return dsp.build_url("admin", "network", "wireless", self.netid)
1527 function wifinet.get_network(self)
1528 return self:get_networks()[1]
1531 function wifinet.get_networks(self)
1534 for net in utl.imatch(tostring(self.iwdata.network)) do
1535 if _uci_real:get("network", net) == "interface" then
1536 nets[#nets+1] = network(net)
1539 table.sort(nets, function(a, b) return a.sid < b.sid end)
1543 function wifinet.get_interface(self)
1544 return interface(self:ifname())
1548 -- setup base protocols
1549 _M:register_protocol("static")
1550 _M:register_protocol("dhcp")
1552 local dhcpv6 = _M:register_protocol("dhcpv6")
1553 function dhcpv6.is_installed(self)
1554 return nfs.access("/lib/netifd/proto/dhcpv6.sh")
1557 _M:register_protocol("none")
1560 -- load protocol extensions
1561 local exts = nfs.dir(utl.libpath() .. "/model/network")
1565 if ext:match("%.lua$") then
1566 require("luci.model.network." .. ext:gsub("%.lua$", ""))