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