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