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

Revision 8051, 29.7 KB (checked in by jow, 18 months ago)

libs/core: fix undefined tostring() in network model

  • 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 nxo = require "nixio"
29local nfs = require "nixio.fs"
30local ipc = require "luci.ip"
31local sys = require "luci.sys"
32local utl = require "luci.util"
33local dsp = require "luci.dispatcher"
34local uci = require "luci.model.uci"
35
36module "luci.model.network"
37
38
39IFACE_PATTERNS_VIRTUAL  = { }
40IFACE_PATTERNS_IGNORE   = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^lo$" }
41IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
42
43
44protocol = utl.class()
45
46local _protocols = { }
47
48local _interfaces, _bridge, _switch, _tunnel
49local _uci_real, _uci_state
50
51function _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
79end
80
81function _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
102end
103
104function _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
110end
111
112function _get(c, s, o)
113    return _uci_real:get(c, s, o)
114end
115
116function _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
123end
124
125function _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
133end
134
135function _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
170end
171
172function _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
180end
181
182function _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)
190end
191
192
193function 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
263end
264
265function save(self, ...)
266    _uci_real:save(...)
267    _uci_real:load(...)
268end
269
270function commit(self, ...)
271    _uci_real:commit(...)
272    _uci_real:load(...)
273end
274
275function 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
283end
284
285function get_protocol(self, protoname, netname)
286    local v = _protocols[protoname]
287    if v then
288        return v(netname or "__dummy__")
289    end
290end
291
292function 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
299end
300
301function 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
316end
317
318function register_pattern_virtual(self, pat)
319    IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat
320end
321
322
323function has_ipv6(self)
324    return nfs.access("/proc/net/ipv6_route")
325end
326
327function 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
342end
343
344function get_network(self, n)
345    if n and _uci_real:get("network", n) == "interface" then
346        return network(n)
347    end
348end
349
350function 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
365end
366
367function 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
387end
388
389function 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
427end
428
429function 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
448end
449
450function 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
530end
531
532function ignore_interface(self, x)
533    return _iface_ignore(x)
534end
535
536function get_wifidev(self, dev)
537    if _uci_real:get("wireless", dev) == "wifi-device" then
538        return wifidev(dev)
539    end
540end
541
542function 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
555end
556
557function get_wifinet(self, net)
558    local wnet = _wifi_lookup(net)
559    if wnet then
560        return wifinet(wnet)
561    end
562end
563
564function 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
571end
572
573function 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
580end
581
582
583function 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
589end
590
591function protocol.__init__(self, name)
592    self.sid = name
593end
594
595function 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 ""
601end
602
603function 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
619end
620
621function protocol.get(self, opt)
622    return _get("network", self.sid, opt)
623end
624
625function protocol.set(self, opt, val)
626    return _set("network", self.sid, opt, val)
627end
628
629function 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
660end
661
662function protocol.proto(self)
663    return "none"
664end
665
666function 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
677end
678
679function protocol.type(self)
680    return self:_get("type")
681end
682
683function protocol.name(self)
684    return self.sid
685end
686
687function 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
694end
695
696function 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
704end
705
706function protocol.metric(self)
707    return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
708end
709
710function protocol.ipaddr(self)
711    return self:_ip("ipaddr", 4)
712end
713
714function protocol.netmask(self)
715    return self:_ip("netmask", 4)
716end
717
718function protocol.gwaddr(self)
719    return self:_ip("gateway", 4)
720end
721
722function protocol.dnsaddrs(self)
723    return self:_ip("dns", 4, true)
724end
725
726function 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
741end
742
743function 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
752end
753
754function protocol.dns6addrs(self)
755    return self:_ip("dns", 6, true)
756end
757
758function protocol.is_bridge(self)
759    return (not self:is_virtual() and self:type() == "bridge")
760end
761
762function protocol.opkg_package(self)
763    return nil
764end
765
766function protocol.is_installed(self)
767    return true
768end
769
770function protocol.is_virtual(self)
771    return false
772end
773
774function protocol.is_floating(self)
775    return false
776end
777
778function 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
798end
799
800function 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
819end
820
821function 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
831end
832
833function 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
860end
861
862function 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
896end
897
898function 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
922end
923
924function protocol.adminlink(self)
925    return dsp.build_url("admin", "network", "network", self.sid)
926end
927
928
929interface = utl.class()
930
931function 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
941end
942
943function interface.name(self)
944    return self.wif and self.wif:ifname() or self.ifname
945end
946
947function interface.mac(self)
948    return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper()
949end
950
951function interface.ipaddrs(self)
952    return self.dev and self.dev.ipaddrs or { }
953end
954
955function interface.ip6addrs(self)
956    return self.dev and self.dev.ip6addrs or { }
957end
958
959function 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
973end
974
975function 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
984end
985
986function 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
996end
997
998function 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
1013end
1014
1015function interface.adminlink(self)
1016    if self.wif then
1017        return self.wif:adminlink()
1018    end
1019end
1020
1021function 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
1030end
1031
1032function interface.bridge_id(self)
1033    if self.br then
1034        return self.br.id
1035    else
1036        return nil
1037    end
1038end
1039
1040function interface.bridge_stp(self)
1041    if self.br then
1042        return self.br.stp
1043    else
1044        return false
1045    end
1046end
1047
1048function 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
1054end
1055
1056function interface.is_bridge(self)
1057    return (self:type() == "bridge")
1058end
1059
1060function interface.is_bridgeport(self)
1061    return self.dev and self.dev.bridge and true or false
1062end
1063
1064function interface.tx_bytes(self)
1065    return self.dev and self.dev.stats
1066        and self.dev.stats.tx_bytes or 0
1067end
1068
1069function interface.rx_bytes(self)
1070    return self.dev and self.dev.stats
1071        and self.dev.stats.rx_bytes or 0
1072end
1073
1074function interface.tx_packets(self)
1075    return self.dev and self.dev.stats
1076        and self.dev.stats.tx_packets or 0
1077end
1078
1079function interface.rx_packets(self)
1080    return self.dev and self.dev.stats
1081        and self.dev.stats.rx_packets or 0
1082end
1083
1084function 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
1104end
1105
1106function interface.get_wifinet(self)
1107    return self.wif
1108end
1109
1110
1111wifidev = utl.class()
1112
1113function wifidev.__init__(self, dev)
1114    self.sid    = dev
1115    self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
1116end
1117
1118function wifidev.get(self, opt)
1119    return _get("wireless", self.sid, opt)
1120end
1121
1122function wifidev.set(self, opt, val)
1123    return _set("wireless", self.sid, opt, val)
1124end
1125
1126function wifidev.name(self)
1127    return self.sid
1128end
1129
1130function 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
1137end
1138
1139function 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() }
1155end
1156
1157function 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
1171end
1172
1173function 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
1182end
1183
1184function 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
1195end
1196
1197function 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
1205end
1206
1207function 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
1220end
1221
1222
1223wifinet = utl.class()
1224
1225function 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 { }
1248end
1249
1250function wifinet.get(self, opt)
1251    return _get("wireless", self.sid, opt)
1252end
1253
1254function wifinet.set(self, opt, val)
1255    return _set("wireless", self.sid, opt, val)
1256end
1257
1258function wifinet.mode(self)
1259    return _uci_state:get("wireless", self.sid, "mode") or "ap"
1260end
1261
1262function wifinet.ssid(self)
1263    return _uci_state:get("wireless", self.sid, "ssid")
1264end
1265
1266function wifinet.bssid(self)
1267    return _uci_state:get("wireless", self.sid, "bssid")
1268end
1269
1270function wifinet.network(self)
1271    return _uci_state:get("wifinet", self.sid, "network")
1272end
1273
1274function wifinet.id(self)
1275    return self.netid
1276end
1277
1278function wifinet.name(self)
1279    return self.sid
1280end
1281
1282function 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
1288end
1289
1290function wifinet.get_device(self)
1291    if self.iwdata.device then
1292        return wifidev(self.iwdata.device)
1293    end
1294end
1295
1296function wifinet.is_up(self)
1297    return (self.iwdata.up == "1")
1298end
1299
1300function 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
1311end
1312
1313function wifinet.active_mode_i18n(self)
1314    return i18n.translate(self:active_mode())
1315end
1316
1317function wifinet.active_ssid(self)
1318    return _stror(self.iwinfo.ssid, self.iwdata.ssid)
1319end
1320
1321function wifinet.active_bssid(self)
1322    return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
1323end
1324
1325function wifinet.active_encryption(self)
1326    local enc = self.iwinfo and self.iwinfo.encryption
1327    return enc and enc.description or "-"
1328end
1329
1330function wifinet.assoclist(self)
1331    return self.iwinfo.assoclist or { }
1332end
1333
1334function wifinet.frequency(self)
1335    local freq = self.iwinfo.frequency
1336    if freq and freq > 0 then
1337        return "%.03f" % (freq / 1000)
1338    end
1339end
1340
1341function wifinet.bitrate(self)
1342    local rate = self.iwinfo.bitrate
1343    if rate and rate > 0 then
1344        return (rate / 1000)
1345    end
1346end
1347
1348function wifinet.channel(self)
1349    return self.iwinfo.channel or
1350        tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
1351end
1352
1353function wifinet.signal(self)
1354    return self.iwinfo.signal or 0
1355end
1356
1357function wifinet.noise(self)
1358    return self.iwinfo.noise or 0
1359end
1360
1361function wifinet.country(self)
1362    return self.iwinfo.country or "00"
1363end
1364
1365function wifinet.txpower(self)
1366    local pwr = (self.iwinfo.txpower or 0)
1367    return pwr + self:txpower_offset()
1368end
1369
1370function wifinet.txpower_offset(self)
1371    return self.iwinfo.txpower_offset or 0
1372end
1373
1374function 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
1388end
1389
1390function 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
1399end
1400
1401function wifinet.shortname(self)
1402    return "%s %q" %{
1403        i18n.translate(self:active_mode()),
1404        self:active_ssid() or self:active_bssid()
1405    }
1406end
1407
1408function 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    }
1415end
1416
1417function wifinet.adminlink(self)
1418    return dsp.build_url("admin", "network", "wireless", self.netid)
1419end
1420
1421function 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
1426end
1427
1428function wifinet.get_interface(self)
1429    return interface(self:ifname())
1430end
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
1439local exts = nfs.dir(utl.libpath() .. "/model/network")
1440if 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
1447end
Note: See TracBrowser for help on using the browser.