3c0964841a7545daaf3e8b9aedb69a7324c27764
[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 or list 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 if ifc and ifc.ip6addrs then
609 local a
610 for _, a in ipairs(ifc.ip6addrs) do
611 if not a:is6linklocal() then
612 ip6 = a:string()
613 break
614 end
615 end
616 end
617 end
618 return ip6
619 end
620
621 function network.gw6addr(self)
622 local ip6 = self:_ip("ip6gw", 6)
623 if not ip6 then
624 local dr6 = sys.net.defaultroute6()
625 if dr6 and dr6.device == self:ifname() then
626 return dr6.nexthop:string()
627 end
628 end
629 return ip6
630 end
631
632 function network.dns6addrs(self)
633 return self:_ip("dns", 6, true)
634 end
635
636 function network.is_bridge(self)
637 return (self:type() == "bridge")
638 end
639
640 function network.is_virtual(self)
641 local p = self:proto()
642 return (
643 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
644 p == "pppoe" or p == "pppoa"
645 )
646 end
647
648 function network.is_empty(self)
649 if self:is_virtual() then
650 return false
651 else
652 local rv = true
653
654 if (self:_get("ifname") or ""):match("%S+") then
655 rv = false
656 end
657
658 uci_r:foreach("wireless", "wifi-iface",
659 function(s)
660 if s.network == self.sid then
661 rv = false
662 return false
663 end
664 end)
665
666 return rv
667 end
668 end
669
670 function network.add_interface(self, ifname)
671 if not self:is_virtual() then
672 if type(ifname) ~= "string" then
673 ifname = ifname:name()
674 else
675 ifname = ifname:match("[^%s:]+")
676 end
677
678 -- remove the interface from all ifaces
679 uci_r:foreach("network", "interface",
680 function(s)
681 _list_del("network", s['.name'], "ifname", ifname)
682 end)
683
684 -- if its a wifi interface, change its network option
685 local wif = _wifi_lookup(ifname)
686 if wif then
687 uci_r:set("wireless", wif, "network", self.sid)
688
689 -- add iface to our iface list
690 else
691 _list_add("network", self.sid, "ifname", ifname)
692 end
693 end
694 end
695
696 function network.del_interface(self, ifname)
697 if not self:is_virtual() then
698 if utl.instanceof(ifname, interface) then
699 ifname = ifname:name()
700 else
701 ifname = ifname:match("[^%s:]+")
702 end
703
704 -- if its a wireless interface, clear its network option
705 local wif = _wifi_lookup(ifname)
706 if wif then uci_r:delete("wireless", wif, "network") end
707
708 -- remove the interface
709 _list_del("network", self.sid, "ifname", ifname)
710 end
711 end
712
713 function network.get_interfaces(self)
714 local ifaces = { }
715
716 local ifn
717 if self:is_virtual() then
718 ifn = self:proto() .. "-" .. self.sid
719 ifaces = { interface(ifn) }
720 else
721 local nfs = { }
722 for ifn in utl.imatch(self:get("ifname")) do
723 ifn = ifn:match("[^:]+")
724 nfs[ifn] = interface(ifn)
725 end
726
727 for ifn in utl.kspairs(nfs) do
728 ifaces[#ifaces+1] = nfs[ifn]
729 end
730
731 local num = { }
732 local wfs = { }
733 uci_r:foreach("wireless", "wifi-iface",
734 function(s)
735 if s.device then
736 num[s.device] = num[s.device] and num[s.device] + 1 or 1
737 if s.network == self.sid then
738 ifn = "%s.network%d" %{ s.device, num[s.device] }
739 wfs[ifn] = interface(ifn)
740 end
741 end
742 end)
743
744 for ifn in utl.kspairs(wfs) do
745 ifaces[#ifaces+1] = wfs[ifn]
746 end
747 end
748
749 return ifaces
750 end
751
752 function network.contains_interface(self, ifname)
753 if type(ifname) ~= "string" then
754 ifname = ifname:name()
755 else
756 ifname = ifname:match("[^%s:]+")
757 end
758
759 local ifn
760 if self:is_virtual() then
761 ifn = self:proto() .. "-" .. self.sid
762 return ifname == ifn
763 else
764 for ifn in utl.imatch(self:get("ifname")) do
765 ifn = ifn:match("[^:]+")
766 if ifn == ifname then
767 return true
768 end
769 end
770
771 local wif = _wifi_lookup(ifname)
772 if wif then
773 return (uci_r:get("wireless", wif, "network") == self.sid)
774 end
775 end
776
777 return false
778 end
779
780 function network.adminlink(self)
781 return dsp.build_url("admin", "network", "network", self.sid)
782 end
783
784
785 interface = utl.class()
786 function interface.__init__(self, ifname)
787 local wif = _wifi_lookup(ifname)
788 if wif then self.wif = wifinet(wif) end
789
790 self.ifname = self.ifname or ifname
791 self.dev = ifs[self.ifname]
792 end
793
794 function interface.name(self)
795 return self.wif and self.wif:ifname() or self.ifname
796 end
797
798 function interface.mac(self)
799 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
800 end
801
802 function interface.ipaddrs(self)
803 return self.dev and self.dev.ipaddrs or { }
804 end
805
806 function interface.ip6addrs(self)
807 return self.dev and self.dev.ip6addrs or { }
808 end
809
810 function interface.type(self)
811 if self.wif or _wifi_iface(self.ifname) then
812 return "wifi"
813 elseif brs[self.ifname] then
814 return "bridge"
815 elseif sws[self.ifname] or self.ifname:match("%.") then
816 return "switch"
817 else
818 return "ethernet"
819 end
820 end
821
822 function interface.shortname(self)
823 if self.wif then
824 return "%s %q" %{
825 self.wif:active_mode(),
826 self.wif:active_ssid() or self.wif:active_bssid()
827 }
828 else
829 return self.ifname
830 end
831 end
832
833 function interface.get_i18n(self)
834 if self.wif then
835 return "%s: %s %q" %{
836 i18n.translate("Wireless Network"),
837 self.wif:active_mode(),
838 self.wif:active_ssid() or self.wif:active_bssid()
839 }
840 else
841 return "%s: %q" %{ self:get_type_i18n(), self:name() }
842 end
843 end
844
845 function interface.get_type_i18n(self)
846 local x = self:type()
847 if x == "wifi" then
848 return i18n.translate("Wireless Adapter")
849 elseif x == "bridge" then
850 return i18n.translate("Bridge")
851 elseif x == "switch" then
852 return i18n.translate("Ethernet Switch")
853 else
854 return i18n.translate("Ethernet Adapter")
855 end
856 end
857
858 function interface.adminlink(self)
859 if self.wif then
860 return self.wif:adminlink()
861 end
862 end
863
864 function interface.ports(self)
865 if self.br then
866 local iface
867 local ifaces = { }
868 for _, iface in ipairs(self.br.ifnames) do
869 ifaces[#ifaces+1] = interface(iface.name)
870 end
871 return ifaces
872 end
873 end
874
875 function interface.bridge_id(self)
876 if self.br then
877 return self.br.id
878 else
879 return nil
880 end
881 end
882
883 function interface.bridge_stp(self)
884 if self.br then
885 return self.br.stp
886 else
887 return false
888 end
889 end
890
891 function interface.is_up(self)
892 if self.wif then
893 return self.wif:is_up()
894 else
895 return self.dev and self.dev.flags and self.dev.flags.up or false
896 end
897 end
898
899 function interface.is_bridge(self)
900 return (self:type() == "bridge")
901 end
902
903 function interface.is_bridgeport(self)
904 return self.dev and self.dev.bridge and true or false
905 end
906
907 function interface.tx_bytes(self)
908 return self.dev and self.dev.stats
909 and self.dev.stats.tx_bytes or 0
910 end
911
912 function interface.rx_bytes(self)
913 return self.dev and self.dev.stats
914 and self.dev.stats.rx_bytes or 0
915 end
916
917 function interface.tx_packets(self)
918 return self.dev and self.dev.stats
919 and self.dev.stats.tx_packets or 0
920 end
921
922 function interface.rx_packets(self)
923 return self.dev and self.dev.stats
924 and self.dev.stats.rx_packets or 0
925 end
926
927 function interface.get_network(self)
928 if self.dev and self.dev.network then
929 self.network = _M:get_network(self.dev.network)
930 end
931
932 if not self.network then
933 local net
934 for _, net in ipairs(_M:get_networks()) do
935 if net:contains_interface(self.ifname) or
936 net:ifname() == self.ifname
937 then
938 self.network = net
939 return net
940 end
941 end
942 else
943 return self.network
944 end
945 end
946
947 function interface.get_wifinet(self)
948 return self.wif
949 end
950
951
952 wifidev = utl.class()
953 function wifidev.__init__(self, dev)
954 self.sid = dev
955 end
956
957 function wifidev.get(self, opt)
958 return _get("wireless", self.sid, opt)
959 end
960
961 function wifidev.set(self, opt, val)
962 return _set("wireless", self.sid, opt, val)
963 end
964
965 function wifidev.name(self)
966 return self.sid
967 end
968
969 function wifidev.is_up(self)
970 local up = false
971
972 uci_s:foreach("wireless", "wifi-iface",
973 function(s)
974 if s.device == self.sid then
975 if s.up == "1" then
976 up = true
977 return false
978 end
979 end
980 end)
981
982 return up
983 end
984
985 function wifidev.get_wifinet(self, net)
986 if uci_r:get("wireless", net) == "wifi-iface" then
987 return wifinet(net)
988 else
989 local wnet = _wifi_lookup(net)
990 if wnet then
991 return wifinet(wnet)
992 end
993 end
994 end
995
996 function wifidev.get_wifinets(self)
997 local nets = { }
998
999 uci_r:foreach("wireless", "wifi-iface",
1000 function(s)
1001 if s.device == self.sid then
1002 nets[#nets+1] = wifinet(s['.name'])
1003 end
1004 end)
1005
1006 return nets
1007 end
1008
1009 function wifidev.add_wifinet(self, options)
1010 options = options or { }
1011 options.device = self.sid
1012
1013 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1014 if wnet then
1015 return wifinet(wnet, options)
1016 end
1017 end
1018
1019 function wifidev.del_wifinet(self, net)
1020 if utl.instanceof(net, wifinet) then
1021 net = net.sid
1022 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1023 net = _wifi_lookup(net)
1024 end
1025
1026 if net and uci_r:get("wireless", net, "device") == self.sid then
1027 uci_r:delete("wireless", net)
1028 return true
1029 end
1030
1031 return false
1032 end
1033
1034
1035 wifinet = utl.class()
1036 function wifinet.__init__(self, net, data)
1037 self.sid = net
1038
1039 local num = { }
1040 local netid
1041 uci_r:foreach("wireless", "wifi-iface",
1042 function(s)
1043 if s.device then
1044 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1045 if s['.name'] == self.sid then
1046 netid = "%s.network%d" %{ s.device, num[s.device] }
1047 return false
1048 end
1049 end
1050 end)
1051
1052 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1053
1054 self.netid = netid
1055 self.wdev = dev
1056 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1057 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1058 uci_r:get_all("wireless", self.sid) or { }
1059 end
1060
1061 function wifinet.get(self, opt)
1062 return _get("wireless", self.sid, opt)
1063 end
1064
1065 function wifinet.set(self, opt, val)
1066 return _set("wireless", self.sid, opt, val)
1067 end
1068
1069 function wifinet.mode(self)
1070 return uci_s:get("wireless", self.sid, "mode") or "ap"
1071 end
1072
1073 function wifinet.ssid(self)
1074 return uci_s:get("wireless", self.sid, "ssid")
1075 end
1076
1077 function wifinet.bssid(self)
1078 return uci_s:get("wireless", self.sid, "bssid")
1079 end
1080
1081 function wifinet.network(self)
1082 return uci_s:get("wifinet", self.sid, "network")
1083 end
1084
1085 function wifinet.name(self)
1086 return self.sid
1087 end
1088
1089 function wifinet.ifname(self)
1090 local ifname = self.iwinfo.ifname
1091 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1092 ifname = self.wdev
1093 end
1094 return ifname
1095 end
1096
1097 function wifinet.get_device(self)
1098 if self.iwdata.device then
1099 return wifidev(self.iwdata.device)
1100 end
1101 end
1102
1103 function wifinet.is_up(self)
1104 return (self.iwdata.up == "1")
1105 end
1106
1107 function wifinet.active_mode(self)
1108 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1109
1110 if m == "ap" then m = "Master"
1111 elseif m == "sta" then m = "Client"
1112 elseif m == "adhoc" then m = "Ad-Hoc"
1113 elseif m == "mesh" then m = "Mesh"
1114 elseif m == "monitor" then m = "Monitor"
1115 end
1116
1117 return m
1118 end
1119
1120 function wifinet.active_mode_i18n(self)
1121 return i18n.translate(self:active_mode())
1122 end
1123
1124 function wifinet.active_ssid(self)
1125 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1126 end
1127
1128 function wifinet.active_bssid(self)
1129 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1130 end
1131
1132 function wifinet.active_encryption(self)
1133 local enc = self.iwinfo and self.iwinfo.encryption
1134 return enc and enc.description or "-"
1135 end
1136
1137 function wifinet.assoclist(self)
1138 return self.iwinfo.assoclist or { }
1139 end
1140
1141 function wifinet.frequency(self)
1142 local freq = self.iwinfo.frequency
1143 if freq and freq > 0 then
1144 return "%.03f" % (freq / 1000)
1145 end
1146 end
1147
1148 function wifinet.bitrate(self)
1149 local rate = self.iwinfo.bitrate
1150 if rate and rate > 0 then
1151 return (rate / 1000)
1152 end
1153 end
1154
1155 function wifinet.channel(self)
1156 return self.iwinfo.channel or
1157 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1158 end
1159
1160 function wifinet.signal(self)
1161 return self.iwinfo.signal or 0
1162 end
1163
1164 function wifinet.noise(self)
1165 return self.iwinfo.noise or 0
1166 end
1167
1168 function wifinet.signal_level(self, s, n)
1169 if self:active_bssid() ~= "00:00:00:00:00:00" then
1170 local signal = s or self:signal()
1171 local noise = n or self:noise()
1172
1173 if signal < 0 and noise < 0 then
1174 local snr = -1 * (noise - signal)
1175 return math.floor(snr / 5)
1176 else
1177 return 0
1178 end
1179 else
1180 return -1
1181 end
1182 end
1183
1184 function wifinet.signal_percent(self)
1185 local qc = self.iwinfo.quality or 0
1186 local qm = self.iwinfo.quality_max or 0
1187
1188 if qc > 0 and qm > 0 then
1189 return math.floor((100 / qm) * qc)
1190 else
1191 return 0
1192 end
1193 end
1194
1195 function wifinet.shortname(self)
1196 return "%s %q" %{
1197 i18n.translate(self:active_mode()),
1198 self:active_ssid() or self:active_bssid()
1199 }
1200 end
1201
1202 function wifinet.get_i18n(self)
1203 return "%s: %s %q (%s)" %{
1204 i18n.translate("Wireless Network"),
1205 i18n.translate(self:active_mode()),
1206 self:active_ssid() or self:active_bssid(),
1207 self:ifname()
1208 }
1209 end
1210
1211 function wifinet.adminlink(self)
1212 return dsp.build_url("admin", "network", "wireless", self.netid)
1213 end
1214
1215 function wifinet.get_network(self)
1216 if uci_r:get("network", self.iwdata.network) == "interface" then
1217 return network(self.iwdata.network)
1218 end
1219 end
1220
1221 function wifinet.get_interface(self)
1222 return interface(self:ifname())
1223 end