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