61da9dfd0414ebf7af04ca135fe934ca4437b38b
[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.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
931 self.wif = wifinet(wif)
932 self.ifname = _uci_state:get("wireless", wif, "ifname")
933 end
934
935 self.ifname = self.ifname or ifname
936 self.dev = _interfaces[self.ifname]
937 self.network = network
938 end
939
940 function interface.name(self)
941 return self.wif and self.wif:ifname() or self.ifname
942 end
943
944 function interface.mac(self)
945 return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper()
946 end
947
948 function interface.ipaddrs(self)
949 return self.dev and self.dev.ipaddrs or { }
950 end
951
952 function interface.ip6addrs(self)
953 return self.dev and self.dev.ip6addrs or { }
954 end
955
956 function interface.type(self)
957 if self.wif or _wifi_iface(self.ifname) then
958 return "wifi"
959 elseif _bridge[self.ifname] then
960 return "bridge"
961 elseif _tunnel[self.ifname] then
962 return "tunnel"
963 elseif self.ifname:match("%.") then
964 return "vlan"
965 elseif _switch[self.ifname] then
966 return "switch"
967 else
968 return "ethernet"
969 end
970 end
971
972 function interface.shortname(self)
973 if self.wif then
974 return "%s %q" %{
975 self.wif:active_mode(),
976 self.wif:active_ssid() or self.wif:active_bssid()
977 }
978 else
979 return self.ifname
980 end
981 end
982
983 function interface.get_i18n(self)
984 if self.wif then
985 return "%s: %s %q" %{
986 i18n.translate("Wireless Network"),
987 self.wif:active_mode(),
988 self.wif:active_ssid() or self.wif:active_bssid()
989 }
990 else
991 return "%s: %q" %{ self:get_type_i18n(), self:name() }
992 end
993 end
994
995 function interface.get_type_i18n(self)
996 local x = self:type()
997 if x == "wifi" then
998 return i18n.translate("Wireless Adapter")
999 elseif x == "bridge" then
1000 return i18n.translate("Bridge")
1001 elseif x == "switch" then
1002 return i18n.translate("Ethernet Switch")
1003 elseif x == "vlan" then
1004 return i18n.translate("VLAN Interface")
1005 elseif x == "tunnel" then
1006 return i18n.translate("Tunnel Interface")
1007 else
1008 return i18n.translate("Ethernet Adapter")
1009 end
1010 end
1011
1012 function interface.adminlink(self)
1013 if self.wif then
1014 return self.wif:adminlink()
1015 end
1016 end
1017
1018 function interface.ports(self)
1019 if self.br then
1020 local iface
1021 local ifaces = { }
1022 for _, iface in ipairs(self.br.ifnames) do
1023 ifaces[#ifaces+1] = interface(iface.name)
1024 end
1025 return ifaces
1026 end
1027 end
1028
1029 function interface.bridge_id(self)
1030 if self.br then
1031 return self.br.id
1032 else
1033 return nil
1034 end
1035 end
1036
1037 function interface.bridge_stp(self)
1038 if self.br then
1039 return self.br.stp
1040 else
1041 return false
1042 end
1043 end
1044
1045 function interface.is_up(self)
1046 if self.wif then
1047 return self.wif:is_up()
1048 else
1049 return self.dev and self.dev.flags and self.dev.flags.up or false
1050 end
1051 end
1052
1053 function interface.is_bridge(self)
1054 return (self:type() == "bridge")
1055 end
1056
1057 function interface.is_bridgeport(self)
1058 return self.dev and self.dev.bridge and true or false
1059 end
1060
1061 function interface.tx_bytes(self)
1062 return self.dev and self.dev.stats
1063 and self.dev.stats.tx_bytes or 0
1064 end
1065
1066 function interface.rx_bytes(self)
1067 return self.dev and self.dev.stats
1068 and self.dev.stats.rx_bytes or 0
1069 end
1070
1071 function interface.tx_packets(self)
1072 return self.dev and self.dev.stats
1073 and self.dev.stats.tx_packets or 0
1074 end
1075
1076 function interface.rx_packets(self)
1077 return self.dev and self.dev.stats
1078 and self.dev.stats.rx_packets or 0
1079 end
1080
1081 function interface.get_network(self)
1082 if not self.network then
1083 if self.dev and self.dev.network then
1084 self.network = _M:get_network(self.dev.network)
1085 end
1086 end
1087
1088 if not self.network then
1089 local net
1090 for _, net in ipairs(_M:get_networks()) do
1091 if net:contains_interface(self.ifname) or
1092 net:ifname() == self.ifname
1093 then
1094 self.network = net
1095 return net
1096 end
1097 end
1098 else
1099 return self.network
1100 end
1101 end
1102
1103 function interface.get_wifinet(self)
1104 return self.wif
1105 end
1106
1107
1108 wifidev = utl.class()
1109
1110 function wifidev.__init__(self, dev)
1111 self.sid = dev
1112 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1113 end
1114
1115 function wifidev.get(self, opt)
1116 return _get("wireless", self.sid, opt)
1117 end
1118
1119 function wifidev.set(self, opt, val)
1120 return _set("wireless", self.sid, opt, val)
1121 end
1122
1123 function wifidev.name(self)
1124 return self.sid
1125 end
1126
1127 function wifidev.hwmodes(self)
1128 local l = self.iwinfo.hwmodelist
1129 if l and next(l) then
1130 return l
1131 else
1132 return { b = true, g = true }
1133 end
1134 end
1135
1136 function wifidev.get_i18n(self)
1137 local t = "Generic"
1138 if self.iwinfo.type == "wl" then
1139 t = "Broadcom"
1140 elseif self.iwinfo.type == "madwifi" then
1141 t = "Atheros"
1142 end
1143
1144 local m = ""
1145 local l = self:hwmodes()
1146 if l.a then m = m .. "a" end
1147 if l.b then m = m .. "b" end
1148 if l.g then m = m .. "g" end
1149 if l.n then m = m .. "n" end
1150
1151 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1152 end
1153
1154 function wifidev.is_up(self)
1155 local up = false
1156
1157 _uci_state:foreach("wireless", "wifi-iface",
1158 function(s)
1159 if s.device == self.sid then
1160 if s.up == "1" then
1161 up = true
1162 return false
1163 end
1164 end
1165 end)
1166
1167 return up
1168 end
1169
1170 function wifidev.get_wifinet(self, net)
1171 if _uci_real:get("wireless", net) == "wifi-iface" then
1172 return wifinet(net)
1173 else
1174 local wnet = _wifi_lookup(net)
1175 if wnet then
1176 return wifinet(wnet)
1177 end
1178 end
1179 end
1180
1181 function wifidev.get_wifinets(self)
1182 local nets = { }
1183
1184 _uci_real:foreach("wireless", "wifi-iface",
1185 function(s)
1186 if s.device == self.sid then
1187 nets[#nets+1] = wifinet(s['.name'])
1188 end
1189 end)
1190
1191 return nets
1192 end
1193
1194 function wifidev.add_wifinet(self, options)
1195 options = options or { }
1196 options.device = self.sid
1197
1198 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1199 if wnet then
1200 return wifinet(wnet, options)
1201 end
1202 end
1203
1204 function wifidev.del_wifinet(self, net)
1205 if utl.instanceof(net, wifinet) then
1206 net = net.sid
1207 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1208 net = _wifi_lookup(net)
1209 end
1210
1211 if net and _uci_real:get("wireless", net, "device") == self.sid then
1212 _uci_real:delete("wireless", net)
1213 return true
1214 end
1215
1216 return false
1217 end
1218
1219
1220 wifinet = utl.class()
1221
1222 function wifinet.__init__(self, net, data)
1223 self.sid = net
1224
1225 local num = { }
1226 local netid
1227 _uci_real:foreach("wireless", "wifi-iface",
1228 function(s)
1229 if s.device then
1230 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1231 if s['.name'] == self.sid then
1232 netid = "%s.network%d" %{ s.device, num[s.device] }
1233 return false
1234 end
1235 end
1236 end)
1237
1238 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1239
1240 self.netid = netid
1241 self.wdev = dev
1242 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1243 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1244 _uci_real:get_all("wireless", self.sid) or { }
1245 end
1246
1247 function wifinet.get(self, opt)
1248 return _get("wireless", self.sid, opt)
1249 end
1250
1251 function wifinet.set(self, opt, val)
1252 return _set("wireless", self.sid, opt, val)
1253 end
1254
1255 function wifinet.mode(self)
1256 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1257 end
1258
1259 function wifinet.ssid(self)
1260 return _uci_state:get("wireless", self.sid, "ssid")
1261 end
1262
1263 function wifinet.bssid(self)
1264 return _uci_state:get("wireless", self.sid, "bssid")
1265 end
1266
1267 function wifinet.network(self)
1268 return _uci_state:get("wifinet", self.sid, "network")
1269 end
1270
1271 function wifinet.id(self)
1272 return self.netid
1273 end
1274
1275 function wifinet.name(self)
1276 return self.sid
1277 end
1278
1279 function wifinet.ifname(self)
1280 local ifname = self.iwinfo.ifname
1281 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1282 ifname = self.wdev
1283 end
1284 return ifname
1285 end
1286
1287 function wifinet.get_device(self)
1288 if self.iwdata.device then
1289 return wifidev(self.iwdata.device)
1290 end
1291 end
1292
1293 function wifinet.is_up(self)
1294 return (self.iwdata.up == "1")
1295 end
1296
1297 function wifinet.active_mode(self)
1298 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1299
1300 if m == "ap" then m = "Master"
1301 elseif m == "sta" then m = "Client"
1302 elseif m == "adhoc" then m = "Ad-Hoc"
1303 elseif m == "mesh" then m = "Mesh"
1304 elseif m == "monitor" then m = "Monitor"
1305 end
1306
1307 return m
1308 end
1309
1310 function wifinet.active_mode_i18n(self)
1311 return i18n.translate(self:active_mode())
1312 end
1313
1314 function wifinet.active_ssid(self)
1315 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1316 end
1317
1318 function wifinet.active_bssid(self)
1319 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1320 end
1321
1322 function wifinet.active_encryption(self)
1323 local enc = self.iwinfo and self.iwinfo.encryption
1324 return enc and enc.description or "-"
1325 end
1326
1327 function wifinet.assoclist(self)
1328 return self.iwinfo.assoclist or { }
1329 end
1330
1331 function wifinet.frequency(self)
1332 local freq = self.iwinfo.frequency
1333 if freq and freq > 0 then
1334 return "%.03f" % (freq / 1000)
1335 end
1336 end
1337
1338 function wifinet.bitrate(self)
1339 local rate = self.iwinfo.bitrate
1340 if rate and rate > 0 then
1341 return (rate / 1000)
1342 end
1343 end
1344
1345 function wifinet.channel(self)
1346 return self.iwinfo.channel or
1347 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1348 end
1349
1350 function wifinet.signal(self)
1351 return self.iwinfo.signal or 0
1352 end
1353
1354 function wifinet.noise(self)
1355 return self.iwinfo.noise or 0
1356 end
1357
1358 function wifinet.country(self)
1359 return self.iwinfo.country or "00"
1360 end
1361
1362 function wifinet.txpower(self)
1363 return self.iwinfo.txpower or 0
1364 end
1365
1366 function wifinet.signal_level(self, s, n)
1367 if self:active_bssid() ~= "00:00:00:00:00:00" then
1368 local signal = s or self:signal()
1369 local noise = n or self:noise()
1370
1371 if signal < 0 and noise < 0 then
1372 local snr = -1 * (noise - signal)
1373 return math.floor(snr / 5)
1374 else
1375 return 0
1376 end
1377 else
1378 return -1
1379 end
1380 end
1381
1382 function wifinet.signal_percent(self)
1383 local qc = self.iwinfo.quality or 0
1384 local qm = self.iwinfo.quality_max or 0
1385
1386 if qc > 0 and qm > 0 then
1387 return math.floor((100 / qm) * qc)
1388 else
1389 return 0
1390 end
1391 end
1392
1393 function wifinet.shortname(self)
1394 return "%s %q" %{
1395 i18n.translate(self:active_mode()),
1396 self:active_ssid() or self:active_bssid()
1397 }
1398 end
1399
1400 function wifinet.get_i18n(self)
1401 return "%s: %s %q (%s)" %{
1402 i18n.translate("Wireless Network"),
1403 i18n.translate(self:active_mode()),
1404 self:active_ssid() or self:active_bssid(),
1405 self:ifname()
1406 }
1407 end
1408
1409 function wifinet.adminlink(self)
1410 return dsp.build_url("admin", "network", "wireless", self.netid)
1411 end
1412
1413 function wifinet.get_network(self)
1414 local net = tostring(self.iwdata.network)
1415 if net and _uci_real:get("network", net) == "interface" then
1416 return network(net)
1417 end
1418 end
1419
1420 function wifinet.get_interface(self)
1421 return interface(self:ifname())
1422 end
1423
1424
1425 -- setup base protocols
1426 _M:register_protocol("static")
1427 _M:register_protocol("dhcp")
1428 _M:register_protocol("none")
1429
1430 -- load protocol extensions
1431 local exts = nfs.dir(utl.libpath() .. "/model/network")
1432 if exts then
1433 local ext
1434 for ext in exts do
1435 if ext:match("%.lua$") then
1436 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1437 end
1438 end
1439 end