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