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