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