Merge pull request #2408 from YuriPet/master
[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_alias(self)
1163 local ifn, parent = nil, nil
1164
1165 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1166 if #ifn > 1 and ifn:byte(1) == 64 then
1167 parent = ifn:sub(2)
1168 elseif parent ~= nil then
1169 parent = nil
1170 end
1171 end
1172
1173 return parent
1174 end
1175
1176 function protocol.is_empty(self)
1177 if self:is_floating() then
1178 return false
1179 else
1180 local empty = true
1181
1182 if (self:_get("ifname") or ""):match("%S+") then
1183 empty = false
1184 end
1185
1186 if empty and _wifi_netid_by_netname(self.sid) then
1187 empty = false
1188 end
1189
1190 return empty
1191 end
1192 end
1193
1194 function protocol.is_up(self)
1195 return (self:_ubus("up") == true)
1196 end
1197
1198 function protocol.add_interface(self, ifname)
1199 ifname = _M:ifnameof(ifname)
1200 if ifname and not self:is_floating() then
1201 -- if its a wifi interface, change its network option
1202 local wif = _wifi_sid_by_ifname(ifname)
1203 if wif then
1204 _append("wireless", wif, "network", self.sid)
1205
1206 -- add iface to our iface list
1207 else
1208 _append("network", self.sid, "ifname", ifname)
1209 end
1210 end
1211 end
1212
1213 function protocol.del_interface(self, ifname)
1214 ifname = _M:ifnameof(ifname)
1215 if ifname and not self:is_floating() then
1216 -- if its a wireless interface, clear its network option
1217 local wif = _wifi_sid_by_ifname(ifname)
1218 if wif then _filter("wireless", wif, "network", self.sid) end
1219
1220 -- remove the interface
1221 _filter("network", self.sid, "ifname", ifname)
1222 end
1223 end
1224
1225 function protocol.get_interface(self)
1226 if self:is_virtual() then
1227 _tunnel[self:proto() .. "-" .. self.sid] = true
1228 return interface(self:proto() .. "-" .. self.sid, self)
1229 elseif self:is_bridge() then
1230 _bridge["br-" .. self.sid] = true
1231 return interface("br-" .. self.sid, self)
1232 else
1233 local ifn = self:_ubus("l3_device") or self:_ubus("device")
1234 if ifn then
1235 return interface(ifn, self)
1236 end
1237
1238 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1239 ifn = ifn:match("^[^:/]+")
1240 return ifn and interface(ifn, self)
1241 end
1242
1243 ifn = _wifi_netid_by_netname(self.sid)
1244 return ifn and interface(ifn, self)
1245 end
1246 end
1247
1248 function protocol.get_interfaces(self)
1249 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
1250 local ifaces = { }
1251
1252 local ifn
1253 local nfs = { }
1254 for ifn in utl.imatch(self:get("ifname")) do
1255 ifn = ifn:match("^[^:/]+")
1256 nfs[ifn] = interface(ifn, self)
1257 end
1258
1259 for ifn in utl.kspairs(nfs) do
1260 ifaces[#ifaces+1] = nfs[ifn]
1261 end
1262
1263 local wfs = { }
1264 _uci:foreach("wireless", "wifi-iface",
1265 function(s)
1266 if s.device then
1267 local net
1268 for net in utl.imatch(s.network) do
1269 if net == self.sid then
1270 ifn = _wifi_netid_by_sid(s[".name"])
1271 if ifn then
1272 wfs[ifn] = interface(ifn, self)
1273 end
1274 end
1275 end
1276 end
1277 end)
1278
1279 for ifn in utl.kspairs(wfs) do
1280 ifaces[#ifaces+1] = wfs[ifn]
1281 end
1282
1283 return ifaces
1284 end
1285 end
1286
1287 function protocol.contains_interface(self, ifname)
1288 ifname = _M:ifnameof(ifname)
1289 if not ifname then
1290 return false
1291 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
1292 return true
1293 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1294 return true
1295 else
1296 local ifn
1297 for ifn in utl.imatch(self:get("ifname")) do
1298 ifn = ifn:match("[^:]+")
1299 if ifn == ifname then
1300 return true
1301 end
1302 end
1303
1304 local wif = _wifi_sid_by_ifname(ifname)
1305 if wif then
1306 local n
1307 for n in utl.imatch(_uci:get("wireless", wif, "network")) do
1308 if n == self.sid then
1309 return true
1310 end
1311 end
1312 end
1313 end
1314
1315 return false
1316 end
1317
1318 function protocol.adminlink(self)
1319 local stat, dsp = pcall(require, "luci.dispatcher")
1320 return stat and dsp.build_url("admin", "network", "network", self.sid)
1321 end
1322
1323
1324 interface = utl.class()
1325
1326 function interface.__init__(self, ifname, network)
1327 local wif = _wifi_sid_by_ifname(ifname)
1328 if wif then
1329 self.wif = wifinet(wif)
1330 self.ifname = self.wif:ifname()
1331 end
1332
1333 self.ifname = self.ifname or ifname
1334 self.dev = _interfaces[self.ifname]
1335 self.network = network
1336 end
1337
1338 function interface._ubus(self, field)
1339 if not _ubusdevcache[self.ifname] then
1340 _ubusdevcache[self.ifname] = utl.ubus("network.device", "status",
1341 { name = self.ifname })
1342 end
1343 if _ubusdevcache[self.ifname] and field then
1344 return _ubusdevcache[self.ifname][field]
1345 end
1346 return _ubusdevcache[self.ifname]
1347 end
1348
1349 function interface.name(self)
1350 return self.wif and self.wif:ifname() or self.ifname
1351 end
1352
1353 function interface.mac(self)
1354 return ipc.checkmac(self:_ubus("macaddr"))
1355 end
1356
1357 function interface.ipaddrs(self)
1358 return self.dev and self.dev.ipaddrs or { }
1359 end
1360
1361 function interface.ip6addrs(self)
1362 return self.dev and self.dev.ip6addrs or { }
1363 end
1364
1365 function interface.type(self)
1366 if self.ifname and self.ifname:byte(1) == 64 then
1367 return "alias"
1368 elseif self.wif or _wifi_iface(self.ifname) then
1369 return "wifi"
1370 elseif _bridge[self.ifname] then
1371 return "bridge"
1372 elseif _tunnel[self.ifname] then
1373 return "tunnel"
1374 elseif self.ifname:match("%.") then
1375 return "vlan"
1376 elseif _switch[self.ifname] then
1377 return "switch"
1378 else
1379 return "ethernet"
1380 end
1381 end
1382
1383 function interface.shortname(self)
1384 if self.wif then
1385 return self.wif:shortname()
1386 else
1387 return self.ifname
1388 end
1389 end
1390
1391 function interface.get_i18n(self)
1392 if self.wif then
1393 return "%s: %s %q" %{
1394 lng.translate("Wireless Network"),
1395 self.wif:active_mode(),
1396 self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id() or "?"
1397 }
1398 else
1399 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1400 end
1401 end
1402
1403 function interface.get_type_i18n(self)
1404 local x = self:type()
1405 if x == "alias" then
1406 return lng.translate("Alias Interface")
1407 elseif x == "wifi" then
1408 return lng.translate("Wireless Adapter")
1409 elseif x == "bridge" then
1410 return lng.translate("Bridge")
1411 elseif x == "switch" then
1412 return lng.translate("Ethernet Switch")
1413 elseif x == "vlan" then
1414 if _switch[self.ifname] then
1415 return lng.translate("Switch VLAN")
1416 else
1417 return lng.translate("Software VLAN")
1418 end
1419 elseif x == "tunnel" then
1420 return lng.translate("Tunnel Interface")
1421 else
1422 return lng.translate("Ethernet Adapter")
1423 end
1424 end
1425
1426 function interface.adminlink(self)
1427 if self.wif then
1428 return self.wif:adminlink()
1429 end
1430 end
1431
1432 function interface.ports(self)
1433 local members = self:_ubus("bridge-members")
1434 if members then
1435 local _, iface
1436 local ifaces = { }
1437 for _, iface in ipairs(members) do
1438 ifaces[#ifaces+1] = interface(iface)
1439 end
1440 end
1441 end
1442
1443 function interface.bridge_id(self)
1444 if self.br then
1445 return self.br.id
1446 else
1447 return nil
1448 end
1449 end
1450
1451 function interface.bridge_stp(self)
1452 if self.br then
1453 return self.br.stp
1454 else
1455 return false
1456 end
1457 end
1458
1459 function interface.is_up(self)
1460 local up = self:_ubus("up")
1461 if up == nil then
1462 up = (self:type() == "alias")
1463 end
1464 return up or false
1465 end
1466
1467 function interface.is_bridge(self)
1468 return (self:type() == "bridge")
1469 end
1470
1471 function interface.is_bridgeport(self)
1472 return self.dev and self.dev.bridge and true or false
1473 end
1474
1475 function interface.tx_bytes(self)
1476 local stat = self:_ubus("statistics")
1477 return stat and stat.tx_bytes or 0
1478 end
1479
1480 function interface.rx_bytes(self)
1481 local stat = self:_ubus("statistics")
1482 return stat and stat.rx_bytes or 0
1483 end
1484
1485 function interface.tx_packets(self)
1486 local stat = self:_ubus("statistics")
1487 return stat and stat.tx_packets or 0
1488 end
1489
1490 function interface.rx_packets(self)
1491 local stat = self:_ubus("statistics")
1492 return stat and stat.rx_packets or 0
1493 end
1494
1495 function interface.get_network(self)
1496 return self:get_networks()[1]
1497 end
1498
1499 function interface.get_networks(self)
1500 if not self.networks then
1501 local nets = { }
1502 local _, net
1503 for _, net in ipairs(_M:get_networks()) do
1504 if net:contains_interface(self.ifname) or
1505 net:ifname() == self.ifname
1506 then
1507 nets[#nets+1] = net
1508 end
1509 end
1510 table.sort(nets, function(a, b) return a.sid < b.sid end)
1511 self.networks = nets
1512 return nets
1513 else
1514 return self.networks
1515 end
1516 end
1517
1518 function interface.get_wifinet(self)
1519 return self.wif
1520 end
1521
1522
1523 wifidev = utl.class()
1524
1525 function wifidev.__init__(self, name)
1526 local t, n = _uci:get("wireless", name)
1527 if t == "wifi-device" and n ~= nil then
1528 self.sid = n
1529 self.iwinfo = _wifi_iwinfo_by_ifname(self.sid, true)
1530 end
1531 self.sid = self.sid or name
1532 self.iwinfo = self.iwinfo or { ifname = self.sid }
1533 end
1534
1535 function wifidev.get(self, opt)
1536 return _get("wireless", self.sid, opt)
1537 end
1538
1539 function wifidev.set(self, opt, val)
1540 return _set("wireless", self.sid, opt, val)
1541 end
1542
1543 function wifidev.name(self)
1544 return self.sid
1545 end
1546
1547 function wifidev.hwmodes(self)
1548 local l = self.iwinfo.hwmodelist
1549 if l and next(l) then
1550 return l
1551 else
1552 return { b = true, g = true }
1553 end
1554 end
1555
1556 function wifidev.get_i18n(self)
1557 local t = self.iwinfo.hardware_name or "Generic"
1558 if self.iwinfo.type == "wl" then
1559 t = "Broadcom"
1560 end
1561
1562 local m = ""
1563 local l = self:hwmodes()
1564 if l.a then m = m .. "a" end
1565 if l.b then m = m .. "b" end
1566 if l.g then m = m .. "g" end
1567 if l.n then m = m .. "n" end
1568 if l.ac then m = "ac" end
1569
1570 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1571 end
1572
1573 function wifidev.is_up(self)
1574 if _ubuswificache[self.sid] then
1575 return (_ubuswificache[self.sid].up == true)
1576 end
1577
1578 return false
1579 end
1580
1581 function wifidev.get_wifinet(self, net)
1582 if _uci:get("wireless", net) == "wifi-iface" then
1583 return wifinet(net)
1584 else
1585 local wnet = _wifi_sid_by_ifname(net)
1586 if wnet then
1587 return wifinet(wnet)
1588 end
1589 end
1590 end
1591
1592 function wifidev.get_wifinets(self)
1593 local nets = { }
1594
1595 _uci:foreach("wireless", "wifi-iface",
1596 function(s)
1597 if s.device == self.sid then
1598 nets[#nets+1] = wifinet(s['.name'])
1599 end
1600 end)
1601
1602 return nets
1603 end
1604
1605 function wifidev.add_wifinet(self, options)
1606 options = options or { }
1607 options.device = self.sid
1608
1609 local wnet = _uci:section("wireless", "wifi-iface", nil, options)
1610 if wnet then
1611 return wifinet(wnet, options)
1612 end
1613 end
1614
1615 function wifidev.del_wifinet(self, net)
1616 if utl.instanceof(net, wifinet) then
1617 net = net.sid
1618 elseif _uci:get("wireless", net) ~= "wifi-iface" then
1619 net = _wifi_sid_by_ifname(net)
1620 end
1621
1622 if net and _uci:get("wireless", net, "device") == self.sid then
1623 _uci:delete("wireless", net)
1624 return true
1625 end
1626
1627 return false
1628 end
1629
1630
1631 wifinet = utl.class()
1632
1633 function wifinet.__init__(self, name, data)
1634 local sid, netid, radioname, radiostate, netstate
1635
1636 -- lookup state by radio#.network# notation
1637 sid = _wifi_sid_by_netid(name)
1638 if sid then
1639 netid = name
1640 radioname, radiostate, netstate = _wifi_state_by_sid(sid)
1641 else
1642 -- lookup state by ifname (e.g. wlan0)
1643 radioname, radiostate, netstate = _wifi_state_by_ifname(name)
1644 if radioname and radiostate and netstate then
1645 sid = netstate.section
1646 netid = _wifi_netid_by_sid(sid)
1647 else
1648 -- lookup state by uci section id (e.g. cfg053579)
1649 radioname, radiostate, netstate = _wifi_state_by_sid(name)
1650 if radioname and radiostate and netstate then
1651 sid = name
1652 netid = _wifi_netid_by_sid(sid)
1653 else
1654 -- no state available, try to resolve from uci
1655 netid, radioname = _wifi_netid_by_sid(name)
1656 if netid and radioname then
1657 sid = name
1658 end
1659 end
1660 end
1661 end
1662
1663 local iwinfo =
1664 (netstate and _wifi_iwinfo_by_ifname(netstate.ifname)) or
1665 (radioname and _wifi_iwinfo_by_ifname(radioname)) or
1666 { ifname = (netid or sid or name) }
1667
1668 self.sid = sid or name
1669 self.wdev = iwinfo.ifname
1670 self.iwinfo = iwinfo
1671 self.netid = netid
1672 self._ubusdata = {
1673 radio = radioname,
1674 dev = radiostate,
1675 net = netstate
1676 }
1677 end
1678
1679 function wifinet.ubus(self, ...)
1680 local n, v = self._ubusdata
1681 for n = 1, select('#', ...) do
1682 if type(v) == "table" then
1683 v = v[select(n, ...)]
1684 else
1685 return nil
1686 end
1687 end
1688 return v
1689 end
1690
1691 function wifinet.get(self, opt)
1692 return _get("wireless", self.sid, opt)
1693 end
1694
1695 function wifinet.set(self, opt, val)
1696 return _set("wireless", self.sid, opt, val)
1697 end
1698
1699 function wifinet.mode(self)
1700 return self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1701 end
1702
1703 function wifinet.ssid(self)
1704 return self:ubus("net", "config", "ssid") or self:get("ssid")
1705 end
1706
1707 function wifinet.bssid(self)
1708 return self:ubus("net", "config", "bssid") or self:get("bssid")
1709 end
1710
1711 function wifinet.network(self)
1712 local net, networks = nil, { }
1713 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1714 networks[#networks+1] = net
1715 end
1716 return networks
1717 end
1718
1719 function wifinet.id(self)
1720 return self.netid
1721 end
1722
1723 function wifinet.name(self)
1724 return self.sid
1725 end
1726
1727 function wifinet.ifname(self)
1728 local ifname = self:ubus("net", "ifname") or self.iwinfo.ifname
1729 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1730 ifname = self.netid
1731 end
1732 return ifname
1733 end
1734
1735 function wifinet.get_device(self)
1736 local dev = self:ubus("radio") or self:get("device")
1737 return dev and wifidev(dev) or nil
1738 end
1739
1740 function wifinet.is_up(self)
1741 local ifc = self:get_interface()
1742 return (ifc and ifc:is_up() or false)
1743 end
1744
1745 function wifinet.active_mode(self)
1746 local m = self.iwinfo.mode or self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1747
1748 if m == "ap" then m = "Master"
1749 elseif m == "sta" then m = "Client"
1750 elseif m == "adhoc" then m = "Ad-Hoc"
1751 elseif m == "mesh" then m = "Mesh"
1752 elseif m == "monitor" then m = "Monitor"
1753 end
1754
1755 return m
1756 end
1757
1758 function wifinet.active_mode_i18n(self)
1759 return lng.translate(self:active_mode())
1760 end
1761
1762 function wifinet.active_ssid(self)
1763 return self.iwinfo.ssid or self:ubus("net", "config", "ssid") or self:get("ssid")
1764 end
1765
1766 function wifinet.active_bssid(self)
1767 return self.iwinfo.bssid or self:ubus("net", "config", "bssid") or self:get("bssid")
1768 end
1769
1770 function wifinet.active_encryption(self)
1771 local enc = self.iwinfo and self.iwinfo.encryption
1772 return enc and enc.description or "-"
1773 end
1774
1775 function wifinet.assoclist(self)
1776 return self.iwinfo.assoclist or { }
1777 end
1778
1779 function wifinet.frequency(self)
1780 local freq = self.iwinfo.frequency
1781 if freq and freq > 0 then
1782 return "%.03f" % (freq / 1000)
1783 end
1784 end
1785
1786 function wifinet.bitrate(self)
1787 local rate = self.iwinfo.bitrate
1788 if rate and rate > 0 then
1789 return (rate / 1000)
1790 end
1791 end
1792
1793 function wifinet.channel(self)
1794 return self.iwinfo.channel or self:ubus("dev", "config", "channel") or
1795 tonumber(self:get("channel"))
1796 end
1797
1798 function wifinet.signal(self)
1799 return self.iwinfo.signal or 0
1800 end
1801
1802 function wifinet.noise(self)
1803 return self.iwinfo.noise or 0
1804 end
1805
1806 function wifinet.country(self)
1807 return self.iwinfo.country or self:ubus("dev", "config", "country") or "00"
1808 end
1809
1810 function wifinet.txpower(self)
1811 local pwr = (self.iwinfo.txpower or 0)
1812 return pwr + self:txpower_offset()
1813 end
1814
1815 function wifinet.txpower_offset(self)
1816 return self.iwinfo.txpower_offset or 0
1817 end
1818
1819 function wifinet.signal_level(self, s, n)
1820 if self:active_bssid() ~= "00:00:00:00:00:00" then
1821 local signal = s or self:signal()
1822 local noise = n or self:noise()
1823
1824 if signal < 0 and noise < 0 then
1825 local snr = -1 * (noise - signal)
1826 return math.floor(snr / 5)
1827 else
1828 return 0
1829 end
1830 else
1831 return -1
1832 end
1833 end
1834
1835 function wifinet.signal_percent(self)
1836 local qc = self.iwinfo.quality or 0
1837 local qm = self.iwinfo.quality_max or 0
1838
1839 if qc > 0 and qm > 0 then
1840 return math.floor((100 / qm) * qc)
1841 else
1842 return 0
1843 end
1844 end
1845
1846 function wifinet.shortname(self)
1847 return "%s %q" %{
1848 lng.translate(self:active_mode()),
1849 self:active_ssid() or self:active_bssid() or self:id()
1850 }
1851 end
1852
1853 function wifinet.get_i18n(self)
1854 return "%s: %s %q (%s)" %{
1855 lng.translate("Wireless Network"),
1856 lng.translate(self:active_mode()),
1857 self:active_ssid() or self:active_bssid() or self:id(),
1858 self:ifname()
1859 }
1860 end
1861
1862 function wifinet.adminlink(self)
1863 local stat, dsp = pcall(require, "luci.dispatcher")
1864 return dsp and dsp.build_url("admin", "network", "wireless", self.netid)
1865 end
1866
1867 function wifinet.get_network(self)
1868 return self:get_networks()[1]
1869 end
1870
1871 function wifinet.get_networks(self)
1872 local nets = { }
1873 local net
1874 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1875 if _uci:get("network", net) == "interface" then
1876 nets[#nets+1] = network(net)
1877 end
1878 end
1879 table.sort(nets, function(a, b) return a.sid < b.sid end)
1880 return nets
1881 end
1882
1883 function wifinet.get_interface(self)
1884 return interface(self:ifname())
1885 end
1886
1887
1888 -- setup base protocols
1889 _M:register_protocol("static")
1890 _M:register_protocol("dhcp")
1891 _M:register_protocol("none")
1892
1893 -- load protocol extensions
1894 local exts = nfs.dir(utl.libpath() .. "/model/network")
1895 if exts then
1896 local ext
1897 for ext in exts do
1898 if ext:match("%.lua$") then
1899 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1900 end
1901 end
1902 end