luci-base: add is_auto function
[project/luci.git] / modules / luci-base / 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 in 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 false
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 elseif b then
375 b.ifnames[#b.ifnames+1] = _interfaces[r[2]]
376 b.ifnames[#b.ifnames].bridge = b
377 end
378 end
379 end
380
381 -- read switch topology
382 local boardinfo = jsc.parse(nfs.readfile("/etc/board.json") or "")
383 if type(boardinfo) == "table" and type(boardinfo.switch) == "table" then
384 local switch, layout
385 for switch, layout in pairs(boardinfo.switch) do
386 if type(layout) == "table" and type(layout.ports) == "table" then
387 local _, port
388 local ports = { }
389 local nports = { }
390 local netdevs = { }
391
392 for _, port in ipairs(layout.ports) do
393 if type(port) == "table" and
394 type(port.num) == "number" and
395 (type(port.role) == "string" or
396 type(port.device) == "string")
397 then
398 local spec = {
399 num = port.num,
400 role = port.role or "cpu",
401 index = port.index or port.num
402 }
403
404 if port.device then
405 spec.device = port.device
406 spec.tagged = port.need_tag
407 netdevs[tostring(port.num)] = port.device
408 end
409
410 ports[#ports+1] = spec
411
412 if port.role then
413 nports[port.role] = (nports[port.role] or 0) + 1
414 end
415 end
416 end
417
418 table.sort(ports, function(a, b)
419 if a.role ~= b.role then
420 return (a.role < b.role)
421 end
422
423 return (a.index < b.index)
424 end)
425
426 local pnum, role
427 for _, port in ipairs(ports) do
428 if port.role ~= role then
429 role = port.role
430 pnum = 1
431 end
432
433 if role == "cpu" then
434 port.label = "CPU (%s)" % port.device
435 elseif nports[role] > 1 then
436 port.label = "%s %d" %{ role:upper(), pnum }
437 pnum = pnum + 1
438 else
439 port.label = role:upper()
440 end
441
442 port.role = nil
443 port.index = nil
444 end
445
446 _swtopo[switch] = {
447 ports = ports,
448 netdevs = netdevs
449 }
450 end
451 end
452 end
453
454 return _M
455 end
456
457 function save(self, ...)
458 _uci:save(...)
459 _uci:load(...)
460 end
461
462 function commit(self, ...)
463 _uci:commit(...)
464 _uci:load(...)
465 end
466
467 function ifnameof(self, x)
468 if utl.instanceof(x, interface) then
469 return x:name()
470 elseif utl.instanceof(x, protocol) then
471 return x:ifname()
472 elseif type(x) == "string" then
473 return x:match("^[^:]+")
474 end
475 end
476
477 function get_protocol(self, protoname, netname)
478 local v = _protocols[protoname]
479 if v then
480 return v(netname or "__dummy__")
481 end
482 end
483
484 function get_protocols(self)
485 local p = { }
486 local _, v
487 for _, v in ipairs(_protocols) do
488 p[#p+1] = v("__dummy__")
489 end
490 return p
491 end
492
493 function register_protocol(self, protoname)
494 local proto = utl.class(protocol)
495
496 function proto.__init__(self, name)
497 self.sid = name
498 end
499
500 function proto.proto(self)
501 return protoname
502 end
503
504 _protocols[#_protocols+1] = proto
505 _protocols[protoname] = proto
506
507 return proto
508 end
509
510 function register_pattern_virtual(self, pat)
511 IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
512 end
513
514 function register_error_code(self, code, message)
515 if type(code) == "string" and
516 type(message) == "string" and
517 not IFACE_ERRORS[code]
518 then
519 IFACE_ERRORS[code] = message
520 return true
521 end
522
523 return false
524 end
525
526 function has_ipv6(self)
527 return nfs.access("/proc/net/ipv6_route")
528 end
529
530 function add_network(self, n, options)
531 local oldnet = self:get_network(n)
532 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
533 if _uci:section("network", "interface", n, options) then
534 return network(n)
535 end
536 elseif oldnet and oldnet:is_empty() then
537 if options then
538 local k, v
539 for k, v in pairs(options) do
540 oldnet:set(k, v)
541 end
542 end
543 return oldnet
544 end
545 end
546
547 function get_network(self, n)
548 if n and _uci:get("network", n) == "interface" then
549 return network(n)
550 elseif n then
551 local stat = utl.ubus("network.interface", "status", { interface = n })
552 if type(stat) == "table" and
553 type(stat.proto) == "string"
554 then
555 return network(n, stat.proto)
556 end
557 end
558 end
559
560 function get_networks(self)
561 local nets = { }
562 local nls = { }
563
564 _uci:foreach("network", "interface",
565 function(s)
566 nls[s['.name']] = network(s['.name'])
567 end)
568
569 local dump = utl.ubus("network.interface", "dump", { })
570 if type(dump) == "table" and
571 type(dump.interface) == "table"
572 then
573 local _, net
574 for _, net in ipairs(dump.interface) do
575 if type(net) == "table" and
576 type(net.proto) == "string" and
577 type(net.interface) == "string"
578 then
579 if not nls[net.interface] then
580 nls[net.interface] = network(net.interface, net.proto)
581 end
582 end
583 end
584 end
585
586 local n
587 for n in utl.kspairs(nls) do
588 nets[#nets+1] = nls[n]
589 end
590
591 return nets
592 end
593
594 function del_network(self, n)
595 local r = _uci:delete("network", n)
596 if r then
597 _uci:delete_all("luci", "ifstate",
598 function(s) return (s.interface == n) end)
599
600 _uci:delete_all("network", "alias",
601 function(s) return (s.interface == n) end)
602
603 _uci:delete_all("network", "route",
604 function(s) return (s.interface == n) end)
605
606 _uci:delete_all("network", "route6",
607 function(s) return (s.interface == n) end)
608
609 _uci:foreach("wireless", "wifi-iface",
610 function(s)
611 local net
612 local rest = { }
613 for net in utl.imatch(s.network) do
614 if net ~= n then
615 rest[#rest+1] = net
616 end
617 end
618 if #rest > 0 then
619 _uci:set("wireless", s['.name'], "network",
620 table.concat(rest, " "))
621 else
622 _uci:delete("wireless", s['.name'], "network")
623 end
624 end)
625 end
626 return r
627 end
628
629 function rename_network(self, old, new)
630 local r
631 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
632 r = _uci:section("network", "interface", new, _uci:get_all("network", old))
633
634 if r then
635 _uci:foreach("network", "alias",
636 function(s)
637 if s.interface == old then
638 _uci:set("network", s['.name'], "interface", new)
639 end
640 end)
641
642 _uci:foreach("network", "route",
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", "route6",
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("wireless", "wifi-iface",
657 function(s)
658 local net
659 local list = { }
660 for net in utl.imatch(s.network) do
661 if net == old then
662 list[#list+1] = new
663 else
664 list[#list+1] = net
665 end
666 end
667 if #list > 0 then
668 _uci:set("wireless", s['.name'], "network",
669 table.concat(list, " "))
670 end
671 end)
672
673 _uci:delete("network", old)
674 end
675 end
676 return r or false
677 end
678
679 function get_interface(self, i)
680 if _interfaces[i] or _wifi_iface(i) then
681 return interface(i)
682 else
683 local netid = _wifi_netid_by_sid(i)
684 return netid and interface(netid)
685 end
686 end
687
688 function get_interfaces(self)
689 local iface
690 local ifaces = { }
691 local nfs = { }
692
693 -- find normal interfaces
694 _uci:foreach("network", "interface",
695 function(s)
696 for iface in utl.imatch(s.ifname) do
697 if not _iface_ignore(iface) and not _iface_virtual(iface) and not _wifi_iface(iface) then
698 nfs[iface] = interface(iface)
699 end
700 end
701 end)
702
703 for iface in utl.kspairs(_interfaces) do
704 if not (nfs[iface] or _iface_ignore(iface) or _iface_virtual(iface) or _wifi_iface(iface)) then
705 nfs[iface] = interface(iface)
706 end
707 end
708
709 -- find vlan interfaces
710 _uci:foreach("network", "switch_vlan",
711 function(s)
712 if type(s.ports) ~= "string" or
713 type(s.device) ~= "string" or
714 type(_swtopo[s.device]) ~= "table"
715 then
716 return
717 end
718
719 local pnum, ptag
720 for pnum, ptag in s.ports:gmatch("(%d+)([tu]?)") do
721 local netdev = _swtopo[s.device].netdevs[pnum]
722 if netdev then
723 if not nfs[netdev] then
724 nfs[netdev] = interface(netdev)
725 end
726 _switch[netdev] = true
727
728 if ptag == "t" then
729 local vid = tonumber(s.vid or s.vlan)
730 if vid ~= nil and vid >= 0 and vid <= 4095 then
731 local iface = "%s.%d" %{ netdev, vid }
732 if not nfs[iface] then
733 nfs[iface] = interface(iface)
734 end
735 _switch[iface] = true
736 end
737 end
738 end
739 end
740 end)
741
742 for iface in utl.kspairs(nfs) do
743 ifaces[#ifaces+1] = nfs[iface]
744 end
745
746 -- find wifi interfaces
747 local num = { }
748 local wfs = { }
749 _uci:foreach("wireless", "wifi-iface",
750 function(s)
751 if s.device then
752 num[s.device] = num[s.device] and num[s.device] + 1 or 1
753 local i = "%s.network%d" %{ s.device, num[s.device] }
754 wfs[i] = interface(i)
755 end
756 end)
757
758 for iface in utl.kspairs(wfs) do
759 ifaces[#ifaces+1] = wfs[iface]
760 end
761
762 return ifaces
763 end
764
765 function ignore_interface(self, x)
766 return _iface_ignore(x)
767 end
768
769 function get_wifidev(self, dev)
770 if _uci:get("wireless", dev) == "wifi-device" then
771 return wifidev(dev)
772 end
773 end
774
775 function get_wifidevs(self)
776 local devs = { }
777 local wfd = { }
778
779 _uci:foreach("wireless", "wifi-device",
780 function(s) wfd[#wfd+1] = s['.name'] end)
781
782 local dev
783 for _, dev in utl.vspairs(wfd) do
784 devs[#devs+1] = wifidev(dev)
785 end
786
787 return devs
788 end
789
790 function get_wifinet(self, net)
791 local wnet = _wifi_sid_by_ifname(net)
792 if wnet then
793 return wifinet(wnet)
794 end
795 end
796
797 function add_wifinet(self, net, options)
798 if type(options) == "table" and options.device and
799 _uci:get("wireless", options.device) == "wifi-device"
800 then
801 local wnet = _uci:section("wireless", "wifi-iface", nil, options)
802 return wifinet(wnet)
803 end
804 end
805
806 function del_wifinet(self, net)
807 local wnet = _wifi_sid_by_ifname(net)
808 if wnet then
809 _uci:delete("wireless", wnet)
810 return true
811 end
812 return false
813 end
814
815 function get_status_by_route(self, addr, mask)
816 local route_statuses = { }
817 local _, object
818 for _, object in ipairs(utl.ubus()) do
819 local net = object:match("^network%.interface%.(.+)")
820 if net then
821 local s = utl.ubus(object, "status", {})
822 if s and s.route then
823 local rt
824 for _, rt in ipairs(s.route) do
825 if not rt.table and rt.target == addr and rt.mask == mask then
826 route_statuses[net] = s
827 end
828 end
829 end
830 end
831 end
832
833 return route_statuses
834 end
835
836 function get_status_by_address(self, addr)
837 local _, object
838 for _, object in ipairs(utl.ubus()) do
839 local net = object:match("^network%.interface%.(.+)")
840 if net then
841 local s = utl.ubus(object, "status", {})
842 if s and s['ipv4-address'] then
843 local a
844 for _, a in ipairs(s['ipv4-address']) do
845 if a.address == addr then
846 return net, s
847 end
848 end
849 end
850 if s and s['ipv6-address'] then
851 local a
852 for _, a in ipairs(s['ipv6-address']) do
853 if a.address == addr then
854 return net, s
855 end
856 end
857 end
858 if s and s['ipv6-prefix-assignment'] then
859 local a
860 for _, a in ipairs(s['ipv6-prefix-assignment']) do
861 if a and a['local-address'] and a['local-address'].address == addr then
862 return net, s
863 end
864 end
865 end
866 end
867 end
868 end
869
870 function get_wan_networks(self)
871 local k, v
872 local wan_nets = { }
873 local route_statuses = self:get_status_by_route("0.0.0.0", 0)
874
875 for k, v in pairs(route_statuses) do
876 wan_nets[#wan_nets+1] = network(k, v.proto)
877 end
878
879 return wan_nets
880 end
881
882 function get_wan6_networks(self)
883 local k, v
884 local wan6_nets = { }
885 local route_statuses = self:get_status_by_route("::", 0)
886
887 for k, v in pairs(route_statuses) do
888 wan6_nets[#wan6_nets+1] = network(k, v.proto)
889 end
890
891 return wan6_nets
892 end
893
894 function get_switch_topologies(self)
895 return _swtopo
896 end
897
898
899 function network(name, proto)
900 if name then
901 local p = proto or _uci:get("network", name, "proto")
902 local c = p and _protocols[p] or protocol
903 return c(name)
904 end
905 end
906
907 function protocol.__init__(self, name)
908 self.sid = name
909 end
910
911 function protocol._get(self, opt)
912 local v = _uci:get("network", self.sid, opt)
913 if type(v) == "table" then
914 return table.concat(v, " ")
915 end
916 return v or ""
917 end
918
919 function protocol._ubus(self, field)
920 if not _ubusnetcache[self.sid] then
921 _ubusnetcache[self.sid] = utl.ubus("network.interface.%s" % self.sid,
922 "status", { })
923 end
924 if _ubusnetcache[self.sid] and field then
925 return _ubusnetcache[self.sid][field]
926 end
927 return _ubusnetcache[self.sid]
928 end
929
930 function protocol.get(self, opt)
931 return _get("network", self.sid, opt)
932 end
933
934 function protocol.set(self, opt, val)
935 return _set("network", self.sid, opt, val)
936 end
937
938 function protocol.ifname(self)
939 local ifname
940 if self:is_floating() then
941 ifname = self:_ubus("l3_device")
942 else
943 ifname = self:_ubus("device")
944 end
945 if not ifname then
946 ifname = _wifi_netid_by_netname(self.sid)
947 end
948 return ifname
949 end
950
951 function protocol.proto(self)
952 return "none"
953 end
954
955 function protocol.get_i18n(self)
956 local p = self:proto()
957 if p == "none" then
958 return lng.translate("Unmanaged")
959 elseif p == "static" then
960 return lng.translate("Static address")
961 elseif p == "dhcp" then
962 return lng.translate("DHCP client")
963 else
964 return lng.translate("Unknown")
965 end
966 end
967
968 function protocol.type(self)
969 return self:_get("type")
970 end
971
972 function protocol.name(self)
973 return self.sid
974 end
975
976 function protocol.uptime(self)
977 return self:_ubus("uptime") or 0
978 end
979
980 function protocol.expires(self)
981 local u = self:_ubus("uptime")
982 local d = self:_ubus("data")
983
984 if type(u) == "number" and type(d) == "table" and
985 type(d.leasetime) == "number"
986 then
987 local r = (d.leasetime - (u % d.leasetime))
988 return r > 0 and r or 0
989 end
990
991 return -1
992 end
993
994 function protocol.metric(self)
995 return self:_ubus("metric") or 0
996 end
997
998 function protocol.zonename(self)
999 local d = self:_ubus("data")
1000
1001 if type(d) == "table" and type(d.zone) == "string" then
1002 return d.zone
1003 end
1004
1005 return nil
1006 end
1007
1008 function protocol.ipaddr(self)
1009 local addrs = self:_ubus("ipv4-address")
1010 return addrs and #addrs > 0 and addrs[1].address
1011 end
1012
1013 function protocol.ipaddrs(self)
1014 local addrs = self:_ubus("ipv4-address")
1015 local rv = { }
1016
1017 if type(addrs) == "table" then
1018 local n, addr
1019 for n, addr in ipairs(addrs) do
1020 rv[#rv+1] = "%s/%d" %{ addr.address, addr.mask }
1021 end
1022 end
1023
1024 return rv
1025 end
1026
1027 function protocol.netmask(self)
1028 local addrs = self:_ubus("ipv4-address")
1029 return addrs and #addrs > 0 and
1030 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
1031 end
1032
1033 function protocol.gwaddr(self)
1034 local _, route
1035 for _, route in ipairs(self:_ubus("route") or { }) do
1036 if route.target == "0.0.0.0" and route.mask == 0 then
1037 return route.nexthop
1038 end
1039 end
1040 end
1041
1042 function protocol.dnsaddrs(self)
1043 local dns = { }
1044 local _, addr
1045 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
1046 if not addr:match(":") then
1047 dns[#dns+1] = addr
1048 end
1049 end
1050 return dns
1051 end
1052
1053 function protocol.ip6addr(self)
1054 local addrs = self:_ubus("ipv6-address")
1055 if addrs and #addrs > 0 then
1056 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
1057 else
1058 addrs = self:_ubus("ipv6-prefix-assignment")
1059 if addrs and #addrs > 0 then
1060 return "%s/%d" %{ addrs[1].address, addrs[1].mask }
1061 end
1062 end
1063 end
1064
1065 function protocol.ip6addrs(self)
1066 local addrs = self:_ubus("ipv6-address")
1067 local rv = { }
1068 local n, addr
1069
1070 if type(addrs) == "table" then
1071 for n, addr in ipairs(addrs) do
1072 rv[#rv+1] = "%s/%d" %{ addr.address, addr.mask }
1073 end
1074 end
1075
1076 addrs = self:_ubus("ipv6-prefix-assignment")
1077
1078 if type(addrs) == "table" then
1079 for n, addr in ipairs(addrs) do
1080 if type(addr["local-address"]) == "table" and
1081 type(addr["local-address"].mask) == "number" and
1082 type(addr["local-address"].address) == "string"
1083 then
1084 rv[#rv+1] = "%s/%d" %{
1085 addr["local-address"].address,
1086 addr["local-address"].mask
1087 }
1088 end
1089 end
1090 end
1091
1092 return rv
1093 end
1094
1095 function protocol.gw6addr(self)
1096 local _, route
1097 for _, route in ipairs(self:_ubus("route") or { }) do
1098 if route.target == "::" and route.mask == 0 then
1099 return ipc.IPv6(route.nexthop):string()
1100 end
1101 end
1102 end
1103
1104 function protocol.dns6addrs(self)
1105 local dns = { }
1106 local _, addr
1107 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
1108 if addr:match(":") then
1109 dns[#dns+1] = addr
1110 end
1111 end
1112 return dns
1113 end
1114
1115 function protocol.ip6prefix(self)
1116 local prefix = self:_ubus("ipv6-prefix")
1117 if prefix and #prefix > 0 then
1118 return "%s/%d" %{ prefix[1].address, prefix[1].mask }
1119 end
1120 end
1121
1122 function protocol.errors(self)
1123 local _, err, rv
1124 local errors = self:_ubus("errors")
1125 if type(errors) == "table" then
1126 for _, err in ipairs(errors) do
1127 if type(err) == "table" and
1128 type(err.code) == "string"
1129 then
1130 rv = rv or { }
1131 rv[#rv+1] = IFACE_ERRORS[err.code] or lng.translatef("Unknown error (%s)", err.code)
1132 end
1133 end
1134 end
1135 return rv
1136 end
1137
1138 function protocol.is_bridge(self)
1139 return (not self:is_virtual() and self:type() == "bridge")
1140 end
1141
1142 function protocol.opkg_package(self)
1143 return nil
1144 end
1145
1146 function protocol.is_installed(self)
1147 return true
1148 end
1149
1150 function protocol.is_virtual(self)
1151 return false
1152 end
1153
1154 function protocol.is_floating(self)
1155 return false
1156 end
1157
1158 function protocol.is_dynamic(self)
1159 return (self:_ubus("dynamic") == true)
1160 end
1161
1162 function protocol.is_auto(self)
1163 local auto = self:_get("auto")
1164
1165 if auto == "0" then
1166 return false
1167 else
1168 return true
1169 end
1170 end
1171
1172 function protocol.is_alias(self)
1173 local ifn, parent = nil, nil
1174
1175 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1176 if #ifn > 1 and ifn:byte(1) == 64 then
1177 parent = ifn:sub(2)
1178 elseif parent ~= nil then
1179 parent = nil
1180 end
1181 end
1182
1183 return parent
1184 end
1185
1186 function protocol.is_empty(self)
1187 if self:is_floating() then
1188 return false
1189 else
1190 local empty = true
1191
1192 if (self:_get("ifname") or ""):match("%S+") then
1193 empty = false
1194 end
1195
1196 if empty and _wifi_netid_by_netname(self.sid) then
1197 empty = false
1198 end
1199
1200 return empty
1201 end
1202 end
1203
1204 function protocol.is_up(self)
1205 return (self:_ubus("up") == true)
1206 end
1207
1208 function protocol.add_interface(self, ifname)
1209 ifname = _M:ifnameof(ifname)
1210 if ifname and not self:is_floating() then
1211 -- if its a wifi interface, change its network option
1212 local wif = _wifi_sid_by_ifname(ifname)
1213 if wif then
1214 _append("wireless", wif, "network", self.sid)
1215
1216 -- add iface to our iface list
1217 else
1218 _append("network", self.sid, "ifname", ifname)
1219 end
1220 end
1221 end
1222
1223 function protocol.del_interface(self, ifname)
1224 ifname = _M:ifnameof(ifname)
1225 if ifname and not self:is_floating() then
1226 -- if its a wireless interface, clear its network option
1227 local wif = _wifi_sid_by_ifname(ifname)
1228 if wif then _filter("wireless", wif, "network", self.sid) end
1229
1230 -- remove the interface
1231 _filter("network", self.sid, "ifname", ifname)
1232 end
1233 end
1234
1235 function protocol.get_interface(self)
1236 if self:is_virtual() then
1237 _tunnel[self:proto() .. "-" .. self.sid] = true
1238 return interface(self:proto() .. "-" .. self.sid, self)
1239 elseif self:is_bridge() then
1240 _bridge["br-" .. self.sid] = true
1241 return interface("br-" .. self.sid, self)
1242 else
1243 local ifn = self:_ubus("l3_device") or self:_ubus("device")
1244 if ifn then
1245 return interface(ifn, self)
1246 end
1247
1248 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1249 ifn = ifn:match("^[^:/]+")
1250 return ifn and interface(ifn, self)
1251 end
1252
1253 ifn = _wifi_netid_by_netname(self.sid)
1254 return ifn and interface(ifn, self)
1255 end
1256 end
1257
1258 function protocol.get_interfaces(self)
1259 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
1260 local ifaces = { }
1261
1262 local ifn
1263 local nfs = { }
1264 for ifn in utl.imatch(self:get("ifname")) do
1265 ifn = ifn:match("^[^:/]+")
1266 nfs[ifn] = interface(ifn, self)
1267 end
1268
1269 for ifn in utl.kspairs(nfs) do
1270 ifaces[#ifaces+1] = nfs[ifn]
1271 end
1272
1273 local wfs = { }
1274 _uci:foreach("wireless", "wifi-iface",
1275 function(s)
1276 if s.device then
1277 local net
1278 for net in utl.imatch(s.network) do
1279 if net == self.sid then
1280 ifn = _wifi_netid_by_sid(s[".name"])
1281 if ifn then
1282 wfs[ifn] = interface(ifn, self)
1283 end
1284 end
1285 end
1286 end
1287 end)
1288
1289 for ifn in utl.kspairs(wfs) do
1290 ifaces[#ifaces+1] = wfs[ifn]
1291 end
1292
1293 return ifaces
1294 end
1295 end
1296
1297 function protocol.contains_interface(self, ifname)
1298 ifname = _M:ifnameof(ifname)
1299 if not ifname then
1300 return false
1301 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
1302 return true
1303 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1304 return true
1305 else
1306 local ifn
1307 for ifn in utl.imatch(self:get("ifname")) do
1308 ifn = ifn:match("[^:]+")
1309 if ifn == ifname then
1310 return true
1311 end
1312 end
1313
1314 local wif = _wifi_sid_by_ifname(ifname)
1315 if wif then
1316 local n
1317 for n in utl.imatch(_uci:get("wireless", wif, "network")) do
1318 if n == self.sid then
1319 return true
1320 end
1321 end
1322 end
1323 end
1324
1325 return false
1326 end
1327
1328 function protocol.adminlink(self)
1329 local stat, dsp = pcall(require, "luci.dispatcher")
1330 return stat and dsp.build_url("admin", "network", "network", self.sid)
1331 end
1332
1333
1334 interface = utl.class()
1335
1336 function interface.__init__(self, ifname, network)
1337 local wif = _wifi_sid_by_ifname(ifname)
1338 if wif then
1339 self.wif = wifinet(wif)
1340 self.ifname = self.wif:ifname()
1341 end
1342
1343 self.ifname = self.ifname or ifname
1344 self.dev = _interfaces[self.ifname]
1345 self.network = network
1346 end
1347
1348 function interface._ubus(self, field)
1349 if not _ubusdevcache[self.ifname] then
1350 _ubusdevcache[self.ifname] = utl.ubus("network.device", "status",
1351 { name = self.ifname })
1352 end
1353 if _ubusdevcache[self.ifname] and field then
1354 return _ubusdevcache[self.ifname][field]
1355 end
1356 return _ubusdevcache[self.ifname]
1357 end
1358
1359 function interface.name(self)
1360 return self.wif and self.wif:ifname() or self.ifname
1361 end
1362
1363 function interface.mac(self)
1364 return ipc.checkmac(self:_ubus("macaddr"))
1365 end
1366
1367 function interface.ipaddrs(self)
1368 return self.dev and self.dev.ipaddrs or { }
1369 end
1370
1371 function interface.ip6addrs(self)
1372 return self.dev and self.dev.ip6addrs or { }
1373 end
1374
1375 function interface.type(self)
1376 if self.ifname and self.ifname:byte(1) == 64 then
1377 return "alias"
1378 elseif self.wif or _wifi_iface(self.ifname) then
1379 return "wifi"
1380 elseif _bridge[self.ifname] then
1381 return "bridge"
1382 elseif _tunnel[self.ifname] then
1383 return "tunnel"
1384 elseif self.ifname:match("%.") then
1385 return "vlan"
1386 elseif _switch[self.ifname] then
1387 return "switch"
1388 else
1389 return "ethernet"
1390 end
1391 end
1392
1393 function interface.shortname(self)
1394 if self.wif then
1395 return self.wif:shortname()
1396 else
1397 return self.ifname
1398 end
1399 end
1400
1401 function interface.get_i18n(self)
1402 if self.wif then
1403 return "%s: %s %q" %{
1404 lng.translate("Wireless Network"),
1405 self.wif:active_mode(),
1406 self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id() or "?"
1407 }
1408 else
1409 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1410 end
1411 end
1412
1413 function interface.get_type_i18n(self)
1414 local x = self:type()
1415 if x == "alias" then
1416 return lng.translate("Alias Interface")
1417 elseif x == "wifi" then
1418 return lng.translate("Wireless Adapter")
1419 elseif x == "bridge" then
1420 return lng.translate("Bridge")
1421 elseif x == "switch" then
1422 return lng.translate("Ethernet Switch")
1423 elseif x == "vlan" then
1424 if _switch[self.ifname] then
1425 return lng.translate("Switch VLAN")
1426 else
1427 return lng.translate("Software VLAN")
1428 end
1429 elseif x == "tunnel" then
1430 return lng.translate("Tunnel Interface")
1431 else
1432 return lng.translate("Ethernet Adapter")
1433 end
1434 end
1435
1436 function interface.adminlink(self)
1437 if self.wif then
1438 return self.wif:adminlink()
1439 end
1440 end
1441
1442 function interface.ports(self)
1443 local members = self:_ubus("bridge-members")
1444 if members then
1445 local _, iface
1446 local ifaces = { }
1447 for _, iface in ipairs(members) do
1448 ifaces[#ifaces+1] = interface(iface)
1449 end
1450 end
1451 end
1452
1453 function interface.bridge_id(self)
1454 if self.br then
1455 return self.br.id
1456 else
1457 return nil
1458 end
1459 end
1460
1461 function interface.bridge_stp(self)
1462 if self.br then
1463 return self.br.stp
1464 else
1465 return false
1466 end
1467 end
1468
1469 function interface.is_up(self)
1470 local up = self:_ubus("up")
1471 if up == nil then
1472 up = (self:type() == "alias")
1473 end
1474 return up or false
1475 end
1476
1477 function interface.is_bridge(self)
1478 return (self:type() == "bridge")
1479 end
1480
1481 function interface.is_bridgeport(self)
1482 return self.dev and self.dev.bridge and true or false
1483 end
1484
1485 function interface.tx_bytes(self)
1486 local stat = self:_ubus("statistics")
1487 return stat and stat.tx_bytes or 0
1488 end
1489
1490 function interface.rx_bytes(self)
1491 local stat = self:_ubus("statistics")
1492 return stat and stat.rx_bytes or 0
1493 end
1494
1495 function interface.tx_packets(self)
1496 local stat = self:_ubus("statistics")
1497 return stat and stat.tx_packets or 0
1498 end
1499
1500 function interface.rx_packets(self)
1501 local stat = self:_ubus("statistics")
1502 return stat and stat.rx_packets or 0
1503 end
1504
1505 function interface.get_network(self)
1506 return self:get_networks()[1]
1507 end
1508
1509 function interface.get_networks(self)
1510 if not self.networks then
1511 local nets = { }
1512 local _, net
1513 for _, net in ipairs(_M:get_networks()) do
1514 if net:contains_interface(self.ifname) or
1515 net:ifname() == self.ifname
1516 then
1517 nets[#nets+1] = net
1518 end
1519 end
1520 table.sort(nets, function(a, b) return a.sid < b.sid end)
1521 self.networks = nets
1522 return nets
1523 else
1524 return self.networks
1525 end
1526 end
1527
1528 function interface.get_wifinet(self)
1529 return self.wif
1530 end
1531
1532
1533 wifidev = utl.class()
1534
1535 function wifidev.__init__(self, name)
1536 local t, n = _uci:get("wireless", name)
1537 if t == "wifi-device" and n ~= nil then
1538 self.sid = n
1539 self.iwinfo = _wifi_iwinfo_by_ifname(self.sid, true)
1540 end
1541 self.sid = self.sid or name
1542 self.iwinfo = self.iwinfo or { ifname = self.sid }
1543 end
1544
1545 function wifidev.get(self, opt)
1546 return _get("wireless", self.sid, opt)
1547 end
1548
1549 function wifidev.set(self, opt, val)
1550 return _set("wireless", self.sid, opt, val)
1551 end
1552
1553 function wifidev.name(self)
1554 return self.sid
1555 end
1556
1557 function wifidev.hwmodes(self)
1558 local l = self.iwinfo.hwmodelist
1559 if l and next(l) then
1560 return l
1561 else
1562 return { b = true, g = true }
1563 end
1564 end
1565
1566 function wifidev.get_i18n(self)
1567 local t = self.iwinfo.hardware_name or "Generic"
1568 if self.iwinfo.type == "wl" then
1569 t = "Broadcom"
1570 end
1571
1572 local m = ""
1573 local l = self:hwmodes()
1574 if l.a then m = m .. "a" end
1575 if l.b then m = m .. "b" end
1576 if l.g then m = m .. "g" end
1577 if l.n then m = m .. "n" end
1578 if l.ac then m = "ac" end
1579
1580 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1581 end
1582
1583 function wifidev.is_up(self)
1584 if _ubuswificache[self.sid] then
1585 return (_ubuswificache[self.sid].up == true)
1586 end
1587
1588 return false
1589 end
1590
1591 function wifidev.get_wifinet(self, net)
1592 if _uci:get("wireless", net) == "wifi-iface" then
1593 return wifinet(net)
1594 else
1595 local wnet = _wifi_sid_by_ifname(net)
1596 if wnet then
1597 return wifinet(wnet)
1598 end
1599 end
1600 end
1601
1602 function wifidev.get_wifinets(self)
1603 local nets = { }
1604
1605 _uci:foreach("wireless", "wifi-iface",
1606 function(s)
1607 if s.device == self.sid then
1608 nets[#nets+1] = wifinet(s['.name'])
1609 end
1610 end)
1611
1612 return nets
1613 end
1614
1615 function wifidev.add_wifinet(self, options)
1616 options = options or { }
1617 options.device = self.sid
1618
1619 local wnet = _uci:section("wireless", "wifi-iface", nil, options)
1620 if wnet then
1621 return wifinet(wnet, options)
1622 end
1623 end
1624
1625 function wifidev.del_wifinet(self, net)
1626 if utl.instanceof(net, wifinet) then
1627 net = net.sid
1628 elseif _uci:get("wireless", net) ~= "wifi-iface" then
1629 net = _wifi_sid_by_ifname(net)
1630 end
1631
1632 if net and _uci:get("wireless", net, "device") == self.sid then
1633 _uci:delete("wireless", net)
1634 return true
1635 end
1636
1637 return false
1638 end
1639
1640
1641 wifinet = utl.class()
1642
1643 function wifinet.__init__(self, name, data)
1644 local sid, netid, radioname, radiostate, netstate
1645
1646 -- lookup state by radio#.network# notation
1647 sid = _wifi_sid_by_netid(name)
1648 if sid then
1649 netid = name
1650 radioname, radiostate, netstate = _wifi_state_by_sid(sid)
1651 else
1652 -- lookup state by ifname (e.g. wlan0)
1653 radioname, radiostate, netstate = _wifi_state_by_ifname(name)
1654 if radioname and radiostate and netstate then
1655 sid = netstate.section
1656 netid = _wifi_netid_by_sid(sid)
1657 else
1658 -- lookup state by uci section id (e.g. cfg053579)
1659 radioname, radiostate, netstate = _wifi_state_by_sid(name)
1660 if radioname and radiostate and netstate then
1661 sid = name
1662 netid = _wifi_netid_by_sid(sid)
1663 else
1664 -- no state available, try to resolve from uci
1665 netid, radioname = _wifi_netid_by_sid(name)
1666 if netid and radioname then
1667 sid = name
1668 end
1669 end
1670 end
1671 end
1672
1673 local iwinfo =
1674 (netstate and _wifi_iwinfo_by_ifname(netstate.ifname)) or
1675 (radioname and _wifi_iwinfo_by_ifname(radioname)) or
1676 { ifname = (netid or sid or name) }
1677
1678 self.sid = sid or name
1679 self.wdev = iwinfo.ifname
1680 self.iwinfo = iwinfo
1681 self.netid = netid
1682 self._ubusdata = {
1683 radio = radioname,
1684 dev = radiostate,
1685 net = netstate
1686 }
1687 end
1688
1689 function wifinet.ubus(self, ...)
1690 local n, v = self._ubusdata
1691 for n = 1, select('#', ...) do
1692 if type(v) == "table" then
1693 v = v[select(n, ...)]
1694 else
1695 return nil
1696 end
1697 end
1698 return v
1699 end
1700
1701 function wifinet.get(self, opt)
1702 return _get("wireless", self.sid, opt)
1703 end
1704
1705 function wifinet.set(self, opt, val)
1706 return _set("wireless", self.sid, opt, val)
1707 end
1708
1709 function wifinet.mode(self)
1710 return self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1711 end
1712
1713 function wifinet.ssid(self)
1714 return self:ubus("net", "config", "ssid") or self:get("ssid")
1715 end
1716
1717 function wifinet.bssid(self)
1718 return self:ubus("net", "config", "bssid") or self:get("bssid")
1719 end
1720
1721 function wifinet.network(self)
1722 local net, networks = nil, { }
1723 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1724 networks[#networks+1] = net
1725 end
1726 return networks
1727 end
1728
1729 function wifinet.id(self)
1730 return self.netid
1731 end
1732
1733 function wifinet.name(self)
1734 return self.sid
1735 end
1736
1737 function wifinet.ifname(self)
1738 local ifname = self:ubus("net", "ifname") or self.iwinfo.ifname
1739 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1740 ifname = self.netid
1741 end
1742 return ifname
1743 end
1744
1745 function wifinet.get_device(self)
1746 local dev = self:ubus("radio") or self:get("device")
1747 return dev and wifidev(dev) or nil
1748 end
1749
1750 function wifinet.is_up(self)
1751 local ifc = self:get_interface()
1752 return (ifc and ifc:is_up() or false)
1753 end
1754
1755 function wifinet.active_mode(self)
1756 local m = self.iwinfo.mode or self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1757
1758 if m == "ap" then m = "Master"
1759 elseif m == "sta" then m = "Client"
1760 elseif m == "adhoc" then m = "Ad-Hoc"
1761 elseif m == "mesh" then m = "Mesh"
1762 elseif m == "monitor" then m = "Monitor"
1763 end
1764
1765 return m
1766 end
1767
1768 function wifinet.active_mode_i18n(self)
1769 return lng.translate(self:active_mode())
1770 end
1771
1772 function wifinet.active_ssid(self)
1773 return self.iwinfo.ssid or self:ubus("net", "config", "ssid") or self:get("ssid")
1774 end
1775
1776 function wifinet.active_bssid(self)
1777 return self.iwinfo.bssid or self:ubus("net", "config", "bssid") or self:get("bssid")
1778 end
1779
1780 function wifinet.active_encryption(self)
1781 local enc = self.iwinfo and self.iwinfo.encryption
1782 return enc and enc.description or "-"
1783 end
1784
1785 function wifinet.assoclist(self)
1786 return self.iwinfo.assoclist or { }
1787 end
1788
1789 function wifinet.frequency(self)
1790 local freq = self.iwinfo.frequency
1791 if freq and freq > 0 then
1792 return "%.03f" % (freq / 1000)
1793 end
1794 end
1795
1796 function wifinet.bitrate(self)
1797 local rate = self.iwinfo.bitrate
1798 if rate and rate > 0 then
1799 return (rate / 1000)
1800 end
1801 end
1802
1803 function wifinet.channel(self)
1804 return self.iwinfo.channel or self:ubus("dev", "config", "channel") or
1805 tonumber(self:get("channel"))
1806 end
1807
1808 function wifinet.signal(self)
1809 return self.iwinfo.signal or 0
1810 end
1811
1812 function wifinet.noise(self)
1813 return self.iwinfo.noise or 0
1814 end
1815
1816 function wifinet.country(self)
1817 return self.iwinfo.country or self:ubus("dev", "config", "country") or "00"
1818 end
1819
1820 function wifinet.txpower(self)
1821 local pwr = (self.iwinfo.txpower or 0)
1822 return pwr + self:txpower_offset()
1823 end
1824
1825 function wifinet.txpower_offset(self)
1826 return self.iwinfo.txpower_offset or 0
1827 end
1828
1829 function wifinet.signal_level(self, s, n)
1830 if self:active_bssid() ~= "00:00:00:00:00:00" then
1831 local signal = s or self:signal()
1832 local noise = n or self:noise()
1833
1834 if signal < 0 and noise < 0 then
1835 local snr = -1 * (noise - signal)
1836 return math.floor(snr / 5)
1837 else
1838 return 0
1839 end
1840 else
1841 return -1
1842 end
1843 end
1844
1845 function wifinet.signal_percent(self)
1846 local qc = self.iwinfo.quality or 0
1847 local qm = self.iwinfo.quality_max or 0
1848
1849 if qc > 0 and qm > 0 then
1850 return math.floor((100 / qm) * qc)
1851 else
1852 return 0
1853 end
1854 end
1855
1856 function wifinet.shortname(self)
1857 return "%s %q" %{
1858 lng.translate(self:active_mode()),
1859 self:active_ssid() or self:active_bssid() or self:id()
1860 }
1861 end
1862
1863 function wifinet.get_i18n(self)
1864 return "%s: %s %q (%s)" %{
1865 lng.translate("Wireless Network"),
1866 lng.translate(self:active_mode()),
1867 self:active_ssid() or self:active_bssid() or self:id(),
1868 self:ifname()
1869 }
1870 end
1871
1872 function wifinet.adminlink(self)
1873 local stat, dsp = pcall(require, "luci.dispatcher")
1874 return dsp and dsp.build_url("admin", "network", "wireless", self.netid)
1875 end
1876
1877 function wifinet.get_network(self)
1878 return self:get_networks()[1]
1879 end
1880
1881 function wifinet.get_networks(self)
1882 local nets = { }
1883 local net
1884 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1885 if _uci:get("network", net) == "interface" then
1886 nets[#nets+1] = network(net)
1887 end
1888 end
1889 table.sort(nets, function(a, b) return a.sid < b.sid end)
1890 return nets
1891 end
1892
1893 function wifinet.get_interface(self)
1894 return interface(self:ifname())
1895 end
1896
1897
1898 -- setup base protocols
1899 _M:register_protocol("static")
1900 _M:register_protocol("dhcp")
1901 _M:register_protocol("none")
1902
1903 -- load protocol extensions
1904 local exts = nfs.dir(utl.libpath() .. "/model/network")
1905 if exts then
1906 local ext
1907 for ext in exts do
1908 if ext:match("%.lua$") then
1909 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1910 end
1911 end
1912 end