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