libs/core: remove now obsolete uint() wrapper in network model
[project/luci.git] / libs / core / luasrc / model / network.lua
1 --[[
2 LuCI - Network model
3
4 Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local type, next, pairs, ipairs, loadfile, table
21 = type, next, pairs, ipairs, loadfile, table
22
23 local tonumber, tostring, math = tonumber, tostring, math
24
25 local require = require
26
27 local bus = require "ubus"
28 local nxo = require "nixio"
29 local nfs = require "nixio.fs"
30 local ipc = require "luci.ip"
31 local sys = require "luci.sys"
32 local utl = require "luci.util"
33 local dsp = require "luci.dispatcher"
34 local uci = require "luci.model.uci"
35 local lng = require "luci.i18n"
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", "^gre%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 local net
388 local rest = { }
389 for net in utl.imatch(s.network) do
390 if net ~= n then
391 rest[#rest+1] = net
392 end
393 end
394 if #rest > 0 then
395 _uci_real:set("wireless", s['.name'], "network",
396 table.concat(rest, " "))
397 else
398 _uci_real:delete("wireless", s['.name'], "network")
399 end
400 end)
401 end
402 return r
403 end
404
405 function rename_network(self, old, new)
406 local r
407 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
408 r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
409
410 if r then
411 _uci_real:foreach("network", "alias",
412 function(s)
413 if s.interface == old then
414 _uci_real:set("network", s['.name'], "interface", new)
415 end
416 end)
417
418 _uci_real:foreach("network", "route",
419 function(s)
420 if s.interface == old then
421 _uci_real:set("network", s['.name'], "interface", new)
422 end
423 end)
424
425 _uci_real:foreach("network", "route6",
426 function(s)
427 if s.interface == old then
428 _uci_real:set("network", s['.name'], "interface", new)
429 end
430 end)
431
432 _uci_real:foreach("wireless", "wifi-iface",
433 function(s)
434 local net
435 local list = { }
436 for net in utl.imatch(s.network) do
437 if net == old then
438 list[#list+1] = new
439 else
440 list[#list+1] = net
441 end
442 end
443 if #list > 0 then
444 _uci_real:set("wireless", s['.name'], "network",
445 table.concat(list, " "))
446 end
447 end)
448
449 _uci_real:delete("network", old)
450 end
451 end
452 return r or false
453 end
454
455 function get_interface(self, i)
456 if _interfaces[i] or _wifi_iface(i) then
457 return interface(i)
458 else
459 local ifc
460 local num = { }
461 _uci_real:foreach("wireless", "wifi-iface",
462 function(s)
463 if s.device then
464 num[s.device] = num[s.device] and num[s.device] + 1 or 1
465 if s['.name'] == i then
466 ifc = interface(
467 "%s.network%d" %{s.device, num[s.device] })
468 return false
469 end
470 end
471 end)
472 return ifc
473 end
474 end
475
476 function get_interfaces(self)
477 local iface
478 local ifaces = { }
479 local seen = { }
480 local nfs = { }
481 local baseof = { }
482
483 -- find normal interfaces
484 _uci_real:foreach("network", "interface",
485 function(s)
486 for iface in utl.imatch(s.ifname) do
487 if not _iface_ignore(iface) and not _wifi_iface(iface) then
488 seen[iface] = true
489 nfs[iface] = interface(iface)
490 end
491 end
492 end)
493
494 for iface in utl.kspairs(_interfaces) do
495 if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
496 nfs[iface] = interface(iface)
497 end
498 end
499
500 -- find vlan interfaces
501 _uci_real:foreach("network", "switch_vlan",
502 function(s)
503 if not s.device then
504 return
505 end
506
507 local base = baseof[s.device]
508 if not base then
509 if not s.device:match("^eth%d") then
510 local l
511 for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
512 if not base then
513 base = l:match("^%w+: (%w+)")
514 end
515 end
516 if not base or not base:match("^eth%d") then
517 base = "eth0"
518 end
519 else
520 base = s.device
521 end
522 baseof[s.device] = base
523 end
524
525 local vid = tonumber(s.vid or s.vlan)
526 if vid ~= nil and vid >= 0 and vid <= 4095 then
527 local iface = "%s.%d" %{ base, vid }
528 if not seen[iface] then
529 seen[iface] = true
530 nfs[iface] = interface(iface)
531 end
532 end
533 end)
534
535 for iface in utl.kspairs(nfs) do
536 ifaces[#ifaces+1] = nfs[iface]
537 end
538
539 -- find wifi interfaces
540 local num = { }
541 local wfs = { }
542 _uci_real:foreach("wireless", "wifi-iface",
543 function(s)
544 if s.device then
545 num[s.device] = num[s.device] and num[s.device] + 1 or 1
546 local i = "%s.network%d" %{ s.device, num[s.device] }
547 wfs[i] = interface(i)
548 end
549 end)
550
551 for iface in utl.kspairs(wfs) do
552 ifaces[#ifaces+1] = wfs[iface]
553 end
554
555 return ifaces
556 end
557
558 function ignore_interface(self, x)
559 return _iface_ignore(x)
560 end
561
562 function get_wifidev(self, dev)
563 if _uci_real:get("wireless", dev) == "wifi-device" then
564 return wifidev(dev)
565 end
566 end
567
568 function get_wifidevs(self)
569 local devs = { }
570 local wfd = { }
571
572 _uci_real:foreach("wireless", "wifi-device",
573 function(s) wfd[#wfd+1] = s['.name'] end)
574
575 local dev
576 for _, dev in utl.vspairs(wfd) do
577 devs[#devs+1] = wifidev(dev)
578 end
579
580 return devs
581 end
582
583 function get_wifinet(self, net)
584 local wnet = _wifi_lookup(net)
585 if wnet then
586 return wifinet(wnet)
587 end
588 end
589
590 function add_wifinet(self, net, options)
591 if type(options) == "table" and options.device and
592 _uci_real:get("wireless", options.device) == "wifi-device"
593 then
594 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
595 return wifinet(wnet)
596 end
597 end
598
599 function del_wifinet(self, net)
600 local wnet = _wifi_lookup(net)
601 if wnet then
602 _uci_real:delete("wireless", wnet)
603 return true
604 end
605 return false
606 end
607
608 function get_status_by_route(self, addr, mask)
609 local _, object
610 for _, object in ipairs(_ubus:objects()) do
611 local net = object:match("^network%.interface%.(.+)")
612 if net then
613 local s = _ubus:call(object, "status", {})
614 if s and s.route then
615 local rt
616 for _, rt in ipairs(s.route) do
617 if rt.target == addr and rt.mask == mask then
618 return net, s
619 end
620 end
621 end
622 end
623 end
624 end
625
626 function get_status_by_address(self, addr)
627 local _, object
628 for _, object in ipairs(_ubus:objects()) do
629 local net = object:match("^network%.interface%.(.+)")
630 if net then
631 local s = _ubus:call(object, "status", {})
632 if s and s['ipv4-address'] then
633 local a
634 for _, a in ipairs(s['ipv4-address']) do
635 if a.address == addr then
636 return net, s
637 end
638 end
639 end
640 if s and s['ipv6-address'] then
641 local a
642 for _, a in ipairs(s['ipv6-address']) do
643 if a.address == addr then
644 return net, s
645 end
646 end
647 end
648 end
649 end
650 end
651
652 function get_wannet(self)
653 local net = self:get_status_by_route("0.0.0.0", 0)
654 return net and network(net)
655 end
656
657 function get_wandev(self)
658 local _, stat = self:get_status_by_route("0.0.0.0", 0)
659 return stat and interface(stat.l3_device or stat.device)
660 end
661
662 function get_wan6net(self)
663 local net = self:get_status_by_route("::", 0)
664 return net and network(net)
665 end
666
667 function get_wan6dev(self)
668 local _, stat = self:get_status_by_route("::", 0)
669 return stat and interface(stat.l3_device or stat.device)
670 end
671
672
673 function network(name, proto)
674 if name then
675 local p = proto or _uci_real:get("network", name, "proto")
676 local c = p and _protocols[p] or protocol
677 return c(name)
678 end
679 end
680
681 function protocol.__init__(self, name)
682 self.sid = name
683 end
684
685 function protocol._get(self, opt)
686 local v = _uci_real:get("network", self.sid, opt)
687 if type(v) == "table" then
688 return table.concat(v, " ")
689 end
690 return v or ""
691 end
692
693 function protocol._ubus(self, field)
694 if not _ubusnetcache[self.sid] then
695 _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
696 "status", { })
697 end
698 if _ubusnetcache[self.sid] and field then
699 return _ubusnetcache[self.sid][field]
700 end
701 return _ubusnetcache[self.sid]
702 end
703
704 function protocol.get(self, opt)
705 return _get("network", self.sid, opt)
706 end
707
708 function protocol.set(self, opt, val)
709 return _set("network", self.sid, opt, val)
710 end
711
712 function protocol.ifname(self)
713 local ifname
714 if self:is_floating() then
715 ifname = self:_ubus("l3_device")
716 else
717 ifname = self:_ubus("device")
718 end
719 if not ifname then
720 local num = { }
721 _uci_real:foreach("wireless", "wifi-iface",
722 function(s)
723 if s.device then
724 num[s.device] = num[s.device]
725 and num[s.device] + 1 or 1
726
727 local net
728 for net in utl.imatch(s.network) do
729 if net == self.sid then
730 ifname = "%s.network%d" %{ s.device, num[s.device] }
731 return false
732 end
733 end
734 end
735 end)
736 end
737 return ifname
738 end
739
740 function protocol.proto(self)
741 return "none"
742 end
743
744 function protocol.get_i18n(self)
745 local p = self:proto()
746 if p == "none" then
747 return lng.translate("Unmanaged")
748 elseif p == "static" then
749 return lng.translate("Static address")
750 elseif p == "dhcp" then
751 return lng.translate("DHCP client")
752 else
753 return lng.translate("Unknown")
754 end
755 end
756
757 function protocol.type(self)
758 return self:_get("type")
759 end
760
761 function protocol.name(self)
762 return self.sid
763 end
764
765 function protocol.uptime(self)
766 return self:_ubus("uptime") or 0
767 end
768
769 function protocol.expires(self)
770 local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
771 local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
772 if a and l then
773 l = l - (nxo.sysinfo().uptime - a)
774 return l > 0 and l or 0
775 end
776 return -1
777 end
778
779 function protocol.metric(self)
780 return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
781 end
782
783 function protocol.ipaddr(self)
784 local addrs = self:_ubus("ipv4-address")
785 return addrs and #addrs > 0 and addrs[1].address
786 end
787
788 function protocol.netmask(self)
789 local addrs = self:_ubus("ipv4-address")
790 return addrs and #addrs > 0 and
791 ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
792 end
793
794 function protocol.gwaddr(self)
795 local _, route
796 for _, route in ipairs(self:_ubus("route") or { }) do
797 if route.target == "0.0.0.0" and route.mask == 0 then
798 return route.nexthop
799 end
800 end
801 end
802
803 function protocol.dnsaddrs(self)
804 local dns = { }
805 local _, addr
806 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
807 if not addr:match(":") then
808 dns[#dns+1] = addr
809 end
810 end
811 return dns
812 end
813
814 function protocol.ip6addr(self)
815 local addrs = self:_ubus("ipv6-address")
816 return addrs and #addrs > 0
817 and "%s/%d" %{ addrs[1].address, addrs[1].mask }
818 end
819
820 function protocol.gw6addr(self)
821 local _, route
822 for _, route in ipairs(self:_ubus("route") or { }) do
823 if route.target == "::" and route.mask == 0 then
824 return ipc.IPv6(route.nexthop):string()
825 end
826 end
827 end
828
829 function protocol.dns6addrs(self)
830 local dns = { }
831 local _, addr
832 for _, addr in ipairs(self:_ubus("dns-server") or { }) do
833 if addr:match(":") then
834 dns[#dns+1] = addr
835 end
836 end
837 return dns
838 end
839
840 function protocol.is_bridge(self)
841 return (not self:is_virtual() and self:type() == "bridge")
842 end
843
844 function protocol.opkg_package(self)
845 return nil
846 end
847
848 function protocol.is_installed(self)
849 return true
850 end
851
852 function protocol.is_virtual(self)
853 return false
854 end
855
856 function protocol.is_floating(self)
857 return false
858 end
859
860 function protocol.is_empty(self)
861 if self:is_floating() then
862 return false
863 else
864 local rv = true
865
866 if (self:_get("ifname") or ""):match("%S+") then
867 rv = false
868 end
869
870 _uci_real:foreach("wireless", "wifi-iface",
871 function(s)
872 local n
873 for n in utl.imatch(s.network) do
874 if n == self.sid then
875 rv = false
876 return false
877 end
878 end
879 end)
880
881 return rv
882 end
883 end
884
885 function protocol.add_interface(self, ifname)
886 ifname = _M:ifnameof(ifname)
887 if ifname and not self:is_floating() then
888 -- if its a wifi interface, change its network option
889 local wif = _wifi_lookup(ifname)
890 if wif then
891 _append("wireless", wif, "network", self.sid)
892
893 -- add iface to our iface list
894 else
895 _append("network", self.sid, "ifname", ifname)
896 end
897 end
898 end
899
900 function protocol.del_interface(self, ifname)
901 ifname = _M:ifnameof(ifname)
902 if ifname and not self:is_floating() then
903 -- if its a wireless interface, clear its network option
904 local wif = _wifi_lookup(ifname)
905 if wif then _filter("wireless", wif, "network", self.sid) end
906
907 -- remove the interface
908 _filter("network", self.sid, "ifname", ifname)
909 end
910 end
911
912 function protocol.get_interface(self)
913 if self:is_virtual() then
914 _tunnel[self:proto() .. "-" .. self.sid] = true
915 return interface(self:proto() .. "-" .. self.sid, self)
916 elseif self:is_bridge() then
917 _bridge["br-" .. self.sid] = true
918 return interface("br-" .. self.sid, self)
919 else
920 local ifn = nil
921 local num = { }
922 for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
923 ifn = ifn:match("^[^:/]+")
924 return ifn and interface(ifn, self)
925 end
926 ifn = nil
927 _uci_real:foreach("wireless", "wifi-iface",
928 function(s)
929 if s.device then
930 num[s.device] = num[s.device] and num[s.device] + 1 or 1
931
932 local net
933 for net in utl.imatch(s.network) do
934 if net == self.sid then
935 ifn = "%s.network%d" %{ s.device, num[s.device] }
936 return false
937 end
938 end
939 end
940 end)
941 return ifn and interface(ifn, self)
942 end
943 end
944
945 function protocol.get_interfaces(self)
946 if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
947 local ifaces = { }
948
949 local ifn
950 local nfs = { }
951 for ifn in utl.imatch(self:get("ifname")) do
952 ifn = ifn:match("^[^:/]+")
953 nfs[ifn] = interface(ifn, self)
954 end
955
956 for ifn in utl.kspairs(nfs) do
957 ifaces[#ifaces+1] = nfs[ifn]
958 end
959
960 local num = { }
961 local wfs = { }
962 _uci_real:foreach("wireless", "wifi-iface",
963 function(s)
964 if s.device then
965 num[s.device] = num[s.device] and num[s.device] + 1 or 1
966
967 local net
968 for net in utl.imatch(s.network) do
969 if net == self.sid then
970 ifn = "%s.network%d" %{ s.device, num[s.device] }
971 wfs[ifn] = interface(ifn, self)
972 end
973 end
974 end
975 end)
976
977 for ifn in utl.kspairs(wfs) do
978 ifaces[#ifaces+1] = wfs[ifn]
979 end
980
981 return ifaces
982 end
983 end
984
985 function protocol.contains_interface(self, ifname)
986 ifname = _M:ifnameof(ifname)
987 if not ifname then
988 return false
989 elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
990 return true
991 elseif self:is_bridge() and "br-" .. self.sid == ifname then
992 return true
993 else
994 local ifn
995 for ifn in utl.imatch(self:get("ifname")) do
996 ifn = ifn:match("[^:]+")
997 if ifn == ifname then
998 return true
999 end
1000 end
1001
1002 local wif = _wifi_lookup(ifname)
1003 if wif then
1004 local n
1005 for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
1006 if n == self.sid then
1007 return true
1008 end
1009 end
1010 end
1011 end
1012
1013 return false
1014 end
1015
1016 function protocol.adminlink(self)
1017 return dsp.build_url("admin", "network", "network", self.sid)
1018 end
1019
1020
1021 interface = utl.class()
1022
1023 function interface.__init__(self, ifname, network)
1024 local wif = _wifi_lookup(ifname)
1025 if wif then
1026 self.wif = wifinet(wif)
1027 self.ifname = _uci_state:get("wireless", wif, "ifname")
1028 end
1029
1030 self.ifname = self.ifname or ifname
1031 self.dev = _interfaces[self.ifname]
1032 self.network = network
1033 end
1034
1035 function interface._ubus(self, field)
1036 if not _ubusdevcache[self.ifname] then
1037 _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
1038 { name = self.ifname })
1039 end
1040 if _ubusdevcache[self.ifname] and field then
1041 return _ubusdevcache[self.ifname][field]
1042 end
1043 return _ubusdevcache[self.ifname]
1044 end
1045
1046 function interface.name(self)
1047 return self.wif and self.wif:ifname() or self.ifname
1048 end
1049
1050 function interface.mac(self)
1051 return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
1052 end
1053
1054 function interface.ipaddrs(self)
1055 return self.dev and self.dev.ipaddrs or { }
1056 end
1057
1058 function interface.ip6addrs(self)
1059 return self.dev and self.dev.ip6addrs or { }
1060 end
1061
1062 function interface.type(self)
1063 if self.wif or _wifi_iface(self.ifname) then
1064 return "wifi"
1065 elseif _bridge[self.ifname] then
1066 return "bridge"
1067 elseif _tunnel[self.ifname] then
1068 return "tunnel"
1069 elseif self.ifname:match("%.") then
1070 return "vlan"
1071 elseif _switch[self.ifname] then
1072 return "switch"
1073 else
1074 return "ethernet"
1075 end
1076 end
1077
1078 function interface.shortname(self)
1079 if self.wif then
1080 return "%s %q" %{
1081 self.wif:active_mode(),
1082 self.wif:active_ssid() or self.wif:active_bssid()
1083 }
1084 else
1085 return self.ifname
1086 end
1087 end
1088
1089 function interface.get_i18n(self)
1090 if self.wif then
1091 return "%s: %s %q" %{
1092 lng.translate("Wireless Network"),
1093 self.wif:active_mode(),
1094 self.wif:active_ssid() or self.wif:active_bssid()
1095 }
1096 else
1097 return "%s: %q" %{ self:get_type_i18n(), self:name() }
1098 end
1099 end
1100
1101 function interface.get_type_i18n(self)
1102 local x = self:type()
1103 if x == "wifi" then
1104 return lng.translate("Wireless Adapter")
1105 elseif x == "bridge" then
1106 return lng.translate("Bridge")
1107 elseif x == "switch" then
1108 return lng.translate("Ethernet Switch")
1109 elseif x == "vlan" then
1110 return lng.translate("VLAN Interface")
1111 elseif x == "tunnel" then
1112 return lng.translate("Tunnel Interface")
1113 else
1114 return lng.translate("Ethernet Adapter")
1115 end
1116 end
1117
1118 function interface.adminlink(self)
1119 if self.wif then
1120 return self.wif:adminlink()
1121 end
1122 end
1123
1124 function interface.ports(self)
1125 local members = self:_ubus("bridge-members")
1126 if members then
1127 local _, iface
1128 local ifaces = { }
1129 for _, iface in ipairs(members) do
1130 ifaces[#ifaces+1] = interface(iface)
1131 end
1132 end
1133 end
1134
1135 function interface.bridge_id(self)
1136 if self.br then
1137 return self.br.id
1138 else
1139 return nil
1140 end
1141 end
1142
1143 function interface.bridge_stp(self)
1144 if self.br then
1145 return self.br.stp
1146 else
1147 return false
1148 end
1149 end
1150
1151 function interface.is_up(self)
1152 if self.wif then
1153 return self.wif:is_up()
1154 else
1155 return self:_ubus("up") or false
1156 end
1157 end
1158
1159 function interface.is_bridge(self)
1160 return (self:type() == "bridge")
1161 end
1162
1163 function interface.is_bridgeport(self)
1164 return self.dev and self.dev.bridge and true or false
1165 end
1166
1167 function interface.tx_bytes(self)
1168 local stat = self:_ubus("statistics")
1169 return stat and stat.tx_bytes or 0
1170 end
1171
1172 function interface.rx_bytes(self)
1173 local stat = self:_ubus("statistics")
1174 return stat and stat.rx_bytes or 0
1175 end
1176
1177 function interface.tx_packets(self)
1178 local stat = self:_ubus("statistics")
1179 return stat and stat.tx_packets or 0
1180 end
1181
1182 function interface.rx_packets(self)
1183 local stat = self:_ubus("statistics")
1184 return stat and stat.rx_packets or 0
1185 end
1186
1187 function interface.get_network(self)
1188 return self:get_networks()[1]
1189 end
1190
1191 function interface.get_networks(self)
1192 if not self.networks then
1193 local nets = { }
1194 local _, net
1195 for _, net in ipairs(_M:get_networks()) do
1196 if net:contains_interface(self.ifname) or
1197 net:ifname() == self.ifname
1198 then
1199 nets[#nets+1] = net
1200 end
1201 end
1202 table.sort(nets, function(a, b) return a.sid < b.sid end)
1203 self.networks = nets
1204 return nets
1205 else
1206 return self.networks
1207 end
1208 end
1209
1210 function interface.get_wifinet(self)
1211 return self.wif
1212 end
1213
1214
1215 wifidev = utl.class()
1216
1217 function wifidev.__init__(self, dev)
1218 self.sid = dev
1219 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1220 end
1221
1222 function wifidev.get(self, opt)
1223 return _get("wireless", self.sid, opt)
1224 end
1225
1226 function wifidev.set(self, opt, val)
1227 return _set("wireless", self.sid, opt, val)
1228 end
1229
1230 function wifidev.name(self)
1231 return self.sid
1232 end
1233
1234 function wifidev.hwmodes(self)
1235 local l = self.iwinfo.hwmodelist
1236 if l and next(l) then
1237 return l
1238 else
1239 return { b = true, g = true }
1240 end
1241 end
1242
1243 function wifidev.get_i18n(self)
1244 local t = "Generic"
1245 if self.iwinfo.type == "wl" then
1246 t = "Broadcom"
1247 elseif self.iwinfo.type == "madwifi" then
1248 t = "Atheros"
1249 end
1250
1251 local m = ""
1252 local l = self:hwmodes()
1253 if l.a then m = m .. "a" end
1254 if l.b then m = m .. "b" end
1255 if l.g then m = m .. "g" end
1256 if l.n then m = m .. "n" end
1257
1258 return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1259 end
1260
1261 function wifidev.is_up(self)
1262 local up = false
1263
1264 _uci_state:foreach("wireless", "wifi-iface",
1265 function(s)
1266 if s.device == self.sid then
1267 if s.up == "1" then
1268 up = true
1269 return false
1270 end
1271 end
1272 end)
1273
1274 return up
1275 end
1276
1277 function wifidev.get_wifinet(self, net)
1278 if _uci_real:get("wireless", net) == "wifi-iface" then
1279 return wifinet(net)
1280 else
1281 local wnet = _wifi_lookup(net)
1282 if wnet then
1283 return wifinet(wnet)
1284 end
1285 end
1286 end
1287
1288 function wifidev.get_wifinets(self)
1289 local nets = { }
1290
1291 _uci_real:foreach("wireless", "wifi-iface",
1292 function(s)
1293 if s.device == self.sid then
1294 nets[#nets+1] = wifinet(s['.name'])
1295 end
1296 end)
1297
1298 return nets
1299 end
1300
1301 function wifidev.add_wifinet(self, options)
1302 options = options or { }
1303 options.device = self.sid
1304
1305 local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1306 if wnet then
1307 return wifinet(wnet, options)
1308 end
1309 end
1310
1311 function wifidev.del_wifinet(self, net)
1312 if utl.instanceof(net, wifinet) then
1313 net = net.sid
1314 elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1315 net = _wifi_lookup(net)
1316 end
1317
1318 if net and _uci_real:get("wireless", net, "device") == self.sid then
1319 _uci_real:delete("wireless", net)
1320 return true
1321 end
1322
1323 return false
1324 end
1325
1326
1327 wifinet = utl.class()
1328
1329 function wifinet.__init__(self, net, data)
1330 self.sid = net
1331
1332 local num = { }
1333 local netid
1334 _uci_real:foreach("wireless", "wifi-iface",
1335 function(s)
1336 if s.device then
1337 num[s.device] = num[s.device] and num[s.device] + 1 or 1
1338 if s['.name'] == self.sid then
1339 netid = "%s.network%d" %{ s.device, num[s.device] }
1340 return false
1341 end
1342 end
1343 end)
1344
1345 local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1346
1347 self.netid = netid
1348 self.wdev = dev
1349 self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1350 self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1351 _uci_real:get_all("wireless", self.sid) or { }
1352 end
1353
1354 function wifinet.get(self, opt)
1355 return _get("wireless", self.sid, opt)
1356 end
1357
1358 function wifinet.set(self, opt, val)
1359 return _set("wireless", self.sid, opt, val)
1360 end
1361
1362 function wifinet.mode(self)
1363 return _uci_state:get("wireless", self.sid, "mode") or "ap"
1364 end
1365
1366 function wifinet.ssid(self)
1367 return _uci_state:get("wireless", self.sid, "ssid")
1368 end
1369
1370 function wifinet.bssid(self)
1371 return _uci_state:get("wireless", self.sid, "bssid")
1372 end
1373
1374 function wifinet.network(self)
1375 return _uci_state:get("wifinet", self.sid, "network")
1376 end
1377
1378 function wifinet.id(self)
1379 return self.netid
1380 end
1381
1382 function wifinet.name(self)
1383 return self.sid
1384 end
1385
1386 function wifinet.ifname(self)
1387 local ifname = self.iwinfo.ifname
1388 if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1389 ifname = self.wdev
1390 end
1391 return ifname
1392 end
1393
1394 function wifinet.get_device(self)
1395 if self.iwdata.device then
1396 return wifidev(self.iwdata.device)
1397 end
1398 end
1399
1400 function wifinet.is_up(self)
1401 return (self.iwdata.up == "1")
1402 end
1403
1404 function wifinet.active_mode(self)
1405 local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1406
1407 if m == "ap" then m = "Master"
1408 elseif m == "sta" then m = "Client"
1409 elseif m == "adhoc" then m = "Ad-Hoc"
1410 elseif m == "mesh" then m = "Mesh"
1411 elseif m == "monitor" then m = "Monitor"
1412 end
1413
1414 return m
1415 end
1416
1417 function wifinet.active_mode_i18n(self)
1418 return lng.translate(self:active_mode())
1419 end
1420
1421 function wifinet.active_ssid(self)
1422 return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1423 end
1424
1425 function wifinet.active_bssid(self)
1426 return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1427 end
1428
1429 function wifinet.active_encryption(self)
1430 local enc = self.iwinfo and self.iwinfo.encryption
1431 return enc and enc.description or "-"
1432 end
1433
1434 function wifinet.assoclist(self)
1435 return self.iwinfo.assoclist or { }
1436 end
1437
1438 function wifinet.frequency(self)
1439 local freq = self.iwinfo.frequency
1440 if freq and freq > 0 then
1441 return "%.03f" % (freq / 1000)
1442 end
1443 end
1444
1445 function wifinet.bitrate(self)
1446 local rate = self.iwinfo.bitrate
1447 if rate and rate > 0 then
1448 return (rate / 1000)
1449 end
1450 end
1451
1452 function wifinet.channel(self)
1453 return self.iwinfo.channel or
1454 tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1455 end
1456
1457 function wifinet.signal(self)
1458 return self.iwinfo.signal or 0
1459 end
1460
1461 function wifinet.noise(self)
1462 return self.iwinfo.noise or 0
1463 end
1464
1465 function wifinet.country(self)
1466 return self.iwinfo.country or "00"
1467 end
1468
1469 function wifinet.txpower(self)
1470 local pwr = (self.iwinfo.txpower or 0)
1471 return pwr + self:txpower_offset()
1472 end
1473
1474 function wifinet.txpower_offset(self)
1475 return self.iwinfo.txpower_offset or 0
1476 end
1477
1478 function wifinet.signal_level(self, s, n)
1479 if self:active_bssid() ~= "00:00:00:00:00:00" then
1480 local signal = s or self:signal()
1481 local noise = n or self:noise()
1482
1483 if signal < 0 and noise < 0 then
1484 local snr = -1 * (noise - signal)
1485 return math.floor(snr / 5)
1486 else
1487 return 0
1488 end
1489 else
1490 return -1
1491 end
1492 end
1493
1494 function wifinet.signal_percent(self)
1495 local qc = self.iwinfo.quality or 0
1496 local qm = self.iwinfo.quality_max or 0
1497
1498 if qc > 0 and qm > 0 then
1499 return math.floor((100 / qm) * qc)
1500 else
1501 return 0
1502 end
1503 end
1504
1505 function wifinet.shortname(self)
1506 return "%s %q" %{
1507 lng.translate(self:active_mode()),
1508 self:active_ssid() or self:active_bssid()
1509 }
1510 end
1511
1512 function wifinet.get_i18n(self)
1513 return "%s: %s %q (%s)" %{
1514 lng.translate("Wireless Network"),
1515 lng.translate(self:active_mode()),
1516 self:active_ssid() or self:active_bssid(),
1517 self:ifname()
1518 }
1519 end
1520
1521 function wifinet.adminlink(self)
1522 return dsp.build_url("admin", "network", "wireless", self.netid)
1523 end
1524
1525 function wifinet.get_network(self)
1526 return self:get_networks()[1]
1527 end
1528
1529 function wifinet.get_networks(self)
1530 local nets = { }
1531 local net
1532 for net in utl.imatch(tostring(self.iwdata.network)) do
1533 if _uci_real:get("network", net) == "interface" then
1534 nets[#nets+1] = network(net)
1535 end
1536 end
1537 table.sort(nets, function(a, b) return a.sid < b.sid end)
1538 return nets
1539 end
1540
1541 function wifinet.get_interface(self)
1542 return interface(self:ifname())
1543 end
1544
1545
1546 -- setup base protocols
1547 _M:register_protocol("static")
1548 _M:register_protocol("dhcp")
1549 _M:register_protocol("none")
1550
1551 -- load protocol extensions
1552 local exts = nfs.dir(utl.libpath() .. "/model/network")
1553 if exts then
1554 local ext
1555 for ext in exts do
1556 if ext:match("%.lua$") then
1557 require("luci.model.network." .. ext:gsub("%.lua$", ""))
1558 end
1559 end
1560 end