libs/core: more fixes in network model
[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 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
782 local ifaces = { }
783
784 local ifn
785 local nfs = { }
786 for ifn in utl.imatch(self:get("ifname")) do
787 ifn = ifn:match("^[^:/]+")
788 nfs[ifn] = interface(ifn, self)
789 end
790
791 for ifn in utl.kspairs(nfs) do
792 ifaces[#ifaces+1] = nfs[ifn]
793 end
794
795 local num = { }
796 local wfs = { }
797 uci_r:foreach("wireless", "wifi-iface",
798 function(s)
799 if s.device then
800 num[s.device] = num[s.device] and num[s.device] + 1 or 1
801 if s.network == self.sid then
802 ifn = "%s.network%d" %{ s.device, num[s.device] }
803 wfs[ifn] = interface(ifn, self)
804 end
805 end
806 end)
807
808 for ifn in utl.kspairs(wfs) do
809 ifaces[#ifaces+1] = wfs[ifn]
810 end
811
812 return ifaces
813 end
814 end
815
816 function network.contains_interface(self, ifname)
817 if type(ifname) ~= "string" then
818 ifname = ifname:name()
819 else
820 ifname = ifname:match("[^%s:]+")
821 end
822
823 if self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
824 return true
825 elseif self:is_bridge() and "br-" .. self.sid == ifname then
826 return true
827 else
828 local ifn
829 for ifn in utl.imatch(self:get("ifname")) do
830 ifn = ifn:match("[^:]+")
831 if ifn == ifname then
832 return true
833 end
834 end
835
836 local wif = _wifi_lookup(ifname)
837 if wif then
838 return (uci_r:get("wireless", wif, "network") == self.sid)
839 end
840 end
841
842 return false
843 end
844
845 function network.adminlink(self)
846 return dsp.build_url("admin", "network", "network", self.sid)
847 end
848
849
850 interface = utl.class()
851 function interface.__init__(self, ifname, network)
852 local wif = _wifi_lookup(ifname)
853 if wif then self.wif = wifinet(wif) end
854
855 self.ifname = self.ifname or ifname
856 self.dev = ifs[self.ifname]
857 self.network = network
858 end
859
860 function interface.name(self)
861 return self.wif and self.wif:ifname() or self.ifname
862 end
863
864 function interface.mac(self)
865 return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper()
866 end
867
868 function interface.ipaddrs(self)
869 return self.dev and self.dev.ipaddrs or { }
870 end
871
872 function interface.ip6addrs(self)
873 return self.dev and self.dev.ip6addrs or { }
874 end
875
876 function interface.type(self)
877 if self.wif or _wifi_iface(self.ifname) then
878 return "wifi"
879 elseif brs[self.ifname] then
880 return "bridge"
881 elseif tns[self.ifname] then
882 return "tunnel"
883 elseif self.ifname:match("%.") then
884 return "vlan"
885 elseif sws[self.ifname] then
886 return "switch"
887 else
888 return "ethernet"
889 end
890 end
891
892 function interface.shortname(self)
893 if self.wif then
894 return "%s %q" %{
895 self.wif:active_mode(),
896 self.wif:active_ssid() or self.wif:active_bssid()
897 }
898 else
899 return self.ifname
900 end
901 end
902
903 function interface.get_i18n(self)
904 if self.wif then
905 return "%s: %s %q" %{
906 i18n.translate("Wireless Network"),
907 self.wif:active_mode(),
908 self.wif:active_ssid() or self.wif:active_bssid()
909 }
910 else
911 return "%s: %q" %{ self:get_type_i18n(), self:name() }
912 end
913 end
914
915 function interface.get_type_i18n(self)
916 local x = self:type()
917 if x == "wifi" then
918 return i18n.translate("Wireless Adapter")
919 elseif x == "bridge" then
920 return i18n.translate("Bridge")
921 elseif x == "switch" then
922 return i18n.translate("Ethernet Switch")
923 elseif x == "vlan" then
924 return i18n.translate("VLAN Interface")
925 elseif x == "tunnel" then
926 return i18n.translate("Tunnel Interface")
927 else
928 return i18n.translate("Ethernet Adapter")
929 end
930 end
931
932 function interface.adminlink(self)
933 if self.wif then
934 return self.wif:adminlink()
935 end
936 end
937
938 function interface.ports(self)
939 if self.br then
940 local iface
941 local ifaces = { }
942 for _, iface in ipairs(self.br.ifnames) do
943 ifaces[#ifaces+1] = interface(iface.name)
944 end
945 return ifaces
946 end
947 end
948
949 function interface.bridge_id(self)
950 if self.br then
951 return self.br.id
952 else
953 return nil
954 end
955 end
956
957 function interface.bridge_stp(self)
958 if self.br then
959 return self.br.stp
960 else
961 return false
962 end
963 end
964
965 function interface.is_up(self)
966 if self.wif then
967 return self.wif:is_up()
968 else
969 return self.dev and self.dev.flags and self.dev.flags.up or false
970 end
971 end
972
973 function interface.is_bridge(self)
974 return (self:type() == "bridge")
975 end
976
977 function interface.is_bridgeport(self)
978 return self.dev and self.dev.bridge and true or false
979 end
980
981 function interface.tx_bytes(self)
982 return self.dev and self.dev.stats
983 and self.dev.stats.tx_bytes or 0
984 end
985
986 function interface.rx_bytes(self)
987 return self.dev and self.dev.stats
988 and self.dev.stats.rx_bytes or 0
989 end
990
991 function interface.tx_packets(self)
992 return self.dev and self.dev.stats
993 and self.dev.stats.tx_packets or 0
994 end
995
996 function interface.rx_packets(self)
997 return self.dev and self.dev.stats
998 and self.dev.stats.rx_packets or 0
999 end
1000
1001 function interface.get_network(self)
1002 if not self.network then
1003 if self.dev and self.dev.network then
1004 self.network = _M:get_network(self.dev.network)
1005 end
1006 end
1007
1008 if not self.network then
1009 local net
1010 for _, net in ipairs(_M:get_networks()) do
1011 if net:contains_interface(self.ifname) or
1012 net:ifname() == self.ifname
1013 then
1014 self.network = net
1015 return net
1016 end
1017 end
1018 else
1019 return self.network
1020 end
1021 end
1022
1023 function interface.get_wifinet(self)
1024 return self.wif
1025 end
1026
1027
1028 wifidev = utl.class()
1029 function wifidev.__init__(self, dev)
1030 self.sid = dev
1031 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1032 end
1033
1034 function wifidev.get(self, opt)
1035 return _get("wireless", self.sid, opt)
1036 end
1037
1038 function wifidev.set(self, opt, val)
1039 return _set("wireless", self.sid, opt, val)
1040 end
1041
1042 function wifidev.name(self)
1043 return self.sid
1044 end
1045
1046 function wifidev.hwmodes(self)
1047 local l = self.iwinfo.hwmodelist
1048 if l and next(l) then
1049 return l
1050 else
1051 return { b = true, g = true }
1052 end
1053 end
1054
1055 function wifidev.get_i18n(self)
1056 local t = "Generic"
1057 if self.iwinfo.type == "wl" then
1058 t = "Broadcom"
1059 elseif self.iwinfo.type == "madwifi" then
1060 t = "Atheros"
1061 end
1062
1063 local m = ""
1064 local l = self:hwmodes()
1065 if l.a then m = m .. "a" end
1066 if l.b then m = m .. "b" end
1067 if l.g then m = m .. "g" end
1068 if l.n then m = m .. "n" end
1069
1070 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1071 end
1072
1073 function wifidev.is_up(self)
1074 local up = false
1075
1076 uci_s:foreach("wireless", "wifi-iface",
1077 function(s)
1078 if s.device == self.sid then
1079 if s.up == "1" then
1080 up = true
1081 return false
1082 end
1083 end
1084 end)
1085
1086 return up
1087 end
1088
1089 function wifidev.get_wifinet(self, net)
1090 if uci_r:get("wireless", net) == "wifi-iface" then
1091 return wifinet(net)
1092 else
1093 local wnet = _wifi_lookup(net)
1094 if wnet then
1095 return wifinet(wnet)
1096 end
1097 end
1098 end
1099
1100 function wifidev.get_wifinets(self)
1101 local nets = { }
1102
1103 uci_r:foreach("wireless", "wifi-iface",
1104 function(s)
1105 if s.device == self.sid then
1106 nets[#nets+1] = wifinet(s['.name'])
1107 end
1108 end)
1109
1110 return nets
1111 end
1112
1113 function wifidev.add_wifinet(self, options)
1114 options = options or { }
1115 options.device = self.sid
1116
1117 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1118 if wnet then
1119 return wifinet(wnet, options)
1120 end
1121 end
1122
1123 function wifidev.del_wifinet(self, net)
1124 if utl.instanceof(net, wifinet) then
1125 net = net.sid
1126 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1127 net = _wifi_lookup(net)
1128 end
1129
1130 if net and uci_r:get("wireless", net, "device") == self.sid then
1131 uci_r:delete("wireless", net)
1132 return true
1133 end
1134
1135 return false
1136 end
1137
1138
1139 wifinet = utl.class()
1140 function wifinet.__init__(self, net, data)
1141 self.sid = net
1142
1143 local num = { }
1144 local netid
1145 uci_r:foreach("wireless", "wifi-iface",
1146 function(s)
1147 if s.device then
1148 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1149 if s['.name'] == self.sid then
1150 netid = "%s.network%d" %{ s.device, num[s.device] }
1151 return false
1152 end
1153 end
1154 end)
1155
1156 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1157
1158 self.netid = netid
1159 self.wdev = dev
1160 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1161 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1162 uci_r:get_all("wireless", self.sid) or { }
1163 end
1164
1165 function wifinet.get(self, opt)
1166 return _get("wireless", self.sid, opt)
1167 end
1168
1169 function wifinet.set(self, opt, val)
1170 return _set("wireless", self.sid, opt, val)
1171 end
1172
1173 function wifinet.mode(self)
1174 return uci_s:get("wireless", self.sid, "mode") or "ap"
1175 end
1176
1177 function wifinet.ssid(self)
1178 return uci_s:get("wireless", self.sid, "ssid")
1179 end
1180
1181 function wifinet.bssid(self)
1182 return uci_s:get("wireless", self.sid, "bssid")
1183 end
1184
1185 function wifinet.network(self)
1186 return uci_s:get("wifinet", self.sid, "network")
1187 end
1188
1189 function wifinet.id(self)
1190 return self.netid
1191 end
1192
1193 function wifinet.name(self)
1194 return self.sid
1195 end
1196
1197 function wifinet.ifname(self)
1198 local ifname = self.iwinfo.ifname
1199 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1200 ifname = self.wdev
1201 end
1202 return ifname
1203 end
1204
1205 function wifinet.get_device(self)
1206 if self.iwdata.device then
1207 return wifidev(self.iwdata.device)
1208 end
1209 end
1210
1211 function wifinet.is_up(self)
1212 return (self.iwdata.up == "1")
1213 end
1214
1215 function wifinet.active_mode(self)
1216 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1217
1218 if m == "ap" then m = "Master"
1219 elseif m == "sta" then m = "Client"
1220 elseif m == "adhoc" then m = "Ad-Hoc"
1221 elseif m == "mesh" then m = "Mesh"
1222 elseif m == "monitor" then m = "Monitor"
1223 end
1224
1225 return m
1226 end
1227
1228 function wifinet.active_mode_i18n(self)
1229 return i18n.translate(self:active_mode())
1230 end
1231
1232 function wifinet.active_ssid(self)
1233 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1234 end
1235
1236 function wifinet.active_bssid(self)
1237 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1238 end
1239
1240 function wifinet.active_encryption(self)
1241 local enc = self.iwinfo and self.iwinfo.encryption
1242 return enc and enc.description or "-"
1243 end
1244
1245 function wifinet.assoclist(self)
1246 return self.iwinfo.assoclist or { }
1247 end
1248
1249 function wifinet.frequency(self)
1250 local freq = self.iwinfo.frequency
1251 if freq and freq > 0 then
1252 return "%.03f" % (freq / 1000)
1253 end
1254 end
1255
1256 function wifinet.bitrate(self)
1257 local rate = self.iwinfo.bitrate
1258 if rate and rate > 0 then
1259 return (rate / 1000)
1260 end
1261 end
1262
1263 function wifinet.channel(self)
1264 return self.iwinfo.channel or
1265 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1266 end
1267
1268 function wifinet.signal(self)
1269 return self.iwinfo.signal or 0
1270 end
1271
1272 function wifinet.noise(self)
1273 return self.iwinfo.noise or 0
1274 end
1275
1276 function wifinet.country(self)
1277 return self.iwinfo.country or "00"
1278 end
1279
1280 function wifinet.txpower(self)
1281 return self.iwinfo.txpower or 0
1282 end
1283
1284 function wifinet.signal_level(self, s, n)
1285 if self:active_bssid() ~= "00:00:00:00:00:00" then
1286 local signal = s or self:signal()
1287 local noise = n or self:noise()
1288
1289 if signal < 0 and noise < 0 then
1290 local snr = -1 * (noise - signal)
1291 return math.floor(snr / 5)
1292 else
1293 return 0
1294 end
1295 else
1296 return -1
1297 end
1298 end
1299
1300 function wifinet.signal_percent(self)
1301 local qc = self.iwinfo.quality or 0
1302 local qm = self.iwinfo.quality_max or 0
1303
1304 if qc > 0 and qm > 0 then
1305 return math.floor((100 / qm) * qc)
1306 else
1307 return 0
1308 end
1309 end
1310
1311 function wifinet.shortname(self)
1312 return "%s %q" %{
1313 i18n.translate(self:active_mode()),
1314 self:active_ssid() or self:active_bssid()
1315 }
1316 end
1317
1318 function wifinet.get_i18n(self)
1319 return "%s: %s %q (%s)" %{
1320 i18n.translate("Wireless Network"),
1321 i18n.translate(self:active_mode()),
1322 self:active_ssid() or self:active_bssid(),
1323 self:ifname()
1324 }
1325 end
1326
1327 function wifinet.adminlink(self)
1328 return dsp.build_url("admin", "network", "wireless", self.netid)
1329 end
1330
1331 function wifinet.get_network(self)
1332 if uci_r:get("network", self.iwdata.network) == "interface" then
1333 return network(self.iwdata.network)
1334 end
1335 end
1336
1337 function wifinet.get_interface(self)
1338 return interface(self:ifname())
1339 end