dd2bdfb90633517a20677dcd4d54f1b10e7d4941
[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 local baseof = { }
453
454 -- find normal interfaces
455 _uci_real:foreach("network", "interface",
456 function(s)
457 for iface in utl.imatch(s.ifname) do
458 if not _iface_ignore(iface) and not _wifi_iface(iface) then
459 seen[iface] = true
460 nfs[iface] = interface(iface)
461 end
462 end
463 end)
464
465 for iface in utl.kspairs(_interfaces) do
466 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
467 nfs[iface] = interface(iface)
468 end
469 end
470
471 -- find vlan interfaces
472 _uci_real:foreach("network", "switch_vlan",
473 function(s)
474 if not s.device then
475 return
476 end
477
478 local base = baseof[s.device]
479 if not base then
480 if not s.device:match("^eth%d") then
481 local l
482 for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
483 if not base then
484 base = l:match("^%w+: (%w+)")
485 end
486 end
487 if not base or not base:match("^eth%d") then
488 base = "eth0"
489 end
490 else
491 base = s.device
492 end
493 baseof[s.device] = base
494 end
495
496 local vid = tonumber(s.vid or s.vlan)
497 if vid ~= nil and vid >= 0 and vid <= 4095 then
498 local iface = "%s.%d" %{ base, vid }
499 if not seen[iface] then
500 seen[iface] = true
501 nfs[iface] = interface(iface)
502 end
503 end
504 end)
505
506 for iface in utl.kspairs(nfs) do
507 ifaces[#ifaces+1] = nfs[iface]
508 end
509
510 -- find wifi interfaces
511 local num = { }
512 local wfs = { }
513 _uci_real:foreach("wireless", "wifi-iface",
514 function(s)
515 if s.device then
516 num[s.device] = num[s.device] and num[s.device] + 1 or 1
517 local i = "%s.network%d" %{ s.device, num[s.device] }
518 wfs[i] = interface(i)
519 end
520 end)
521
522 for iface in utl.kspairs(wfs) do
523 ifaces[#ifaces+1] = wfs[iface]
524 end
525
526 return ifaces
527 end
528
529 function ignore_interface(self, x)
530 return _iface_ignore(x)
531 end
532
533 function get_wifidev(self, dev)
534 if _uci_real:get("wireless", dev) == "wifi-device" then
535 return wifidev(dev)
536 end
537 end
538
539 function get_wifidevs(self)
540 local devs = { }
541 local wfd = { }
542
543 _uci_real:foreach("wireless", "wifi-device",
544 function(s) wfd[#wfd+1] = s['.name'] end)
545
546 local dev
547 for _, dev in utl.vspairs(wfd) do
548 devs[#devs+1] = wifidev(dev)
549 end
550
551 return devs
552 end
553
554 function get_wifinet(self, net)
555 local wnet = _wifi_lookup(net)
556 if wnet then
557 return wifinet(wnet)
558 end
559 end
560
561 function add_wifinet(self, net, options)
562 if type(options) == "table" and options.device and
563 _uci_real:get("wireless", options.device) == "wifi-device"
564 then
565 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
566 return wifinet(wnet)
567 end
568 end
569
570 function del_wifinet(self, net)
571 local wnet = _wifi_lookup(net)
572 if wnet then
573 _uci_real:delete("wireless", wnet)
574 return true
575 end
576 return false
577 end
578
579
580 function network(name, proto)
581 if name then
582 local p = proto or _uci_real:get("network", name, "proto")
583 local c = p and _protocols[p] or protocol
584 return c(name)
585 end
586 end
587
588 function protocol.__init__(self, name)
589 self.sid = name
590 end
591
592 function protocol._get(self, opt)
593 local v = _uci_real:get("network", self.sid, opt)
594 if type(v) == "table" then
595 return table.concat(v, " ")
596 end
597 return v or ""
598 end
599
600 function protocol._ip(self, opt, family, list)
601 local ip = _uci_state:get("network", self.sid, opt)
602 local fc = (family == 6) and ipc.IPv6 or ipc.IPv4
603 if ip or list then
604 if list then
605 local l = { }
606 for ip in utl.imatch(ip) do
607 ip = fc(ip)
608 if ip then l[#l+1] = ip:string() end
609 end
610 return l
611 else
612 ip = fc(ip)
613 return ip and ip:string()
614 end
615 end
616 end
617
618 function protocol.get(self, opt)
619 return _get("network", self.sid, opt)
620 end
621
622 function protocol.set(self, opt, val)
623 return _set("network", self.sid, opt, val)
624 end
625
626 function protocol.ifname(self)
627 local p = self:proto()
628 if self:is_bridge() then
629 return "br-" .. self.sid
630 elseif self:is_virtual() then
631 return p .. "-" .. self.sid
632 else
633 local num = { }
634 local dev = _uci_real:get("network", self.sid, "ifname") or
635 _uci_state:get("network", self.sid, "ifname")
636
637 dev = (type(dev) == "table") and dev[1] or dev
638 dev = (dev ~= nil) and dev:match("%S+")
639
640 if not dev then
641 _uci_real:foreach("wireless", "wifi-iface",
642 function(s)
643 if s.device then
644 num[s.device] = num[s.device]
645 and num[s.device] + 1 or 1
646
647 if s.network == self.sid then
648 dev = "%s.network%d" %{ s.device, num[s.device] }
649 return false
650 end
651 end
652 end)
653 end
654
655 return dev
656 end
657 end
658
659 function protocol.proto(self)
660 return "none"
661 end
662
663 function protocol.get_i18n(self)
664 local p = self:proto()
665 if p == "none" then
666 return i18n.translate("Unmanaged")
667 elseif p == "static" then
668 return i18n.translate("Static address")
669 elseif p == "dhcp" then
670 return i18n.translate("DHCP client")
671 else
672 return i18n.translate("Unknown")
673 end
674 end
675
676 function protocol.type(self)
677 return self:_get("type")
678 end
679
680 function protocol.name(self)
681 return self.sid
682 end
683
684 function protocol.uptime(self)
685 local cnt = tonumber(_uci_state:get("network", self.sid, "connect_time"))
686 if cnt ~= nil then
687 return nxo.sysinfo().uptime - cnt
688 else
689 return 0
690 end
691 end
692
693 function protocol.expires(self)
694 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
695 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
696 if a and l then
697 l = l - (nxo.sysinfo().uptime - a)
698 return l > 0 and l or 0
699 end
700 return -1
701 end
702
703 function protocol.metric(self)
704 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
705 end
706
707 function protocol.ipaddr(self)
708 return self:_ip("ipaddr", 4)
709 end
710
711 function protocol.netmask(self)
712 return self:_ip("netmask", 4)
713 end
714
715 function protocol.gwaddr(self)
716 return self:_ip("gateway", 4)
717 end
718
719 function protocol.dnsaddrs(self)
720 return self:_ip("dns", 4, true)
721 end
722
723 function protocol.ip6addr(self)
724 local ip6 = self:_ip("ip6addr", 6)
725 if not ip6 then
726 local ifc = _interfaces[self:ifname()]
727 if ifc and ifc.ip6addrs then
728 local a
729 for _, a in ipairs(ifc.ip6addrs) do
730 if not a:is6linklocal() then
731 ip6 = a:string()
732 break
733 end
734 end
735 end
736 end
737 return ip6
738 end
739
740 function protocol.gw6addr(self)
741 local ip6 = self:_ip("ip6gw", 6)
742 if not ip6 then
743 local dr6 = sys.net.defaultroute6()
744 if dr6 and dr6.device == self:ifname() then
745 return dr6.nexthop:string()
746 end
747 end
748 return ip6
749 end
750
751 function protocol.dns6addrs(self)
752 return self:_ip("dns", 6, true)
753 end
754
755 function protocol.is_bridge(self)
756 return (not self:is_virtual() and self:type() == "bridge")
757 end
758
759 function protocol.opkg_package(self)
760 return nil
761 end
762
763 function protocol.is_installed(self)
764 return true
765 end
766
767 function protocol.is_virtual(self)
768 return false
769 end
770
771 function protocol.is_floating(self)
772 return false
773 end
774
775 function protocol.is_empty(self)
776 if self:is_floating() then
777 return false
778 else
779 local rv = true
780
781 if (self:_get("ifname") or ""):match("%S+") then
782 rv = false
783 end
784
785 _uci_real:foreach("wireless", "wifi-iface",
786 function(s)
787 if s.network == self.sid then
788 rv = false
789 return false
790 end
791 end)
792
793 return rv
794 end
795 end
796
797 function protocol.add_interface(self, ifname)
798 ifname = _M:ifnameof(ifname)
799 if ifname and not self:is_floating() then
800 -- remove the interface from all ifaces
801 _uci_real:foreach("network", "interface",
802 function(s)
803 _filter("network", s['.name'], "ifname", ifname)
804 end)
805
806 -- if its a wifi interface, change its network option
807 local wif = _wifi_lookup(ifname)
808 if wif then
809 _uci_real:set("wireless", wif, "network", self.sid)
810
811 -- add iface to our iface list
812 else
813 _append("network", self.sid, "ifname", ifname)
814 end
815 end
816 end
817
818 function protocol.del_interface(self, ifname)
819 ifname = _M:ifnameof(ifname)
820 if ifname and not self:is_floating() then
821 -- if its a wireless interface, clear its network option
822 local wif = _wifi_lookup(ifname)
823 if wif then _uci_real:delete("wireless", wif, "network") end
824
825 -- remove the interface
826 _filter("network", self.sid, "ifname", ifname)
827 end
828 end
829
830 function protocol.get_interface(self)
831 if self:is_virtual() then
832 _tunnel[self:proto() .. "-" .. self.sid] = true
833 return interface(self:proto() .. "-" .. self.sid, self)
834 elseif self:is_bridge() then
835 _bridge["br-" .. self.sid] = true
836 return interface("br-" .. self.sid, self)
837 else
838 local ifn = nil
839 local num = { }
840 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
841 ifn = ifn:match("^[^:/]+")
842 return ifn and interface(ifn, self)
843 end
844 ifn = nil
845 _uci_real:foreach("wireless", "wifi-iface",
846 function(s)
847 if s.device then
848 num[s.device] = num[s.device] and num[s.device] + 1 or 1
849 if s.network == self.sid then
850 ifn = s.ifname or "%s.network%d" %{ s.device, num[s.device] }
851 return false
852 end
853 end
854 end)
855 return ifn and interface(ifn, self)
856 end
857 end
858
859 function protocol.get_interfaces(self)
860 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
861 local ifaces = { }
862
863 local ifn
864 local nfs = { }
865 for ifn in utl.imatch(self:get("ifname")) do
866 ifn = ifn:match("^[^:/]+")
867 nfs[ifn] = interface(ifn, self)
868 end
869
870 for ifn in utl.kspairs(nfs) do
871 ifaces[#ifaces+1] = nfs[ifn]
872 end
873
874 local num = { }
875 local wfs = { }
876 _uci_real:foreach("wireless", "wifi-iface",
877 function(s)
878 if s.device then
879 num[s.device] = num[s.device] and num[s.device] + 1 or 1
880 if s.network == self.sid then
881 ifn = "%s.network%d" %{ s.device, num[s.device] }
882 wfs[ifn] = interface(ifn, self)
883 end
884 end
885 end)
886
887 for ifn in utl.kspairs(wfs) do
888 ifaces[#ifaces+1] = wfs[ifn]
889 end
890
891 return ifaces
892 end
893 end
894
895 function protocol.contains_interface(self, ifname)
896 ifname = _M:ifnameof(ifname)
897 if not ifname then
898 return false
899 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
900 return true
901 elseif self:is_bridge() and "br-" .. self.sid == ifname then
902 return true
903 else
904 local ifn
905 for ifn in utl.imatch(self:get("ifname")) do
906 ifn = ifn:match("[^:]+")
907 if ifn == ifname then
908 return true
909 end
910 end
911
912 local wif = _wifi_lookup(ifname)
913 if wif then
914 return (_uci_real:get("wireless", wif, "network") == self.sid)
915 end
916 end
917
918 return false
919 end
920
921 function protocol.adminlink(self)
922 return dsp.build_url("admin", "network", "network", self.sid)
923 end
924
925
926 interface = utl.class()
927
928 function interface.__init__(self, ifname, network)
929 local wif = _wifi_lookup(ifname)
930 if wif then self.wif = wifinet(wif) end
931
932 self.ifname = self.ifname or ifname
933 self.dev = _interfaces[self.ifname]
934 self.network = network
935 end
936
937 function interface.name(self)
938 return self.wif and self.wif:ifname() or self.ifname
939 end
940
941 function interface.mac(self)
942 return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper()
943 end
944
945 function interface.ipaddrs(self)
946 return self.dev and self.dev.ipaddrs or { }
947 end
948
949 function interface.ip6addrs(self)
950 return self.dev and self.dev.ip6addrs or { }
951 end
952
953 function interface.type(self)
954 if self.wif or _wifi_iface(self.ifname) then
955 return "wifi"
956 elseif _bridge[self.ifname] then
957 return "bridge"
958 elseif _tunnel[self.ifname] then
959 return "tunnel"
960 elseif self.ifname:match("%.") then
961 return "vlan"
962 elseif _switch[self.ifname] then
963 return "switch"
964 else
965 return "ethernet"
966 end
967 end
968
969 function interface.shortname(self)
970 if self.wif then
971 return "%s %q" %{
972 self.wif:active_mode(),
973 self.wif:active_ssid() or self.wif:active_bssid()
974 }
975 else
976 return self.ifname
977 end
978 end
979
980 function interface.get_i18n(self)
981 if self.wif then
982 return "%s: %s %q" %{
983 i18n.translate("Wireless Network"),
984 self.wif:active_mode(),
985 self.wif:active_ssid() or self.wif:active_bssid()
986 }
987 else
988 return "%s: %q" %{ self:get_type_i18n(), self:name() }
989 end
990 end
991
992 function interface.get_type_i18n(self)
993 local x = self:type()
994 if x == "wifi" then
995 return i18n.translate("Wireless Adapter")
996 elseif x == "bridge" then
997 return i18n.translate("Bridge")
998 elseif x == "switch" then
999 return i18n.translate("Ethernet Switch")
1000 elseif x == "vlan" then
1001 return i18n.translate("VLAN Interface")
1002 elseif x == "tunnel" then
1003 return i18n.translate("Tunnel Interface")
1004 else
1005 return i18n.translate("Ethernet Adapter")
1006 end
1007 end
1008
1009 function interface.adminlink(self)
1010 if self.wif then
1011 return self.wif:adminlink()
1012 end
1013 end
1014
1015 function interface.ports(self)
1016 if self.br then
1017 local iface
1018 local ifaces = { }
1019 for _, iface in ipairs(self.br.ifnames) do
1020 ifaces[#ifaces+1] = interface(iface.name)
1021 end
1022 return ifaces
1023 end
1024 end
1025
1026 function interface.bridge_id(self)
1027 if self.br then
1028 return self.br.id
1029 else
1030 return nil
1031 end
1032 end
1033
1034 function interface.bridge_stp(self)
1035 if self.br then
1036 return self.br.stp
1037 else
1038 return false
1039 end
1040 end
1041
1042 function interface.is_up(self)
1043 if self.wif then
1044 return self.wif:is_up()
1045 else
1046 return self.dev and self.dev.flags and self.dev.flags.up or false
1047 end
1048 end
1049
1050 function interface.is_bridge(self)
1051 return (self:type() == "bridge")
1052 end
1053
1054 function interface.is_bridgeport(self)
1055 return self.dev and self.dev.bridge and true or false
1056 end
1057
1058 function interface.tx_bytes(self)
1059 return self.dev and self.dev.stats
1060 and self.dev.stats.tx_bytes or 0
1061 end
1062
1063 function interface.rx_bytes(self)
1064 return self.dev and self.dev.stats
1065 and self.dev.stats.rx_bytes or 0
1066 end
1067
1068 function interface.tx_packets(self)
1069 return self.dev and self.dev.stats
1070 and self.dev.stats.tx_packets or 0
1071 end
1072
1073 function interface.rx_packets(self)
1074 return self.dev and self.dev.stats
1075 and self.dev.stats.rx_packets or 0
1076 end
1077
1078 function interface.get_network(self)
1079 if not self.network then
1080 if self.dev and self.dev.network then
1081 self.network = _M:get_network(self.dev.network)
1082 end
1083 end
1084
1085 if not self.network then
1086 local net
1087 for _, net in ipairs(_M:get_networks()) do
1088 if net:contains_interface(self.ifname) or
1089 net:ifname() == self.ifname
1090 then
1091 self.network = net
1092 return net
1093 end
1094 end
1095 else
1096 return self.network
1097 end
1098 end
1099
1100 function interface.get_wifinet(self)
1101 return self.wif
1102 end
1103
1104
1105 wifidev = utl.class()
1106
1107 function wifidev.__init__(self, dev)
1108 self.sid = dev
1109 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1110 end
1111
1112 function wifidev.get(self, opt)
1113 return _get("wireless", self.sid, opt)
1114 end
1115
1116 function wifidev.set(self, opt, val)
1117 return _set("wireless", self.sid, opt, val)
1118 end
1119
1120 function wifidev.name(self)
1121 return self.sid
1122 end
1123
1124 function wifidev.hwmodes(self)
1125 local l = self.iwinfo.hwmodelist
1126 if l and next(l) then
1127 return l
1128 else
1129 return { b = true, g = true }
1130 end
1131 end
1132
1133 function wifidev.get_i18n(self)
1134 local t = "Generic"
1135 if self.iwinfo.type == "wl" then
1136 t = "Broadcom"
1137 elseif self.iwinfo.type == "madwifi" then
1138 t = "Atheros"
1139 end
1140
1141 local m = ""
1142 local l = self:hwmodes()
1143 if l.a then m = m .. "a" end
1144 if l.b then m = m .. "b" end
1145 if l.g then m = m .. "g" end
1146 if l.n then m = m .. "n" end
1147
1148 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1149 end
1150
1151 function wifidev.is_up(self)
1152 local up = false
1153
1154 _uci_state:foreach("wireless", "wifi-iface",
1155 function(s)
1156 if s.device == self.sid then
1157 if s.up == "1" then
1158 up = true
1159 return false
1160 end
1161 end
1162 end)
1163
1164 return up
1165 end
1166
1167 function wifidev.get_wifinet(self, net)
1168 if _uci_real:get("wireless", net) == "wifi-iface" then
1169 return wifinet(net)
1170 else
1171 local wnet = _wifi_lookup(net)
1172 if wnet then
1173 return wifinet(wnet)
1174 end
1175 end
1176 end
1177
1178 function wifidev.get_wifinets(self)
1179 local nets = { }
1180
1181 _uci_real:foreach("wireless", "wifi-iface",
1182 function(s)
1183 if s.device == self.sid then
1184 nets[#nets+1] = wifinet(s['.name'])
1185 end
1186 end)
1187
1188 return nets
1189 end
1190
1191 function wifidev.add_wifinet(self, options)
1192 options = options or { }
1193 options.device = self.sid
1194
1195 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1196 if wnet then
1197 return wifinet(wnet, options)
1198 end
1199 end
1200
1201 function wifidev.del_wifinet(self, net)
1202 if utl.instanceof(net, wifinet) then
1203 net = net.sid
1204 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1205 net = _wifi_lookup(net)
1206 end
1207
1208 if net and _uci_real:get("wireless", net, "device") == self.sid then
1209 _uci_real:delete("wireless", net)
1210 return true
1211 end
1212
1213 return false
1214 end
1215
1216
1217 wifinet = utl.class()
1218
1219 function wifinet.__init__(self, net, data)
1220 self.sid = net
1221
1222 local num = { }
1223 local netid
1224 _uci_real:foreach("wireless", "wifi-iface",
1225 function(s)
1226 if s.device then
1227 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1228 if s['.name'] == self.sid then
1229 netid = "%s.network%d" %{ s.device, num[s.device] }
1230 return false
1231 end
1232 end
1233 end)
1234
1235 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1236
1237 self.netid = netid
1238 self.wdev = dev
1239 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1240 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1241 _uci_real:get_all("wireless", self.sid) or { }
1242 end
1243
1244 function wifinet.get(self, opt)
1245 return _get("wireless", self.sid, opt)
1246 end
1247
1248 function wifinet.set(self, opt, val)
1249 return _set("wireless", self.sid, opt, val)
1250 end
1251
1252 function wifinet.mode(self)
1253 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1254 end
1255
1256 function wifinet.ssid(self)
1257 return _uci_state:get("wireless", self.sid, "ssid")
1258 end
1259
1260 function wifinet.bssid(self)
1261 return _uci_state:get("wireless", self.sid, "bssid")
1262 end
1263
1264 function wifinet.network(self)
1265 return _uci_state:get("wifinet", self.sid, "network")
1266 end
1267
1268 function wifinet.id(self)
1269 return self.netid
1270 end
1271
1272 function wifinet.name(self)
1273 return self.sid
1274 end
1275
1276 function wifinet.ifname(self)
1277 local ifname = self.iwinfo.ifname
1278 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1279 ifname = self.wdev
1280 end
1281 return ifname
1282 end
1283
1284 function wifinet.get_device(self)
1285 if self.iwdata.device then
1286 return wifidev(self.iwdata.device)
1287 end
1288 end
1289
1290 function wifinet.is_up(self)
1291 return (self.iwdata.up == "1")
1292 end
1293
1294 function wifinet.active_mode(self)
1295 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1296
1297 if m == "ap" then m = "Master"
1298 elseif m == "sta" then m = "Client"
1299 elseif m == "adhoc" then m = "Ad-Hoc"
1300 elseif m == "mesh" then m = "Mesh"
1301 elseif m == "monitor" then m = "Monitor"
1302 end
1303
1304 return m
1305 end
1306
1307 function wifinet.active_mode_i18n(self)
1308 return i18n.translate(self:active_mode())
1309 end
1310
1311 function wifinet.active_ssid(self)
1312 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1313 end
1314
1315 function wifinet.active_bssid(self)
1316 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1317 end
1318
1319 function wifinet.active_encryption(self)
1320 local enc = self.iwinfo and self.iwinfo.encryption
1321 return enc and enc.description or "-"
1322 end
1323
1324 function wifinet.assoclist(self)
1325 return self.iwinfo.assoclist or { }
1326 end
1327
1328 function wifinet.frequency(self)
1329 local freq = self.iwinfo.frequency
1330 if freq and freq > 0 then
1331 return "%.03f" % (freq / 1000)
1332 end
1333 end
1334
1335 function wifinet.bitrate(self)
1336 local rate = self.iwinfo.bitrate
1337 if rate and rate > 0 then
1338 return (rate / 1000)
1339 end
1340 end
1341
1342 function wifinet.channel(self)
1343 return self.iwinfo.channel or
1344 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1345 end
1346
1347 function wifinet.signal(self)
1348 return self.iwinfo.signal or 0
1349 end
1350
1351 function wifinet.noise(self)
1352 return self.iwinfo.noise or 0
1353 end
1354
1355 function wifinet.country(self)
1356 return self.iwinfo.country or "00"
1357 end
1358
1359 function wifinet.txpower(self)
1360 return self.iwinfo.txpower or 0
1361 end
1362
1363 function wifinet.signal_level(self, s, n)
1364 if self:active_bssid() ~= "00:00:00:00:00:00" then
1365 local signal = s or self:signal()
1366 local noise = n or self:noise()
1367
1368 if signal < 0 and noise < 0 then
1369 local snr = -1 * (noise - signal)
1370 return math.floor(snr / 5)
1371 else
1372 return 0
1373 end
1374 else
1375 return -1
1376 end
1377 end
1378
1379 function wifinet.signal_percent(self)
1380 local qc = self.iwinfo.quality or 0
1381 local qm = self.iwinfo.quality_max or 0
1382
1383 if qc > 0 and qm > 0 then
1384 return math.floor((100 / qm) * qc)
1385 else
1386 return 0
1387 end
1388 end
1389
1390 function wifinet.shortname(self)
1391 return "%s %q" %{
1392 i18n.translate(self:active_mode()),
1393 self:active_ssid() or self:active_bssid()
1394 }
1395 end
1396
1397 function wifinet.get_i18n(self)
1398 return "%s: %s %q (%s)" %{
1399 i18n.translate("Wireless Network"),
1400 i18n.translate(self:active_mode()),
1401 self:active_ssid() or self:active_bssid(),
1402 self:ifname()
1403 }
1404 end
1405
1406 function wifinet.adminlink(self)
1407 return dsp.build_url("admin", "network", "wireless", self.netid)
1408 end
1409
1410 function wifinet.get_network(self)
1411 if _uci_real:get("network", self.iwdata.network) == "interface" then
1412 return network(self.iwdata.network)
1413 end
1414 end
1415
1416 function wifinet.get_interface(self)
1417 return interface(self:ifname())
1418 end
1419
1420
1421 -- setup base protocols
1422 _M:register_protocol("static")
1423 _M:register_protocol("dhcp")
1424 _M:register_protocol("none")
1425
1426 -- load protocol extensions
1427 local exts = nfs.dir(utl.libpath() .. "/model/network")
1428 if exts then
1429 local ext
1430 for ext in exts do
1431 if ext:match("%.lua$") then
1432 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1433 end
1434 end
1435 end