45864719a4cc99d9225c6c35005b757cfb25f7c1
[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, next, pairs, ipairs, loadfile, table, tonumber, math, i18n
21 = type, next, 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_virtual(x)
154 return (
155 x:match("^6in4-%w") or x:match("^6to4-%w") or x:match("^3g-%w") or
156 x:match("^ppp-%w") or x:match("^pppoe-%w") or x:match("^pppoa-%w") or
157 x:match("^relay-%w")
158 )
159 end
160
161 function _iface_ignore(x)
162 return (
163 x:match("^wmaster%d") or x:match("^wifi%d") or x:match("^hwsim%d") or
164 x:match("^imq%d") or x:match("^mon.wlan%d") or
165 x == "sit0" or x == "lo" or _iface_virtual(x)
166 )
167 end
168
169
170 function init(cursor)
171 uci_r = cursor or uci_r or uci.cursor()
172 uci_s = uci_r:substate()
173
174 ifs = { }
175 brs = { }
176 sws = { }
177
178 -- read interface information
179 local n, i
180 for n, i in ipairs(nxo.getifaddrs()) do
181 local name = i.name:match("[^:]+")
182 local prnt = name:match("^([^%.]+)%.")
183
184 if _iface_virtual(name) or not _iface_ignore(name) then
185 ifs[name] = ifs[name] or {
186 idx = i.ifindex or n,
187 name = name,
188 rawname = i.name,
189 flags = { },
190 ipaddrs = { },
191 ip6addrs = { }
192 }
193
194 if prnt then
195 sws[name] = true
196 sws[prnt] = true
197 end
198
199 if i.family == "packet" then
200 ifs[name].flags = i.flags
201 ifs[name].stats = i.data
202 ifs[name].macaddr = i.addr
203 elseif i.family == "inet" then
204 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
205 elseif i.family == "inet6" then
206 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
207 end
208 end
209 end
210
211 -- read bridge informaton
212 local b, l
213 for l in utl.execi("brctl show") do
214 if not l:match("STP") then
215 local r = utl.split(l, "%s+", nil, true)
216 if #r == 4 then
217 b = {
218 name = r[1],
219 id = r[2],
220 stp = r[3] == "yes",
221 ifnames = { ifs[r[4]] }
222 }
223 if b.ifnames[1] then
224 b.ifnames[1].bridge = b
225 end
226 brs[r[1]] = b
227 elseif b then
228 b.ifnames[#b.ifnames+1] = ifs[r[2]]
229 b.ifnames[#b.ifnames].bridge = b
230 end
231 end
232 end
233
234 return _M
235 end
236
237 function save(self, ...)
238 uci_r:save(...)
239 uci_r:load(...)
240 end
241
242 function commit(self, ...)
243 uci_r:commit(...)
244 uci_r:load(...)
245 end
246
247 function has_ipv6(self)
248 return nfs.access("/proc/net/ipv6_route")
249 end
250
251 function add_network(self, n, options)
252 local oldnet = self:get_network(n)
253 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
254 if uci_r:section("network", "interface", n, options) then
255 return network(n)
256 end
257 elseif oldnet and oldnet:is_empty() then
258 if options then
259 local k, v
260 for k, v in pairs(options) do
261 oldnet:set(k, v)
262 end
263 end
264 return oldnet
265 end
266 end
267
268 function get_network(self, n)
269 if n and uci_r:get("network", n) == "interface" then
270 return network(n)
271 end
272 end
273
274 function get_networks(self)
275 local nets = { }
276 local nls = { }
277
278 uci_r:foreach("network", "interface",
279 function(s)
280 nls[s['.name']] = network(s['.name'])
281 end)
282
283 local n
284 for n in utl.kspairs(nls) do
285 nets[#nets+1] = nls[n]
286 end
287
288 return nets
289 end
290
291 function del_network(self, n)
292 local r = uci_r:delete("network", n)
293 if r then
294 uci_r:delete_all("network", "alias",
295 function(s) return (s.interface == n) end)
296
297 uci_r:delete_all("network", "route",
298 function(s) return (s.interface == n) end)
299
300 uci_r:delete_all("network", "route6",
301 function(s) return (s.interface == n) end)
302
303 uci_r:foreach("wireless", "wifi-iface",
304 function(s)
305 if s.network == n then
306 uci_r:delete("wireless", s['.name'], "network")
307 end
308 end)
309 end
310 return r
311 end
312
313 function rename_network(self, old, new)
314 local r
315 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
316 r = uci_r:section("network", "interface", new, uci_r:get_all("network", old))
317
318 if r then
319 uci_r:foreach("network", "alias",
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", "route",
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("network", "route6",
334 function(s)
335 if s.interface == old then
336 uci_r:set("network", s['.name'], "interface", new)
337 end
338 end)
339
340 uci_r:foreach("wireless", "wifi-iface",
341 function(s)
342 if s.network == old then
343 uci_r:set("wireless", s['.name'], "network", new)
344 end
345 end)
346
347 uci_r:delete("network", old)
348 end
349 end
350 return r or false
351 end
352
353 function get_interface(self, i)
354 if ifs[i] or _wifi_iface(i) then
355 return interface(i)
356 else
357 local ifc
358 local num = { }
359 uci_r:foreach("wireless", "wifi-iface",
360 function(s)
361 if s.device then
362 num[s.device] = num[s.device] and num[s.device] + 1 or 1
363 if s['.name'] == i then
364 ifc = interface(
365 "%s.network%d" %{s.device, num[s.device] })
366 return false
367 end
368 end
369 end)
370 return ifc
371 end
372 end
373
374 function get_interfaces(self)
375 local iface
376 local ifaces = { }
377 local seen = { }
378 local nfs = { }
379
380 -- find normal interfaces
381 uci_r:foreach("network", "interface",
382 function(s)
383 for iface in utl.imatch(s.ifname) do
384 if not _iface_ignore(iface) and not _wifi_iface(iface) then
385 seen[iface] = true
386 nfs[iface] = interface(iface)
387 end
388 end
389 end)
390
391 for iface in utl.kspairs(ifs) do
392 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
393 nfs[iface] = interface(iface)
394 end
395 end
396
397 -- find vlan interfaces
398 uci_r:foreach("network", "switch_vlan",
399 function(s)
400 local base = s.device or "-"
401 if not base:match("^eth%d") then
402 base = "eth0"
403 end
404
405 local vid = tonumber(s.vid or s.vlan)
406 if vid ~= nil and vid >= 0 and vid <= 4095 then
407 local iface = "%s.%d" %{ base, vid }
408 if not seen[iface] then
409 seen[iface] = true
410 nfs[iface] = interface(iface)
411 end
412 end
413 end)
414
415 for iface in utl.kspairs(nfs) do
416 ifaces[#ifaces+1] = nfs[iface]
417 end
418
419 -- find wifi interfaces
420 local num = { }
421 local wfs = { }
422 uci_r:foreach("wireless", "wifi-iface",
423 function(s)
424 if s.device then
425 num[s.device] = num[s.device] and num[s.device] + 1 or 1
426 local i = "%s.network%d" %{ s.device, num[s.device] }
427 wfs[i] = interface(i)
428 end
429 end)
430
431 for iface in utl.kspairs(wfs) do
432 ifaces[#ifaces+1] = wfs[iface]
433 end
434
435 return ifaces
436 end
437
438 function ignore_interface(self, x)
439 return _iface_ignore(x)
440 end
441
442 function get_wifidev(self, dev)
443 if uci_r:get("wireless", dev) == "wifi-device" then
444 return wifidev(dev)
445 end
446 end
447
448 function get_wifidevs(self)
449 local devs = { }
450 local wfd = { }
451
452 uci_r:foreach("wireless", "wifi-device",
453 function(s) wfd[#wfd+1] = s['.name'] end)
454
455 local dev
456 for _, dev in utl.vspairs(wfd) do
457 devs[#devs+1] = wifidev(dev)
458 end
459
460 return devs
461 end
462
463 function get_wifinet(self, net)
464 local wnet = _wifi_lookup(net)
465 if wnet then
466 return wifinet(wnet)
467 end
468 end
469
470 function add_wifinet(self, net, options)
471 if type(options) == "table" and options.device and
472 uci_r:get("wireless", options.device) == "wifi-device"
473 then
474 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
475 return wifinet(wnet)
476 end
477 end
478
479 function del_wifinet(self, net)
480 local wnet = _wifi_lookup(net)
481 if wnet then
482 uci_r:delete("wireless", wnet)
483 return true
484 end
485 return false
486 end
487
488
489 network = utl.class()
490
491 function network.__init__(self, name)
492 self.sid = name
493 end
494
495 function network._get(self, opt)
496 local v = uci_r:get("network", self.sid, opt)
497 if type(v) == "table" then
498 return table.concat(v, " ")
499 end
500 return v or ""
501 end
502
503 function network._ip(self, opt, family, list)
504 local ip = uci_s:get("network", self.sid, opt)
505 local fc = (family == 6) and ipc.IPv6 or ipc.IPv4
506 if ip or list then
507 if list then
508 local l = { }
509 for ip in utl.imatch(ip) do
510 ip = fc(ip)
511 if ip then l[#l+1] = ip:string() end
512 end
513 return l
514 else
515 ip = fc(ip)
516 return ip and ip:string()
517 end
518 end
519 end
520
521 function network.get(self, opt)
522 return _get("network", self.sid, opt)
523 end
524
525 function network.set(self, opt, val)
526 return _set("network", self.sid, opt, val)
527 end
528
529 function network.ifname(self)
530 local p = self:proto()
531 if self:is_bridge() then
532 return "br-" .. self.sid
533 elseif self:proto() == "relay" then
534 return uci_s:get("network", self.sid, "up") == "1" and "lo" or nil
535 elseif self:is_virtual() then
536 return p .. "-" .. self.sid
537 else
538 local num = { }
539 local dev = uci_r:get("network", self.sid, "ifname") or
540 uci_s:get("network", self.sid, "ifname")
541
542 dev = (type(dev) == "table") and dev[1] or dev
543 dev = (dev ~= nil) and dev:match("%S+")
544
545 if not dev then
546 uci_r:foreach("wireless", "wifi-iface",
547 function(s)
548 if s.device then
549 num[s.device] = num[s.device]
550 and num[s.device] + 1 or 1
551
552 if s.network == self.sid then
553 dev = "%s.network%d" %{ s.device, num[s.device] }
554 return false
555 end
556 end
557 end)
558 end
559
560 return dev
561 end
562 end
563
564 function network.device(self)
565 local dev = uci_r:get("network", self.sid, "device") or
566 uci_s:get("network", self.sid, "device")
567
568 dev = (type(dev) == "table") and dev[1] or dev
569
570 if not dev or dev:match("[^%w%-%.%s]") then
571 dev = uci_r:get("network", self.sid, "ifname") or
572 uci_s:get("network", self.sid, "ifname")
573
574 dev = (type(dev) == "table") and dev[1] or dev
575 end
576
577 for dev in utl.imatch(dev) do
578 return dev
579 end
580 end
581
582 function network.proto(self)
583 return self:_get("proto") or "none"
584 end
585
586 function network.type(self)
587 return self:_get("type")
588 end
589
590 function network.name(self)
591 return self.sid
592 end
593
594 function network.uptime(self)
595 local cnt = tonumber(uci_s:get("network", self.sid, "connect_time"))
596 if cnt ~= nil then
597 return nxo.sysinfo().uptime - cnt
598 else
599 return 0
600 end
601 end
602
603 function network.expires(self)
604 local a = tonumber(uci_s:get("network", self.sid, "lease_acquired"))
605 local l = tonumber(uci_s:get("network", self.sid, "lease_lifetime"))
606 if a and l then
607 l = l - (nxo.sysinfo().uptime - a)
608 return l > 0 and l or 0
609 end
610 return -1
611 end
612
613 function network.metric(self)
614 return tonumber(uci_s:get("network", self.sid, "metric")) or 0
615 end
616
617 function network.ipaddr(self)
618 return self:_ip("ipaddr", 4)
619 end
620
621 function network.netmask(self)
622 return self:_ip("netmask", 4)
623 end
624
625 function network.gwaddr(self)
626 return self:_ip("gateway", 4)
627 end
628
629 function network.dnsaddrs(self)
630 return self:_ip("dns", 4, true)
631 end
632
633 function network.ip6addr(self)
634 local ip6 = self:_ip("ip6addr", 6)
635 if not ip6 then
636 local ifc = ifs[self:ifname()]
637 if ifc and ifc.ip6addrs then
638 local a
639 for _, a in ipairs(ifc.ip6addrs) do
640 if not a:is6linklocal() then
641 ip6 = a:string()
642 break
643 end
644 end
645 end
646 end
647 return ip6
648 end
649
650 function network.gw6addr(self)
651 local ip6 = self:_ip("ip6gw", 6)
652 if not ip6 then
653 local dr6 = sys.net.defaultroute6()
654 if dr6 and dr6.device == self:ifname() then
655 return dr6.nexthop:string()
656 end
657 end
658 return ip6
659 end
660
661 function network.dns6addrs(self)
662 return self:_ip("dns", 6, true)
663 end
664
665 function network.is_bridge(self)
666 return (self:type() == "bridge")
667 end
668
669 function network.is_virtual(self)
670 local p = self:proto()
671 return (
672 p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or
673 p == "pppoe" or p == "pppoa" or p == "relay"
674 )
675 end
676
677 function network.is_empty(self)
678 if self:is_virtual() then
679 return false
680 else
681 local rv = true
682
683 if (self:_get("ifname") or ""):match("%S+") then
684 rv = false
685 end
686
687 uci_r:foreach("wireless", "wifi-iface",
688 function(s)
689 if s.network == self.sid then
690 rv = false
691 return false
692 end
693 end)
694
695 return rv
696 end
697 end
698
699 function network.add_interface(self, ifname)
700 if not self:is_virtual() then
701 if type(ifname) ~= "string" then
702 ifname = ifname:name()
703 else
704 ifname = ifname:match("[^%s:]+")
705 end
706
707 -- remove the interface from all ifaces
708 uci_r:foreach("network", "interface",
709 function(s)
710 _list_del("network", s['.name'], "ifname", ifname)
711 end)
712
713 -- if its a wifi interface, change its network option
714 local wif = _wifi_lookup(ifname)
715 if wif then
716 uci_r:set("wireless", wif, "network", self.sid)
717
718 -- add iface to our iface list
719 else
720 _list_add("network", self.sid, "ifname", ifname)
721 end
722 end
723 end
724
725 function network.del_interface(self, ifname)
726 if not self:is_virtual() then
727 if utl.instanceof(ifname, interface) then
728 ifname = ifname:name()
729 else
730 ifname = ifname:match("[^%s:]+")
731 end
732
733 -- if its a wireless interface, clear its network option
734 local wif = _wifi_lookup(ifname)
735 if wif then uci_r:delete("wireless", wif, "network") end
736
737 -- remove the interface
738 _list_del("network", self.sid, "ifname", ifname)
739 end
740 end
741
742 function network.get_interfaces(self)
743 local ifaces = { }
744
745 local ifn
746 if self:is_virtual() then
747 ifn = self:proto() .. "-" .. self.sid
748 ifaces = { interface(ifn) }
749 else
750 local nfs = { }
751 for ifn in utl.imatch(self:get("ifname")) do
752 ifn = ifn:match("[^:]+")
753 nfs[ifn] = interface(ifn)
754 end
755
756 for ifn in utl.kspairs(nfs) do
757 ifaces[#ifaces+1] = nfs[ifn]
758 end
759
760 local num = { }
761 local wfs = { }
762 uci_r:foreach("wireless", "wifi-iface",
763 function(s)
764 if s.device then
765 num[s.device] = num[s.device] and num[s.device] + 1 or 1
766 if s.network == self.sid then
767 ifn = "%s.network%d" %{ s.device, num[s.device] }
768 wfs[ifn] = interface(ifn)
769 end
770 end
771 end)
772
773 for ifn in utl.kspairs(wfs) do
774 ifaces[#ifaces+1] = wfs[ifn]
775 end
776 end
777
778 return ifaces
779 end
780
781 function network.contains_interface(self, ifname)
782 if type(ifname) ~= "string" then
783 ifname = ifname:name()
784 else
785 ifname = ifname:match("[^%s:]+")
786 end
787
788 local ifn
789 if self:is_virtual() then
790 ifn = self:proto() .. "-" .. self.sid
791 return ifname == ifn
792 else
793 for ifn in utl.imatch(self:get("ifname")) do
794 ifn = ifn:match("[^:]+")
795 if ifn == ifname then
796 return true
797 end
798 end
799
800 local wif = _wifi_lookup(ifname)
801 if wif then
802 return (uci_r:get("wireless", wif, "network") == self.sid)
803 end
804 end
805
806 return false
807 end
808
809 function network.adminlink(self)
810 return dsp.build_url("admin", "network", "network", self.sid)
811 end
812
813
814 interface = utl.class()
815 function interface.__init__(self, ifname)
816 local wif = _wifi_lookup(ifname)
817 if wif then self.wif = wifinet(wif) end
818
819 self.ifname = self.ifname or ifname
820 self.dev = ifs[self.ifname]
821 end
822
823 function interface.name(self)
824 return self.wif and self.wif:ifname() or self.ifname
825 end
826
827 function interface.mac(self)
828 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
829 end
830
831 function interface.ipaddrs(self)
832 return self.dev and self.dev.ipaddrs or { }
833 end
834
835 function interface.ip6addrs(self)
836 return self.dev and self.dev.ip6addrs or { }
837 end
838
839 function interface.type(self)
840 if self.wif or _wifi_iface(self.ifname) then
841 return "wifi"
842 elseif brs[self.ifname] then
843 return "bridge"
844 elseif self.ifname:match("%.") then
845 return "vlan"
846 elseif sws[self.ifname] then
847 return "switch"
848 else
849 return "ethernet"
850 end
851 end
852
853 function interface.shortname(self)
854 if self.wif then
855 return "%s %q" %{
856 self.wif:active_mode(),
857 self.wif:active_ssid() or self.wif:active_bssid()
858 }
859 else
860 return self.ifname
861 end
862 end
863
864 function interface.get_i18n(self)
865 if self.wif then
866 return "%s: %s %q" %{
867 i18n.translate("Wireless Network"),
868 self.wif:active_mode(),
869 self.wif:active_ssid() or self.wif:active_bssid()
870 }
871 else
872 return "%s: %q" %{ self:get_type_i18n(), self:name() }
873 end
874 end
875
876 function interface.get_type_i18n(self)
877 local x = self:type()
878 if x == "wifi" then
879 return i18n.translate("Wireless Adapter")
880 elseif x == "bridge" then
881 return i18n.translate("Bridge")
882 elseif x == "switch" then
883 return i18n.translate("Ethernet Switch")
884 elseif x == "vlan" then
885 return i18n.translate("VLAN Interface")
886 else
887 return i18n.translate("Ethernet Adapter")
888 end
889 end
890
891 function interface.adminlink(self)
892 if self.wif then
893 return self.wif:adminlink()
894 end
895 end
896
897 function interface.ports(self)
898 if self.br then
899 local iface
900 local ifaces = { }
901 for _, iface in ipairs(self.br.ifnames) do
902 ifaces[#ifaces+1] = interface(iface.name)
903 end
904 return ifaces
905 end
906 end
907
908 function interface.bridge_id(self)
909 if self.br then
910 return self.br.id
911 else
912 return nil
913 end
914 end
915
916 function interface.bridge_stp(self)
917 if self.br then
918 return self.br.stp
919 else
920 return false
921 end
922 end
923
924 function interface.is_up(self)
925 if self.wif then
926 return self.wif:is_up()
927 else
928 return self.dev and self.dev.flags and self.dev.flags.up or false
929 end
930 end
931
932 function interface.is_bridge(self)
933 return (self:type() == "bridge")
934 end
935
936 function interface.is_bridgeport(self)
937 return self.dev and self.dev.bridge and true or false
938 end
939
940 function interface.tx_bytes(self)
941 return self.dev and self.dev.stats
942 and self.dev.stats.tx_bytes or 0
943 end
944
945 function interface.rx_bytes(self)
946 return self.dev and self.dev.stats
947 and self.dev.stats.rx_bytes or 0
948 end
949
950 function interface.tx_packets(self)
951 return self.dev and self.dev.stats
952 and self.dev.stats.tx_packets or 0
953 end
954
955 function interface.rx_packets(self)
956 return self.dev and self.dev.stats
957 and self.dev.stats.rx_packets or 0
958 end
959
960 function interface.get_network(self)
961 if self.dev and self.dev.network then
962 self.network = _M:get_network(self.dev.network)
963 end
964
965 if not self.network then
966 local net
967 for _, net in ipairs(_M:get_networks()) do
968 if net:contains_interface(self.ifname) or
969 net:ifname() == self.ifname
970 then
971 self.network = net
972 return net
973 end
974 end
975 else
976 return self.network
977 end
978 end
979
980 function interface.get_wifinet(self)
981 return self.wif
982 end
983
984
985 wifidev = utl.class()
986 function wifidev.__init__(self, dev)
987 self.sid = dev
988 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
989 end
990
991 function wifidev.get(self, opt)
992 return _get("wireless", self.sid, opt)
993 end
994
995 function wifidev.set(self, opt, val)
996 return _set("wireless", self.sid, opt, val)
997 end
998
999 function wifidev.name(self)
1000 return self.sid
1001 end
1002
1003 function wifidev.hwmodes(self)
1004 local l = self.iwinfo.hwmodelist
1005 if l and next(l) then
1006 return l
1007 else
1008 return { b = true, g = true }
1009 end
1010 end
1011
1012 function wifidev.get_i18n(self)
1013 local t = "Generic"
1014 if self.iwinfo.type == "wl" then
1015 t = "Broadcom"
1016 elseif self.iwinfo.type == "madwifi" then
1017 t = "Atheros"
1018 end
1019
1020 local m = ""
1021 local l = self:hwmodes()
1022 if l.a then m = m .. "a" end
1023 if l.b then m = m .. "b" end
1024 if l.g then m = m .. "g" end
1025 if l.n then m = m .. "n" end
1026
1027 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1028 end
1029
1030 function wifidev.is_up(self)
1031 local up = false
1032
1033 uci_s:foreach("wireless", "wifi-iface",
1034 function(s)
1035 if s.device == self.sid then
1036 if s.up == "1" then
1037 up = true
1038 return false
1039 end
1040 end
1041 end)
1042
1043 return up
1044 end
1045
1046 function wifidev.get_wifinet(self, net)
1047 if uci_r:get("wireless", net) == "wifi-iface" then
1048 return wifinet(net)
1049 else
1050 local wnet = _wifi_lookup(net)
1051 if wnet then
1052 return wifinet(wnet)
1053 end
1054 end
1055 end
1056
1057 function wifidev.get_wifinets(self)
1058 local nets = { }
1059
1060 uci_r:foreach("wireless", "wifi-iface",
1061 function(s)
1062 if s.device == self.sid then
1063 nets[#nets+1] = wifinet(s['.name'])
1064 end
1065 end)
1066
1067 return nets
1068 end
1069
1070 function wifidev.add_wifinet(self, options)
1071 options = options or { }
1072 options.device = self.sid
1073
1074 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1075 if wnet then
1076 return wifinet(wnet, options)
1077 end
1078 end
1079
1080 function wifidev.del_wifinet(self, net)
1081 if utl.instanceof(net, wifinet) then
1082 net = net.sid
1083 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1084 net = _wifi_lookup(net)
1085 end
1086
1087 if net and uci_r:get("wireless", net, "device") == self.sid then
1088 uci_r:delete("wireless", net)
1089 return true
1090 end
1091
1092 return false
1093 end
1094
1095
1096 wifinet = utl.class()
1097 function wifinet.__init__(self, net, data)
1098 self.sid = net
1099
1100 local num = { }
1101 local netid
1102 uci_r:foreach("wireless", "wifi-iface",
1103 function(s)
1104 if s.device then
1105 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1106 if s['.name'] == self.sid then
1107 netid = "%s.network%d" %{ s.device, num[s.device] }
1108 return false
1109 end
1110 end
1111 end)
1112
1113 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1114
1115 self.netid = netid
1116 self.wdev = dev
1117 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1118 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1119 uci_r:get_all("wireless", self.sid) or { }
1120 end
1121
1122 function wifinet.get(self, opt)
1123 return _get("wireless", self.sid, opt)
1124 end
1125
1126 function wifinet.set(self, opt, val)
1127 return _set("wireless", self.sid, opt, val)
1128 end
1129
1130 function wifinet.mode(self)
1131 return uci_s:get("wireless", self.sid, "mode") or "ap"
1132 end
1133
1134 function wifinet.ssid(self)
1135 return uci_s:get("wireless", self.sid, "ssid")
1136 end
1137
1138 function wifinet.bssid(self)
1139 return uci_s:get("wireless", self.sid, "bssid")
1140 end
1141
1142 function wifinet.network(self)
1143 return uci_s:get("wifinet", self.sid, "network")
1144 end
1145
1146 function wifinet.id(self)
1147 return self.netid
1148 end
1149
1150 function wifinet.name(self)
1151 return self.sid
1152 end
1153
1154 function wifinet.ifname(self)
1155 local ifname = self.iwinfo.ifname
1156 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1157 ifname = self.wdev
1158 end
1159 return ifname
1160 end
1161
1162 function wifinet.get_device(self)
1163 if self.iwdata.device then
1164 return wifidev(self.iwdata.device)
1165 end
1166 end
1167
1168 function wifinet.is_up(self)
1169 return (self.iwdata.up == "1")
1170 end
1171
1172 function wifinet.active_mode(self)
1173 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1174
1175 if m == "ap" then m = "Master"
1176 elseif m == "sta" then m = "Client"
1177 elseif m == "adhoc" then m = "Ad-Hoc"
1178 elseif m == "mesh" then m = "Mesh"
1179 elseif m == "monitor" then m = "Monitor"
1180 end
1181
1182 return m
1183 end
1184
1185 function wifinet.active_mode_i18n(self)
1186 return i18n.translate(self:active_mode())
1187 end
1188
1189 function wifinet.active_ssid(self)
1190 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1191 end
1192
1193 function wifinet.active_bssid(self)
1194 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1195 end
1196
1197 function wifinet.active_encryption(self)
1198 local enc = self.iwinfo and self.iwinfo.encryption
1199 return enc and enc.description or "-"
1200 end
1201
1202 function wifinet.assoclist(self)
1203 return self.iwinfo.assoclist or { }
1204 end
1205
1206 function wifinet.frequency(self)
1207 local freq = self.iwinfo.frequency
1208 if freq and freq > 0 then
1209 return "%.03f" % (freq / 1000)
1210 end
1211 end
1212
1213 function wifinet.bitrate(self)
1214 local rate = self.iwinfo.bitrate
1215 if rate and rate > 0 then
1216 return (rate / 1000)
1217 end
1218 end
1219
1220 function wifinet.channel(self)
1221 return self.iwinfo.channel or
1222 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1223 end
1224
1225 function wifinet.signal(self)
1226 return self.iwinfo.signal or 0
1227 end
1228
1229 function wifinet.noise(self)
1230 return self.iwinfo.noise or 0
1231 end
1232
1233 function wifinet.country(self)
1234 return self.iwinfo.country or "00"
1235 end
1236
1237 function wifinet.txpower(self)
1238 return self.iwinfo.txpower or 0
1239 end
1240
1241 function wifinet.signal_level(self, s, n)
1242 if self:active_bssid() ~= "00:00:00:00:00:00" then
1243 local signal = s or self:signal()
1244 local noise = n or self:noise()
1245
1246 if signal < 0 and noise < 0 then
1247 local snr = -1 * (noise - signal)
1248 return math.floor(snr / 5)
1249 else
1250 return 0
1251 end
1252 else
1253 return -1
1254 end
1255 end
1256
1257 function wifinet.signal_percent(self)
1258 local qc = self.iwinfo.quality or 0
1259 local qm = self.iwinfo.quality_max or 0
1260
1261 if qc > 0 and qm > 0 then
1262 return math.floor((100 / qm) * qc)
1263 else
1264 return 0
1265 end
1266 end
1267
1268 function wifinet.shortname(self)
1269 return "%s %q" %{
1270 i18n.translate(self:active_mode()),
1271 self:active_ssid() or self:active_bssid()
1272 }
1273 end
1274
1275 function wifinet.get_i18n(self)
1276 return "%s: %s %q (%s)" %{
1277 i18n.translate("Wireless Network"),
1278 i18n.translate(self:active_mode()),
1279 self:active_ssid() or self:active_bssid(),
1280 self:ifname()
1281 }
1282 end
1283
1284 function wifinet.adminlink(self)
1285 return dsp.build_url("admin", "network", "wireless", self.netid)
1286 end
1287
1288 function wifinet.get_network(self)
1289 if uci_r:get("network", self.iwdata.network) == "interface" then
1290 return network(self.iwdata.network)
1291 end
1292 end
1293
1294 function wifinet.get_interface(self)
1295 return interface(self:ifname())
1296 end