129f70d71ec567c0a344ec8eba8fefc61d905a49
[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) then
856 self.network = net
857 return net
858 end
859 end
860 else
861 return self.network
862 end
863 end
864
865 function interface.get_wifinet(self)
866 return self.wif
867 end
868
869
870 wifidev = utl.class()
871 function wifidev.__init__(self, dev)
872 self.sid = dev
873 end
874
875 function wifidev.get(self, opt)
876 return _get("wireless", self.sid, opt)
877 end
878
879 function wifidev.set(self, opt, val)
880 return _set("wireless", self.sid, opt, val)
881 end
882
883 function wifidev.name(self)
884 return self.sid
885 end
886
887 function wifidev.is_up(self)
888 local up = false
889
890 uci_s:foreach("wireless", "wifi-iface",
891 function(s)
892 if s.device == self.sid then
893 if s.up == "1" then
894 up = true
895 return false
896 end
897 end
898 end)
899
900 return up
901 end
902
903 function wifidev.get_wifinet(self, net)
904 if uci_r:get("wireless", net) == "wifi-iface" then
905 return wifinet(net)
906 else
907 local wnet = _wifi_lookup(net)
908 if wnet then
909 return wifinet(wnet)
910 end
911 end
912 end
913
914 function wifidev.get_wifinets(self)
915 local nets = { }
916
917 uci_r:foreach("wireless", "wifi-iface",
918 function(s)
919 if s.device == self.sid then
920 nets[#nets+1] = wifinet(s['.name'])
921 end
922 end)
923
924 return nets
925 end
926
927 function wifidev.add_wifinet(self, options)
928 options = options or { }
929 options.device = self.sid
930
931 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
932 if wnet then
933 return wifinet(wnet, options)
934 end
935 end
936
937 function wifidev.del_wifinet(self, net)
938 if utl.instanceof(net, wifinet) then
939 net = net.sid
940 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
941 net = _wifi_lookup(net)
942 end
943
944 if net and uci_r:get("wireless", net, "device") == self.sid then
945 uci_r:delete("wireless", net)
946 return true
947 end
948
949 return false
950 end
951
952
953 wifinet = utl.class()
954 function wifinet.__init__(self, net, data)
955 self.sid = net
956
957 local num = { }
958 local netid
959 uci_r:foreach("wireless", "wifi-iface",
960 function(s)
961 if s.device then
962 num[s.device] = num[s.device] and num[s.device] + 1 or 1
963 if s['.name'] == self.sid then
964 netid = "%s.network%d" %{ s.device, num[s.device] }
965 return false
966 end
967 end
968 end)
969
970 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
971
972 self.netid = netid
973 self.wdev = dev
974 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
975 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
976 uci_r:get_all("wireless", self.sid) or { }
977 end
978
979 function wifinet.get(self, opt)
980 return _get("wireless", self.sid, opt)
981 end
982
983 function wifinet.set(self, opt, val)
984 return _set("wireless", self.sid, opt, val)
985 end
986
987 function wifinet.mode(self)
988 return uci_s:get("wireless", self.sid, "mode") or "ap"
989 end
990
991 function wifinet.ssid(self)
992 return uci_s:get("wireless", self.sid, "ssid")
993 end
994
995 function wifinet.bssid(self)
996 return uci_s:get("wireless", self.sid, "bssid")
997 end
998
999 function wifinet.network(self)
1000 return uci_s:get("wifinet", self.sid, "network")
1001 end
1002
1003 function wifinet.name(self)
1004 return self.sid
1005 end
1006
1007 function wifinet.ifname(self)
1008 local ifname = self.iwinfo.ifname
1009 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1010 ifname = self.wdev
1011 end
1012 return ifname
1013 end
1014
1015 function wifinet.get_device(self)
1016 if self.iwdata.device then
1017 return wifidev(self.iwdata.device)
1018 end
1019 end
1020
1021 function wifinet.is_up(self)
1022 return (self.iwdata.up == "1")
1023 end
1024
1025 function wifinet.active_mode(self)
1026 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1027
1028 if m == "ap" then m = "Master"
1029 elseif m == "sta" then m = "Client"
1030 elseif m == "adhoc" then m = "Ad-Hoc"
1031 elseif m == "mesh" then m = "Mesh"
1032 elseif m == "monitor" then m = "Monitor"
1033 end
1034
1035 return m
1036 end
1037
1038 function wifinet.active_mode_i18n(self)
1039 return i18n.translate(self:active_mode())
1040 end
1041
1042 function wifinet.active_ssid(self)
1043 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1044 end
1045
1046 function wifinet.active_bssid(self)
1047 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1048 end
1049
1050 function wifinet.active_encryption(self)
1051 local enc = self.iwinfo and self.iwinfo.encryption
1052 return enc and enc.description or "-"
1053 end
1054
1055 function wifinet.assoclist(self)
1056 return self.iwinfo.assoclist or { }
1057 end
1058
1059 function wifinet.frequency(self)
1060 local freq = self.iwinfo.frequency
1061 if freq and freq > 0 then
1062 return "%.03f" % (freq / 1000)
1063 end
1064 end
1065
1066 function wifinet.bitrate(self)
1067 local rate = self.iwinfo.bitrate
1068 if rate and rate > 0 then
1069 return (rate / 1000)
1070 end
1071 end
1072
1073 function wifinet.channel(self)
1074 return self.iwinfo.channel or
1075 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1076 end
1077
1078 function wifinet.signal(self)
1079 return self.iwinfo.signal or 0
1080 end
1081
1082 function wifinet.noise(self)
1083 return self.iwinfo.noise or 0
1084 end
1085
1086 function wifinet.signal_level(self, s, n)
1087 if self:active_bssid() ~= "00:00:00:00:00:00" then
1088 local signal = s or self:signal()
1089 local noise = n or self:noise()
1090
1091 if signal < 0 and noise < 0 then
1092 local snr = -1 * (noise - signal)
1093 return math.floor(snr / 5)
1094 else
1095 return 0
1096 end
1097 else
1098 return -1
1099 end
1100 end
1101
1102 function wifinet.signal_percent(self)
1103 local qc = self.iwinfo.quality or 0
1104 local qm = self.iwinfo.quality_max or 0
1105
1106 if qc > 0 and qm > 0 then
1107 return math.floor((100 / qm) * qc)
1108 else
1109 return 0
1110 end
1111 end
1112
1113 function wifinet.shortname(self)
1114 return "%s %q" %{
1115 i18n.translate(self:active_mode()),
1116 self:active_ssid() or self:active_bssid()
1117 }
1118 end
1119
1120 function wifinet.get_i18n(self)
1121 return "%s: %s %q (%s)" %{
1122 i18n.translate("Wireless Network"),
1123 i18n.translate(self:active_mode()),
1124 self:active_ssid() or self:active_bssid(),
1125 self:ifname()
1126 }
1127 end
1128
1129 function wifinet.adminlink(self)
1130 return dsp.build_url("admin", "network", "wireless", self.netid)
1131 end
1132
1133 function wifinet.get_network(self)
1134 if uci_r:get("network", self.iwdata.network) == "interface" then
1135 return network(self.iwdata.network)
1136 end
1137 end
1138
1139 function wifinet.get_interface(self)
1140 return interface(self:ifname())
1141 end