--[[ LuCI - Network model Copyright 2009 Jo-Philipp Wich Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ]]-- local type, pairs, ipairs, table = type, pairs, ipairs, table local lmo = require "lmo" local nxo = require "nixio" local iwi = require "iwinfo" local ipc = require "luci.ip" local utl = require "luci.util" local uct = require "luci.model.uci.bind" module "luci.model.network" local ub = uct.bind("network") local ifs, brs function init(cursor) if cursor then cursor:unload("network") cursor:load("network") ub:init(cursor) ifs = { } brs = { } -- read interface information local n, i for n, i in ipairs(nxo.getifaddrs()) do local name = i.name:match("[^:]+") if not _M:ignore_interface(name) then ifs[name] = ifs[name] or { idx = i.ifindex or n, name = name, rawname = i.name, flags = { }, ipaddrs = { }, ip6addrs = { } } if i.family == "packet" then ifs[name].flags = i.flags ifs[name].stats = i.data ifs[name].macaddr = i.addr elseif i.family == "inet" then ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask) elseif i.family == "inet6" then ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask) end end end -- read bridge informaton local b, l for l in utl.execi("brctl show") do if not l:match("STP") then local r = utl.split(l, "%s+", nil, true) if #r == 4 then b = { name = r[1], id = r[2], stp = r[3] == "yes", ifnames = { ifs[r[4]] } } if b.ifnames[1] then b.ifnames[1].bridge = b end brs[r[1]] = b elseif b then b.ifnames[#b.ifnames+1] = ifs[r[2]] b.ifnames[#b.ifnames].bridge = b end end end end 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 return network(n) end end end function get_network(self, n) if n and ub.uci:get("network", n) == "interface" then return network(n) end end function get_networks(self) local nets = { } ub.uci:foreach("network", "interface", function(s) nets[#nets+1] = network(s['.name']) end) return nets end function del_network(self, n) local r = ub.uci:delete("network", n) if r then ub.uci:foreach("network", "alias", function(s) if s.interface == n then ub.uci:delete("network", s['.name']) end end) ub.uci:foreach("network", "route", function(s) if s.interface == n then ub.uci:delete("network", s['.name']) end end) ub.uci:foreach("network", "route6", function(s) if s.interface == n then ub.uci:delete("network", s['.name']) end end) end return r end function rename_network(self, old, new) local r if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then r = ub.uci:section("network", "interface", new, ub.uci:get_all("network", old)) if r then ub.uci:foreach("network", "alias", function(s) if s.interface == old then ub.uci:set("network", s['.name'], "interface", new) end end) ub.uci:foreach("network", "route", function(s) if s.interface == old then ub.uci:set("network", s['.name'], "interface", new) end end) ub.uci:foreach("network", "route6", function(s) if s.interface == old then ub.uci:set("network", s['.name'], "interface", new) end end) end end return r or false end function get_interface(self, i) return ifs[i] and interface(i) end function get_interfaces(self) local ifaces = { } local iface for iface, _ in pairs(ifs) do ifaces[#ifaces+1] = interface(iface) end return ifaces 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") end network = ub:section("interface") network:property("device") network:property("ifname") network:property("proto") network:property("type") function network.name(self) return self.sid end function network.is_bridge(self) return (self:type() == "bridge") end function network.add_interface(self, ifname) if type(ifname) ~= "string" then ifname = ifname:ifname() end if ifs[ifname] then self:ifname(ub:list((self:ifname() or ''), ifname)) end end function network.del_interface(self, ifname) if type(ifname) ~= "string" then ifname = ifname:ifname() end self:ifname(ub:list((self:ifname() or ''), nil, ifname)) end function network.get_interfaces(self) local ifaces = { } local iface for _, iface in ub:list( (self:ifname() or '') .. ' ' .. (self:device() or '') ) do iface = iface:match("[^:]+") if ifs[iface] then ifaces[#ifaces+1] = interface(iface) end end return ifaces end function contains_interface(self, iface) local i local ifaces = ub:list( (self:ifname() or '') .. ' ' .. (self:device() or '') ) if type(iface) ~= "string" then iface = iface:ifname() end for _, i in ipairs(ifaces) do if i == iface then return true end end return false end interface = utl.class() function interface.__init__(self, ifname) if ifs[ifname] then self.ifname = ifname self.dev = ifs[ifname] self.br = brs[ifname] end end function interface.name(self) return self.ifname end function interface.type(self) if iwi.type(self.ifname) and iwi.type(self.ifname) ~= "dummy" then return "wifi" elseif brs[self.ifname] then return "bridge" elseif self.ifname:match("%.") then return "switch" else return "ethernet" end end function interface.ports(self) if self.br then local iface local ifaces = { } for _, iface in ipairs(self.br.ifnames) do ifaces[#ifaces+1] = interface(iface) end return ifaces end end function interface.is_up(self) return self.dev.flags and self.dev.flags.up end function interface.is_bridge(self) return (self:type() == "bridge") 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 end end end