root/luci/trunk/libs/core/luasrc/model/network.lua @ 9269

Revision 9269, 31.4 KB (checked in by jow, 9 months ago)

libs/core: remove route enabled check in network model after netifd update in OpenWrt? trunk

  • Property svn:keywords set to Id
Line 
1--[[
2LuCI - Network model
3
4Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18]]--
19
20local type, next, pairs, ipairs, loadfile, table
21    = type, next, pairs, ipairs, loadfile, table
22
23local tonumber, tostring, math, i18n
24    = tonumber, tostring, math, luci.i18n
25
26local require = require
27
28local bus = require "ubus"
29local nxo = require "nixio"
30local nfs = require "nixio.fs"
31local ipc = require "luci.ip"
32local sys = require "luci.sys"
33local utl = require "luci.util"
34local dsp = require "luci.dispatcher"
35local uci = require "luci.model.uci"
36
37module "luci.model.network"
38
39
40IFACE_PATTERNS_VIRTUAL  = { }
41IFACE_PATTERNS_IGNORE   = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" }
42IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
43
44
45protocol = utl.class()
46
47local _protocols = { }
48
49local _interfaces, _bridge, _switch, _tunnel
50local _ubus, _ubusnetcache, _ubusdevcache
51local _uci_real, _uci_state
52
53function _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
81end
82
83function _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
104end
105
106function _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
112end
113
114function _get(c, s, o)
115    return _uci_real:get(c, s, o)
116end
117
118function _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
125end
126
127function _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
135end
136
137function _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
172end
173
174function _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
182end
183
184function _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)
192end
193
194
195function 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
269end
270
271function save(self, ...)
272    _uci_real:save(...)
273    _uci_real:load(...)
274end
275
276function commit(self, ...)
277    _uci_real:commit(...)
278    _uci_real:load(...)
279end
280
281function 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
289end
290
291function get_protocol(self, protoname, netname)
292    local v = _protocols[protoname]
293    if v then
294        return v(netname or "__dummy__")
295    end
296end
297
298function 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
305end
306
307function 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
322end
323
324function register_pattern_virtual(self, pat)
325    IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
326end
327
328
329function has_ipv6(self)
330    return nfs.access("/proc/net/ipv6_route")
331end
332
333function 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
348end
349
350function get_network(self, n)
351    if n and _uci_real:get("network", n) == "interface" then
352        return network(n)
353    end
354end
355
356function 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
371end
372
373function 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
393end
394
395function 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
433end
434
435function 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
454end
455
456function 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
536end
537
538function ignore_interface(self, x)
539    return _iface_ignore(x)
540end
541
542function get_wifidev(self, dev)
543    if _uci_real:get("wireless", dev) == "wifi-device" then
544        return wifidev(dev)
545    end
546end
547
548function 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
561end
562
563function get_wifinet(self, net)
564    local wnet = _wifi_lookup(net)
565    if wnet then
566        return wifinet(wnet)
567    end
568end
569
570function 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
577end
578
579function 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
586end
587
588function get_status_by_route(self, addr, mask)
589    local _, object
590    for _, object in ipairs(_ubus:objects()) do
591        local net = object:match("^network%.interface%.(.+)")
592        if net then
593            local s = _ubus:call(object, "status", {})
594            if s and s.route then
595                local rt
596                for _, rt in ipairs(s.route) do
597                    if rt.target == addr and rt.mask == mask then
598                        return net, s
599                    end
600                end
601            end
602        end
603    end
604end
605
606function get_wannet(self)
607    local net = self:get_status_by_route("0.0.0.0", 0)
608    return net and network(net)
609end
610
611function get_wandev(self)
612    local _, stat = self:get_status_by_route("0.0.0.0", 0)
613    return stat and interface(stat.l3_device or stat.device)
614end
615
616function get_wan6net(self)
617    local net = self:get_status_by_route("::", 0)
618    return net and network(net)
619end
620
621function get_wan6dev(self)
622    local _, stat = self:get_status_by_route("::", 0)
623    return stat and interface(stat.l3_device or stat.device)
624end
625
626
627function network(name, proto)
628    if name then
629        local p = proto or _uci_real:get("network", name, "proto")
630        local c = p and _protocols[p] or protocol
631        return c(name)
632    end
633end
634
635function protocol.__init__(self, name)
636    self.sid = name
637end
638
639function protocol._get(self, opt)
640    local v = _uci_real:get("network", self.sid, opt)
641    if type(v) == "table" then
642        return table.concat(v, " ")
643    end
644    return v or ""
645end
646
647function protocol._ubus(self, field)
648    if not _ubusnetcache[self.sid] then
649        _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
650                                             "status", { })
651    end
652    if _ubusnetcache[self.sid] and field then
653        return _ubusnetcache[self.sid][field]
654    end
655    return _ubusnetcache[self.sid]
656end
657
658function protocol.get(self, opt)
659    return _get("network", self.sid, opt)
660end
661
662function protocol.set(self, opt, val)
663    return _set("network", self.sid, opt, val)
664end
665
666function protocol.ifname(self)
667    local ifname
668    if self:is_floating() then
669        ifname = self:_ubus("l3_device")
670    else
671        ifname = self:_ubus("device")
672    end
673    if not ifname then
674        local num = { }
675        _uci_real:foreach("wireless", "wifi-iface",
676            function(s)
677                if s.device then
678                    num[s.device] = num[s.device]
679                        and num[s.device] + 1 or 1
680
681                    if s.network == self.sid then
682                        ifname = "%s.network%d" %{ s.device, num[s.device] }
683                        return false
684                    end
685                end
686            end)
687    end
688    return ifname
689end
690
691function protocol.proto(self)
692    return "none"
693end
694
695function protocol.get_i18n(self)
696    local p = self:proto()
697    if p == "none" then
698        return i18n.translate("Unmanaged")
699    elseif p == "static" then
700        return i18n.translate("Static address")
701    elseif p == "dhcp" then
702        return i18n.translate("DHCP client")
703    else
704        return i18n.translate("Unknown")
705    end
706end
707
708function protocol.type(self)
709    return self:_get("type")
710end
711
712function protocol.name(self)
713    return self.sid
714end
715
716function protocol.uptime(self)
717    return self:_ubus("uptime") or 0
718end
719
720function protocol.expires(self)
721    local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
722    local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
723    if a and l then
724        l = l - (nxo.sysinfo().uptime - a)
725        return l > 0 and l or 0
726    end
727    return -1
728end
729
730function protocol.metric(self)
731    return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
732end
733
734function protocol.ipaddr(self)
735    local addrs = self:_ubus("ipv4-address")
736    return addrs and #addrs > 0 and addrs[1].address
737end
738
739function protocol.netmask(self)
740    local addrs = self:_ubus("ipv4-address")
741    return addrs and #addrs > 0 and
742        ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string()
743end
744
745function protocol.gwaddr(self)
746    local _, route
747    for _, route in ipairs(self:_ubus("route") or { }) do
748        if route.target == "0.0.0.0" and route.mask == 0 then
749            return route.nexthop
750        end
751    end
752end
753
754function protocol.dnsaddrs(self)
755    local dns = { }
756    local _, addr
757    for _, addr in ipairs(self:_ubus("dns-server") or { }) do
758        if not addr:match(":") then
759            dns[#dns+1] = addr
760        end
761    end
762    return dns
763end
764
765function protocol.ip6addr(self)
766    local addrs = self:_ubus("ipv6-address")
767    return addrs and #addrs > 0
768        and "%s/%d" %{ addrs[1].address, addrs[1].mask }
769end
770
771function protocol.gw6addr(self)
772    local _, route
773    for _, route in ipairs(self:_ubus("route") or { }) do
774        if route.target == "::" and route.mask == 0 then
775            return ipc.IPv6(route.nexthop):string()
776        end
777    end
778end
779
780function protocol.dns6addrs(self)
781    local dns = { }
782    local _, addr
783    for _, addr in ipairs(self:_ubus("dns-server") or { }) do
784        if addr:match(":") then
785            dns[#dns+1] = addr
786        end
787    end
788    return dns
789end
790
791function protocol.is_bridge(self)
792    return (not self:is_virtual() and self:type() == "bridge")
793end
794
795function protocol.opkg_package(self)
796    return nil
797end
798
799function protocol.is_installed(self)
800    return true
801end
802
803function protocol.is_virtual(self)
804    return false
805end
806
807function protocol.is_floating(self)
808    return false
809end
810
811function protocol.is_empty(self)
812    if self:is_floating() then
813        return false
814    else
815        local rv = true
816
817        if (self:_get("ifname") or ""):match("%S+") then
818            rv = false
819        end
820
821        _uci_real:foreach("wireless", "wifi-iface",
822            function(s)
823                local n
824                for n in utl.imatch(s.network) do
825                    if n == self.sid then
826                        rv = false
827                        return false
828                    end
829                end
830            end)
831
832        return rv
833    end
834end
835
836function protocol.add_interface(self, ifname)
837    ifname = _M:ifnameof(ifname)
838    if ifname and not self:is_floating() then
839        -- if its a wifi interface, change its network option
840        local wif = _wifi_lookup(ifname)
841        if wif then
842            _append("wireless", wif, "network", self.sid)
843
844        -- add iface to our iface list
845        else
846            _append("network", self.sid, "ifname", ifname)
847        end
848    end
849end
850
851function protocol.del_interface(self, ifname)
852    ifname = _M:ifnameof(ifname)
853    if ifname and not self:is_floating() then
854        -- if its a wireless interface, clear its network option
855        local wif = _wifi_lookup(ifname)
856        if wif then _filter("wireless", wif, "network", self.sid) end
857
858        -- remove the interface
859        _filter("network", self.sid, "ifname", ifname)
860    end
861end
862
863function protocol.get_interface(self)
864    if self:is_virtual() then
865        _tunnel[self:proto() .. "-" .. self.sid] = true
866        return interface(self:proto() .. "-" .. self.sid, self)
867    elseif self:is_bridge() then
868        _bridge["br-" .. self.sid] = true
869        return interface("br-" .. self.sid, self)
870    else
871        local ifn = nil
872        local num = { }
873        for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
874            ifn = ifn:match("^[^:/]+")
875            return ifn and interface(ifn, self)
876        end
877        ifn = nil
878        _uci_real:foreach("wireless", "wifi-iface",
879            function(s)
880                if s.device then
881                    num[s.device] = num[s.device] and num[s.device] + 1 or 1
882                    if s.network == self.sid then
883                        ifn = "%s.network%d" %{ s.device, num[s.device] }
884                        return false
885                    end
886                end
887            end)
888        return ifn and interface(ifn, self)
889    end
890end
891
892function protocol.get_interfaces(self)
893    if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then
894        local ifaces = { }
895
896        local ifn
897        local nfs = { }
898        for ifn in utl.imatch(self:get("ifname")) do
899            ifn = ifn:match("^[^:/]+")
900            nfs[ifn] = interface(ifn, self)
901        end
902
903        for ifn in utl.kspairs(nfs) do
904            ifaces[#ifaces+1] = nfs[ifn]
905        end
906
907        local num = { }
908        local wfs = { }
909        _uci_real:foreach("wireless", "wifi-iface",
910            function(s)
911                if s.device then
912                    num[s.device] = num[s.device] and num[s.device] + 1 or 1
913                    if s.network == self.sid then
914                        ifn = "%s.network%d" %{ s.device, num[s.device] }
915                        wfs[ifn] = interface(ifn, self)
916                    end
917                end
918            end)
919
920        for ifn in utl.kspairs(wfs) do
921            ifaces[#ifaces+1] = wfs[ifn]
922        end
923
924        return ifaces
925    end
926end
927
928function protocol.contains_interface(self, ifname)
929    ifname = _M:ifnameof(ifname)
930    if not ifname then
931        return false
932    elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then
933        return true
934    elseif self:is_bridge() and "br-" .. self.sid == ifname then
935        return true
936    else
937        local ifn
938        for ifn in utl.imatch(self:get("ifname")) do
939            ifn = ifn:match("[^:]+")
940            if ifn == ifname then
941                return true
942            end
943        end
944
945        local wif = _wifi_lookup(ifname)
946        if wif then
947            local n
948            for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
949                if n == self.sid then
950                    return true
951                end
952            end
953        end
954    end
955
956    return false
957end
958
959function protocol.adminlink(self)
960    return dsp.build_url("admin", "network", "network", self.sid)
961end
962
963
964interface = utl.class()
965
966function interface.__init__(self, ifname, network)
967    local wif = _wifi_lookup(ifname)
968    if wif then
969        self.wif    = wifinet(wif)
970        self.ifname = _uci_state:get("wireless", wif, "ifname")
971    end
972
973    self.ifname  = self.ifname or ifname
974    self.dev     = _interfaces[self.ifname]
975    self.network = network
976end
977
978function interface._ubus(self, field)
979    if not _ubusdevcache[self.ifname] then
980        _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
981                                                { name = self.ifname })
982    end
983    if _ubusdevcache[self.ifname] and field then
984        return _ubusdevcache[self.ifname][field]
985    end
986    return _ubusdevcache[self.ifname]
987end
988
989function interface.name(self)
990    return self.wif and self.wif:ifname() or self.ifname
991end
992
993function interface.mac(self)
994    return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
995end
996
997function interface.ipaddrs(self)
998    return self.dev and self.dev.ipaddrs or { }
999end
1000
1001function interface.ip6addrs(self)
1002    return self.dev and self.dev.ip6addrs or { }
1003end
1004
1005function interface.type(self)
1006    if self.wif or _wifi_iface(self.ifname) then
1007        return "wifi"
1008    elseif _bridge[self.ifname] then
1009        return "bridge"
1010    elseif _tunnel[self.ifname] then
1011        return "tunnel"
1012    elseif self.ifname:match("%.") then
1013        return "vlan"
1014    elseif _switch[self.ifname] then
1015        return "switch"
1016    else
1017        return "ethernet"
1018    end
1019end
1020
1021function interface.shortname(self)
1022    if self.wif then
1023        return "%s %q" %{
1024            self.wif:active_mode(),
1025            self.wif:active_ssid() or self.wif:active_bssid()
1026        }
1027    else
1028        return self.ifname
1029    end
1030end
1031
1032function interface.get_i18n(self)
1033    if self.wif then
1034        return "%s: %s %q" %{
1035            i18n.translate("Wireless Network"),
1036            self.wif:active_mode(),
1037            self.wif:active_ssid() or self.wif:active_bssid()
1038        }
1039    else
1040        return "%s: %q" %{ self:get_type_i18n(), self:name() }
1041    end
1042end
1043
1044function interface.get_type_i18n(self)
1045    local x = self:type()
1046    if x == "wifi" then
1047        return i18n.translate("Wireless Adapter")
1048    elseif x == "bridge" then
1049        return i18n.translate("Bridge")
1050    elseif x == "switch" then
1051        return i18n.translate("Ethernet Switch")
1052    elseif x == "vlan" then
1053        return i18n.translate("VLAN Interface")
1054    elseif x == "tunnel" then
1055        return i18n.translate("Tunnel Interface")
1056    else
1057        return i18n.translate("Ethernet Adapter")
1058    end
1059end
1060
1061function interface.adminlink(self)
1062    if self.wif then
1063        return self.wif:adminlink()
1064    end
1065end
1066
1067function interface.ports(self)
1068    local members = self:_ubus("bridge-members")
1069    if members then
1070        local _, iface
1071        local ifaces = { }
1072        for _, iface in ipairs(members) do
1073            ifaces[#ifaces+1] = interface(iface)
1074        end
1075    end
1076end
1077
1078function interface.bridge_id(self)
1079    if self.br then
1080        return self.br.id
1081    else
1082        return nil
1083    end
1084end
1085
1086function interface.bridge_stp(self)
1087    if self.br then
1088        return self.br.stp
1089    else
1090        return false
1091    end
1092end
1093
1094function interface.is_up(self)
1095    if self.wif then
1096        return self.wif:is_up()
1097    else
1098        return self:_ubus("up") or false
1099    end
1100end
1101
1102function interface.is_bridge(self)
1103    return (self:type() == "bridge")
1104end
1105
1106function interface.is_bridgeport(self)
1107    return self.dev and self.dev.bridge and true or false
1108end
1109
1110local function uint(x)
1111    if x then
1112        return (x < 0) and ((2^32) + x) or x
1113    end
1114    return 0
1115end
1116
1117function interface.tx_bytes(self)
1118    local stat = self:_ubus("statistics")
1119    return stat and uint(stat.tx_bytes) or 0
1120end
1121
1122function interface.rx_bytes(self)
1123    local stat = self:_ubus("statistics")
1124    return stat and uint(stat.rx_bytes) or 0
1125end
1126
1127function interface.tx_packets(self)
1128    local stat = self:_ubus("statistics")
1129    return stat and uint(stat.tx_packets) or 0
1130end
1131
1132function interface.rx_packets(self)
1133    local stat = self:_ubus("statistics")
1134    return stat and uint(stat.rx_packets) or 0
1135end
1136
1137function interface.get_network(self)
1138    return self:get_networks()[1]
1139end
1140
1141function interface.get_networks(self)
1142    if not self.networks then
1143        local nets = { }
1144        local _, net
1145        for _, net in ipairs(_M:get_networks()) do
1146            if net:contains_interface(self.ifname) or
1147               net:ifname() == self.ifname
1148            then
1149                nets[#nets+1] = net
1150            end
1151        end
1152        table.sort(nets, function(a, b) return a.sid < b.sid end)
1153        self.networks = nets
1154        return nets
1155    else
1156        return self.networks
1157    end
1158end
1159
1160function interface.get_wifinet(self)
1161    return self.wif
1162end
1163
1164
1165wifidev = utl.class()
1166
1167function wifidev.__init__(self, dev)
1168    self.sid    = dev
1169    self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1170end
1171
1172function wifidev.get(self, opt)
1173    return _get("wireless", self.sid, opt)
1174end
1175
1176function wifidev.set(self, opt, val)
1177    return _set("wireless", self.sid, opt, val)
1178end
1179
1180function wifidev.name(self)
1181    return self.sid
1182end
1183
1184function wifidev.hwmodes(self)
1185    local l = self.iwinfo.hwmodelist
1186    if l and next(l) then
1187        return l
1188    else
1189        return { b = true, g = true }
1190    end
1191end
1192
1193function wifidev.get_i18n(self)
1194    local t = "Generic"
1195    if self.iwinfo.type == "wl" then
1196        t = "Broadcom"
1197    elseif self.iwinfo.type == "madwifi" then
1198        t = "Atheros"
1199    end
1200
1201    local m = ""
1202    local l = self:hwmodes()
1203    if l.a then m = m .. "a" end
1204    if l.b then m = m .. "b" end
1205    if l.g then m = m .. "g" end
1206    if l.n then m = m .. "n" end
1207
1208    return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() }
1209end
1210
1211function wifidev.is_up(self)
1212    local up = false
1213
1214    _uci_state:foreach("wireless", "wifi-iface",
1215        function(s)
1216            if s.device == self.sid then
1217                if s.up == "1" then
1218                    up = true
1219                    return false
1220                end
1221            end
1222        end)
1223
1224    return up
1225end
1226
1227function wifidev.get_wifinet(self, net)
1228    if _uci_real:get("wireless", net) == "wifi-iface" then
1229        return wifinet(net)
1230    else
1231        local wnet = _wifi_lookup(net)
1232        if wnet then
1233            return wifinet(wnet)
1234        end
1235    end
1236end
1237
1238function wifidev.get_wifinets(self)
1239    local nets = { }
1240
1241    _uci_real:foreach("wireless", "wifi-iface",
1242        function(s)
1243            if s.device == self.sid then
1244                nets[#nets+1] = wifinet(s['.name'])
1245            end
1246        end)
1247
1248    return nets
1249end
1250
1251function wifidev.add_wifinet(self, options)
1252    options = options or { }
1253    options.device = self.sid
1254
1255    local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
1256    if wnet then
1257        return wifinet(wnet, options)
1258    end
1259end
1260
1261function wifidev.del_wifinet(self, net)
1262    if utl.instanceof(net, wifinet) then
1263        net = net.sid
1264    elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
1265        net = _wifi_lookup(net)
1266    end
1267
1268    if net and _uci_real:get("wireless", net, "device") == self.sid then
1269        _uci_real:delete("wireless", net)
1270        return true
1271    end
1272
1273    return false
1274end
1275
1276
1277wifinet = utl.class()
1278
1279function wifinet.__init__(self, net, data)
1280    self.sid = net
1281
1282    local num = { }
1283    local netid
1284    _uci_real:foreach("wireless", "wifi-iface",
1285        function(s)
1286            if s.device then
1287                num[s.device] = num[s.device] and num[s.device] + 1 or 1
1288                if s['.name'] == self.sid then
1289                    netid = "%s.network%d" %{ s.device, num[s.device] }
1290                    return false
1291                end
1292            end
1293        end)
1294
1295    local dev = _uci_state:get("wireless", self.sid, "ifname") or netid
1296
1297    self.netid  = netid
1298    self.wdev   = dev
1299    self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1300    self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
1301        _uci_real:get_all("wireless", self.sid) or { }
1302end
1303
1304function wifinet.get(self, opt)
1305    return _get("wireless", self.sid, opt)
1306end
1307
1308function wifinet.set(self, opt, val)
1309    return _set("wireless", self.sid, opt, val)
1310end
1311
1312function wifinet.mode(self)
1313    return _uci_state:get("wireless", self.sid, "mode") or "ap"
1314end
1315
1316function wifinet.ssid(self)
1317    return _uci_state:get("wireless", self.sid, "ssid")
1318end
1319
1320function wifinet.bssid(self)
1321    return _uci_state:get("wireless", self.sid, "bssid")
1322end
1323
1324function wifinet.network(self)
1325    return _uci_state:get("wifinet", self.sid, "network")
1326end
1327
1328function wifinet.id(self)
1329    return self.netid
1330end
1331
1332function wifinet.name(self)
1333    return self.sid
1334end
1335
1336function wifinet.ifname(self)
1337    local ifname = self.iwinfo.ifname
1338    if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
1339        ifname = self.wdev
1340    end
1341    return ifname
1342end
1343
1344function wifinet.get_device(self)
1345    if self.iwdata.device then
1346        return wifidev(self.iwdata.device)
1347    end
1348end
1349
1350function wifinet.is_up(self)
1351    return (self.iwdata.up == "1")
1352end
1353
1354function wifinet.active_mode(self)
1355    local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
1356
1357    if     m == "ap"      then m = "Master"
1358    elseif m == "sta"     then m = "Client"
1359    elseif m == "adhoc"   then m = "Ad-Hoc"
1360    elseif m == "mesh"    then m = "Mesh"
1361    elseif m == "monitor" then m = "Monitor"
1362    end
1363
1364    return m
1365end
1366
1367function wifinet.active_mode_i18n(self)
1368    return i18n.translate(self:active_mode())
1369end
1370
1371function wifinet.active_ssid(self)
1372    return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1373end
1374
1375function wifinet.active_bssid(self)
1376    return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1377end
1378
1379function wifinet.active_encryption(self)
1380    local enc = self.iwinfo and self.iwinfo.encryption
1381    return enc and enc.description or "-"
1382end
1383
1384function wifinet.assoclist(self)
1385    return self.iwinfo.assoclist or { }
1386end
1387
1388function wifinet.frequency(self)
1389    local freq = self.iwinfo.frequency
1390    if freq and freq > 0 then
1391        return "%.03f" % (freq / 1000)
1392    end
1393end
1394
1395function wifinet.bitrate(self)
1396    local rate = self.iwinfo.bitrate
1397    if rate and rate > 0 then
1398        return (rate / 1000)
1399    end
1400end
1401
1402function wifinet.channel(self)
1403    return self.iwinfo.channel or
1404        tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1405end
1406
1407function wifinet.signal(self)
1408    return self.iwinfo.signal or 0
1409end
1410
1411function wifinet.noise(self)
1412    return self.iwinfo.noise or 0
1413end
1414
1415function wifinet.country(self)
1416    return self.iwinfo.country or "00"
1417end
1418
1419function wifinet.txpower(self)
1420    local pwr = (self.iwinfo.txpower or 0)
1421    return pwr + self:txpower_offset()
1422end
1423
1424function wifinet.txpower_offset(self)
1425    return self.iwinfo.txpower_offset or 0
1426end
1427
1428function wifinet.signal_level(self, s, n)
1429    if self:active_bssid() ~= "00:00:00:00:00:00" then
1430        local signal = s or self:signal()
1431        local noise  = n or self:noise()
1432
1433        if signal < 0 and noise < 0 then
1434            local snr = -1 * (noise - signal)
1435            return math.floor(snr / 5)
1436        else
1437            return 0
1438        end
1439    else
1440        return -1
1441    end
1442end
1443
1444function wifinet.signal_percent(self)
1445    local qc = self.iwinfo.quality or 0
1446    local qm = self.iwinfo.quality_max or 0
1447
1448    if qc > 0 and qm > 0 then
1449        return math.floor((100 / qm) * qc)
1450    else
1451        return 0
1452    end
1453end
1454
1455function wifinet.shortname(self)
1456    return "%s %q" %{
1457        i18n.translate(self:active_mode()),
1458        self:active_ssid() or self:active_bssid()
1459    }
1460end
1461
1462function wifinet.get_i18n(self)
1463    return "%s: %s %q (%s)" %{
1464        i18n.translate("Wireless Network"),
1465        i18n.translate(self:active_mode()),
1466        self:active_ssid() or self:active_bssid(),
1467        self:ifname()
1468    }
1469end
1470
1471function wifinet.adminlink(self)
1472    return dsp.build_url("admin", "network", "wireless", self.netid)
1473end
1474
1475function wifinet.get_network(self)
1476    return self:get_networks()[1]
1477end
1478
1479function wifinet.get_networks(self)
1480    local nets = { }
1481    local net
1482    for net in utl.imatch(tostring(self.iwdata.network)) do
1483        if _uci_real:get("network", net) == "interface" then
1484            nets[#nets+1] = network(net)
1485        end
1486    end
1487    table.sort(nets, function(a, b) return a.sid < b.sid end)
1488    return nets
1489end
1490
1491function wifinet.get_interface(self)
1492    return interface(self:ifname())
1493end
1494
1495
1496-- setup base protocols
1497_M:register_protocol("static")
1498_M:register_protocol("dhcp")
1499_M:register_protocol("none")
1500
1501-- load protocol extensions
1502local exts = nfs.dir(utl.libpath() .. "/model/network")
1503if exts then
1504    local ext
1505    for ext in exts do
1506        if ext:match("%.lua$") then
1507            require("luci.model.network." .. ext:gsub("%.lua$", ""))
1508        end
1509    end
1510end
Note: See TracBrowser for help on using the browser.