libs/core: fix type in luci.model.wireless
[project/luci.git] / libs / core / luasrc / model / network.lua
index 3a7e38a..e1e9f45 100644 (file)
@@ -17,11 +17,12 @@ limitations under the License.
 
 ]]--
 
-local type, pairs, ipairs, table, i18n
-       = type, pairs, ipairs, table, luci.i18n
+local type, pairs, ipairs, loadfile, table, i18n
+       = type, pairs, ipairs, loadfile, table, luci.i18n
 
 local lmo = require "lmo"
 local nxo = require "nixio"
+local nfs = require "nixio.fs"
 local iwi = require "iwinfo"
 local ipc = require "luci.ip"
 local utl = require "luci.util"
@@ -29,9 +30,31 @@ local uct = require "luci.model.uci.bind"
 
 module "luci.model.network"
 
+-- load extensions
+local ext
+local handler = { }
+
+for ext in nfs.glob(utl.libpath() .. "/model/network/*.lua") do
+       if nfs.access(ext) then
+               local m = loadfile(ext)
+               if m then
+                       handler[#handler+1] = m()
+               end
+       end
+end
+
+function foreach_handler(code, ...)
+       local h
+       for _, h in ipairs(handler) do
+               if code(h, ...) then
+                       return true
+               end
+       end
+       return false
+end
 
 local ub = uct.bind("network")
-local ifs, brs
+local ifs, brs, sws
 
 function init(cursor)
        if cursor then
@@ -41,11 +64,19 @@ function init(cursor)
 
                ifs = { }
                brs = { }
+               sws = { }
+
+               -- init handler
+               foreach_handler(function(h)
+                       h:init(cursor)
+                       h:find_interfaces(ifs, brs)
+               end)
 
                -- read interface information
                local n, i
                for n, i in ipairs(nxo.getifaddrs()) do
                        local name = i.name:match("[^:]+")
+                       local prnt = name:match("^([^%.]+)%.")
 
                        if not _M:ignore_interface(name) then
                                ifs[name] = ifs[name] or {
@@ -57,6 +88,11 @@ function init(cursor)
                                        ip6addrs = { }
                                }
 
+                               if prnt then
+                                       sws[name] = true
+                                       sws[prnt] = true
+                               end
+
                                if i.family == "packet" then
                                        ifs[name].flags   = i.flags
                                        ifs[name].stats   = i.data
@@ -67,7 +103,7 @@ function init(cursor)
                                        ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
                                end
                        end
-               end             
+               end
 
                -- read bridge informaton
                local b, l
@@ -94,6 +130,10 @@ function init(cursor)
        end
 end
 
+function has_ipv6(self)
+       return nfs.access("/proc/net/ipv6_route")
+end
+
 function add_network(self, n, options)
        if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
                if ub.uci:section("network", "interface", n, options) then
@@ -138,6 +178,8 @@ function del_network(self, n)
                                        ub.uci:delete("network", s['.name'])
                                end
                        end)
+
+               foreach_handler(function(h) h:del_network(n) end)
        end
        return r
 end
@@ -167,13 +209,24 @@ function rename_network(self, old, new)
                                                ub.uci:set("network", s['.name'], "interface", new)
                                        end
                                end)
+
+                       foreach_handler(function(h) h:rename_network(old, new) end)
                end
        end
        return r or false
 end
 
 function get_interface(self, i)
-       return ifs[i] and interface(i)
+       if ifs[i] then
+               return interface(i)
+       else
+               local j
+               for j, _ in pairs(ifs) do
+                       if ifs[j].sid == i then
+                               return interface(j)
+                       end
+               end
+       end
 end
 
 function get_interfaces(self)
@@ -186,8 +239,12 @@ function get_interfaces(self)
 end
 
 function ignore_interface(self, x)
-       return (x:match("^wmaster%d") or x:match("^wifi%d")
-               or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
+       if foreach_handler(function(h) return h:ignore_interface(x) end) then
+               return true
+       else
+               return (x:match("^wmaster%d") or x:match("^wifi%d")
+                       or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
+       end
 end
 
 
@@ -206,11 +263,27 @@ function network.is_bridge(self)
 end
 
 function network.add_interface(self, ifname)
+       local ifaces, iface
+
        if type(ifname) ~= "string" then
-               ifname = ifname:name()
+               ifaces = { ifname:name() }
+       else
+               ifaces = ub:list(ifname)
        end
-       if ifs[ifname] then
-               self:ifname(ub:list((self:ifname() or ''), ifname))
+
+       for _, iface in ipairs(ifaces) do
+               if ifs[iface] then
+                       -- make sure the interface is removed from all networks
+                       local i = interface(iface)
+                       local n = i:get_network()
+                       if n then n:del_interface(iface) end
+
+                       if ifs[iface].handler then
+                               ifs[iface].handler:add_interface(self, iface, ifs[iface])
+                       else
+                               self:ifname(ub:list((self:ifname() or ''), iface))
+                       end
+               end
        end
 end
 
@@ -218,28 +291,34 @@ function network.del_interface(self, ifname)
        if type(ifname) ~= "string" then
                ifname = ifname:name()
        end
-       self:ifname(ub:list((self:ifname() or ''), nil, ifname))
+
+       if ifs[ifname] and ifs[ifname].handler then
+               ifs[ifname].handler:del_interface(self, ifname, ifs[ifname])
+       else
+               self:ifname(ub:list((self:ifname() or ''), nil, ifname))
+       end
 end
 
 function network.get_interfaces(self)
        local ifaces = { }
        local iface
-       for _, iface in ub:list(
-               (self:ifname() or '') .. ' ' .. (self:device() or '')
-       ) do
+       for _, iface in ipairs(ub:list(self:ifname())) do
                iface = iface:match("[^:]+")
                if ifs[iface] then
                        ifaces[#ifaces+1] = interface(iface)
                end
        end
+       for iface, _ in pairs(ifs) do
+               if ifs[iface].network == self:name() then
+                       ifaces[#ifaces+1] = interface(iface)
+               end
+       end
        return ifaces
 end
 
 function network.contains_interface(self, iface)
        local i
-       local ifaces = ub:list(
-               (self:ifname() or '') .. ' ' .. (self:device() or '')
-       )
+       local ifaces = ub:list(self:ifname())
 
        if type(iface) ~= "string" then
                iface = iface:name()
@@ -251,6 +330,12 @@ function network.contains_interface(self, iface)
                end
        end
 
+       for i, _ in pairs(ifs) do
+               if ifs[i].dev and ifs[i].dev.network == self:name() then
+                       return true
+               end
+       end
+
        return false
 end
 
@@ -268,18 +353,46 @@ function interface.name(self)
        return self.ifname
 end
 
+function interface.mac(self)
+       return self.dev.macaddr or "00:00:00:00:00:00"
+end
+
+function interface.ipaddrs(self)
+       return self.dev.ipaddrs or { }
+end
+
+function interface.ip6addrs(self)
+       return self.dev.ip6addrs or { }
+end
+
 function interface.type(self)
-       if iwi.type(self.ifname) and iwi.type(self.ifname) ~= "dummy" then
-               return "wifi"
+       if self.dev and self.dev.type then
+               return self.dev.type
        elseif brs[self.ifname] then
                return "bridge"
-       elseif self.ifname:match("%.") then
+       elseif sws[self.ifname] or self.ifname:match("%.") then
                return "switch"
        else
                return "ethernet"
        end
 end
 
+function interface.shortname(self)
+       if self.dev and self.dev.handler then
+               return self.dev.handler:shortname(self)
+       else
+               return self.ifname
+       end
+end
+
+function interface.get_i18n(self)
+       if self.dev and self.dev.handler then
+               return self.dev.handler:get_i18n(self)
+       else
+               return "%s: %q" %{ self:get_type_i18n(), self:name() }
+       end
+end
+
 function interface.get_type_i18n(self)
        local x = self:type()
        if x == "wifi" then
@@ -298,12 +411,28 @@ function interface.ports(self)
                local iface
                local ifaces = { }
                for _, iface in ipairs(self.br.ifnames) do
-                       ifaces[#ifaces+1] = interface(iface)
+                       ifaces[#ifaces+1] = interface(iface.name)
                end
                return ifaces
        end
 end
 
+function interface.bridge_id(self)
+       if self.br then
+               return self.br.id
+       else
+               return nil
+       end
+end
+
+function interface.bridge_stp(self)
+       if self.br then
+               return self.br.stp
+       else
+               return false
+       end
+end
+
 function interface.is_up(self)
        return self.dev.flags and self.dev.flags.up
 end
@@ -312,12 +441,45 @@ function interface.is_bridge(self)
        return (self:type() == "bridge")
 end
 
+function interface.is_bridgeport(self)
+       return self.dev and self.dev.bridge and true or false
+end
+
+function interface.tx_bytes(self)
+       return self.dev and self.dev.stats
+               and self.dev.stats.tx_bytes or 0
+end
+
+function interface.rx_bytes(self)
+       return self.dev and self.dev.stats
+               and self.dev.stats.rx_bytes or 0
+end
+
+function interface.tx_packets(self)
+       return self.dev and self.dev.stats
+               and self.dev.stats.tx_packets or 0
+end
+
+function interface.rx_packets(self)
+       return self.dev and self.dev.stats
+               and self.dev.stats.rx_packets or 0
+end
+
 function interface.get_network(self)
-       local net
-       for _, net in ipairs(_M:get_networks()) do
-               if net:contains_interface(self.ifname) then
-                       return net
+       if self.dev and self.dev.network then
+               self.network = _M:get_network(self.dev.network)
+       end
+
+       if not self.network then
+               local net
+               for _, net in ipairs(_M:get_networks()) do
+                       if net:contains_interface(self.ifname) then
+                               self.network = net
+                               return net
+                       end
                end
+       else
+               return self.network
        end
 end