Merge pull request #1951 from tano-systems/luci-base-network-fix
[project/luci.git] / modules / luci-compat / luasrc / model / network.lua
1 -- Copyright 2009-2015 Jo-Philipp Wich <jow@openwrt.org>
2 -- Licensed to the public under the Apache License 2.0.
3
4 local type, next, pairs, ipairs, loadfile, table, select
5 = type, next, pairs, ipairs, loadfile, table, select
6
7 local tonumber, tostring, math = tonumber, tostring, math
8
9 local pcall, require, setmetatable = pcall, require, setmetatable
10
11 local nxo = require "nixio"
12 local nfs = require "nixio.fs"
13 local ipc = require "luci.ip"
14 local utl = require "luci.util"
15 local uci = require "luci.model.uci"
16 local lng = require "luci.i18n"
17 local jsc = require "luci.jsonc"
18
19 module "luci.model.network"
20
21
22 IFACE_PATTERNS_VIRTUAL = { }
23 IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^gretap%d", "^ip6gre%d", "^ip6tnl%d", "^tunl%d", "^lo$" }
24 IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
25
26 IFACE_ERRORS = {
27 CONNECT_FAILED = lng.translate("Connection attempt failed"),
28 INVALID_ADDRESS = lng.translate("IP address is invalid"),
29 INVALID_GATEWAY = lng.translate("Gateway address is invalid"),
30 INVALID_LOCAL_ADDRESS = lng.translate("Local IP address is invalid"),
31 MISSING_ADDRESS = lng.translate("IP address is missing"),
32 MISSING_PEER_ADDRESS = lng.translate("Peer address is missing"),
33 NO_DEVICE = lng.translate("Network device is not present"),
34 NO_IFACE = lng.translate("Unable to determine device name"),
35 NO_IFNAME = lng.translate("Unable to determine device name"),
36 NO_WAN_ADDRESS = lng.translate("Unable to determine external IP address"),
37 NO_WAN_LINK = lng.translate("Unable to determine upstream interface"),
38 PEER_RESOLVE_FAIL = lng.translate("Unable to resolve peer host name"),
39 PIN_FAILED = lng.translate("PIN code rejected")
40 }
41
42
43 protocol = utl.class()
44
45 local _protocols = { }
46
47 local _interfaces, _bridge, _switch, _tunnel, _swtopo
48 local _ubusnetcache, _ubusdevcache, _ubuswificache
49 local _uci
50
51 function _filter(c, s, o, r)
52 local val = _uci:get(c, s, o)
53 if val then
54 local l = { }
55 if type(val) == "string" then
56 for val in val:gmatch("%S+") do
57 if val ~= r then
58 l[#l+1] = val
59 end
60 end
61 if #l > 0 then
62 _uci:set(c, s, o, table.concat(l, " "))
63 else
64 _uci:delete(c, s, o)
65 end
66 elseif type(val) == "table" then
67 for _, val in ipairs(val) do
68 if val ~= r then
69 l[#l+1] = val
70 end
71 end
72 if #l > 0 then
73 _uci:set(c, s, o, l)
74 else
75 _uci:delete(c, s, o)
76 end
77 end
78 end
79 end
80
81 function _append(c, s, o, a)
82 local val = _uci:get(c, s, o) or ""
83 if type(val) == "string" then
84 local l = { }
85 for val in val:gmatch("%S+") do
86 if val ~= a then
87 l[#l+1] = val
88 end
89 end
90 l[#l+1] = a
91 _uci:set(c, s, o, table.concat(l, " "))
92 elseif type(val) == "table" then
93 local l = { }
94 for _, val in ipairs(val) do
95 if val ~= a then
96 l[#l+1] = val
97 end
98 end
99 l[#l+1] = a
100 _uci:set(c, s, o, l)
101 end
102 end
103
104 function _stror(s1, s2)
105 if not s1 or #s1 == 0 then
106 return s2 and #s2 > 0 and s2
107 else
108 return s1
109 end
110 end
111
112 function _get(c, s, o)
113 return _uci:get(c, s, o)
114 end
115
116 function _set(c, s, o, v)
117 if v ~= nil then
118 if type(v) == "boolean" then v = v and "1" or "0" end
119 return _uci:set(c, s, o, v)
120 else
121 return _uci:delete(c, s, o)
122 end
123 end
124
125 local function _wifi_state()
126 if not next(_ubuswificache) then
127 _ubuswificache = utl.ubus("network.wireless", "status", {}) or {}
128 end
129 return _ubuswificache
130 end
131
132 local function _wifi_state_by_sid(sid)
133 local t1, n1 = _uci:get("wireless", sid)
134 if t1 == "wifi-iface" and n1 ~= nil then
135 local radioname, radiostate
136 for radioname, radiostate in pairs(_wifi_state()) do
137 if type(radiostate) == "table" and
138 type(radiostate.interfaces) == "table"
139 then
140 local netidx, netstate
141 for netidx, netstate in ipairs(radiostate.interfaces) do
142 if type(netstate) == "table" and
143 type(netstate.section) == "string"
144 then
145 local t2, n2 = _uci:get("wireless", netstate.section)
146 if t1 == t2 and n1 == n2 then
147 return radioname, radiostate, netstate
148 end
149 end
150 end
151 end
152 end
153 end
154 end
155
156 local function _wifi_state_by_ifname(ifname)
157 if type(ifname) == "string" then
158 local radioname, radiostate
159 for radioname, radiostate in pairs(_wifi_state()) do
160 if type(radiostate) == "table" and
161 type(radiostate.interfaces) == "table"
162 then
163 local netidx, netstate
164 for netidx, netstate in ipairs(radiostate.interfaces) do
165 if type(netstate) == "table" and
166 type(netstate.ifname) == "string" and
167 netstate.ifname == ifname
168 then
169 return radioname, radiostate, netstate
170 end
171 end
172 end
173 end
174 end
175 end
176
177 function _wifi_iface(x)
178 local _, p
179 for _, p in ipairs(IFACE_PATTERNS_WIRELESS) do
180 if x:match(p) then
181 return true
182 end
183 end
184 return (nfs.access("/sys/class/net/%s/phy80211" % x) == true)
185 end
186
187 local function _wifi_iwinfo_by_ifname(ifname, force_phy_only)
188 local stat, iwinfo = pcall(require, "iwinfo")
189 local iwtype = stat and type(ifname) == "string" and iwinfo.type(ifname)
190 local is_nonphy_op = {
191 bitrate = true,
192 quality = true,
193 quality_max = true,
194 mode = true,
195 ssid = true,
196 bssid = true,
197 assoclist = true,
198 encryption = true
199 }
200
201 if iwtype then
202 -- if we got a type but no real netdev, we're referring to a phy
203 local phy_only = force_phy_only or (ipc.link(ifname).type ~= 1)
204
205 return setmetatable({}, {
206 __index = function(t, k)
207 if k == "ifname" then
208 return ifname
209 elseif phy_only and is_nonphy_op[k] then
210 return nil
211 elseif iwinfo[iwtype][k] then
212 return iwinfo[iwtype][k](ifname)
213 end
214 end
215 })
216 end
217 end
218
219 local function _wifi_sid_by_netid(netid)
220 if type(netid) == "string" then
221 local radioname, netidx = netid:match("^(%w+)%.network(%d+)$")
222 if radioname and netidx then
223 local i, n = 0, nil
224
225 netidx = tonumber(netidx)
226 _uci:foreach("wireless", "wifi-iface",
227 function(s)
228 if s.device == radioname then
229 i = i + 1
230 if i == netidx then
231 n = s[".name"]
232 return false
233 end
234 end
235 end)
236
237 return n
238 end
239 end
240 end
241
242 function _wifi_sid_by_ifname(ifn)
243 local sid = _wifi_sid_by_netid(ifn)
244 if sid then
245 return sid
246 end
247
248 local _, _, netstate = _wifi_state_by_ifname(ifn)
249 if netstate and type(netstate.section) == "string" then
250 return netstate.section
251 end
252 end
253
254 local function _wifi_netid_by_sid(sid)
255 local t, n = _uci:get("wireless", sid)
256 if t == "wifi-iface" and n ~= nil then
257 local radioname = _uci:get("wireless", n, "device")
258 if type(radioname) == "string" then
259 local i, netid = 0, nil
260
261 _uci:foreach("wireless", "wifi-iface",
262 function(s)
263 if s.device == radioname then
264 i = i + 1
265 if s[".name"] == n then
266 netid = "%s.network%d" %{ radioname, i }
267 return false
268 end
269 end
270 end)
271
272 return netid, radioname
273 end
274 end
275 end
276
277 local function _wifi_netid_by_netname(name)
278 local netid = nil
279
280 _uci:foreach("wireless", "wifi-iface",
281 function(s)
282 local net
283 for net in utl.imatch(s.network) do
284 if net == name then
285 netid = _wifi_netid_by_sid(s[".name"])
286 return false
287 end
288 end
289 end)
290
291 return netid
292 end
293
294 function _iface_virtual(x)
295 local _, p
296 for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do
297 if x:match(p) then
298 return true
299 end
300 end
301 return false
302 end
303
304 function _iface_ignore(x)
305 local _, p
306 for _, p in ipairs(IFACE_PATTERNS_IGNORE) do
307 if x:match(p) then
308 return true
309 end
310 end
311 return false
312 end
313
314 function init(cursor)
315 _uci = cursor or _uci or uci.cursor()
316
317 _interfaces = { }
318 _bridge = { }
319 _switch = { }
320 _tunnel = { }
321 _swtopo = { }
322
323 _ubusnetcache = { }
324 _ubusdevcache = { }
325 _ubuswificache = { }
326
327 -- read interface information
328 local n, i
329 for n, i in ipairs(nxo.getifaddrs()) do
330 local name = i.name:match("[^:]+")
331
332 if _iface_virtual(name) then
333 _tunnel[name] = true
334 end
335
336 if _tunnel[name] or not (_iface_ignore(name) or _iface_virtual(name)) then
337 _interfaces[name] = _interfaces[name] or {
338 idx = i.ifindex or n,
339 name = name,
340 rawname = i.name,
341 flags = { },
342 ipaddrs = { },
343 ip6addrs = { }
344 }
345
346 if i.family == "packet" then
347 _interfaces[name].flags = i.flags
348 _interfaces[name].stats = i.data
349 _interfaces[name].macaddr = ipc.checkmac(i.addr)
350 elseif i.family == "inet" then
351 _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
352 elseif i.family == "inet6" then
353 _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
354 end
355 end
356 end
357
358 -- read bridge informaton
359 local b, l
360 for l in utl.execi("brctl show") do
361 if not l:match("STP") then
362 local r = utl.split(l, "%s+", nil, true)
363 if #r == 4 then
364 b = {
365 name = r[1],
366 id = r[2],
367 stp = r[3] == "yes",
368 ifnames = { _interfaces[r[4]] }
369 }
370 if b.ifnames[1] then
371 b.ifnames[1].bridge = b
372 end
373 _bridge[r[1]] = b
374 _interfaces[r[1]].bridge = b
375 elseif b then
376 b.ifnames[#b.ifnames+1] = _interfaces[r[2]]
377 b.ifnames[#b.ifnames].bridge = b
378 end
379 end
380 end
381
382 -- read switch topology
383 local boardinfo = jsc.parse(nfs.readfile("/etc/board.json") or "")
384 if type(boardinfo) == "table" and type(boardinfo.switch) == "table" then
385 local switch, layout
386 for switch, layout in pairs(boardinfo.switch) do
387 if type(layout) == "table" and type(layout.ports) == "table" then
388 local _, port
389 local ports = { }
390 local nports = { }
391 local netdevs = { }
392
393 for _, port in ipairs(layout.ports) do
394 if type(port) == "table" and
395 type(port.num) == "number" and
396 (type(port.role) == "string" or
397 type(port.device) == "string")
398 then
399 local spec = {
400 num = port.num,
401 role = port.role or "cpu",
402 index = port.index or port.num
403 }
404
405 if port.device then
406 spec.device = port.device
407 spec.tagged = port.need_tag
408 netdevs[tostring(port.num)] = port.device
409 end
410
411 ports[#ports+1] = spec
412
413 if port.role then
414 nports[port.role] = (nports[port.role] or 0) + 1
415 end
416 end
417 end
418
419 table.sort(ports, function(a, b)
420 if a.role ~= b.role then
421 return (a.role < b.role)
422 end
423
424 return (a.index < b.index)
425 end)
426
427 local pnum, role
428 for _, port in ipairs(ports) do
429 if port.role ~= role then
430 role = port.role
431 pnum = 1
432 end
433
434 if role == "cpu" then
435 port.label = "CPU (%s)" % port.device
436 elseif nports[role] > 1 then
437 port.label = "%s %d" %{ role:upper(), pnum }
438 pnum = pnum + 1
439 else
440 port.label = role:upper()
441 end
442
443 port.role = nil
444 port.index = nil
445 end
446
447 _swtopo[switch] = {
448 ports = ports,
449 netdevs = netdevs
450 }
451 end
452 end
453 end
454
455 return _M
456 end
457
458 function save(self, ...)
459 _uci:save(...)
460 _uci:load(...)
461 end
462
463 function commit(self, ...)
464 _uci:commit(...)
465 _uci:load(...)
466 end
467
468 function ifnameof(self, x)
469 if utl.instanceof(x, interface) then
470 return x:name()
471 elseif utl.instanceof(x, protocol) then
472 return x:ifname()
473 elseif type(x) == "string" then
474 return x:match("^[^:]+")
475 end
476 end
477
478 function get_protocol(self, protoname, netname)
479 local v = _protocols[protoname]
480 if v then
481 return v(netname or "__dummy__")
482 end
483 end
484
485 function get_protocols(self)
486 local p = { }
487 local _, v
488 for _, v in ipairs(_protocols) do
489 p[#p+1] = v("__dummy__")
490 end
491 return p
492 end
493
494 function register_protocol(self, protoname)
495 local proto = utl.class(protocol)
496
497 function proto.__init__(self, name)
498 self.sid = name
499 end
500
501 function proto.proto(self)
502 return protoname
503 end
504
505 _protocols[#_protocols+1] = proto
506 _protocols[protoname] = proto
507
508 return proto
509 end
510
511 function register_pattern_virtual(self, pat)
512 IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
513 end
514
515 function register_error_code(self, code, message)
516 if type(code) == "string" and
517 type(message) == "string" and
518 not IFACE_ERRORS[code]
519 then
520 IFACE_ERRORS[code] = message
521 return true
522 end
523
524 return false
525 end
526
527 function has_ipv6(self)
528 return nfs.access("/proc/net/ipv6_route")
529 end
530
531 function add_network(self, n, options)
532 local oldnet = self:get_network(n)
533 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
534 if _uci:section("network", "interface", n, options) then
535 return network(n)
536 end
537 elseif oldnet and oldnet:is_empty() then
538 if options then
539 local k, v
540 for k, v in pairs(options) do
541 oldnet:set(k, v)
542 end
543 end
544 return oldnet
545 end
546 end
547
548 function get_network(self, n)
549 if n and _uci:get("network", n) == "interface" then
550 return network(n)
551 elseif n then
552 local stat = utl.ubus("network.interface", "status", { interface = n })
553 if type(stat) == "table" and
554 type(stat.proto) == "string"
555 then
556 return network(n, stat.proto)
557 end
558 end
559 end
560
561 function get_networks(self)
562 local nets = { }
563 local nls = { }
564
565 _uci:foreach("network", "interface",
566 function(s)
567 nls[s['.name']] = network(s['.name'])
568 end)
569
570 local dump = utl.ubus("network.interface", "dump", { })
571 if type(dump) == "table" and
572 type(dump.interface) == "table"
573 then
574 local _, net
575 for _, net in ipairs(dump.interface) do
576 if type(net) == "table" and
577 type(net.proto) == "string" and
578 type(net.interface) == "string"
579 then
580 if not nls[net.interface] then
581 nls[net.interface] = network(net.interface, net.proto)
582 end
583 end
584 end
585 end
586
587 local n
588 for n in utl.kspairs(nls) do
589 nets[#nets+1] = nls[n]
590 end
591
592 return nets
593 end
594
595 function del_network(self, n)
596 local r = _uci:delete("network", n)
597 if r then
598 _uci:delete_all("luci", "ifstate",
599 function(s) return (s.interface == n) end)
600
601 _uci:delete_all("network", "alias",
602 function(s) return (s.interface == n) end)
603
604 _uci:delete_all("network", "route",
605 function(s) return (s.interface == n) end)
606
607 _uci:delete_all("network", "route6",
608 function(s) return (s.interface == n) end)
609
610 _uci:foreach("wireless", "wifi-iface",
611 function(s)
612 local net
613 local rest = { }
614 for net in utl.imatch(s.network) do
615 if net ~= n then
616 rest[#rest+1] = net
617 end
618 end
619 if #rest > 0 then
620 _uci:set("wireless", s['.name'], "network",
621 table.concat(rest, " "))
622 else
623 _uci:delete("wireless", s['.name'], "network")
624 end
625 end)
626
627 local ok, fw = pcall(require, "luci.model.firewall")
628 if ok then
629 fw.init()
630 fw:del_network(n)
631 end
632 end
633 return r
634 end
635
636 function rename_network(self, old, new)
637 local r
638 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
639 r = _uci:section("network", "interface", new, _uci:get_all("network", old))
640
641 if r then
642 _uci:foreach("network", "alias",
643 function(s)
644 if s.interface == old then
645 _uci:set("network", s['.name'], "interface", new)
646 end
647 end)
648
649 _uci:foreach("network", "route",
650 function(s)
651 if s.interface == old then
652 _uci:set("network", s['.name'], "interface", new)
653 end
654 end)
655
656 _uci:foreach("network", "route6",
657 function(s)
658 if s.interface == old then
659 _uci:set("network", s['.name'], "interface", new)
660 end
661 end)
662
663 _uci:foreach("wireless", "wifi-iface",
664 function(s)
665 local net
666 local list = { }
667 for net in utl.imatch(s.network) do
668 if net == old then
669 list[#list+1] = new
670 else
671 list[#list+1] = net
672 end
673 end
674 if #list > 0 then
675 _uci:set("wireless", s['.name'], "network",
676 table.concat(list, " "))
677 end
678 end)
679
680 _uci:delete("network", old)
681 end
682 end
683 return r or false
684 end
685
686 function get_interface(self, i)
687 if _interfaces[i] or _wifi_iface(i) then
688 return interface(i)
689 else
690 local netid = _wifi_netid_by_sid(i)
691 return netid and interface(netid)
692 end
693 end
694
695 function get_interfaces(self)
696 local iface
697 local ifaces = { }
698 local nfs = { }
699
700 -- find normal interfaces
701 _uci:foreach("network", "interface",
702 function(s)
703 for iface in utl.imatch(s.ifname) do
704 if not _iface_ignore(iface) and not _iface_virtual(iface) and not _wifi_iface(iface) then
705 nfs[iface] = interface(iface)
706 end
707 end
708 end)
709
710 for iface in utl.kspairs(_interfaces) do
711 if not (nfs[iface] or _iface_ignore(iface) or _iface_virtual(iface) or _wifi_iface(iface)) then
712 nfs[iface] = interface(iface)
713 end
714 end
715
716 -- find vlan interfaces
717 _uci:foreach("network", "switch_vlan",
718 function(s)
719 if type(s.ports) ~= "string" or
720 type(s.device) ~= "string" or
721 type(_swtopo[s.device]) ~= "table"
722 then
723 return
724 end
725
726 local pnum, ptag
727 for pnum, ptag in s.ports:gmatch("(%d+)([tu]?)") do
728 local netdev = _swtopo[s.device].netdevs[pnum]
729 if netdev then
730 if not nfs[netdev] then
731 nfs[netdev] = interface(netdev)
732 end
733 _switch[netdev] = true
734
735 if ptag == "t" then
736 local vid = tonumber(s.vid or s.vlan)
737 if vid ~= nil and vid >= 0 and vid <= 4095 then
738 local iface = "%s.%d" %{ netdev, vid }
739 if not nfs[iface] then
740 nfs[iface] = interface(iface)
741 end
742 _switch[iface] = true
743 end
744 end
745 end
746 end
747 end)
748
749 for iface in utl.kspairs(nfs) do
750 ifaces[#ifaces+1] = nfs[iface]
751 end
752
753 -- find wifi interfaces
754 local num = { }
755 local wfs = { }
756 _uci:foreach("wireless", "wifi-iface",
757 function(s)
758 if s.device then
759 num[s.device] = num[s.device] and num[s.device] + 1 or 1
760 local i = "%s.network%d" %{ s.device, num[s.device] }
761 wfs[i] = interface(i)
762 end
763 end)
764
765 for iface in utl.kspairs(wfs) do
766 ifaces[#ifaces+1] = wfs[iface]
767 end
768
769 return ifaces
770 end
771
772 function ignore_interface(self, x)
773 return _iface_ignore(x)
774 end
775
776 function get_wifidev(self, dev)
777 if _uci:get("wireless", dev) == "wifi-device" then
778 return wifidev(dev)
779 end
780 end
781
782 function get_wifidevs(self)
783 local devs = { }
784 local wfd = { }
785
786 _uci:foreach("wireless", "wifi-device",
787 function(s) wfd[#wfd+1] = s['.name'] end)
788
789 local dev
790 for _, dev in utl.vspairs(wfd) do
791 devs[#devs+1] = wifidev(dev)
792 end
793
794 return devs
795 end
796
797 function get_wifinet(self, net)
798 local wnet = _wifi_sid_by_ifname(net)
799 if wnet then
800 return wifinet(wnet)
801 end
802 end
803
804 function add_wifinet(self, net, options)
805 if type(options) == "table" and options.device and
806 _uci:get("wireless", options.device) == "wifi-device"
807 then
808 local wnet = _uci:section("wireless", "wifi-iface", nil, options)
809 return wifinet(wnet)
810 end
811 end
812
813 function del_wifinet(self, net)
814 local wnet = _wifi_sid_by_ifname(net)
815 if wnet then
816 _uci:delete("wireless", wnet)
817 return true
818 end
819 return false
820 end
821
822 function get_status_by_route(self, addr, mask)
823 local route_statuses = { }
824 local _, object
825 for _, object in ipairs(utl.ubus()) do
826 local net = object:match("^network%.interface%.(.+)")
827 if net then
828 local s = utl.ubus(object, "status", {})
829 if s and s.route then
830 local rt
831 for _, rt in ipairs(s.route) do
832 if not rt.table and rt.target == addr and rt.mask == mask then
833 route_statuses[net] = s
834 end
835 end
836 end
837 end
838 end
839
840 return route_statuses
841 end
842
843 function get_status_by_address(self, addr)
844 local _, object
845 for _, object in ipairs(utl.ubus()) do
846 local net = object:match("^network%.interface%.(.+)")
847 if net then
848 local s = utl.ubus(object, "status", {})
849 if s and s['ipv4-address'] then
850 local a
851 for _, a in ipairs(s['ipv4-address']) do
852 if a.address == addr then
853 return net, s
854 end
855 end
856 end
857 if s and s['ipv6-address'] then
858 local a
859 for _, a in ipairs(s['ipv6-address']) do
860 if a.address == addr then
861 return net, s
862 end
863 end
864 end
865 if s and s['ipv6-prefix-assignment'] then
866 local a
867 for _, a in ipairs(s['ipv6-prefix-assignment']) do
868 if a and a['local-address'] and a['local-address'].address == addr then
869 return net, s
870 end
871 end
872 end
873 end
874 end
875 end
876
877 function get_wan_networks(self)
878 local k, v
879 local wan_nets = { }
880 local route_statuses = self:get_status_by_route("0.0.0.0", 0)
881
882 for k, v in pairs(route_statuses) do
883 wan_nets[#wan_nets+1] = network(k, v.proto)
884 end
885
886 return wan_nets
887 end
888
889 function get_wan6_networks(self)
890 local k, v
891 local wan6_nets = { }
892 local route_statuses = self:get_status_by_route("::", 0)
893
894 for k, v in pairs(route_statuses) do
895 wan6_nets[#wan6_nets+1] = network(k, v.proto)
896 end
897
898 return wan6_nets
899 end
900
901 function get_switch_topologies(self)
902 return _swtopo
903 end
904
905
906 function network(name, proto)
907 if name then
908 local p = proto or _uci:get("network", name, "proto")
909 local c = p and _protocols[p] or protocol
910 return c(name)
911 end
912 end
913
914 function protocol.__init__(self, name)
915 self.sid = name
916 end
917
918 function protocol._get(self, opt)
919 local v = _uci:get("network", self.sid, opt)
920 if type(v) == "table" then
921 return table.concat(v, " ")
922 end
923 return v or ""
924 end
925
926 function protocol._ubus(self, field)
927 if not _ubusnetcache[self.sid] then
928 _ubusnetcache[self.sid] = utl.ubus("network.interface.%s" % self.sid,
929 "status", { })
930 end
931 if _ubusnetcache[self.sid] and field then
932 return _ubusnetcache[self.sid][field]
933 end
934 return _ubusnetcache[self.sid]
935 end
936
937 function protocol.get(self, opt)
938 return _get("network", self.sid, opt)
939 end
940
941 function protocol.set(self, opt, val)
942 return _set("network", self.sid, opt, val)
943 end
944
945 function protocol.ifname(self)
946 local ifname
947 if self:is_floating() then
948 ifname = self:_ubus("l3_device")
949 else
950 ifname = self:_ubus("device")
951 end
952 if not ifname then
953 ifname = _wifi_netid_by_netname(self.sid)
954 end
955 return ifname
956 end
957
958 function protocol.proto(self)
959 return "none"
960 end
961
962 function protocol.get_i18n(self)
963 local p = self:proto()
964 if p == "none" then
965 return lng.translate("Unmanaged")
966 elseif p == "static" then
967 return lng.translate("Static address")
968 elseif p == "dhcp" then
969 return lng.translate("DHCP client")
970 else
971 return lng.translate("Unknown")
972 end
973 end
974
975 function protocol.type(self)
976 return self:_get("type")
977 end
978
979 function protocol.name(self)
980 return self.sid
981 end
982
983 function protocol.uptime(self)
984 return self:_ubus("uptime") or 0
985 end
986
987 function protocol.expires(self)
988 local u = self:_ubus("uptime")
989 local d = self:_ubus("data")
990
991 if type(u) == "number" and type(d) == "table" and
992 type(d.leasetime) == "number"
993 then
994 local r = (d.leasetime - (u % d.leasetime))
995 return r > 0 and r or 0
996 end
997
998 return -1
999 end
1000
1001 function protocol.metric(self)
1002 return self:_ubus("metric") or 0
1003 end
1004
1005 function protocol.zonename(self)
1006 local d = self:_ubus("data")
1007
1008 if type(d) == "table" and type(d.zone) == "string" then
1009 return d.zone
1010 end
1011
1012 return nil
1013 end
1014
1015 function protocol.ipaddr(self)
1016 local addrs = self:_ubus("ipv4-address")
1017 return addrs and #addrs > 0 and addrs[1].address
1018 end
1019
1020 function protocol.ipaddrs(self)
1021 local addrs = self:_ubus("ipv4-address")
1022 local rv = { }
1023
1024 if type(addrs) == "table" then
1025 local n, addr
1026 for n, addr in ipairs(addrs) do
1027 rv[#rv+1] = "%s/%d" %{ addr.address, addr.mask }
1028 end
1029 end
1030
1031 return rv
1032 end
1033
1034 function protocol.netmask(self)
1035 local addrs = self:_ubus("ipv4-address")
1036 return addrs and #addrs > 0 and
1037 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
1038 end
1039
1040 function protocol.gwaddr(self)
1041 local _, route
1042 for _, route in ipairs(self:_ubus("route") or { }) do
1043 if route.target == "0.0.0.0" and route.mask == 0 then
1044 return route.nexthop
1045 end
1046 end
1047 end
1048
1049 function protocol.dnsaddrs(self)
1050 local dns = { }
1051 local _, addr
1052 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
1053 if not addr:match(":") then
1054 dns[#dns+1] = addr
1055 end
1056 end
1057 return dns
1058 end
1059
1060 function protocol.ip6addr(self)
1061 local addrs = self:_ubus("ipv6-address")
1062 if addrs and #addrs > 0 then
1063 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
1064 else
1065 addrs = self:_ubus("ipv6-prefix-assignment")
1066 if addrs and #addrs > 0 then
1067 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
1068 end
1069 end
1070 end
1071
1072 function protocol.ip6addrs(self)
1073 local addrs = self:_ubus("ipv6-address")
1074 local rv = { }
1075 local n, addr
1076
1077 if type(addrs) == "table" then
1078 for n, addr in ipairs(addrs) do
1079 rv[#rv+1] = "%s/%d" %{ addr.address, addr.mask }
1080 end
1081 end
1082
1083 addrs = self:_ubus("ipv6-prefix-assignment")
1084
1085 if type(addrs) == "table" then
1086 for n, addr in ipairs(addrs) do
1087 if type(addr["local-address"]) == "table" and
1088 type(addr["local-address"].mask) == "number" and
1089 type(addr["local-address"].address) == "string"
1090 then
1091 rv[#rv+1] = "%s/%d" %{
1092 addr["local-address"].address,
1093 addr["local-address"].mask
1094 }
1095 end
1096 end
1097 end
1098
1099 return rv
1100 end
1101
1102 function protocol.gw6addr(self)
1103 local _, route
1104 for _, route in ipairs(self:_ubus("route") or { }) do
1105 if route.target == "::" and route.mask == 0 then
1106 return ipc.IPv6(route.nexthop):string()
1107 end
1108 end
1109 end
1110
1111 function protocol.dns6addrs(self)
1112 local dns = { }
1113 local _, addr
1114 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
1115 if addr:match(":") then
1116 dns[#dns+1] = addr
1117 end
1118 end
1119 return dns
1120 end
1121
1122 function protocol.ip6prefix(self)
1123 local prefix = self:_ubus("ipv6-prefix")
1124 if prefix and #prefix > 0 then
1125 return "%s/%d" %{ prefix[1].address, prefix[1].mask }
1126 end
1127 end
1128
1129 function protocol.errors(self)
1130 local _, err, rv
1131 local errors = self:_ubus("errors")
1132 if type(errors) == "table" then
1133 for _, err in ipairs(errors) do
1134 if type(err) == "table" and
1135 type(err.code) == "string"
1136 then
1137 rv = rv or { }
1138 rv[#rv+1] = IFACE_ERRORS[err.code] or lng.translatef("Unknown error (%s)", err.code)
1139 end
1140 end
1141 end
1142 return rv
1143 end
1144
1145 function protocol.is_bridge(self)
1146 return (not self:is_virtual() and self:type() == "bridge")
1147 end
1148
1149 function protocol.opkg_package(self)
1150 return nil
1151 end
1152
1153 function protocol.is_installed(self)
1154 return true
1155 end
1156
1157 function protocol.is_virtual(self)
1158 return false
1159 end
1160
1161 function protocol.is_floating(self)
1162 return false
1163 end
1164
1165 function protocol.is_dynamic(self)
1166 return (self:_ubus("dynamic") == true)
1167 end
1168
1169 function protocol.is_auto(self)
1170 return (self:_get("auto") ~= "0")
1171 end
1172
1173 function protocol.is_alias(self)
1174 local ifn, parent = nil, nil
1175
1176 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1177 if #ifn > 1 and ifn:byte(1) == 64 then
1178 parent = ifn:sub(2)
1179 elseif parent ~= nil then
1180 parent = nil
1181 end
1182 end
1183
1184 return parent
1185 end
1186
1187 function protocol.is_empty(self)
1188 if self:is_floating() then
1189 return false
1190 else
1191 local empty = true
1192
1193 if (self:_get("ifname") or ""):match("%S+") then
1194 empty = false
1195 end
1196
1197 if empty and _wifi_netid_by_netname(self.sid) then
1198 empty = false
1199 end
1200
1201 return empty
1202 end
1203 end
1204
1205 function protocol.is_up(self)
1206 return (self:_ubus("up") == true)
1207 end
1208
1209 function protocol.add_interface(self, ifname)
1210 ifname = _M:ifnameof(ifname)
1211 if ifname and not self:is_floating() then
1212 -- if its a wifi interface, change its network option
1213 local wif = _wifi_sid_by_ifname(ifname)
1214 if wif then
1215 _append("wireless", wif, "network", self.sid)
1216
1217 -- add iface to our iface list
1218 else
1219 _append("network", self.sid, "ifname", ifname)
1220 end
1221 end
1222 end
1223
1224 function protocol.del_interface(self, ifname)
1225 ifname = _M:ifnameof(ifname)
1226 if ifname and not self:is_floating() then
1227 -- if its a wireless interface, clear its network option
1228 local wif = _wifi_sid_by_ifname(ifname)
1229 if wif then _filter("wireless", wif, "network", self.sid) end
1230
1231 -- remove the interface
1232 _filter("network", self.sid, "ifname", ifname)
1233 end
1234 end
1235
1236 function protocol.get_interface(self)
1237 if self:is_virtual() then
1238 _tunnel[self:proto() .. "-" .. self.sid] = true
1239 return interface(self:proto() .. "-" .. self.sid, self)
1240 elseif self:is_bridge() then
1241 _bridge["br-" .. self.sid] = true
1242 return interface("br-" .. self.sid, self)
1243 else
1244 local ifn = self:_ubus("l3_device") or self:_ubus("device")
1245 if ifn then
1246 return interface(ifn, self)
1247 end
1248
1249 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1250 ifn = ifn:match("^[^:/]+")
1251 return ifn and interface(ifn, self)
1252 end
1253
1254 ifn = _wifi_netid_by_netname(self.sid)
1255 return ifn and interface(ifn, self)
1256 end
1257 end
1258
1259 function protocol.get_interfaces(self)
1260 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
1261 local ifaces = { }
1262
1263 local ifn
1264 local nfs = { }
1265 for ifn in utl.imatch(self:get("ifname")) do
1266 ifn = ifn:match("^[^:/]+")
1267 nfs[ifn] = interface(ifn, self)
1268 end
1269
1270 for ifn in utl.kspairs(nfs) do
1271 ifaces[#ifaces+1] = nfs[ifn]
1272 end
1273
1274 local wfs = { }
1275 _uci:foreach("wireless", "wifi-iface",
1276 function(s)
1277 if s.device then
1278 local net
1279 for net in utl.imatch(s.network) do
1280 if net == self.sid then
1281 ifn = _wifi_netid_by_sid(s[".name"])
1282 if ifn then
1283 wfs[ifn] = interface(ifn, self)
1284 end
1285 end
1286 end
1287 end
1288 end)
1289
1290 for ifn in utl.kspairs(wfs) do
1291 ifaces[#ifaces+1] = wfs[ifn]
1292 end
1293
1294 return ifaces
1295 end
1296 end
1297
1298 function protocol.contains_interface(self, ifname)
1299 ifname = _M:ifnameof(ifname)
1300 if not ifname then
1301 return false
1302 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
1303 return true
1304 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1305 return true
1306 else
1307 local ifn
1308 for ifn in utl.imatch(self:get("ifname")) do
1309 ifn = ifn:match("[^:]+")
1310 if ifn == ifname then
1311 return true
1312 end
1313 end
1314
1315 local wif = _wifi_sid_by_ifname(ifname)
1316 if wif then
1317 local n
1318 for n in utl.imatch(_uci:get("wireless", wif, "network")) do
1319 if n == self.sid then
1320 return true
1321 end
1322 end
1323 end
1324 end
1325
1326 return false
1327 end
1328
1329 function protocol.adminlink(self)
1330 local stat, dsp = pcall(require, "luci.dispatcher")
1331 return stat and dsp.build_url("admin", "network", "network", self.sid)
1332 end
1333
1334
1335 interface = utl.class()
1336
1337 function interface.__init__(self, ifname, network)
1338 local wif = _wifi_sid_by_ifname(ifname)
1339 if wif then
1340 self.wif = wifinet(wif)
1341 self.ifname = self.wif:ifname()
1342 end
1343
1344 self.ifname = self.ifname or ifname
1345 self.dev = _interfaces[self.ifname]
1346 self.network = network
1347 end
1348
1349 function interface._ubus(self, field)
1350 if not _ubusdevcache[self.ifname] then
1351 _ubusdevcache[self.ifname] = utl.ubus("network.device", "status",
1352 { name = self.ifname })
1353 end
1354 if _ubusdevcache[self.ifname] and field then
1355 return _ubusdevcache[self.ifname][field]
1356 end
1357 return _ubusdevcache[self.ifname]
1358 end
1359
1360 function interface.name(self)
1361 return self.wif and self.wif:ifname() or self.ifname
1362 end
1363
1364 function interface.mac(self)
1365 return ipc.checkmac(self:_ubus("macaddr"))
1366 end
1367
1368 function interface.ipaddrs(self)
1369 return self.dev and self.dev.ipaddrs or { }
1370 end
1371
1372 function interface.ip6addrs(self)
1373 return self.dev and self.dev.ip6addrs or { }
1374 end
1375
1376 function interface.type(self)
1377 if self.ifname and self.ifname:byte(1) == 64 then
1378 return "alias"
1379 elseif self.wif or _wifi_iface(self.ifname) then
1380 return "wifi"
1381 elseif _bridge[self.ifname] then
1382 return "bridge"
1383 elseif _tunnel[self.ifname] then
1384 return "tunnel"
1385 elseif self.ifname:match("%.") then
1386 return "vlan"
1387 elseif _switch[self.ifname] then
1388 return "switch"
1389 else
1390 return "ethernet"
1391 end
1392 end
1393
1394 function interface.shortname(self)
1395 if self.wif then
1396 return self.wif:shortname()
1397 else
1398 return self.ifname
1399 end
1400 end
1401
1402 function interface.get_i18n(self)
1403 if self.wif then
1404 return "%s: %s %q" %{
1405 lng.translate("Wireless Network"),
1406 self.wif:active_mode(),
1407 self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id() or "?"
1408 }
1409 else
1410 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1411 end
1412 end
1413
1414 function interface.get_type_i18n(self)
1415 local x = self:type()
1416 if x == "alias" then
1417 return lng.translate("Alias Interface")
1418 elseif x == "wifi" then
1419 return lng.translate("Wireless Adapter")
1420 elseif x == "bridge" then
1421 return lng.translate("Bridge")
1422 elseif x == "switch" then
1423 return lng.translate("Ethernet Switch")
1424 elseif x == "vlan" then
1425 if _switch[self.ifname] then
1426 return lng.translate("Switch VLAN")
1427 else
1428 return lng.translate("Software VLAN")
1429 end
1430 elseif x == "tunnel" then
1431 return lng.translate("Tunnel Interface")
1432 else
1433 return lng.translate("Ethernet Adapter")
1434 end
1435 end
1436
1437 function interface.adminlink(self)
1438 if self.wif then
1439 return self.wif:adminlink()
1440 end
1441 end
1442
1443 function interface.ports(self)
1444 local members = self:_ubus("bridge-members")
1445 if members then
1446 local _, iface
1447 local ifaces = { }
1448 for _, iface in ipairs(members) do
1449 ifaces[#ifaces+1] = interface(iface)
1450 end
1451 return ifaces
1452 end
1453 end
1454
1455 function interface.bridge_id(self)
1456 if self.dev and self.dev.bridge then
1457 return self.dev.bridge.id
1458 else
1459 return nil
1460 end
1461 end
1462
1463 function interface.bridge_stp(self)
1464 if self.dev and self.dev.bridge then
1465 return self.dev.bridge.stp
1466 else
1467 return false
1468 end
1469 end
1470
1471 function interface.is_up(self)
1472 local up = self:_ubus("up")
1473 if up == nil then
1474 up = (self:type() == "alias")
1475 end
1476 return up or false
1477 end
1478
1479 function interface.is_bridge(self)
1480 return (self:type() == "bridge")
1481 end
1482
1483 function interface.is_bridgeport(self)
1484 return self.dev and self.dev.bridge and
1485 (self.dev.bridge.name != self:name()) and true or false
1486 end
1487
1488 function interface.tx_bytes(self)
1489 local stat = self:_ubus("statistics")
1490 return stat and stat.tx_bytes or 0
1491 end
1492
1493 function interface.rx_bytes(self)
1494 local stat = self:_ubus("statistics")
1495 return stat and stat.rx_bytes or 0
1496 end
1497
1498 function interface.tx_packets(self)
1499 local stat = self:_ubus("statistics")
1500 return stat and stat.tx_packets or 0
1501 end
1502
1503 function interface.rx_packets(self)
1504 local stat = self:_ubus("statistics")
1505 return stat and stat.rx_packets or 0
1506 end
1507
1508 function interface.get_network(self)
1509 return self:get_networks()[1]
1510 end
1511
1512 function interface.get_networks(self)
1513 if not self.networks then
1514 local nets = { }
1515 local _, net
1516 for _, net in ipairs(_M:get_networks()) do
1517 if net:contains_interface(self.ifname) or
1518 net:ifname() == self.ifname
1519 then
1520 nets[#nets+1] = net
1521 end
1522 end
1523 table.sort(nets, function(a, b) return a.sid < b.sid end)
1524 self.networks = nets
1525 return nets
1526 else
1527 return self.networks
1528 end
1529 end
1530
1531 function interface.get_wifinet(self)
1532 return self.wif
1533 end
1534
1535
1536 wifidev = utl.class()
1537
1538 function wifidev.__init__(self, name)
1539 local t, n = _uci:get("wireless", name)
1540 if t == "wifi-device" and n ~= nil then
1541 self.sid = n
1542 self.iwinfo = _wifi_iwinfo_by_ifname(self.sid, true)
1543 end
1544 self.sid = self.sid or name
1545 self.iwinfo = self.iwinfo or { ifname = self.sid }
1546 end
1547
1548 function wifidev.get(self, opt)
1549 return _get("wireless", self.sid, opt)
1550 end
1551
1552 function wifidev.set(self, opt, val)
1553 return _set("wireless", self.sid, opt, val)
1554 end
1555
1556 function wifidev.name(self)
1557 return self.sid
1558 end
1559
1560 function wifidev.hwmodes(self)
1561 local l = self.iwinfo.hwmodelist
1562 if l and next(l) then
1563 return l
1564 else
1565 return { b = true, g = true }
1566 end
1567 end
1568
1569 function wifidev.get_i18n(self)
1570 local t = self.iwinfo.hardware_name or "Generic"
1571 if self.iwinfo.type == "wl" then
1572 t = "Broadcom"
1573 end
1574
1575 local m = ""
1576 local l = self:hwmodes()
1577 if l.a then m = m .. "a" end
1578 if l.b then m = m .. "b" end
1579 if l.g then m = m .. "g" end
1580 if l.n then m = m .. "n" end
1581 if l.ac then m = "ac" end
1582
1583 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1584 end
1585
1586 function wifidev.is_up(self)
1587 if _ubuswificache[self.sid] then
1588 return (_ubuswificache[self.sid].up == true)
1589 end
1590
1591 return false
1592 end
1593
1594 function wifidev.get_wifinet(self, net)
1595 if _uci:get("wireless", net) == "wifi-iface" then
1596 return wifinet(net)
1597 else
1598 local wnet = _wifi_sid_by_ifname(net)
1599 if wnet then
1600 return wifinet(wnet)
1601 end
1602 end
1603 end
1604
1605 function wifidev.get_wifinets(self)
1606 local nets = { }
1607
1608 _uci:foreach("wireless", "wifi-iface",
1609 function(s)
1610 if s.device == self.sid then
1611 nets[#nets+1] = wifinet(s['.name'])
1612 end
1613 end)
1614
1615 return nets
1616 end
1617
1618 function wifidev.add_wifinet(self, options)
1619 options = options or { }
1620 options.device = self.sid
1621
1622 local wnet = _uci:section("wireless", "wifi-iface", nil, options)
1623 if wnet then
1624 return wifinet(wnet, options)
1625 end
1626 end
1627
1628 function wifidev.del_wifinet(self, net)
1629 if utl.instanceof(net, wifinet) then
1630 net = net.sid
1631 elseif _uci:get("wireless", net) ~= "wifi-iface" then
1632 net = _wifi_sid_by_ifname(net)
1633 end
1634
1635 if net and _uci:get("wireless", net, "device") == self.sid then
1636 _uci:delete("wireless", net)
1637 return true
1638 end
1639
1640 return false
1641 end
1642
1643
1644 wifinet = utl.class()
1645
1646 function wifinet.__init__(self, name, data)
1647 local sid, netid, radioname, radiostate, netstate
1648
1649 -- lookup state by radio#.network# notation
1650 sid = _wifi_sid_by_netid(name)
1651 if sid then
1652 netid = name
1653 radioname, radiostate, netstate = _wifi_state_by_sid(sid)
1654 else
1655 -- lookup state by ifname (e.g. wlan0)
1656 radioname, radiostate, netstate = _wifi_state_by_ifname(name)
1657 if radioname and radiostate and netstate then
1658 sid = netstate.section
1659 netid = _wifi_netid_by_sid(sid)
1660 else
1661 -- lookup state by uci section id (e.g. cfg053579)
1662 radioname, radiostate, netstate = _wifi_state_by_sid(name)
1663 if radioname and radiostate and netstate then
1664 sid = name
1665 netid = _wifi_netid_by_sid(sid)
1666 else
1667 -- no state available, try to resolve from uci
1668 netid, radioname = _wifi_netid_by_sid(name)
1669 if netid and radioname then
1670 sid = name
1671 end
1672 end
1673 end
1674 end
1675
1676 local iwinfo =
1677 (netstate and _wifi_iwinfo_by_ifname(netstate.ifname)) or
1678 (radioname and _wifi_iwinfo_by_ifname(radioname)) or
1679 { ifname = (netid or sid or name) }
1680
1681 self.sid = sid or name
1682 self.wdev = iwinfo.ifname
1683 self.iwinfo = iwinfo
1684 self.netid = netid
1685 self._ubusdata = {
1686 radio = radioname,
1687 dev = radiostate,
1688 net = netstate
1689 }
1690 end
1691
1692 function wifinet.ubus(self, ...)
1693 local n, v = self._ubusdata
1694 for n = 1, select('#', ...) do
1695 if type(v) == "table" then
1696 v = v[select(n, ...)]
1697 else
1698 return nil
1699 end
1700 end
1701 return v
1702 end
1703
1704 function wifinet.get(self, opt)
1705 return _get("wireless", self.sid, opt)
1706 end
1707
1708 function wifinet.set(self, opt, val)
1709 return _set("wireless", self.sid, opt, val)
1710 end
1711
1712 function wifinet.mode(self)
1713 return self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1714 end
1715
1716 function wifinet.ssid(self)
1717 return self:ubus("net", "config", "ssid") or self:get("ssid")
1718 end
1719
1720 function wifinet.bssid(self)
1721 return self:ubus("net", "config", "bssid") or self:get("bssid")
1722 end
1723
1724 function wifinet.network(self)
1725 local net, networks = nil, { }
1726 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1727 networks[#networks+1] = net
1728 end
1729 return networks
1730 end
1731
1732 function wifinet.id(self)
1733 return self.netid
1734 end
1735
1736 function wifinet.name(self)
1737 return self.sid
1738 end
1739
1740 function wifinet.ifname(self)
1741 local ifname = self:ubus("net", "ifname") or self.iwinfo.ifname
1742 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1743 ifname = self.netid
1744 end
1745 return ifname
1746 end
1747
1748 function wifinet.get_device(self)
1749 local dev = self:ubus("radio") or self:get("device")
1750 return dev and wifidev(dev) or nil
1751 end
1752
1753 function wifinet.is_up(self)
1754 local ifc = self:get_interface()
1755 return (ifc and ifc:is_up() or false)
1756 end
1757
1758 function wifinet.active_mode(self)
1759 local m = self.iwinfo.mode or self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1760
1761 if m == "ap" then m = "Master"
1762 elseif m == "sta" then m = "Client"
1763 elseif m == "adhoc" then m = "Ad-Hoc"
1764 elseif m == "mesh" then m = "Mesh"
1765 elseif m == "monitor" then m = "Monitor"
1766 end
1767
1768 return m
1769 end
1770
1771 function wifinet.active_mode_i18n(self)
1772 return lng.translate(self:active_mode())
1773 end
1774
1775 function wifinet.active_ssid(self)
1776 return self.iwinfo.ssid or self:ubus("net", "config", "ssid") or self:get("ssid")
1777 end
1778
1779 function wifinet.active_bssid(self)
1780 return self.iwinfo.bssid or self:ubus("net", "config", "bssid") or self:get("bssid")
1781 end
1782
1783 function wifinet.active_encryption(self)
1784 local enc = self.iwinfo and self.iwinfo.encryption
1785 return enc and enc.description or "-"
1786 end
1787
1788 function wifinet.assoclist(self)
1789 return self.iwinfo.assoclist or { }
1790 end
1791
1792 function wifinet.frequency(self)
1793 local freq = self.iwinfo.frequency
1794 if freq and freq > 0 then
1795 return "%.03f" % (freq / 1000)
1796 end
1797 end
1798
1799 function wifinet.bitrate(self)
1800 local rate = self.iwinfo.bitrate
1801 if rate and rate > 0 then
1802 return (rate / 1000)
1803 end
1804 end
1805
1806 function wifinet.channel(self)
1807 return self.iwinfo.channel or self:ubus("dev", "config", "channel") or
1808 tonumber(self:get("channel"))
1809 end
1810
1811 function wifinet.signal(self)
1812 return self.iwinfo.signal or 0
1813 end
1814
1815 function wifinet.noise(self)
1816 return self.iwinfo.noise or 0
1817 end
1818
1819 function wifinet.country(self)
1820 return self.iwinfo.country or self:ubus("dev", "config", "country") or "00"
1821 end
1822
1823 function wifinet.txpower(self)
1824 local pwr = (self.iwinfo.txpower or 0)
1825 return pwr + self:txpower_offset()
1826 end
1827
1828 function wifinet.txpower_offset(self)
1829 return self.iwinfo.txpower_offset or 0
1830 end
1831
1832 function wifinet.signal_level(self, s, n)
1833 if self:active_bssid() ~= "00:00:00:00:00:00" then
1834 local signal = s or self:signal()
1835 local noise = n or self:noise()
1836
1837 if signal < 0 and noise < 0 then
1838 local snr = -1 * (noise - signal)
1839 return math.floor(snr / 5)
1840 else
1841 return 0
1842 end
1843 else
1844 return -1
1845 end
1846 end
1847
1848 function wifinet.signal_percent(self)
1849 local qc = self.iwinfo.quality or 0
1850 local qm = self.iwinfo.quality_max or 0
1851
1852 if qc > 0 and qm > 0 then
1853 return math.floor((100 / qm) * qc)
1854 else
1855 return 0
1856 end
1857 end
1858
1859 function wifinet.shortname(self)
1860 return "%s %q" %{
1861 lng.translate(self:active_mode()),
1862 self:active_ssid() or self:active_bssid() or self:id()
1863 }
1864 end
1865
1866 function wifinet.get_i18n(self)
1867 return "%s: %s %q (%s)" %{
1868 lng.translate("Wireless Network"),
1869 lng.translate(self:active_mode()),
1870 self:active_ssid() or self:active_bssid() or self:id(),
1871 self:ifname()
1872 }
1873 end
1874
1875 function wifinet.adminlink(self)
1876 local stat, dsp = pcall(require, "luci.dispatcher")
1877 return dsp and dsp.build_url("admin", "network", "wireless", self.netid)
1878 end
1879
1880 function wifinet.get_network(self)
1881 return self:get_networks()[1]
1882 end
1883
1884 function wifinet.get_networks(self)
1885 local nets = { }
1886 local net
1887 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1888 if _uci:get("network", net) == "interface" then
1889 nets[#nets+1] = network(net)
1890 end
1891 end
1892 table.sort(nets, function(a, b) return a.sid < b.sid end)
1893 return nets
1894 end
1895
1896 function wifinet.get_interface(self)
1897 return interface(self:ifname())
1898 end
1899
1900
1901 -- setup base protocols
1902 _M:register_protocol("static")
1903 _M:register_protocol("dhcp")
1904 _M:register_protocol("none")
1905
1906 -- load protocol extensions
1907 local exts = nfs.dir(utl.libpath() .. "/model/network")
1908 if exts then
1909 local ext
1910 for ext in exts do
1911 if ext:match("%.lua$") then
1912 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1913 end
1914 end
1915 end