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