libs/core: fix network is_empty() check for wifi-ifaces which are part of multiple...
[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
589 function network(name, proto)
590 if name then
591 local p = proto or _uci_real:get("network", name, "proto")
592 local c = p and _protocols[p] or protocol
593 return c(name)
594 end
595 end
596
597 function protocol.__init__(self, name)
598 self.sid = name
599 end
600
601 function protocol._get(self, opt)
602 local v = _uci_real:get("network", self.sid, opt)
603 if type(v) == "table" then
604 return table.concat(v, " ")
605 end
606 return v or ""
607 end
608
609 function protocol._ubus(self, field)
610 if not _ubusnetcache[self.sid] then
611 _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
612 "status", { })
613 end
614 if _ubusnetcache[self.sid] and field then
615 return _ubusnetcache[self.sid][field]
616 end
617 return _ubusnetcache[self.sid]
618 end
619
620 function protocol.get(self, opt)
621 return _get("network", self.sid, opt)
622 end
623
624 function protocol.set(self, opt, val)
625 return _set("network", self.sid, opt, val)
626 end
627
628 function protocol.ifname(self)
629 local ifname
630 if self:is_floating() then
631 ifname = self:_ubus("l3_device")
632 else
633 ifname = self:_ubus("device")
634 end
635 if not ifname then
636 local num = { }
637 _uci_real:foreach("wireless", "wifi-iface",
638 function(s)
639 if s.device then
640 num[s.device] = num[s.device]
641 and num[s.device] + 1 or 1
642
643 if s.network == self.sid then
644 ifname = "%s.network%d" %{ s.device, num[s.device] }
645 return false
646 end
647 end
648 end)
649 end
650 return ifname
651 end
652
653 function protocol.proto(self)
654 return "none"
655 end
656
657 function protocol.get_i18n(self)
658 local p = self:proto()
659 if p == "none" then
660 return i18n.translate("Unmanaged")
661 elseif p == "static" then
662 return i18n.translate("Static address")
663 elseif p == "dhcp" then
664 return i18n.translate("DHCP client")
665 else
666 return i18n.translate("Unknown")
667 end
668 end
669
670 function protocol.type(self)
671 return self:_get("type")
672 end
673
674 function protocol.name(self)
675 return self.sid
676 end
677
678 function protocol.uptime(self)
679 return self:_ubus("uptime") or 0
680 end
681
682 function protocol.expires(self)
683 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
684 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
685 if a and l then
686 l = l - (nxo.sysinfo().uptime - a)
687 return l > 0 and l or 0
688 end
689 return -1
690 end
691
692 function protocol.metric(self)
693 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
694 end
695
696 function protocol.ipaddr(self)
697 local addrs = self:_ubus("ipv4-address")
698 return addrs and #addrs > 0 and addrs[1].address
699 end
700
701 function protocol.netmask(self)
702 local addrs = self:_ubus("ipv4-address")
703 return addrs and #addrs > 0 and
704 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
705 end
706
707 function protocol.gwaddr(self)
708 local _, route
709 for _, route in ipairs(self:_ubus("route") or { }) do
710 if route.target == "0.0.0.0" and route.mask == 0 then
711 return route.nexthop
712 end
713 end
714 end
715
716 function protocol.dnsaddrs(self)
717 local dns = { }
718 local _, addr
719 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
720 if not addr:match(":") then
721 dns[#dns+1] = addr
722 end
723 end
724 return dns
725 end
726
727 function protocol.ip6addr(self)
728 local addrs = self:_ubus("ipv6-address")
729 return addrs and #addrs > 0
730 and "%s/%d" %{ addrs[1].address, addrs[1].mask }
731 end
732
733 function protocol.gw6addr(self)
734 local _, route
735 for _, route in ipairs(self:_ubus("route") or { }) do
736 if route.target == "::" and route.mask == 0 then
737 return ipc.IPv6(route.nexthop):string()
738 end
739 end
740 end
741
742 function protocol.dns6addrs(self)
743 local dns = { }
744 local _, addr
745 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
746 if addr:match(":") then
747 dns[#dns+1] = addr
748 end
749 end
750 return dns
751 end
752
753 function protocol.is_bridge(self)
754 return (not self:is_virtual() and self:type() == "bridge")
755 end
756
757 function protocol.opkg_package(self)
758 return nil
759 end
760
761 function protocol.is_installed(self)
762 return true
763 end
764
765 function protocol.is_virtual(self)
766 return false
767 end
768
769 function protocol.is_floating(self)
770 return false
771 end
772
773 function protocol.is_empty(self)
774 if self:is_floating() then
775 return false
776 else
777 local rv = true
778
779 if (self:_get("ifname") or ""):match("%S+") then
780 rv = false
781 end
782
783 _uci_real:foreach("wireless", "wifi-iface",
784 function(s)
785 local n
786 for n in utl.imatch(s.network) do
787 if n == self.sid then
788 rv = false
789 return false
790 end
791 end
792 end)
793
794 return rv
795 end
796 end
797
798 function protocol.add_interface(self, ifname)
799 ifname = _M:ifnameof(ifname)
800 if ifname and not self:is_floating() then
801 -- if its a wifi interface, change its network option
802 local wif = _wifi_lookup(ifname)
803 if wif then
804 _append("wireless", wif, "network", self.sid)
805
806 -- add iface to our iface list
807 else
808 _append("network", self.sid, "ifname", ifname)
809 end
810 end
811 end
812
813 function protocol.del_interface(self, ifname)
814 ifname = _M:ifnameof(ifname)
815 if ifname and not self:is_floating() then
816 -- if its a wireless interface, clear its network option
817 local wif = _wifi_lookup(ifname)
818 if wif then _filter("wireless", wif, "network", self.sid) end
819
820 -- remove the interface
821 _filter("network", self.sid, "ifname", ifname)
822 end
823 end
824
825 function protocol.get_interface(self)
826 if self:is_virtual() then
827 _tunnel[self:proto() .. "-" .. self.sid] = true
828 return interface(self:proto() .. "-" .. self.sid, self)
829 elseif self:is_bridge() then
830 _bridge["br-" .. self.sid] = true
831 return interface("br-" .. self.sid, self)
832 else
833 local ifn = nil
834 local num = { }
835 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
836 ifn = ifn:match("^[^:/]+")
837 return ifn and interface(ifn, self)
838 end
839 ifn = nil
840 _uci_real:foreach("wireless", "wifi-iface",
841 function(s)
842 if s.device then
843 num[s.device] = num[s.device] and num[s.device] + 1 or 1
844 if s.network == self.sid then
845 ifn = "%s.network%d" %{ s.device, num[s.device] }
846 return false
847 end
848 end
849 end)
850 return ifn and interface(ifn, self)
851 end
852 end
853
854 function protocol.get_interfaces(self)
855 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
856 local ifaces = { }
857
858 local ifn
859 local nfs = { }
860 for ifn in utl.imatch(self:get("ifname")) do
861 ifn = ifn:match("^[^:/]+")
862 nfs[ifn] = interface(ifn, self)
863 end
864
865 for ifn in utl.kspairs(nfs) do
866 ifaces[#ifaces+1] = nfs[ifn]
867 end
868
869 local num = { }
870 local wfs = { }
871 _uci_real:foreach("wireless", "wifi-iface",
872 function(s)
873 if s.device then
874 num[s.device] = num[s.device] and num[s.device] + 1 or 1
875 if s.network == self.sid then
876 ifn = "%s.network%d" %{ s.device, num[s.device] }
877 wfs[ifn] = interface(ifn, self)
878 end
879 end
880 end)
881
882 for ifn in utl.kspairs(wfs) do
883 ifaces[#ifaces+1] = wfs[ifn]
884 end
885
886 return ifaces
887 end
888 end
889
890 function protocol.contains_interface(self, ifname)
891 ifname = _M:ifnameof(ifname)
892 if not ifname then
893 return false
894 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
895 return true
896 elseif self:is_bridge() and "br-" .. self.sid == ifname then
897 return true
898 else
899 local ifn
900 for ifn in utl.imatch(self:get("ifname")) do
901 ifn = ifn:match("[^:]+")
902 if ifn == ifname then
903 return true
904 end
905 end
906
907 local wif = _wifi_lookup(ifname)
908 if wif then
909 local n
910 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
911 if n == self.sid then
912 return true
913 end
914 end
915 end
916 end
917
918 return false
919 end
920
921 function protocol.adminlink(self)
922 return dsp.build_url("admin", "network", "network", self.sid)
923 end
924
925
926 interface = utl.class()
927
928 function interface.__init__(self, ifname, network)
929 local wif = _wifi_lookup(ifname)
930 if wif then
931 self.wif = wifinet(wif)
932 self.ifname = _uci_state:get("wireless", wif, "ifname")
933 end
934
935 self.ifname = self.ifname or ifname
936 self.dev = _interfaces[self.ifname]
937 self.network = network
938 end
939
940 function interface._ubus(self, field)
941 if not _ubusdevcache[self.ifname] then
942 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
943 { name = self.ifname })
944 end
945 if _ubusdevcache[self.ifname] and field then
946 return _ubusdevcache[self.ifname][field]
947 end
948 return _ubusdevcache[self.ifname]
949 end
950
951 function interface.name(self)
952 return self.wif and self.wif:ifname() or self.ifname
953 end
954
955 function interface.mac(self)
956 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
957 end
958
959 function interface.ipaddrs(self)
960 return self.dev and self.dev.ipaddrs or { }
961 end
962
963 function interface.ip6addrs(self)
964 return self.dev and self.dev.ip6addrs or { }
965 end
966
967 function interface.type(self)
968 if self.wif or _wifi_iface(self.ifname) then
969 return "wifi"
970 elseif _bridge[self.ifname] then
971 return "bridge"
972 elseif _tunnel[self.ifname] then
973 return "tunnel"
974 elseif self.ifname:match("%.") then
975 return "vlan"
976 elseif _switch[self.ifname] then
977 return "switch"
978 else
979 return "ethernet"
980 end
981 end
982
983 function interface.shortname(self)
984 if self.wif then
985 return "%s %q" %{
986 self.wif:active_mode(),
987 self.wif:active_ssid() or self.wif:active_bssid()
988 }
989 else
990 return self.ifname
991 end
992 end
993
994 function interface.get_i18n(self)
995 if self.wif then
996 return "%s: %s %q" %{
997 i18n.translate("Wireless Network"),
998 self.wif:active_mode(),
999 self.wif:active_ssid() or self.wif:active_bssid()
1000 }
1001 else
1002 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1003 end
1004 end
1005
1006 function interface.get_type_i18n(self)
1007 local x = self:type()
1008 if x == "wifi" then
1009 return i18n.translate("Wireless Adapter")
1010 elseif x == "bridge" then
1011 return i18n.translate("Bridge")
1012 elseif x == "switch" then
1013 return i18n.translate("Ethernet Switch")
1014 elseif x == "vlan" then
1015 return i18n.translate("VLAN Interface")
1016 elseif x == "tunnel" then
1017 return i18n.translate("Tunnel Interface")
1018 else
1019 return i18n.translate("Ethernet Adapter")
1020 end
1021 end
1022
1023 function interface.adminlink(self)
1024 if self.wif then
1025 return self.wif:adminlink()
1026 end
1027 end
1028
1029 function interface.ports(self)
1030 local members = self:_ubus("bridge-members")
1031 if members then
1032 local _, iface
1033 local ifaces = { }
1034 for _, iface in ipairs(members) do
1035 ifaces[#ifaces+1] = interface(iface)
1036 end
1037 end
1038 end
1039
1040 function interface.bridge_id(self)
1041 if self.br then
1042 return self.br.id
1043 else
1044 return nil
1045 end
1046 end
1047
1048 function interface.bridge_stp(self)
1049 if self.br then
1050 return self.br.stp
1051 else
1052 return false
1053 end
1054 end
1055
1056 function interface.is_up(self)
1057 if self.wif then
1058 return self.wif:is_up()
1059 else
1060 return self:_ubus("up") or false
1061 end
1062 end
1063
1064 function interface.is_bridge(self)
1065 return (self:type() == "bridge")
1066 end
1067
1068 function interface.is_bridgeport(self)
1069 return self.dev and self.dev.bridge and true or false
1070 end
1071
1072 local function uint(x)
1073 if x then
1074 return (x < 0) and ((2^32) + x) or x
1075 end
1076 return 0
1077 end
1078
1079 function interface.tx_bytes(self)
1080 local stat = self:_ubus("statistics")
1081 return stat and uint(stat.tx_bytes) or 0
1082 end
1083
1084 function interface.rx_bytes(self)
1085 local stat = self:_ubus("statistics")
1086 return stat and uint(stat.rx_bytes) or 0
1087 end
1088
1089 function interface.tx_packets(self)
1090 local stat = self:_ubus("statistics")
1091 return stat and uint(stat.tx_packets) or 0
1092 end
1093
1094 function interface.rx_packets(self)
1095 local stat = self:_ubus("statistics")
1096 return stat and uint(stat.rx_packets) or 0
1097 end
1098
1099 function interface.get_network(self)
1100 return self:get_networks()[1]
1101 end
1102
1103 function interface.get_networks(self)
1104 if not self.networks then
1105 local nets = { }
1106 local _, net
1107 for _, net in ipairs(_M:get_networks()) do
1108 if net:contains_interface(self.ifname) or
1109 net:ifname() == self.ifname
1110 then
1111 nets[#nets+1] = net
1112 end
1113 end
1114 table.sort(nets, function(a, b) return a.sid < b.sid end)
1115 self.networks = nets
1116 return nets
1117 else
1118 return self.networks
1119 end
1120 end
1121
1122 function interface.get_wifinet(self)
1123 return self.wif
1124 end
1125
1126
1127 wifidev = utl.class()
1128
1129 function wifidev.__init__(self, dev)
1130 self.sid = dev
1131 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1132 end
1133
1134 function wifidev.get(self, opt)
1135 return _get("wireless", self.sid, opt)
1136 end
1137
1138 function wifidev.set(self, opt, val)
1139 return _set("wireless", self.sid, opt, val)
1140 end
1141
1142 function wifidev.name(self)
1143 return self.sid
1144 end
1145
1146 function wifidev.hwmodes(self)
1147 local l = self.iwinfo.hwmodelist
1148 if l and next(l) then
1149 return l
1150 else
1151 return { b = true, g = true }
1152 end
1153 end
1154
1155 function wifidev.get_i18n(self)
1156 local t = "Generic"
1157 if self.iwinfo.type == "wl" then
1158 t = "Broadcom"
1159 elseif self.iwinfo.type == "madwifi" then
1160 t = "Atheros"
1161 end
1162
1163 local m = ""
1164 local l = self:hwmodes()
1165 if l.a then m = m .. "a" end
1166 if l.b then m = m .. "b" end
1167 if l.g then m = m .. "g" end
1168 if l.n then m = m .. "n" end
1169
1170 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1171 end
1172
1173 function wifidev.is_up(self)
1174 local up = false
1175
1176 _uci_state:foreach("wireless", "wifi-iface",
1177 function(s)
1178 if s.device == self.sid then
1179 if s.up == "1" then
1180 up = true
1181 return false
1182 end
1183 end
1184 end)
1185
1186 return up
1187 end
1188
1189 function wifidev.get_wifinet(self, net)
1190 if _uci_real:get("wireless", net) == "wifi-iface" then
1191 return wifinet(net)
1192 else
1193 local wnet = _wifi_lookup(net)
1194 if wnet then
1195 return wifinet(wnet)
1196 end
1197 end
1198 end
1199
1200 function wifidev.get_wifinets(self)
1201 local nets = { }
1202
1203 _uci_real:foreach("wireless", "wifi-iface",
1204 function(s)
1205 if s.device == self.sid then
1206 nets[#nets+1] = wifinet(s['.name'])
1207 end
1208 end)
1209
1210 return nets
1211 end
1212
1213 function wifidev.add_wifinet(self, options)
1214 options = options or { }
1215 options.device = self.sid
1216
1217 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1218 if wnet then
1219 return wifinet(wnet, options)
1220 end
1221 end
1222
1223 function wifidev.del_wifinet(self, net)
1224 if utl.instanceof(net, wifinet) then
1225 net = net.sid
1226 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1227 net = _wifi_lookup(net)
1228 end
1229
1230 if net and _uci_real:get("wireless", net, "device") == self.sid then
1231 _uci_real:delete("wireless", net)
1232 return true
1233 end
1234
1235 return false
1236 end
1237
1238
1239 wifinet = utl.class()
1240
1241 function wifinet.__init__(self, net, data)
1242 self.sid = net
1243
1244 local num = { }
1245 local netid
1246 _uci_real:foreach("wireless", "wifi-iface",
1247 function(s)
1248 if s.device then
1249 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1250 if s['.name'] == self.sid then
1251 netid = "%s.network%d" %{ s.device, num[s.device] }
1252 return false
1253 end
1254 end
1255 end)
1256
1257 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1258
1259 self.netid = netid
1260 self.wdev = dev
1261 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1262 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1263 _uci_real:get_all("wireless", self.sid) or { }
1264 end
1265
1266 function wifinet.get(self, opt)
1267 return _get("wireless", self.sid, opt)
1268 end
1269
1270 function wifinet.set(self, opt, val)
1271 return _set("wireless", self.sid, opt, val)
1272 end
1273
1274 function wifinet.mode(self)
1275 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1276 end
1277
1278 function wifinet.ssid(self)
1279 return _uci_state:get("wireless", self.sid, "ssid")
1280 end
1281
1282 function wifinet.bssid(self)
1283 return _uci_state:get("wireless", self.sid, "bssid")
1284 end
1285
1286 function wifinet.network(self)
1287 return _uci_state:get("wifinet", self.sid, "network")
1288 end
1289
1290 function wifinet.id(self)
1291 return self.netid
1292 end
1293
1294 function wifinet.name(self)
1295 return self.sid
1296 end
1297
1298 function wifinet.ifname(self)
1299 local ifname = self.iwinfo.ifname
1300 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1301 ifname = self.wdev
1302 end
1303 return ifname
1304 end
1305
1306 function wifinet.get_device(self)
1307 if self.iwdata.device then
1308 return wifidev(self.iwdata.device)
1309 end
1310 end
1311
1312 function wifinet.is_up(self)
1313 return (self.iwdata.up == "1")
1314 end
1315
1316 function wifinet.active_mode(self)
1317 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1318
1319 if m == "ap" then m = "Master"
1320 elseif m == "sta" then m = "Client"
1321 elseif m == "adhoc" then m = "Ad-Hoc"
1322 elseif m == "mesh" then m = "Mesh"
1323 elseif m == "monitor" then m = "Monitor"
1324 end
1325
1326 return m
1327 end
1328
1329 function wifinet.active_mode_i18n(self)
1330 return i18n.translate(self:active_mode())
1331 end
1332
1333 function wifinet.active_ssid(self)
1334 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1335 end
1336
1337 function wifinet.active_bssid(self)
1338 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1339 end
1340
1341 function wifinet.active_encryption(self)
1342 local enc = self.iwinfo and self.iwinfo.encryption
1343 return enc and enc.description or "-"
1344 end
1345
1346 function wifinet.assoclist(self)
1347 return self.iwinfo.assoclist or { }
1348 end
1349
1350 function wifinet.frequency(self)
1351 local freq = self.iwinfo.frequency
1352 if freq and freq > 0 then
1353 return "%.03f" % (freq / 1000)
1354 end
1355 end
1356
1357 function wifinet.bitrate(self)
1358 local rate = self.iwinfo.bitrate
1359 if rate and rate > 0 then
1360 return (rate / 1000)
1361 end
1362 end
1363
1364 function wifinet.channel(self)
1365 return self.iwinfo.channel or
1366 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1367 end
1368
1369 function wifinet.signal(self)
1370 return self.iwinfo.signal or 0
1371 end
1372
1373 function wifinet.noise(self)
1374 return self.iwinfo.noise or 0
1375 end
1376
1377 function wifinet.country(self)
1378 return self.iwinfo.country or "00"
1379 end
1380
1381 function wifinet.txpower(self)
1382 local pwr = (self.iwinfo.txpower or 0)
1383 return pwr + self:txpower_offset()
1384 end
1385
1386 function wifinet.txpower_offset(self)
1387 return self.iwinfo.txpower_offset or 0
1388 end
1389
1390 function wifinet.signal_level(self, s, n)
1391 if self:active_bssid() ~= "00:00:00:00:00:00" then
1392 local signal = s or self:signal()
1393 local noise = n or self:noise()
1394
1395 if signal < 0 and noise < 0 then
1396 local snr = -1 * (noise - signal)
1397 return math.floor(snr / 5)
1398 else
1399 return 0
1400 end
1401 else
1402 return -1
1403 end
1404 end
1405
1406 function wifinet.signal_percent(self)
1407 local qc = self.iwinfo.quality or 0
1408 local qm = self.iwinfo.quality_max or 0
1409
1410 if qc > 0 and qm > 0 then
1411 return math.floor((100 / qm) * qc)
1412 else
1413 return 0
1414 end
1415 end
1416
1417 function wifinet.shortname(self)
1418 return "%s %q" %{
1419 i18n.translate(self:active_mode()),
1420 self:active_ssid() or self:active_bssid()
1421 }
1422 end
1423
1424 function wifinet.get_i18n(self)
1425 return "%s: %s %q (%s)" %{
1426 i18n.translate("Wireless Network"),
1427 i18n.translate(self:active_mode()),
1428 self:active_ssid() or self:active_bssid(),
1429 self:ifname()
1430 }
1431 end
1432
1433 function wifinet.adminlink(self)
1434 return dsp.build_url("admin", "network", "wireless", self.netid)
1435 end
1436
1437 function wifinet.get_network(self)
1438 return self:get_networks()[1]
1439 end
1440
1441 function wifinet.get_networks(self)
1442 local nets = { }
1443 local net
1444 for net in utl.imatch(tostring(self.iwdata.network)) do
1445 if _uci_real:get("network", net) == "interface" then
1446 nets[#nets+1] = network(net)
1447 end
1448 end
1449 table.sort(nets, function(a, b) return a.sid < b.sid end)
1450 return nets
1451 end
1452
1453 function wifinet.get_interface(self)
1454 return interface(self:ifname())
1455 end
1456
1457
1458 -- setup base protocols
1459 _M:register_protocol("static")
1460 _M:register_protocol("dhcp")
1461 _M:register_protocol("none")
1462
1463 -- load protocol extensions
1464 local exts = nfs.dir(utl.libpath() .. "/model/network")
1465 if exts then
1466 local ext
1467 for ext in exts do
1468 if ext:match("%.lua$") then
1469 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1470 end
1471 end
1472 end