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