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