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