libs/core: fix some issues 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: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 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 = uci_r:get("network", self.sid, "ifname") or
486 uci_s:get("network", self.sid, "ifname")
487
488 dev = (type(dev) == "table") and dev[1] or dev
489 dev = (dev ~= nil) and dev:match("%S+")
490
491 if not dev then
492 uci_r:foreach("wireless", "wifi-iface",
493 function(s)
494 if s.device then
495 num[s.device] = num[s.device]
496 and num[s.device] + 1 or 1
497
498 if s.network == self.sid then
499 dev = "%s.network%d" %{ s.device, num[s.device] }
500 return false
501 end
502 end
503 end)
504 end
505
506 return dev
507 end
508 end
509
510 function network.device(self)
511 local dev = uci_r:get("network", self.sid, "device") or
512 uci_s:get("network", self.sid, "device")
513
514 dev = (type(dev) == "table") and dev[1] or dev
515
516 if not dev or dev:match("[^%w%-%.%s]") then
517 dev = uci_r:get("network", self.sid, "ifname") or
518 uci_s:get("network", self.sid, "ifname")
519
520 dev = (type(dev) == "table") and dev[1] or dev
521 end
522
523 return dev
524 end
525
526 function network.proto(self)
527 return self:_get("proto") or "none"
528 end
529
530 function network.type(self)
531 return self:_get("type")
532 end
533
534 function network.name(self)
535 return self.sid
536 end
537
538 function network.uptime(self)
539 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
540 if cnt ~= nil then
541 return nxo.sysinfo().uptime - cnt
542 else
543 return 0
544 end
545 end
546
547 function network.is_bridge(self)
548 return (self:type() == "bridge")
549 end
550
551 function network.is_virtual(self)
552 local p = self:proto()
553 return (
554 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
555 p == "pppoe" or p == "pppoa"
556 )
557 end
558
559 function network.is_empty(self)
560 if self:is_virtual() then
561 return false
562 else
563 local rv = true
564
565 if (self:_get("ifname") or ""):match("%S+") then
566 rv = false
567 end
568
569 uci_r:foreach("wireless", "wifi-iface",
570 function(s)
571 if s.network == self.sid then
572 rv = false
573 return false
574 end
575 end)
576
577 return rv
578 end
579 end
580
581 function network.add_interface(self, ifname)
582 if not self:is_virtual() then
583 if type(ifname) ~= "string" then
584 ifname = ifname:name()
585 else
586 ifname = ifname:match("[^%s:]+")
587 end
588
589 -- remove the interface from all ifaces
590 uci_r:foreach("network", "interface",
591 function(s)
592 _list_del("network", s['.name'], "ifname", ifname)
593 end)
594
595 -- if its a wifi interface, change its network option
596 local wif = _wifi_lookup(ifname)
597 if wif then
598 uci_r:set("wireless", wif, "network", self.sid)
599
600 -- add iface to our iface list
601 else
602 _list_add("network", self.sid, "ifname", ifname)
603 end
604 end
605 end
606
607 function network.del_interface(self, ifname)
608 if not self:is_virtual() then
609 if utl.instanceof(ifname, interface) then
610 ifname = ifname:name()
611 else
612 ifname = ifname:match("[^%s:]+")
613 end
614
615 -- if its a wireless interface, clear its network option
616 local wif = _wifi_lookup(ifname)
617 if wif then uci_r:delete("wireless", wif, "network") end
618
619 -- remove the interface
620 _list_del("network", self.sid, "ifname", ifname)
621 end
622 end
623
624 function network.get_interfaces(self)
625 local ifaces = { }
626
627 local ifn
628 if self:is_virtual() then
629 ifn = self:proto() .. "-" .. self.sid
630 ifaces = { interface(ifn) }
631 else
632 local nfs = { }
633 for ifn in utl.imatch(self:get("ifname")) do
634 ifn = ifn:match("[^:]+")
635 nfs[ifn] = interface(ifn)
636 end
637
638 for ifn in utl.kspairs(nfs) do
639 ifaces[#ifaces+1] = nfs[ifn]
640 end
641
642 local num = { }
643 local wfs = { }
644 uci_r:foreach("wireless", "wifi-iface",
645 function(s)
646 if s.device then
647 num[s.device] = num[s.device] and num[s.device] + 1 or 1
648 if s.network == self.sid then
649 ifn = "%s.network%d" %{ s.device, num[s.device] }
650 wfs[ifn] = interface(ifn)
651 end
652 end
653 end)
654
655 for ifn in utl.kspairs(wfs) do
656 ifaces[#ifaces+1] = wfs[ifn]
657 end
658 end
659
660 return ifaces
661 end
662
663 function network.contains_interface(self, ifname)
664 if type(ifname) ~= "string" then
665 ifname = ifname:name()
666 else
667 ifname = ifname:match("[^%s:]+")
668 end
669
670 local ifn
671 if self:is_virtual() then
672 ifn = self:proto() .. "-" .. self.sid
673 return ifname == ifn
674 else
675 for ifn in utl.imatch(self:get("ifname")) do
676 ifn = ifn:match("[^:]+")
677 if ifn == ifname then
678 return true
679 end
680 end
681
682 local wif = _wifi_lookup(ifname)
683 if wif then
684 return (uci_r:get("wireless", wif, "network") == self.sid)
685 end
686 end
687
688 return false
689 end
690
691 function network.adminlink(self)
692 return dsp.build_url("admin", "network", "network", self.sid)
693 end
694
695
696 interface = utl.class()
697 function interface.__init__(self, ifname)
698 local wif = _wifi_lookup(ifname)
699 if wif then self.wif = wifinet(wif) end
700
701 self.ifname = self.ifname or ifname
702 self.dev = ifs[self.ifname]
703 end
704
705 function interface.name(self)
706 return self.wif and self.wif:ifname() or self.ifname
707 end
708
709 function interface.mac(self)
710 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
711 end
712
713 function interface.ipaddrs(self)
714 return self.dev and self.dev.ipaddrs or { }
715 end
716
717 function interface.ip6addrs(self)
718 return self.dev and self.dev.ip6addrs or { }
719 end
720
721 function interface.type(self)
722 if self.wif or _wifi_iface(self.ifname) then
723 return "wifi"
724 elseif brs[self.ifname] then
725 return "bridge"
726 elseif sws[self.ifname] or self.ifname:match("%.") then
727 return "switch"
728 else
729 return "ethernet"
730 end
731 end
732
733 function interface.shortname(self)
734 if self.wif then
735 return "%s %q" %{
736 self.wif:active_mode(),
737 self.wif:active_ssid() or self.wif:active_bssid()
738 }
739 else
740 return self.ifname
741 end
742 end
743
744 function interface.get_i18n(self)
745 if self.wif then
746 return "%s: %s %q" %{
747 i18n.translate("Wireless Network"),
748 self.wif:active_mode(),
749 self.wif:active_ssid() or self.wif:active_bssid()
750 }
751 else
752 return "%s: %q" %{ self:get_type_i18n(), self:name() }
753 end
754 end
755
756 function interface.get_type_i18n(self)
757 local x = self:type()
758 if x == "wifi" then
759 return i18n.translate("Wireless Adapter")
760 elseif x == "bridge" then
761 return i18n.translate("Bridge")
762 elseif x == "switch" then
763 return i18n.translate("Ethernet Switch")
764 else
765 return i18n.translate("Ethernet Adapter")
766 end
767 end
768
769 function interface.adminlink(self)
770 if self.wif then
771 return self.wif:adminlink()
772 end
773 end
774
775 function interface.ports(self)
776 if self.br then
777 local iface
778 local ifaces = { }
779 for _, iface in ipairs(self.br.ifnames) do
780 ifaces[#ifaces+1] = interface(iface.name)
781 end
782 return ifaces
783 end
784 end
785
786 function interface.bridge_id(self)
787 if self.br then
788 return self.br.id
789 else
790 return nil
791 end
792 end
793
794 function interface.bridge_stp(self)
795 if self.br then
796 return self.br.stp
797 else
798 return false
799 end
800 end
801
802 function interface.is_up(self)
803 if self.wif then
804 return self.wif:is_up()
805 else
806 return self.dev and self.dev.flags and self.dev.flags.up or false
807 end
808 end
809
810 function interface.is_bridge(self)
811 return (self:type() == "bridge")
812 end
813
814 function interface.is_bridgeport(self)
815 return self.dev and self.dev.bridge and true or false
816 end
817
818 function interface.tx_bytes(self)
819 return self.dev and self.dev.stats
820 and self.dev.stats.tx_bytes or 0
821 end
822
823 function interface.rx_bytes(self)
824 return self.dev and self.dev.stats
825 and self.dev.stats.rx_bytes or 0
826 end
827
828 function interface.tx_packets(self)
829 return self.dev and self.dev.stats
830 and self.dev.stats.tx_packets or 0
831 end
832
833 function interface.rx_packets(self)
834 return self.dev and self.dev.stats
835 and self.dev.stats.rx_packets or 0
836 end
837
838 function interface.get_network(self)
839 if self.dev and self.dev.network then
840 self.network = _M:get_network(self.dev.network)
841 end
842
843 if not self.network then
844 local net
845 for _, net in ipairs(_M:get_networks()) do
846 if net:contains_interface(self.ifname) then
847 self.network = net
848 return net
849 end
850 end
851 else
852 return self.network
853 end
854 end
855
856 function interface.get_wifinet(self)
857 return self.wif
858 end
859
860
861 wifidev = utl.class()
862 function wifidev.__init__(self, dev)
863 self.sid = dev
864 end
865
866 function wifidev.get(self, opt)
867 return _get("wireless", self.sid, opt)
868 end
869
870 function wifidev.set(self, opt, val)
871 return _set("wireless", self.sid, opt, val)
872 end
873
874 function wifidev.name(self)
875 return self.sid
876 end
877
878 function wifidev.is_up(self)
879 local up = false
880
881 uci_s:foreach("wireless", "wifi-iface",
882 function(s)
883 if s.device == self.sid then
884 if s.up == "1" then
885 up = true
886 return false
887 end
888 end
889 end)
890
891 return up
892 end
893
894 function wifidev.get_wifinet(self, net)
895 if uci_r:get("wireless", net) == "wifi-iface" then
896 return wifinet(net)
897 else
898 local wnet = _wifi_lookup(net)
899 if wnet then
900 return wifinet(wnet)
901 end
902 end
903 end
904
905 function wifidev.get_wifinets(self)
906 local nets = { }
907
908 uci_r:foreach("wireless", "wifi-iface",
909 function(s)
910 if s.device == self.sid then
911 nets[#nets+1] = wifinet(s['.name'])
912 end
913 end)
914
915 return nets
916 end
917
918 function wifidev.add_wifinet(self, options)
919 options = options or { }
920 options.device = self.sid
921
922 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
923 if wnet then
924 return wifinet(wnet, options)
925 end
926 end
927
928 function wifidev.del_wifinet(self, net)
929 if utl.instanceof(net, wifinet) then
930 net = net.sid
931 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
932 net = _wifi_lookup(net)
933 end
934
935 if net and uci_r:get("wireless", net, "device") == self.sid then
936 uci_r:delete("wireless", net)
937 return true
938 end
939
940 return false
941 end
942
943
944 wifinet = utl.class()
945 function wifinet.__init__(self, net, data)
946 self.sid = net
947
948 local num = { }
949 local netid
950 uci_r:foreach("wireless", "wifi-iface",
951 function(s)
952 if s.device then
953 num[s.device] = num[s.device] and num[s.device] + 1 or 1
954 if s['.name'] == self.sid then
955 netid = "%s.network%d" %{ s.device, num[s.device] }
956 return false
957 end
958 end
959 end)
960
961 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
962
963 self.netid = netid
964 self.wdev = dev
965 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
966 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
967 uci_r:get_all("wireless", self.sid) or { }
968 end
969
970 function wifinet.get(self, opt)
971 return _get("wireless", self.sid, opt)
972 end
973
974 function wifinet.set(self, opt, val)
975 return _set("wireless", self.sid, opt, val)
976 end
977
978 function wifinet.mode(self)
979 return uci_s:get("wireless", self.sid, "mode") or "ap"
980 end
981
982 function wifinet.ssid(self)
983 return uci_s:get("wireless", self.sid, "ssid")
984 end
985
986 function wifinet.bssid(self)
987 return uci_s:get("wireless", self.sid, "bssid")
988 end
989
990 function wifinet.network(self)
991 return uci_s:get("wifinet", self.sid, "network")
992 end
993
994 function wifinet.name(self)
995 return self.sid
996 end
997
998 function wifinet.ifname(self)
999 local ifname = self.iwinfo.ifname
1000 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1001 ifname = self.wdev
1002 end
1003 return ifname
1004 end
1005
1006 function wifinet.get_device(self)
1007 if self.iwdata.device then
1008 return wifidev(self.iwdata.device)
1009 end
1010 end
1011
1012 function wifinet.is_up(self)
1013 return (self.iwdata.up == "1")
1014 end
1015
1016 function wifinet.active_mode(self)
1017 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1018
1019 if m == "ap" then m = "AP"
1020 elseif m == "sta" then m = "Client"
1021 elseif m == "adhoc" then m = "Ad-Hoc"
1022 elseif m == "mesh" then m = "Mesh"
1023 elseif m == "monitor" then m = "Monitor"
1024 end
1025
1026 return m
1027 end
1028
1029 function wifinet.active_mode_i18n(self)
1030 return i18n.translate(self:active_mode())
1031 end
1032
1033 function wifinet.active_ssid(self)
1034 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1035 end
1036
1037 function wifinet.active_bssid(self)
1038 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1039 end
1040
1041 function wifinet.active_encryption(self)
1042 local enc = self.iwinfo and self.iwinfo.encryption
1043 return enc and enc.description or "-"
1044 end
1045
1046 function wifinet.assoclist(self)
1047 return self.iwinfo.assoclist or { }
1048 end
1049
1050 function wifinet.frequency(self)
1051 local freq = self.iwinfo.frequency
1052 if freq and freq > 0 then
1053 return "%.03f" % (freq / 1000)
1054 end
1055 end
1056
1057 function wifinet.bitrate(self)
1058 local rate = self.iwinfo.bitrate
1059 if rate and rate > 0 then
1060 return (rate / 1000)
1061 end
1062 end
1063
1064 function wifinet.channel(self)
1065 return self.iwinfo.channel or
1066 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1067 end
1068
1069 function wifinet.signal(self)
1070 return self.iwinfo.signal or 0
1071 end
1072
1073 function wifinet.noise(self)
1074 return self.iwinfo.noise or 0
1075 end
1076
1077 function wifinet.signal_level(self, s, n)
1078 if self:active_bssid() ~= "00:00:00:00:00:00" then
1079 local signal = s or self:signal()
1080 local noise = n or self:noise()
1081
1082 if signal < 0 and noise < 0 then
1083 local snr = -1 * (noise - signal)
1084 return math.floor(snr / 5)
1085 else
1086 return 0
1087 end
1088 else
1089 return -1
1090 end
1091 end
1092
1093 function wifinet.signal_percent(self)
1094 local qc = self.iwinfo.quality or 0
1095 local qm = self.iwinfo.quality_max or 0
1096
1097 if qc > 0 and qm > 0 then
1098 return math.floor((100 / qm) * qc)
1099 else
1100 return 0
1101 end
1102 end
1103
1104 function wifinet.shortname(self)
1105 return "%s %q" %{
1106 i18n.translate(self:active_mode()),
1107 self:active_ssid() or self:active_bssid()
1108 }
1109 end
1110
1111 function wifinet.get_i18n(self)
1112 return "%s: %s %q (%s)" %{
1113 i18n.translate("Wireless Network"),
1114 i18n.translate(self:active_mode()),
1115 self:active_ssid() or self:active_bssid(),
1116 self:ifname()
1117 }
1118 end
1119
1120 function wifinet.adminlink(self)
1121 return dsp.build_url("admin", "network", "wireless",
1122 self.iwdata.device, self.netid)
1123 end
1124
1125 function wifinet.get_network(self)
1126 if uci_r:get("network", self.iwdata.network) == "interface" then
1127 return network(self.iwdata.network)
1128 end
1129 end
1130
1131 function wifinet.get_interface(self)
1132 return interface(self:ifname())
1133 end