libs/core: fix various bugs 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, 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:del(c, s, o, v)
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("^3g-%w") or x:match("^ppp-%w") or x:match("^pppoe-%w") or
158 x:match("^pppoa-%w") or x == "lo"
159 )
160 end
161
162
163 function init(cursor)
164 uci_r = cursor 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 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
246 if uci_r:section("network", "interface", n, options) then
247 return network(n)
248 end
249 end
250 end
251
252 function get_network(self, n)
253 if n and uci_r:get("network", n) == "interface" then
254 return network(n)
255 end
256 end
257
258 function get_networks(self)
259 local nets = { }
260 local nls = { }
261
262 uci_r:foreach("network", "interface",
263 function(s)
264 nls[s['.name']] = network(s['.name'])
265 end)
266
267 local n
268 for n in utl.kspairs(nls) do
269 nets[#nets+1] = nls[n]
270 end
271
272 return nets
273 end
274
275 function del_network(self, n)
276 local r = uci_r:delete("network", n)
277 if r then
278 uci_r:foreach("network", "alias",
279 function(s)
280 if s.interface == n then
281 uci_r:delete("network", s['.name'])
282 end
283 end)
284
285 uci_r:foreach("network", "route",
286 function(s)
287 if s.interface == n then
288 uci_r:delete("network", s['.name'])
289 end
290 end)
291
292 uci_r:foreach("network", "route6",
293 function(s)
294 if s.interface == n then
295 uci_r:delete("network", s['.name'])
296 end
297 end)
298
299 uci_r:foreach("wireless", "wifi-iface",
300 function(s)
301 if s.network == n then
302 uci_r:delete("wireless", s['.name'], "network")
303 end
304 end)
305
306 uci_r:delete("network", n)
307 end
308 return r
309 end
310
311 function rename_network(self, old, new)
312 local r
313 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
314 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
315
316 if r then
317 uci_r:foreach("network", "alias",
318 function(s)
319 if s.interface == old then
320 uci_r:set("network", s['.name'], "interface", new)
321 end
322 end)
323
324 uci_r:foreach("network", "route",
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", "route6",
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("wireless", "wifi-iface",
339 function(s)
340 if s.network == old then
341 uci_r:set("wireless", s['.name'], "network", new)
342 end
343 end)
344
345 uci_r:delete("network", old)
346 end
347 end
348 return r or false
349 end
350
351 function get_interface(self, i)
352 if ifs[i] or _wifi_iface(i) then
353 return interface(i)
354 else
355 local ifc
356 local num = { }
357 uci_r:foreach("wireless", "wifi-iface",
358 function(s)
359 if s.device then
360 num[s.device] = num[s.device] and num[s.device] + 1 or 1
361 if s['.name'] == i then
362 ifc = interface(
363 "%s.network%d" %{s.device, num[s.device] })
364 return false
365 end
366 end
367 end)
368 return ifc
369 end
370 end
371
372 function get_interfaces(self)
373 local iface
374 local ifaces = { }
375
376 -- find normal interfaces
377 for iface in utl.kspairs(ifs) do
378 if not _iface_ignore(iface) and not _wifi_iface(iface) then
379 ifaces[#ifaces+1] = interface(iface)
380 end
381 end
382
383 -- find wifi interfaces
384 local num = { }
385 local wfs = { }
386 uci_r:foreach("wireless", "wifi-iface",
387 function(s)
388 if s.device then
389 num[s.device] = num[s.device] and num[s.device] + 1 or 1
390 local i = "%s.network%d" %{ s.device, num[s.device] }
391 wfs[i] = interface(i)
392 end
393 end)
394
395 for iface in utl.kspairs(wfs) do
396 ifaces[#ifaces+1] = wfs[iface]
397 end
398
399 return ifaces
400 end
401
402 function ignore_interface(self, x)
403 return _iface_ignore(x)
404 end
405
406 function get_wifidev(self, dev)
407 if uci_r:get("wireless", dev) == "wifi-device" then
408 return wifidev(dev)
409 end
410 end
411
412 function get_wifidevs(self)
413 local devs = { }
414 local wfd = { }
415
416 uci_r:foreach("wireless", "wifi-device",
417 function(s) wfd[#wfd+1] = s['.name'] end)
418
419 local dev
420 for _, dev in utl.vspairs(wfd) do
421 devs[#devs+1] = wifidev(dev)
422 end
423
424 return devs
425 end
426
427 function get_wifinet(self, net)
428 local wnet = _wifi_lookup(net)
429 if wnet then
430 return wifinet(wnet)
431 end
432 end
433
434 function add_wifinet(self, net, options)
435 if type(options) == "table" and options.device and
436 uci_r:get("wireless", options.device) == "wifi-device"
437 then
438 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
439 return wifinet(wnet)
440 end
441 end
442
443 function del_wifinet(self, net)
444 local wnet = _wifi_lookup(net)
445 if wnet then
446 uci_r:delete("wireless", wnet)
447 return true
448 end
449 return false
450 end
451
452
453 network = utl.class()
454
455 function network.__init__(self, name)
456 self.sid = name
457 end
458
459 function network._get(self, opt)
460 local v = uci_r:get("network", self.sid, opt)
461 if type(v) == "table" then
462 return table.concat(v, " ")
463 end
464 return v or ""
465 end
466
467 function network.get(self, opt)
468 return _get("network", self.sid, opt)
469 end
470
471 function network.set(self, opt, val)
472 return _set("network", self.sid, opt, val)
473 end
474
475 function network.ifname(self)
476 local p = self:proto()
477 if self:is_bridge() then
478 return "br-" .. self.sid
479 elseif self:is_virtual() then
480 return p .. "-" .. self.sid
481 else
482 local dev = self:_get("ifname") or
483 uci_r:get("network", self.sid, "ifname")
484
485 dev = dev and dev:match("%S+")
486
487 if not dev then
488 uci_r:foreach("wireless", "wifi-iface",
489 function(s)
490 if s.device then
491 num[s.device] = num[s.device]
492 and num[s.device] + 1 or 1
493
494 if s.network == self.sid then
495 dev = "%s.network%d" %{ s.device, num[s.device] }
496 return false
497 end
498 end
499 end)
500 end
501
502 return dev
503 end
504 end
505
506 function network.device(self)
507 local dev = self:_get("device")
508 if not dev or dev:match("[^%w%-%.%s]") then
509 dev = uci_r:get("network", self.sid, "ifname")
510 end
511 return dev
512 end
513
514 function network.proto(self)
515 return self:_get("proto") or "none"
516 end
517
518 function network.type(self)
519 return self:_get("type")
520 end
521
522 function network.name(self)
523 return self.sid
524 end
525
526 function network.is_bridge(self)
527 return (self:type() == "bridge")
528 end
529
530 function network.is_virtual(self)
531 local p = self:proto()
532 return (
533 p == "3g" or p == "6in4" or p == "ppp" or
534 p == "pppoe" or p == "pppoa"
535 )
536 end
537
538 function network.is_empty(self)
539 if self:is_virtual() then
540 return false
541 else
542 local rv = true
543
544 if (self:_get("ifname") or ""):match("%S+") then
545 rv = false
546 end
547
548 uci_r:foreach("wireless", "wifi-iface",
549 function(s)
550 if s.network == self.sid then
551 rv = false
552 return false
553 end
554 end)
555
556 return rv
557 end
558 end
559
560 function network.add_interface(self, ifname)
561 if not self:is_virtual() then
562 if type(ifname) ~= "string" then
563 ifname = ifname:name()
564 else
565 ifname = ifname:match("[^%s:]+")
566 end
567
568 -- remove the interface from all ifaces
569 uci_r:foreach("network", "interface",
570 function(s)
571 _list_del("network", s['.name'], "ifname", ifname)
572 end)
573
574 -- if its a wifi interface, change its network option
575 local wif = _wifi_lookup(ifname)
576 if wif then
577 uci_r:set("wireless", wif, "network", self.sid)
578
579 -- add iface to our iface list
580 else
581 _list_add("network", self.sid, "ifname", ifname)
582 end
583 end
584 end
585
586 function network.del_interface(self, ifname)
587 if not self:is_virtual() then
588 if utl.instanceof(ifname, interface) then
589 ifname = ifname:name()
590 else
591 ifname = ifname:match("[^%s:]+")
592 end
593
594 -- if its a wireless interface, clear its network option
595 local wif = _wifi_lookup(ifname)
596 if wif then uci_r:delete("wireless", wif, "network") end
597
598 -- remove the interface
599 _list_del("network", self.sid, "ifname", ifname)
600 end
601 end
602
603 function network.get_interfaces(self)
604 local ifaces = { }
605
606 local ifn
607 if self:is_virtual() then
608 ifn = self:proto() .. "-" .. self.sid
609 ifaces = { interface(ifn) }
610 else
611 local nfs = { }
612 for ifn in self:_get("ifname"):gmatch("%S+") do
613 ifn = ifn:match("[^:]+")
614 nfs[ifn] = interface(ifn)
615 end
616
617 for ifn in utl.kspairs(nfs) do
618 ifaces[#ifaces+1] = nfs[ifn]
619 end
620
621 local num = { }
622 local wfs = { }
623 uci_r:foreach("wireless", "wifi-iface",
624 function(s)
625 if s.device then
626 num[s.device] = num[s.device] and num[s.device] + 1 or 1
627 if s.network == self.sid then
628 ifn = "%s.network%d" %{ s.device, num[s.device] }
629 wfs[ifn] = interface(ifn)
630 end
631 end
632 end)
633
634 for ifn in utl.kspairs(wfs) do
635 ifaces[#ifaces+1] = wfs[ifn]
636 end
637 end
638
639 return ifaces
640 end
641
642 function network.contains_interface(self, ifname)
643 if type(ifname) ~= "string" then
644 ifname = ifname:name()
645 else
646 ifname = ifname:match("[^%s:]+")
647 end
648
649 local ifn
650 if self:is_virtual() then
651 ifn = self:proto() .. "-" .. self.sid
652 return ifname == ifn
653 else
654 for ifn in self:_get("ifname"):gmatch("%S+") do
655 ifn = ifn:match("[^:]+")
656 if ifn == ifname then
657 return true
658 end
659 end
660
661 local wif = _wifi_lookup(ifname)
662 if wif then
663 return (uci_r:get("wireless", wif, "network") == self.sid)
664 end
665 end
666
667 return false
668 end
669
670 function network.adminlink(self)
671 return dsp.build_url("admin", "network", "network", self.sid)
672 end
673
674
675 interface = utl.class()
676 function interface.__init__(self, ifname)
677 local wif = _wifi_lookup(ifname)
678 if wif then self.wif = wifinet(wif) end
679
680 self.ifname = self.ifname or ifname
681 self.dev = ifs[self.ifname]
682 end
683
684 function interface.name(self)
685 return self.wif and self.wif:ifname() or self.ifname
686 end
687
688 function interface.mac(self)
689 return self.dev and self.dev or "00:00:00:00:00:00"
690 end
691
692 function interface.ipaddrs(self)
693 return self.dev and self.dev.ipaddrs or { }
694 end
695
696 function interface.ip6addrs(self)
697 return self.dev and self.dev.ip6addrs or { }
698 end
699
700 function interface.type(self)
701 if self.wif or _wifi_iface(self.ifname) then
702 return "wifi"
703 elseif brs[self.ifname] then
704 return "bridge"
705 elseif sws[self.ifname] or self.ifname:match("%.") then
706 return "switch"
707 else
708 return "ethernet"
709 end
710 end
711
712 function interface.shortname(self)
713 if self.wif then
714 return "%s %q" %{
715 self.wif:active_mode(),
716 self.wif:active_ssid() or self.wif:active_bssid()
717 }
718 else
719 return self.ifname
720 end
721 end
722
723 function interface.get_i18n(self)
724 if self.wif then
725 return "%s: %s %q" %{
726 i18n.translate("Wireless Network"),
727 self.wif:active_mode(),
728 self.wif:active_ssid() or self.wif:active_bssid()
729 }
730 else
731 return "%s: %q" %{ self:get_type_i18n(), self:name() }
732 end
733 end
734
735 function interface.get_type_i18n(self)
736 local x = self:type()
737 if x == "wifi" then
738 return i18n.translate("Wireless Adapter")
739 elseif x == "bridge" then
740 return i18n.translate("Bridge")
741 elseif x == "switch" then
742 return i18n.translate("Ethernet Switch")
743 else
744 return i18n.translate("Ethernet Adapter")
745 end
746 end
747
748 function interface.adminlink(self)
749 if self.wif then
750 return self.wif:adminlink()
751 end
752 end
753
754 function interface.ports(self)
755 if self.br then
756 local iface
757 local ifaces = { }
758 for _, iface in ipairs(self.br.ifnames) do
759 ifaces[#ifaces+1] = interface(iface.name)
760 end
761 return ifaces
762 end
763 end
764
765 function interface.bridge_id(self)
766 if self.br then
767 return self.br.id
768 else
769 return nil
770 end
771 end
772
773 function interface.bridge_stp(self)
774 if self.br then
775 return self.br.stp
776 else
777 return false
778 end
779 end
780
781 function interface.is_up(self)
782 if self.wif then
783 return self.wif:is_up()
784 else
785 return self.dev and self.dev.flags and self.dev.flags.up or false
786 end
787 end
788
789 function interface.is_bridge(self)
790 return (self:type() == "bridge")
791 end
792
793 function interface.is_bridgeport(self)
794 return self.dev and self.dev.bridge and true or false
795 end
796
797 function interface.tx_bytes(self)
798 return self.dev and self.dev.stats
799 and self.dev.stats.tx_bytes or 0
800 end
801
802 function interface.rx_bytes(self)
803 return self.dev and self.dev.stats
804 and self.dev.stats.rx_bytes or 0
805 end
806
807 function interface.tx_packets(self)
808 return self.dev and self.dev.stats
809 and self.dev.stats.tx_packets or 0
810 end
811
812 function interface.rx_packets(self)
813 return self.dev and self.dev.stats
814 and self.dev.stats.rx_packets or 0
815 end
816
817 function interface.get_network(self)
818 if self.dev and self.dev.network then
819 self.network = _M:get_network(self.dev.network)
820 end
821
822 if not self.network then
823 local net
824 for _, net in ipairs(_M:get_networks()) do
825 if net:contains_interface(self.ifname) then
826 self.network = net
827 return net
828 end
829 end
830 else
831 return self.network
832 end
833 end
834
835 function interface.get_wifinet(self)
836 return self.wif
837 end
838
839
840 wifidev = utl.class()
841 function wifidev.__init__(self, dev)
842 self.sid = dev
843 end
844
845 function wifidev.get(self, opt)
846 return _get("wireless", self.sid, opt)
847 end
848
849 function wifidev.set(self, opt, val)
850 return _set("wireless", self.sid, opt, val)
851 end
852
853 function wifidev.name(self)
854 return self.sid
855 end
856
857 function wifidev.is_up(self)
858 local up = false
859
860 uci_s:foreach("wireless", "wifi-iface",
861 function(s)
862 if s.device == self.sid then
863 if s.up == "1" then
864 up = true
865 return false
866 end
867 end
868 end)
869
870 return up
871 end
872
873 function wifidev.get_wifinet(self, net)
874 if uci_r:get("wireless", net) == "wifi-iface" then
875 return wifinet(net)
876 else
877 local wnet = _wifi_lookup(net)
878 if wnet then
879 return wifinet(wnet)
880 end
881 end
882 end
883
884 function wifidev.get_wifinets(self)
885 local nets = { }
886
887 uci_r:foreach("wireless", "wifi-iface",
888 function(s)
889 if s.device == self.sid then
890 nets[#nets+1] = wifinet(s['.name'])
891 end
892 end)
893
894 return nets
895 end
896
897 function wifidev.add_wifinet(self, options)
898 options = options or { }
899 options.device = self.sid
900
901 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
902 if wnet then
903 return wifinet(wnet, options)
904 end
905 end
906
907 function wifidev.del_wifinet(self, net)
908 if utl.instanceof(net, wifinet) then
909 net = net.sid
910 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
911 net = _wifi_lookup(net)
912 end
913
914 if net and uci_r:get("wireless", net, "device") == self.sid then
915 uci_r:delete("wireless", net)
916 return true
917 end
918
919 return false
920 end
921
922
923 wifinet = utl.class()
924 function wifinet.__init__(self, net, data)
925 self.sid = net
926
927 local dev = uci_s:get("wireless", self.sid, "ifname")
928 if not dev then
929 local num = { }
930 uci_r:foreach("wireless", "wifi-iface",
931 function(s)
932 if s.device then
933 num[s.device] = num[s.device] and num[s.device] + 1 or 1
934 if s['.name'] == self.sid then
935 dev = "%s.network%d" %{ s.device, num[s.device] }
936 return false
937 end
938 end
939 end)
940 end
941
942 self.wdev = dev
943 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
944 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
945 uci_r:get_all("wireless", self.sid) or { }
946 end
947
948 function wifinet.get(self, opt)
949 return _get("wireless", self.sid, opt)
950 end
951
952 function wifinet.set(self, opt, val)
953 return _set("wireless", self.sid, opt, val)
954 end
955
956 function wifinet.mode(self)
957 return uci_s:get("wireless", self.sid, "mode") or "ap"
958 end
959
960 function wifinet.ssid(self)
961 return uci_s:get("wireless", self.sid, "ssid")
962 end
963
964 function wifinet.bssid(self)
965 return uci_s:get("wireless", self.sid, "bssid")
966 end
967
968 function wifinet.network(self)
969 return uci_s:get("wifinet", self.sid, "network")
970 end
971
972 function wifinet.name(self)
973 return self.sid
974 end
975
976 function wifinet.ifname(self)
977 return self.iwinfo.ifname or self.wdev
978 end
979
980 function wifinet.get_device(self)
981 if self.iwdata.device then
982 return wifidev(self.iwdata.device)
983 end
984 end
985
986 function wifinet.is_up(self)
987 return (self.iwdata.up == "1")
988 end
989
990 function wifinet.active_mode(self)
991 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
992
993 if m == "ap" then m = "AP"
994 elseif m == "sta" then m = "Client"
995 elseif m == "adhoc" then m = "Ad-Hoc"
996 elseif m == "mesh" then m = "Mesh"
997 elseif m == "monitor" then m = "Monitor"
998 end
999
1000 return m
1001 end
1002
1003 function wifinet.active_mode_i18n(self)
1004 return i18n.translate(self:active_mode())
1005 end
1006
1007 function wifinet.active_ssid(self)
1008 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1009 end
1010
1011 function wifinet.active_bssid(self)
1012 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1013 end
1014
1015 function wifinet.active_encryption(self)
1016 local enc = self.iwinfo and self.iwinfo.encryption
1017 return enc and enc.description or "-"
1018 end
1019
1020 function wifinet.assoclist(self)
1021 return self.iwinfo.assoclist or { }
1022 end
1023
1024 function wifinet.frequency(self)
1025 local freq = self.iwinfo.frequency
1026 if freq and freq > 0 then
1027 return "%.03f" % (freq / 1000)
1028 end
1029 end
1030
1031 function wifinet.bitrate(self)
1032 local rate = self.iwinfo.bitrate
1033 if rate and rate > 0 then
1034 return (rate / 1000)
1035 end
1036 end
1037
1038 function wifinet.channel(self)
1039 return self.iwinfo.channel or
1040 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1041 end
1042
1043 function wifinet.signal(self)
1044 return self.iwinfo.signal or 0
1045 end
1046
1047 function wifinet.noise(self)
1048 return self.iwinfo.noise or 0
1049 end
1050
1051 function wifinet.signal_level(self, s, n)
1052 if self:active_bssid() ~= "00:00:00:00:00:00" then
1053 local signal = s or self:signal()
1054 local noise = n or self:noise()
1055
1056 if signal < 0 and noise < 0 then
1057 local snr = -1 * (noise - signal)
1058 return math.floor(snr / 5)
1059 else
1060 return 0
1061 end
1062 else
1063 return -1
1064 end
1065 end
1066
1067 function wifinet.signal_percent(self)
1068 local qc = self.iwinfo.quality or 0
1069 local qm = self.iwinfo.quality_max or 0
1070
1071 if qc > 0 and qm > 0 then
1072 return math.floor((100 / qm) * qc)
1073 else
1074 return 0
1075 end
1076 end
1077
1078 function wifinet.shortname(self)
1079 return "%s %q" %{
1080 i18n.translate(self:active_mode()),
1081 self:active_ssid() or self:active_bssid()
1082 }
1083 end
1084
1085 function wifinet.get_i18n(self)
1086 return "%s: %s %q (%s)" %{
1087 i18n.translate("Wireless Network"),
1088 i18n.translate(self:active_mode()),
1089 self:active_ssid() or self:active_bssid(),
1090 self:ifname()
1091 }
1092 end
1093
1094 function wifinet.adminlink(self)
1095 return dsp.build_url("admin", "network", "wireless",
1096 self.iwdata.device, self.wdev)
1097 end
1098
1099 function wifinet.get_network(self)
1100 if uci_r:get("network", self.iwdata.network) == "interface" then
1101 return network(self.iwdata.network)
1102 end
1103 end
1104
1105 function wifinet.get_interface(self)
1106 return interface(self:ifname())
1107 end