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