libs/core: various interface handling fixes in network model
[project/luci.git] / libs / core / luasrc / model / network.lua
1 --[[
2 LuCI - Network model
3
4 Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local type, 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_floating(self)
678 return (self:is_virtual() and self:proto() ~= "pppoe")
679 end
680
681 function network.is_empty(self)
682 if self:is_virtual() then
683 return false
684 else
685 local rv = true
686
687 if (self:_get("ifname") or ""):match("%S+") then
688 rv = false
689 end
690
691 uci_r:foreach("wireless", "wifi-iface",
692 function(s)
693 if s.network == self.sid then
694 rv = false
695 return false
696 end
697 end)
698
699 return rv
700 end
701 end
702
703 function network.add_interface(self, ifname)
704 if not self:is_floating() then
705 if type(ifname) ~= "string" then
706 ifname = ifname:name()
707 else
708 ifname = ifname:match("[^%s:]+")
709 end
710
711 -- remove the interface from all ifaces
712 uci_r:foreach("network", "interface",
713 function(s)
714 _list_del("network", s['.name'], "ifname", ifname)
715 end)
716
717 -- if its a wifi interface, change its network option
718 local wif = _wifi_lookup(ifname)
719 if wif then
720 uci_r:set("wireless", wif, "network", self.sid)
721
722 -- add iface to our iface list
723 else
724 _list_add("network", self.sid, "ifname", ifname)
725 end
726 end
727 end
728
729 function network.del_interface(self, ifname)
730 if not self:is_floating() then
731 if utl.instanceof(ifname, interface) then
732 ifname = ifname:name()
733 else
734 ifname = ifname:match("[^%s:]+")
735 end
736
737 -- if its a wireless interface, clear its network option
738 local wif = _wifi_lookup(ifname)
739 if wif then uci_r:delete("wireless", wif, "network") end
740
741 -- remove the interface
742 _list_del("network", self.sid, "ifname", ifname)
743 end
744 end
745
746 function network.get_interface(self)
747 if self:is_virtual() then
748 return interface(self:proto() .. "-" .. self.sid)
749 elseif self:is_bridge() then
750 return interface("br-" .. self.sid)
751 else
752 local ifn = nil
753 local num = { }
754 for ifn in utl.imatch(uci_s:get("network", self.sid, "ifname")) do
755 ifn = ifn:match("^[^:/]+")
756 return ifn and interface(ifn)
757 end
758 ifn = nil
759 uci_s:foreach("wireless", "wifi-iface",
760 function(s)
761 if s.device then
762 num[s.device] = num[s.device] and num[s.device] + 1 or 1
763 if s.network == self.sid then
764 ifn = s.ifname or "%s.network%d" %{ s.device, num[s.device] }
765 return false
766 end
767 end
768 end)
769 return ifn and interface(ifn)
770 end
771 end
772
773 function network.get_interfaces(self)
774 local ifaces = { }
775
776 local ifn
777 local nfs = { }
778 for ifn in utl.imatch(self:get("ifname")) do
779 ifn = ifn:match("^[^:/]+")
780 nfs[ifn] = interface(ifn)
781 end
782
783 for ifn in utl.kspairs(nfs) do
784 ifaces[#ifaces+1] = nfs[ifn]
785 end
786
787 local num = { }
788 local wfs = { }
789 uci_r:foreach("wireless", "wifi-iface",
790 function(s)
791 if s.device then
792 num[s.device] = num[s.device] and num[s.device] + 1 or 1
793 if s.network == self.sid then
794 ifn = "%s.network%d" %{ s.device, num[s.device] }
795 wfs[ifn] = interface(ifn)
796 end
797 end
798 end)
799
800 for ifn in utl.kspairs(wfs) do
801 ifaces[#ifaces+1] = wfs[ifn]
802
803 -- only bridges may cover more than one interface
804 --if not self:is_bridge() then
805 -- break
806 --end
807 end
808
809 return ifaces
810 end
811
812 function network.contains_interface(self, ifname)
813 if type(ifname) ~= "string" then
814 ifname = ifname:name()
815 else
816 ifname = ifname:match("[^%s:]+")
817 end
818
819 if self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
820 return true
821 elseif self:is_bridge() and "br-" .. self.sid == ifname then
822 return true
823 else
824 local ifn
825 for ifn in utl.imatch(self:get("ifname")) do
826 ifn = ifn:match("[^:]+")
827 if ifn == ifname then
828 return true
829 end
830 end
831
832 local wif = _wifi_lookup(ifname)
833 if wif then
834 return (uci_r:get("wireless", wif, "network") == self.sid)
835 end
836 end
837
838 return false
839 end
840
841 function network.adminlink(self)
842 return dsp.build_url("admin", "network", "network", self.sid)
843 end
844
845
846 interface = utl.class()
847 function interface.__init__(self, ifname)
848 local wif = _wifi_lookup(ifname)
849 if wif then self.wif = wifinet(wif) end
850
851 self.ifname = self.ifname or ifname
852 self.dev = ifs[self.ifname]
853 end
854
855 function interface.name(self)
856 return self.wif and self.wif:ifname() or self.ifname
857 end
858
859 function interface.mac(self)
860 return self.dev and self.dev.macaddr or "00:00:00:00:00:00"
861 end
862
863 function interface.ipaddrs(self)
864 return self.dev and self.dev.ipaddrs or { }
865 end
866
867 function interface.ip6addrs(self)
868 return self.dev and self.dev.ip6addrs or { }
869 end
870
871 function interface.type(self)
872 if self.wif or _wifi_iface(self.ifname) then
873 return "wifi"
874 elseif brs[self.ifname] then
875 return "bridge"
876 elseif self.ifname:match("%.") then
877 return "vlan"
878 elseif sws[self.ifname] then
879 return "switch"
880 else
881 return "ethernet"
882 end
883 end
884
885 function interface.shortname(self)
886 if self.wif then
887 return "%s %q" %{
888 self.wif:active_mode(),
889 self.wif:active_ssid() or self.wif:active_bssid()
890 }
891 else
892 return self.ifname
893 end
894 end
895
896 function interface.get_i18n(self)
897 if self.wif then
898 return "%s: %s %q" %{
899 i18n.translate("Wireless Network"),
900 self.wif:active_mode(),
901 self.wif:active_ssid() or self.wif:active_bssid()
902 }
903 else
904 return "%s: %q" %{ self:get_type_i18n(), self:name() }
905 end
906 end
907
908 function interface.get_type_i18n(self)
909 local x = self:type()
910 if x == "wifi" then
911 return i18n.translate("Wireless Adapter")
912 elseif x == "bridge" then
913 return i18n.translate("Bridge")
914 elseif x == "switch" then
915 return i18n.translate("Ethernet Switch")
916 elseif x == "vlan" then
917 return i18n.translate("VLAN Interface")
918 else
919 return i18n.translate("Ethernet Adapter")
920 end
921 end
922
923 function interface.adminlink(self)
924 if self.wif then
925 return self.wif:adminlink()
926 end
927 end
928
929 function interface.ports(self)
930 if self.br then
931 local iface
932 local ifaces = { }
933 for _, iface in ipairs(self.br.ifnames) do
934 ifaces[#ifaces+1] = interface(iface.name)
935 end
936 return ifaces
937 end
938 end
939
940 function interface.bridge_id(self)
941 if self.br then
942 return self.br.id
943 else
944 return nil
945 end
946 end
947
948 function interface.bridge_stp(self)
949 if self.br then
950 return self.br.stp
951 else
952 return false
953 end
954 end
955
956 function interface.is_up(self)
957 if self.wif then
958 return self.wif:is_up()
959 else
960 return self.dev and self.dev.flags and self.dev.flags.up or false
961 end
962 end
963
964 function interface.is_bridge(self)
965 return (self:type() == "bridge")
966 end
967
968 function interface.is_bridgeport(self)
969 return self.dev and self.dev.bridge and true or false
970 end
971
972 function interface.tx_bytes(self)
973 return self.dev and self.dev.stats
974 and self.dev.stats.tx_bytes or 0
975 end
976
977 function interface.rx_bytes(self)
978 return self.dev and self.dev.stats
979 and self.dev.stats.rx_bytes or 0
980 end
981
982 function interface.tx_packets(self)
983 return self.dev and self.dev.stats
984 and self.dev.stats.tx_packets or 0
985 end
986
987 function interface.rx_packets(self)
988 return self.dev and self.dev.stats
989 and self.dev.stats.rx_packets or 0
990 end
991
992 function interface.get_network(self)
993 if self.dev and self.dev.network then
994 self.network = _M:get_network(self.dev.network)
995 end
996
997 if not self.network then
998 local net
999 for _, net in ipairs(_M:get_networks()) do
1000 if net:contains_interface(self.ifname) or
1001 net:ifname() == self.ifname
1002 then
1003 self.network = net
1004 return net
1005 end
1006 end
1007 else
1008 return self.network
1009 end
1010 end
1011
1012 function interface.get_wifinet(self)
1013 return self.wif
1014 end
1015
1016
1017 wifidev = utl.class()
1018 function wifidev.__init__(self, dev)
1019 self.sid = dev
1020 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1021 end
1022
1023 function wifidev.get(self, opt)
1024 return _get("wireless", self.sid, opt)
1025 end
1026
1027 function wifidev.set(self, opt, val)
1028 return _set("wireless", self.sid, opt, val)
1029 end
1030
1031 function wifidev.name(self)
1032 return self.sid
1033 end
1034
1035 function wifidev.hwmodes(self)
1036 local l = self.iwinfo.hwmodelist
1037 if l and next(l) then
1038 return l
1039 else
1040 return { b = true, g = true }
1041 end
1042 end
1043
1044 function wifidev.get_i18n(self)
1045 local t = "Generic"
1046 if self.iwinfo.type == "wl" then
1047 t = "Broadcom"
1048 elseif self.iwinfo.type == "madwifi" then
1049 t = "Atheros"
1050 end
1051
1052 local m = ""
1053 local l = self:hwmodes()
1054 if l.a then m = m .. "a" end
1055 if l.b then m = m .. "b" end
1056 if l.g then m = m .. "g" end
1057 if l.n then m = m .. "n" end
1058
1059 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1060 end
1061
1062 function wifidev.is_up(self)
1063 local up = false
1064
1065 uci_s:foreach("wireless", "wifi-iface",
1066 function(s)
1067 if s.device == self.sid then
1068 if s.up == "1" then
1069 up = true
1070 return false
1071 end
1072 end
1073 end)
1074
1075 return up
1076 end
1077
1078 function wifidev.get_wifinet(self, net)
1079 if uci_r:get("wireless", net) == "wifi-iface" then
1080 return wifinet(net)
1081 else
1082 local wnet = _wifi_lookup(net)
1083 if wnet then
1084 return wifinet(wnet)
1085 end
1086 end
1087 end
1088
1089 function wifidev.get_wifinets(self)
1090 local nets = { }
1091
1092 uci_r:foreach("wireless", "wifi-iface",
1093 function(s)
1094 if s.device == self.sid then
1095 nets[#nets+1] = wifinet(s['.name'])
1096 end
1097 end)
1098
1099 return nets
1100 end
1101
1102 function wifidev.add_wifinet(self, options)
1103 options = options or { }
1104 options.device = self.sid
1105
1106 local wnet = uci_r:section("wireless", "wifi-iface", nil, options)
1107 if wnet then
1108 return wifinet(wnet, options)
1109 end
1110 end
1111
1112 function wifidev.del_wifinet(self, net)
1113 if utl.instanceof(net, wifinet) then
1114 net = net.sid
1115 elseif uci_r:get("wireless", net) ~= "wifi-iface" then
1116 net = _wifi_lookup(net)
1117 end
1118
1119 if net and uci_r:get("wireless", net, "device") == self.sid then
1120 uci_r:delete("wireless", net)
1121 return true
1122 end
1123
1124 return false
1125 end
1126
1127
1128 wifinet = utl.class()
1129 function wifinet.__init__(self, net, data)
1130 self.sid = net
1131
1132 local num = { }
1133 local netid
1134 uci_r:foreach("wireless", "wifi-iface",
1135 function(s)
1136 if s.device then
1137 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1138 if s['.name'] == self.sid then
1139 netid = "%s.network%d" %{ s.device, num[s.device] }
1140 return false
1141 end
1142 end
1143 end)
1144
1145 local dev = uci_s:get("wireless", self.sid, "ifname") or netid
1146
1147 self.netid = netid
1148 self.wdev = dev
1149 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1150 self.iwdata = data or uci_s:get_all("wireless", self.sid) or
1151 uci_r:get_all("wireless", self.sid) or { }
1152 end
1153
1154 function wifinet.get(self, opt)
1155 return _get("wireless", self.sid, opt)
1156 end
1157
1158 function wifinet.set(self, opt, val)
1159 return _set("wireless", self.sid, opt, val)
1160 end
1161
1162 function wifinet.mode(self)
1163 return uci_s:get("wireless", self.sid, "mode") or "ap"
1164 end
1165
1166 function wifinet.ssid(self)
1167 return uci_s:get("wireless", self.sid, "ssid")
1168 end
1169
1170 function wifinet.bssid(self)
1171 return uci_s:get("wireless", self.sid, "bssid")
1172 end
1173
1174 function wifinet.network(self)
1175 return uci_s:get("wifinet", self.sid, "network")
1176 end
1177
1178 function wifinet.id(self)
1179 return self.netid
1180 end
1181
1182 function wifinet.name(self)
1183 return self.sid
1184 end
1185
1186 function wifinet.ifname(self)
1187 local ifname = self.iwinfo.ifname
1188 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1189 ifname = self.wdev
1190 end
1191 return ifname
1192 end
1193
1194 function wifinet.get_device(self)
1195 if self.iwdata.device then
1196 return wifidev(self.iwdata.device)
1197 end
1198 end
1199
1200 function wifinet.is_up(self)
1201 return (self.iwdata.up == "1")
1202 end
1203
1204 function wifinet.active_mode(self)
1205 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1206
1207 if m == "ap" then m = "Master"
1208 elseif m == "sta" then m = "Client"
1209 elseif m == "adhoc" then m = "Ad-Hoc"
1210 elseif m == "mesh" then m = "Mesh"
1211 elseif m == "monitor" then m = "Monitor"
1212 end
1213
1214 return m
1215 end
1216
1217 function wifinet.active_mode_i18n(self)
1218 return i18n.translate(self:active_mode())
1219 end
1220
1221 function wifinet.active_ssid(self)
1222 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1223 end
1224
1225 function wifinet.active_bssid(self)
1226 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1227 end
1228
1229 function wifinet.active_encryption(self)
1230 local enc = self.iwinfo and self.iwinfo.encryption
1231 return enc and enc.description or "-"
1232 end
1233
1234 function wifinet.assoclist(self)
1235 return self.iwinfo.assoclist or { }
1236 end
1237
1238 function wifinet.frequency(self)
1239 local freq = self.iwinfo.frequency
1240 if freq and freq > 0 then
1241 return "%.03f" % (freq / 1000)
1242 end
1243 end
1244
1245 function wifinet.bitrate(self)
1246 local rate = self.iwinfo.bitrate
1247 if rate and rate > 0 then
1248 return (rate / 1000)
1249 end
1250 end
1251
1252 function wifinet.channel(self)
1253 return self.iwinfo.channel or
1254 tonumber(uci_s:get("wireless", self.iwdata.device, "channel"))
1255 end
1256
1257 function wifinet.signal(self)
1258 return self.iwinfo.signal or 0
1259 end
1260
1261 function wifinet.noise(self)
1262 return self.iwinfo.noise or 0
1263 end
1264
1265 function wifinet.country(self)
1266 return self.iwinfo.country or "00"
1267 end
1268
1269 function wifinet.txpower(self)
1270 return self.iwinfo.txpower or 0
1271 end
1272
1273 function wifinet.signal_level(self, s, n)
1274 if self:active_bssid() ~= "00:00:00:00:00:00" then
1275 local signal = s or self:signal()
1276 local noise = n or self:noise()
1277
1278 if signal < 0 and noise < 0 then
1279 local snr = -1 * (noise - signal)
1280 return math.floor(snr / 5)
1281 else
1282 return 0
1283 end
1284 else
1285 return -1
1286 end
1287 end
1288
1289 function wifinet.signal_percent(self)
1290 local qc = self.iwinfo.quality or 0
1291 local qm = self.iwinfo.quality_max or 0
1292
1293 if qc > 0 and qm > 0 then
1294 return math.floor((100 / qm) * qc)
1295 else
1296 return 0
1297 end
1298 end
1299
1300 function wifinet.shortname(self)
1301 return "%s %q" %{
1302 i18n.translate(self:active_mode()),
1303 self:active_ssid() or self:active_bssid()
1304 }
1305 end
1306
1307 function wifinet.get_i18n(self)
1308 return "%s: %s %q (%s)" %{
1309 i18n.translate("Wireless Network"),
1310 i18n.translate(self:active_mode()),
1311 self:active_ssid() or self:active_bssid(),
1312 self:ifname()
1313 }
1314 end
1315
1316 function wifinet.adminlink(self)
1317 return dsp.build_url("admin", "network", "wireless", self.netid)
1318 end
1319
1320 function wifinet.get_network(self)
1321 if uci_r:get("network", self.iwdata.network) == "interface" then
1322 return network(self.iwdata.network)
1323 end
1324 end
1325
1326 function wifinet.get_interface(self)
1327 return interface(self:ifname())
1328 end