Merge pull request #980 from NvrBst/pull-request-upnp_description
[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.ip6prefix(self)
954 local prefix = self:_ubus("ipv6-prefix")
955 if prefix and #prefix > 0 then
956 return "%s/%d" %{ prefix[1].address, prefix[1].mask }
957 end
958 end
959
960 function protocol.is_bridge(self)
961 return (not self:is_virtual() and self:type() == "bridge")
962 end
963
964 function protocol.opkg_package(self)
965 return nil
966 end
967
968 function protocol.is_installed(self)
969 return true
970 end
971
972 function protocol.is_virtual(self)
973 return false
974 end
975
976 function protocol.is_floating(self)
977 return false
978 end
979
980 function protocol.is_empty(self)
981 if self:is_floating() then
982 return false
983 else
984 local rv = true
985
986 if (self:_get("ifname") or ""):match("%S+") then
987 rv = false
988 end
989
990 _uci:foreach("wireless", "wifi-iface",
991 function(s)
992 local n
993 for n in utl.imatch(s.network) do
994 if n == self.sid then
995 rv = false
996 return false
997 end
998 end
999 end)
1000
1001 return rv
1002 end
1003 end
1004
1005 function protocol.add_interface(self, ifname)
1006 ifname = _M:ifnameof(ifname)
1007 if ifname and not self:is_floating() then
1008 -- if its a wifi interface, change its network option
1009 local wif = _wifi_lookup(ifname)
1010 if wif then
1011 _append("wireless", wif, "network", self.sid)
1012
1013 -- add iface to our iface list
1014 else
1015 _append("network", self.sid, "ifname", ifname)
1016 end
1017 end
1018 end
1019
1020 function protocol.del_interface(self, ifname)
1021 ifname = _M:ifnameof(ifname)
1022 if ifname and not self:is_floating() then
1023 -- if its a wireless interface, clear its network option
1024 local wif = _wifi_lookup(ifname)
1025 if wif then _filter("wireless", wif, "network", self.sid) end
1026
1027 -- remove the interface
1028 _filter("network", self.sid, "ifname", ifname)
1029 end
1030 end
1031
1032 function protocol.get_interface(self)
1033 if self:is_virtual() then
1034 _tunnel[self:proto() .. "-" .. self.sid] = true
1035 return interface(self:proto() .. "-" .. self.sid, self)
1036 elseif self:is_bridge() then
1037 _bridge["br-" .. self.sid] = true
1038 return interface("br-" .. self.sid, self)
1039 else
1040 local ifn = nil
1041 local num = { }
1042 for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
1043 ifn = ifn:match("^[^:/]+")
1044 return ifn and interface(ifn, self)
1045 end
1046 ifn = nil
1047 _uci:foreach("wireless", "wifi-iface",
1048 function(s)
1049 if s.device then
1050 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1051
1052 local net
1053 for net in utl.imatch(s.network) do
1054 if net == self.sid then
1055 ifn = "%s.network%d" %{ s.device, num[s.device] }
1056 return false
1057 end
1058 end
1059 end
1060 end)
1061 return ifn and interface(ifn, self)
1062 end
1063 end
1064
1065 function protocol.get_interfaces(self)
1066 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
1067 local ifaces = { }
1068
1069 local ifn
1070 local nfs = { }
1071 for ifn in utl.imatch(self:get("ifname")) do
1072 ifn = ifn:match("^[^:/]+")
1073 nfs[ifn] = interface(ifn, self)
1074 end
1075
1076 for ifn in utl.kspairs(nfs) do
1077 ifaces[#ifaces+1] = nfs[ifn]
1078 end
1079
1080 local num = { }
1081 local wfs = { }
1082 _uci:foreach("wireless", "wifi-iface",
1083 function(s)
1084 if s.device then
1085 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1086
1087 local net
1088 for net in utl.imatch(s.network) do
1089 if net == self.sid then
1090 ifn = "%s.network%d" %{ s.device, num[s.device] }
1091 wfs[ifn] = interface(ifn, self)
1092 end
1093 end
1094 end
1095 end)
1096
1097 for ifn in utl.kspairs(wfs) do
1098 ifaces[#ifaces+1] = wfs[ifn]
1099 end
1100
1101 return ifaces
1102 end
1103 end
1104
1105 function protocol.contains_interface(self, ifname)
1106 ifname = _M:ifnameof(ifname)
1107 if not ifname then
1108 return false
1109 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
1110 return true
1111 elseif self:is_bridge() and "br-" .. self.sid == ifname then
1112 return true
1113 else
1114 local ifn
1115 for ifn in utl.imatch(self:get("ifname")) do
1116 ifn = ifn:match("[^:]+")
1117 if ifn == ifname then
1118 return true
1119 end
1120 end
1121
1122 local wif = _wifi_lookup(ifname)
1123 if wif then
1124 local n
1125 for n in utl.imatch(_uci:get("wireless", wif, "network")) do
1126 if n == self.sid then
1127 return true
1128 end
1129 end
1130 end
1131 end
1132
1133 return false
1134 end
1135
1136 function protocol.adminlink(self)
1137 return dsp.build_url("admin", "network", "network", self.sid)
1138 end
1139
1140
1141 interface = utl.class()
1142
1143 function interface.__init__(self, ifname, network)
1144 local wif = _wifi_lookup(ifname)
1145 if wif then
1146 self.wif = wifinet(wif)
1147 self.ifname = _wifi_state("section", wif, "ifname")
1148 end
1149
1150 self.ifname = self.ifname or ifname
1151 self.dev = _interfaces[self.ifname]
1152 self.network = network
1153 end
1154
1155 function interface._ubus(self, field)
1156 if not _ubusdevcache[self.ifname] then
1157 _ubusdevcache[self.ifname] = utl.ubus("network.device", "status",
1158 { name = self.ifname })
1159 end
1160 if _ubusdevcache[self.ifname] and field then
1161 return _ubusdevcache[self.ifname][field]
1162 end
1163 return _ubusdevcache[self.ifname]
1164 end
1165
1166 function interface.name(self)
1167 return self.wif and self.wif:ifname() or self.ifname
1168 end
1169
1170 function interface.mac(self)
1171 local mac = self:_ubus("macaddr")
1172 return mac and mac:upper()
1173 end
1174
1175 function interface.ipaddrs(self)
1176 return self.dev and self.dev.ipaddrs or { }
1177 end
1178
1179 function interface.ip6addrs(self)
1180 return self.dev and self.dev.ip6addrs or { }
1181 end
1182
1183 function interface.type(self)
1184 if self.wif or _wifi_iface(self.ifname) then
1185 return "wifi"
1186 elseif _bridge[self.ifname] then
1187 return "bridge"
1188 elseif _tunnel[self.ifname] then
1189 return "tunnel"
1190 elseif self.ifname:match("%.") then
1191 return "vlan"
1192 elseif _switch[self.ifname] then
1193 return "switch"
1194 else
1195 return "ethernet"
1196 end
1197 end
1198
1199 function interface.shortname(self)
1200 if self.wif then
1201 return self.wif:shortname()
1202 else
1203 return self.ifname
1204 end
1205 end
1206
1207 function interface.get_i18n(self)
1208 if self.wif then
1209 return "%s: %s %q" %{
1210 lng.translate("Wireless Network"),
1211 self.wif:active_mode(),
1212 self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id()
1213 }
1214 else
1215 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1216 end
1217 end
1218
1219 function interface.get_type_i18n(self)
1220 local x = self:type()
1221 if x == "wifi" then
1222 return lng.translate("Wireless Adapter")
1223 elseif x == "bridge" then
1224 return lng.translate("Bridge")
1225 elseif x == "switch" then
1226 return lng.translate("Ethernet Switch")
1227 elseif x == "vlan" then
1228 if _switch[self.ifname] then
1229 return lng.translate("Switch VLAN")
1230 else
1231 return lng.translate("Software VLAN")
1232 end
1233 elseif x == "tunnel" then
1234 return lng.translate("Tunnel Interface")
1235 else
1236 return lng.translate("Ethernet Adapter")
1237 end
1238 end
1239
1240 function interface.adminlink(self)
1241 if self.wif then
1242 return self.wif:adminlink()
1243 end
1244 end
1245
1246 function interface.ports(self)
1247 local members = self:_ubus("bridge-members")
1248 if members then
1249 local _, iface
1250 local ifaces = { }
1251 for _, iface in ipairs(members) do
1252 ifaces[#ifaces+1] = interface(iface)
1253 end
1254 end
1255 end
1256
1257 function interface.bridge_id(self)
1258 if self.br then
1259 return self.br.id
1260 else
1261 return nil
1262 end
1263 end
1264
1265 function interface.bridge_stp(self)
1266 if self.br then
1267 return self.br.stp
1268 else
1269 return false
1270 end
1271 end
1272
1273 function interface.is_up(self)
1274 return self:_ubus("up") or false
1275 end
1276
1277 function interface.is_bridge(self)
1278 return (self:type() == "bridge")
1279 end
1280
1281 function interface.is_bridgeport(self)
1282 return self.dev and self.dev.bridge and true or false
1283 end
1284
1285 function interface.tx_bytes(self)
1286 local stat = self:_ubus("statistics")
1287 return stat and stat.tx_bytes or 0
1288 end
1289
1290 function interface.rx_bytes(self)
1291 local stat = self:_ubus("statistics")
1292 return stat and stat.rx_bytes or 0
1293 end
1294
1295 function interface.tx_packets(self)
1296 local stat = self:_ubus("statistics")
1297 return stat and stat.tx_packets or 0
1298 end
1299
1300 function interface.rx_packets(self)
1301 local stat = self:_ubus("statistics")
1302 return stat and stat.rx_packets or 0
1303 end
1304
1305 function interface.get_network(self)
1306 return self:get_networks()[1]
1307 end
1308
1309 function interface.get_networks(self)
1310 if not self.networks then
1311 local nets = { }
1312 local _, net
1313 for _, net in ipairs(_M:get_networks()) do
1314 if net:contains_interface(self.ifname) or
1315 net:ifname() == self.ifname
1316 then
1317 nets[#nets+1] = net
1318 end
1319 end
1320 table.sort(nets, function(a, b) return a.sid < b.sid end)
1321 self.networks = nets
1322 return nets
1323 else
1324 return self.networks
1325 end
1326 end
1327
1328 function interface.get_wifinet(self)
1329 return self.wif
1330 end
1331
1332
1333 wifidev = utl.class()
1334
1335 function wifidev.__init__(self, dev)
1336 self.sid = dev
1337 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1338 end
1339
1340 function wifidev.get(self, opt)
1341 return _get("wireless", self.sid, opt)
1342 end
1343
1344 function wifidev.set(self, opt, val)
1345 return _set("wireless", self.sid, opt, val)
1346 end
1347
1348 function wifidev.name(self)
1349 return self.sid
1350 end
1351
1352 function wifidev.hwmodes(self)
1353 local l = self.iwinfo.hwmodelist
1354 if l and next(l) then
1355 return l
1356 else
1357 return { b = true, g = true }
1358 end
1359 end
1360
1361 function wifidev.get_i18n(self)
1362 local t = "Generic"
1363 if self.iwinfo.type == "wl" then
1364 t = "Broadcom"
1365 end
1366
1367 local m = ""
1368 local l = self:hwmodes()
1369 if l.a then m = m .. "a" end
1370 if l.b then m = m .. "b" end
1371 if l.g then m = m .. "g" end
1372 if l.n then m = m .. "n" end
1373 if l.ac then m = "ac" end
1374
1375 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1376 end
1377
1378 function wifidev.is_up(self)
1379 if _ubuswificache[self.sid] then
1380 return (_ubuswificache[self.sid].up == true)
1381 end
1382
1383 return false
1384 end
1385
1386 function wifidev.get_wifinet(self, net)
1387 if _uci:get("wireless", net) == "wifi-iface" then
1388 return wifinet(net)
1389 else
1390 local wnet = _wifi_lookup(net)
1391 if wnet then
1392 return wifinet(wnet)
1393 end
1394 end
1395 end
1396
1397 function wifidev.get_wifinets(self)
1398 local nets = { }
1399
1400 _uci:foreach("wireless", "wifi-iface",
1401 function(s)
1402 if s.device == self.sid then
1403 nets[#nets+1] = wifinet(s['.name'])
1404 end
1405 end)
1406
1407 return nets
1408 end
1409
1410 function wifidev.add_wifinet(self, options)
1411 options = options or { }
1412 options.device = self.sid
1413
1414 local wnet = _uci:section("wireless", "wifi-iface", nil, options)
1415 if wnet then
1416 return wifinet(wnet, options)
1417 end
1418 end
1419
1420 function wifidev.del_wifinet(self, net)
1421 if utl.instanceof(net, wifinet) then
1422 net = net.sid
1423 elseif _uci:get("wireless", net) ~= "wifi-iface" then
1424 net = _wifi_lookup(net)
1425 end
1426
1427 if net and _uci:get("wireless", net, "device") == self.sid then
1428 _uci:delete("wireless", net)
1429 return true
1430 end
1431
1432 return false
1433 end
1434
1435
1436 wifinet = utl.class()
1437
1438 function wifinet.__init__(self, net, data)
1439 self.sid = net
1440
1441 local n = 0
1442 local num = { }
1443 local netid, sid
1444 _uci:foreach("wireless", "wifi-iface",
1445 function(s)
1446 n = n + 1
1447 if s.device then
1448 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1449 if s['.name'] == self.sid then
1450 sid = "@wifi-iface[%d]" % n
1451 netid = "%s.network%d" %{ s.device, num[s.device] }
1452 return false
1453 end
1454 end
1455 end)
1456
1457 if sid then
1458 local _, k, r, i
1459 for k, r in pairs(_ubuswificache) do
1460 if type(r) == "table" and
1461 type(r.interfaces) == "table"
1462 then
1463 for _, i in ipairs(r.interfaces) do
1464 if type(i) == "table" and i.section == sid then
1465 self._ubusdata = {
1466 radio = k,
1467 dev = r,
1468 net = i
1469 }
1470 end
1471 end
1472 end
1473 end
1474 end
1475
1476 local dev = _wifi_state("section", self.sid, "ifname") or netid
1477
1478 self.netid = netid
1479 self.wdev = dev
1480 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1481 end
1482
1483 function wifinet.ubus(self, ...)
1484 local n, v = self._ubusdata
1485 for n = 1, select('#', ...) do
1486 if type(v) == "table" then
1487 v = v[select(n, ...)]
1488 else
1489 return nil
1490 end
1491 end
1492 return v
1493 end
1494
1495 function wifinet.get(self, opt)
1496 return _get("wireless", self.sid, opt)
1497 end
1498
1499 function wifinet.set(self, opt, val)
1500 return _set("wireless", self.sid, opt, val)
1501 end
1502
1503 function wifinet.mode(self)
1504 return self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1505 end
1506
1507 function wifinet.ssid(self)
1508 return self:ubus("net", "config", "ssid") or self:get("ssid")
1509 end
1510
1511 function wifinet.bssid(self)
1512 return self:ubus("net", "config", "bssid") or self:get("bssid")
1513 end
1514
1515 function wifinet.network(self)
1516 local net, networks = nil, { }
1517 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1518 networks[#networks+1] = net
1519 end
1520 return networks
1521 end
1522
1523 function wifinet.id(self)
1524 return self.netid
1525 end
1526
1527 function wifinet.name(self)
1528 return self.sid
1529 end
1530
1531 function wifinet.ifname(self)
1532 local ifname = self:ubus("net", "ifname") or self.iwinfo.ifname
1533 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1534 ifname = self.wdev
1535 end
1536 return ifname
1537 end
1538
1539 function wifinet.get_device(self)
1540 local dev = self:ubus("radio") or self:get("device")
1541 return dev and wifidev(dev) or nil
1542 end
1543
1544 function wifinet.is_up(self)
1545 local ifc = self:get_interface()
1546 return (ifc and ifc:is_up() or false)
1547 end
1548
1549 function wifinet.active_mode(self)
1550 local m = self.iwinfo.mode or self:ubus("net", "config", "mode") or self:get("mode") or "ap"
1551
1552 if m == "ap" then m = "Master"
1553 elseif m == "sta" then m = "Client"
1554 elseif m == "adhoc" then m = "Ad-Hoc"
1555 elseif m == "mesh" then m = "Mesh"
1556 elseif m == "monitor" then m = "Monitor"
1557 end
1558
1559 return m
1560 end
1561
1562 function wifinet.active_mode_i18n(self)
1563 return lng.translate(self:active_mode())
1564 end
1565
1566 function wifinet.active_ssid(self)
1567 return self.iwinfo.ssid or self:ubus("net", "config", "ssid") or self:get("ssid")
1568 end
1569
1570 function wifinet.active_bssid(self)
1571 return self.iwinfo.bssid or self:ubus("net", "config", "bssid") or self:get("bssid")
1572 end
1573
1574 function wifinet.active_encryption(self)
1575 local enc = self.iwinfo and self.iwinfo.encryption
1576 return enc and enc.description or "-"
1577 end
1578
1579 function wifinet.assoclist(self)
1580 return self.iwinfo.assoclist or { }
1581 end
1582
1583 function wifinet.frequency(self)
1584 local freq = self.iwinfo.frequency
1585 if freq and freq > 0 then
1586 return "%.03f" % (freq / 1000)
1587 end
1588 end
1589
1590 function wifinet.bitrate(self)
1591 local rate = self.iwinfo.bitrate
1592 if rate and rate > 0 then
1593 return (rate / 1000)
1594 end
1595 end
1596
1597 function wifinet.channel(self)
1598 return self.iwinfo.channel or self:ubus("dev", "config", "channel") or
1599 tonumber(self:get("channel"))
1600 end
1601
1602 function wifinet.signal(self)
1603 return self.iwinfo.signal or 0
1604 end
1605
1606 function wifinet.noise(self)
1607 return self.iwinfo.noise or 0
1608 end
1609
1610 function wifinet.country(self)
1611 return self.iwinfo.country or self:ubus("dev", "config", "country") or "00"
1612 end
1613
1614 function wifinet.txpower(self)
1615 local pwr = (self.iwinfo.txpower or 0)
1616 return pwr + self:txpower_offset()
1617 end
1618
1619 function wifinet.txpower_offset(self)
1620 return self.iwinfo.txpower_offset or 0
1621 end
1622
1623 function wifinet.signal_level(self, s, n)
1624 if self:active_bssid() ~= "00:00:00:00:00:00" then
1625 local signal = s or self:signal()
1626 local noise = n or self:noise()
1627
1628 if signal < 0 and noise < 0 then
1629 local snr = -1 * (noise - signal)
1630 return math.floor(snr / 5)
1631 else
1632 return 0
1633 end
1634 else
1635 return -1
1636 end
1637 end
1638
1639 function wifinet.signal_percent(self)
1640 local qc = self.iwinfo.quality or 0
1641 local qm = self.iwinfo.quality_max or 0
1642
1643 if qc > 0 and qm > 0 then
1644 return math.floor((100 / qm) * qc)
1645 else
1646 return 0
1647 end
1648 end
1649
1650 function wifinet.shortname(self)
1651 return "%s %q" %{
1652 lng.translate(self:active_mode()),
1653 self:active_ssid() or self:active_bssid() or self:id()
1654 }
1655 end
1656
1657 function wifinet.get_i18n(self)
1658 return "%s: %s %q (%s)" %{
1659 lng.translate("Wireless Network"),
1660 lng.translate(self:active_mode()),
1661 self:active_ssid() or self:active_bssid() or self:id(),
1662 self:ifname()
1663 }
1664 end
1665
1666 function wifinet.adminlink(self)
1667 return dsp.build_url("admin", "network", "wireless", self.netid)
1668 end
1669
1670 function wifinet.get_network(self)
1671 return self:get_networks()[1]
1672 end
1673
1674 function wifinet.get_networks(self)
1675 local nets = { }
1676 local net
1677 for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
1678 if _uci:get("network", net) == "interface" then
1679 nets[#nets+1] = network(net)
1680 end
1681 end
1682 table.sort(nets, function(a, b) return a.sid < b.sid end)
1683 return nets
1684 end
1685
1686 function wifinet.get_interface(self)
1687 return interface(self:ifname())
1688 end
1689
1690
1691 -- setup base protocols
1692 _M:register_protocol("static")
1693 _M:register_protocol("dhcp")
1694 _M:register_protocol("none")
1695
1696 -- load protocol extensions
1697 local exts = nfs.dir(utl.libpath() .. "/model/network")
1698 if exts then
1699 local ext
1700 for ext in exts do
1701 if ext:match("%.lua$") then
1702 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1703 end
1704 end
1705 end