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