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