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