---[[
-LuCI - Network model
+-- Copyright 2009-2015 Jo-Philipp Wich <jow@openwrt.org>
+-- Licensed to the public under the Apache License 2.0.
-Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
-
-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, next, pairs, ipairs, loadfile, table
- = type, next, pairs, ipairs, loadfile, table
+local type, next, pairs, ipairs, loadfile, table, select
+ = type, next, pairs, ipairs, loadfile, table, select
local tonumber, tostring, math = tonumber, tostring, math
-local require = require
+local pcall, require, setmetatable = pcall, require, setmetatable
-local bus = require "ubus"
local nxo = require "nixio"
local nfs = require "nixio.fs"
local ipc = require "luci.ip"
-local sys = require "luci.sys"
local utl = require "luci.util"
-local dsp = require "luci.dispatcher"
local uci = require "luci.model.uci"
local lng = require "luci.i18n"
+local jsc = require "luci.jsonc"
module "luci.model.network"
IFACE_PATTERNS_VIRTUAL = { }
-IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" }
+IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^gretap%d", "^ip6gre%d", "^ip6tnl%d", "^tunl%d", "^lo$" }
IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
local _protocols = { }
-local _interfaces, _bridge, _switch, _tunnel
-local _ubus, _ubusnetcache, _ubusdevcache, _ubuswificache
-local _uci_real, _uci_state
+local _interfaces, _bridge, _switch, _tunnel, _swtopo
+local _ubusnetcache, _ubusdevcache, _ubuswificache
+local _uci
function _filter(c, s, o, r)
- local val = _uci_real:get(c, s, o)
+ local val = _uci:get(c, s, o)
if val then
local l = { }
if type(val) == "string" then
end
end
if #l > 0 then
- _uci_real:set(c, s, o, table.concat(l, " "))
+ _uci:set(c, s, o, table.concat(l, " "))
else
- _uci_real:delete(c, s, o)
+ _uci:delete(c, s, o)
end
elseif type(val) == "table" then
for _, val in ipairs(val) do
end
end
if #l > 0 then
- _uci_real:set(c, s, o, l)
+ _uci:set(c, s, o, l)
else
- _uci_real:delete(c, s, o)
+ _uci:delete(c, s, o)
end
end
end
end
function _append(c, s, o, a)
- local val = _uci_real:get(c, s, o) or ""
+ local val = _uci:get(c, s, o) or ""
if type(val) == "string" then
local l = { }
for val in val:gmatch("%S+") do
end
end
l[#l+1] = a
- _uci_real:set(c, s, o, table.concat(l, " "))
+ _uci:set(c, s, o, table.concat(l, " "))
elseif type(val) == "table" then
local l = { }
for _, val in ipairs(val) do
end
end
l[#l+1] = a
- _uci_real:set(c, s, o, l)
+ _uci:set(c, s, o, l)
end
end
end
function _get(c, s, o)
- return _uci_real:get(c, s, o)
+ return _uci:get(c, s, o)
end
function _set(c, s, o, v)
if v ~= nil then
if type(v) == "boolean" then v = v and "1" or "0" end
- return _uci_real:set(c, s, o, v)
+ return _uci:set(c, s, o, v)
else
- return _uci_real:delete(c, s, o)
+ return _uci:delete(c, s, o)
+ end
+end
+
+local function _wifi_state()
+ if not next(_ubuswificache) then
+ _ubuswificache = utl.ubus("network.wireless", "status", {}) or {}
+ end
+ return _ubuswificache
+end
+
+local function _wifi_state_by_sid(sid)
+ local t1, n1 = _uci:get("wireless", sid)
+ if t1 == "wifi-iface" and n1 ~= nil then
+ local radioname, radiostate
+ for radioname, radiostate in pairs(_wifi_state()) do
+ if type(radiostate) == "table" and
+ type(radiostate.interfaces) == "table"
+ then
+ local netidx, netstate
+ for netidx, netstate in ipairs(radiostate.interfaces) do
+ if type(netstate) == "table" and
+ type(netstate.section) == "string"
+ then
+ local t2, n2 = _uci:get("wireless", netstate.section)
+ if t1 == t2 and n1 == n2 then
+ return radioname, radiostate, netstate
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+local function _wifi_state_by_ifname(ifname)
+ if type(ifname) == "string" then
+ local radioname, radiostate
+ for radioname, radiostate in pairs(_wifi_state()) do
+ if type(radiostate) == "table" and
+ type(radiostate.interfaces) == "table"
+ then
+ local netidx, netstate
+ for netidx, netstate in ipairs(radiostate.interfaces) do
+ if type(netstate) == "table" and
+ type(netstate.ifname) == "string" and
+ netstate.ifname == ifname
+ then
+ return radioname, radiostate, netstate
+ end
+ end
+ end
+ end
end
end
return false
end
-function _wifi_state(key, val, field)
- local radio, radiostate, ifc, ifcstate
+local function _wifi_iwinfo_by_ifname(ifname, force_phy_only)
+ local stat, iwinfo = pcall(require, "iwinfo")
+ local iwtype = stat and type(ifname) == "string" and iwinfo.type(ifname)
+ local is_nonphy_op = {
+ bitrate = true,
+ quality = true,
+ quality_max = true,
+ mode = true,
+ ssid = true,
+ bssid = true,
+ assoclist = true,
+ encryption = true
+ }
- if not next(_ubuswificache) then
- _ubuswificache = _ubus:call("network.wireless", "status", {}) or {}
-
- -- workaround extended section format
- for radio, radiostate in pairs(_ubuswificache) do
- for ifc, ifcstate in pairs(radiostate.interfaces) do
- if ifcstate.section and ifcstate.section:sub(1, 1) == '@' then
- local s = _uci_real:get_all('wireless.%s' % ifcstate.section)
- if s then
- ifcstate.section = s['.name']
- end
+ if iwtype then
+ -- if we got a type but no real netdev, we're referring to a phy
+ local phy_only = force_phy_only or (ipc.link(ifname).type ~= 1)
+
+ return setmetatable({}, {
+ __index = function(t, k)
+ if k == "ifname" then
+ return ifname
+ elseif phy_only and is_nonphy_op[k] then
+ return nil
+ elseif iwinfo[iwtype][k] then
+ return iwinfo[iwtype][k](ifname)
end
end
- end
+ })
end
+end
- for radio, radiostate in pairs(_ubuswificache) do
- for ifc, ifcstate in pairs(radiostate.interfaces) do
- if ifcstate[key] == val then
- return ifcstate[field]
- end
+local function _wifi_sid_by_netid(netid)
+ if type(netid) == "string" then
+ local radioname, netidx = netid:match("^(%w+)%.network(%d+)$")
+ if radioname and netidx then
+ local i, n = 0, nil
+
+ netidx = tonumber(netidx)
+ _uci:foreach("wireless", "wifi-iface",
+ function(s)
+ if s.device == radioname then
+ i = i + 1
+ if i == netidx then
+ n = s[".name"]
+ return false
+ end
+ end
+ end)
+
+ return n
end
end
end
-function _wifi_lookup(ifn)
- -- got a radio#.network# pseudo iface, locate the corresponding section
- local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
- if radio and ifnidx then
- local sid = nil
- local num = 0
+function _wifi_sid_by_ifname(ifn)
+ local sid = _wifi_sid_by_netid(ifn)
+ if sid then
+ return sid
+ end
- ifnidx = tonumber(ifnidx)
- _uci_real:foreach("wireless", "wifi-iface",
- function(s)
- if s.device == radio then
- num = num + 1
- if num == ifnidx then
- sid = s['.name']
- return false
- end
- end
- end)
+ local _, _, netstate = _wifi_state_by_ifname(ifn)
+ if netstate and type(netstate.section) == "string" then
+ return netstate.section
+ end
+end
- return sid
+local function _wifi_netid_by_sid(sid)
+ local t, n = _uci:get("wireless", sid)
+ if t == "wifi-iface" and n ~= nil then
+ local radioname = _uci:get("wireless", n, "device")
+ if type(radioname) == "string" then
+ local i, netid = 0, nil
- -- looks like wifi, try to locate the section via state vars
- elseif _wifi_iface(ifn) then
- local sid = _wifi_state("ifname", ifn, "section")
- if not sid then
- _uci_state:foreach("wireless", "wifi-iface",
+ _uci:foreach("wireless", "wifi-iface",
function(s)
- if s.ifname == ifn then
- sid = s['.name']
- return false
+ if s.device == radioname then
+ i = i + 1
+ if s[".name"] == n then
+ netid = "%s.network%d" %{ radioname, i }
+ return false
+ end
end
end)
- end
- return sid
+ return netid, radioname
+ end
end
end
+local function _wifi_netid_by_netname(name)
+ local netid = nil
+
+ _uci:foreach("wireless", "wifi-iface",
+ function(s)
+ local net
+ for net in utl.imatch(s.network) do
+ if net == name then
+ netid = _wifi_netid_by_sid(s[".name"])
+ return false
+ end
+ end
+ end)
+
+ return netid
+end
+
function _iface_virtual(x)
local _, p
for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do
return true
end
end
- return _iface_virtual(x)
+ return false
end
-
function init(cursor)
- _uci_real = cursor or _uci_real or uci.cursor()
- _uci_state = _uci_real:substate()
+ _uci = cursor or _uci or uci.cursor()
_interfaces = { }
_bridge = { }
_switch = { }
_tunnel = { }
+ _swtopo = { }
- _ubus = bus.connect()
_ubusnetcache = { }
_ubusdevcache = { }
_ubuswificache = { }
local n, i
for n, i in ipairs(nxo.getifaddrs()) do
local name = i.name:match("[^:]+")
- local prnt = name:match("^([^%.]+)%.")
if _iface_virtual(name) then
_tunnel[name] = true
end
- if _tunnel[name] or not _iface_ignore(name) then
+ if _tunnel[name] or not (_iface_ignore(name) or _iface_virtual(name)) then
_interfaces[name] = _interfaces[name] or {
idx = i.ifindex or n,
name = name,
ip6addrs = { }
}
- if prnt then
- _switch[name] = true
- _switch[prnt] = true
- end
-
if i.family == "packet" then
_interfaces[name].flags = i.flags
_interfaces[name].stats = i.data
end
end
+ -- read switch topology
+ local boardinfo = jsc.parse(nfs.readfile("/etc/board.json") or "")
+ if type(boardinfo) == "table" and type(boardinfo.switch) == "table" then
+ local switch, layout
+ for switch, layout in pairs(boardinfo.switch) do
+ if type(layout) == "table" and type(layout.ports) == "table" then
+ local _, port
+ local ports = { }
+ local nports = { }
+ local netdevs = { }
+
+ for _, port in ipairs(layout.ports) do
+ if type(port) == "table" and
+ type(port.num) == "number" and
+ (type(port.role) == "string" or
+ type(port.device) == "string")
+ then
+ local spec = {
+ num = port.num,
+ role = port.role or "cpu",
+ index = port.index or port.num
+ }
+
+ if port.device then
+ spec.device = port.device
+ spec.tagged = port.need_tag
+ netdevs[tostring(port.num)] = port.device
+ end
+
+ ports[#ports+1] = spec
+
+ if port.role then
+ nports[port.role] = (nports[port.role] or 0) + 1
+ end
+ end
+ end
+
+ table.sort(ports, function(a, b)
+ if a.role ~= b.role then
+ return (a.role < b.role)
+ end
+
+ return (a.index < b.index)
+ end)
+
+ local pnum, role
+ for _, port in ipairs(ports) do
+ if port.role ~= role then
+ role = port.role
+ pnum = 1
+ end
+
+ if role == "cpu" then
+ port.label = "CPU (%s)" % port.device
+ elseif nports[role] > 1 then
+ port.label = "%s %d" %{ role:upper(), pnum }
+ pnum = pnum + 1
+ else
+ port.label = role:upper()
+ end
+
+ port.role = nil
+ port.index = nil
+ end
+
+ _swtopo[switch] = {
+ ports = ports,
+ netdevs = netdevs
+ }
+ end
+ end
+ end
+
return _M
end
function save(self, ...)
- _uci_real:save(...)
- _uci_real:load(...)
+ _uci:save(...)
+ _uci:load(...)
end
function commit(self, ...)
- _uci_real:commit(...)
- _uci_real:load(...)
+ _uci:commit(...)
+ _uci:load(...)
end
function ifnameof(self, x)
function add_network(self, n, options)
local oldnet = self:get_network(n)
if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then
- if _uci_real:section("network", "interface", n, options) then
+ if _uci:section("network", "interface", n, options) then
return network(n)
end
elseif oldnet and oldnet:is_empty() then
end
function get_network(self, n)
- if n and _uci_real:get("network", n) == "interface" then
+ if n and _uci:get("network", n) == "interface" then
return network(n)
end
end
local nets = { }
local nls = { }
- _uci_real:foreach("network", "interface",
+ _uci:foreach("network", "interface",
function(s)
nls[s['.name']] = network(s['.name'])
end)
end
function del_network(self, n)
- local r = _uci_real:delete("network", n)
+ local r = _uci:delete("network", n)
if r then
- _uci_real:delete_all("network", "alias",
+ _uci:delete_all("network", "alias",
function(s) return (s.interface == n) end)
- _uci_real:delete_all("network", "route",
+ _uci:delete_all("network", "route",
function(s) return (s.interface == n) end)
- _uci_real:delete_all("network", "route6",
+ _uci:delete_all("network", "route6",
function(s) return (s.interface == n) end)
- _uci_real:foreach("wireless", "wifi-iface",
+ _uci:foreach("wireless", "wifi-iface",
function(s)
local net
local rest = { }
end
end
if #rest > 0 then
- _uci_real:set("wireless", s['.name'], "network",
+ _uci:set("wireless", s['.name'], "network",
table.concat(rest, " "))
else
- _uci_real:delete("wireless", s['.name'], "network")
+ _uci:delete("wireless", s['.name'], "network")
end
end)
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 = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old))
+ r = _uci:section("network", "interface", new, _uci:get_all("network", old))
if r then
- _uci_real:foreach("network", "alias",
+ _uci:foreach("network", "alias",
function(s)
if s.interface == old then
- _uci_real:set("network", s['.name'], "interface", new)
+ _uci:set("network", s['.name'], "interface", new)
end
end)
- _uci_real:foreach("network", "route",
+ _uci:foreach("network", "route",
function(s)
if s.interface == old then
- _uci_real:set("network", s['.name'], "interface", new)
+ _uci:set("network", s['.name'], "interface", new)
end
end)
- _uci_real:foreach("network", "route6",
+ _uci:foreach("network", "route6",
function(s)
if s.interface == old then
- _uci_real:set("network", s['.name'], "interface", new)
+ _uci:set("network", s['.name'], "interface", new)
end
end)
- _uci_real:foreach("wireless", "wifi-iface",
+ _uci:foreach("wireless", "wifi-iface",
function(s)
local net
local list = { }
end
end
if #list > 0 then
- _uci_real:set("wireless", s['.name'], "network",
+ _uci:set("wireless", s['.name'], "network",
table.concat(list, " "))
end
end)
- _uci_real:delete("network", old)
+ _uci:delete("network", old)
end
end
return r or false
if _interfaces[i] or _wifi_iface(i) then
return interface(i)
else
- local ifc
- local num = { }
- _uci_real:foreach("wireless", "wifi-iface",
- function(s)
- if s.device then
- num[s.device] = num[s.device] and num[s.device] + 1 or 1
- if s['.name'] == i then
- ifc = interface(
- "%s.network%d" %{s.device, num[s.device] })
- return false
- end
- end
- end)
- return ifc
+ local netid = _wifi_netid_by_netname(i)
+ return netid and interface(netid)
end
end
function get_interfaces(self)
local iface
local ifaces = { }
- local seen = { }
local nfs = { }
- local baseof = { }
-- find normal interfaces
- _uci_real:foreach("network", "interface",
+ _uci:foreach("network", "interface",
function(s)
for iface in utl.imatch(s.ifname) do
- if not _iface_ignore(iface) and not _wifi_iface(iface) then
- seen[iface] = true
+ if not _iface_ignore(iface) and not _iface_virtual(iface) and not _wifi_iface(iface) then
nfs[iface] = interface(iface)
end
end
end)
for iface in utl.kspairs(_interfaces) do
- if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
+ if not (nfs[iface] or _iface_ignore(iface) or _iface_virtual(iface) or _wifi_iface(iface)) then
nfs[iface] = interface(iface)
end
end
-- find vlan interfaces
- _uci_real:foreach("network", "switch_vlan",
+ _uci:foreach("network", "switch_vlan",
function(s)
- if not s.device then
+ if type(s.ports) ~= "string" or
+ type(s.device) ~= "string" or
+ type(_swtopo[s.device]) ~= "table"
+ then
return
end
- local base = baseof[s.device]
- if not base then
- if not s.device:match("^eth%d") then
- local l
- for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
- if not base then
- base = l:match("^%w+: (%w+)")
- end
+ local pnum, ptag
+ for pnum, ptag in s.ports:gmatch("(%d+)([tu]?)") do
+ local netdev = _swtopo[s.device].netdevs[pnum]
+ if netdev then
+ if not nfs[netdev] then
+ nfs[netdev] = interface(netdev)
end
- if not base or not base:match("^eth%d") then
- base = "eth0"
+ _switch[netdev] = true
+
+ if ptag == "t" then
+ local vid = tonumber(s.vid or s.vlan)
+ if vid ~= nil and vid >= 0 and vid <= 4095 then
+ local iface = "%s.%d" %{ netdev, vid }
+ if not nfs[iface] then
+ nfs[iface] = interface(iface)
+ end
+ _switch[iface] = true
+ end
end
- else
- base = s.device
- end
- baseof[s.device] = base
- end
-
- local vid = tonumber(s.vid or s.vlan)
- if vid ~= nil and vid >= 0 and vid <= 4095 then
- local iface = "%s.%d" %{ base, vid }
- if not seen[iface] then
- seen[iface] = true
- nfs[iface] = interface(iface)
end
end
end)
-- find wifi interfaces
local num = { }
local wfs = { }
- _uci_real:foreach("wireless", "wifi-iface",
+ _uci:foreach("wireless", "wifi-iface",
function(s)
if s.device then
num[s.device] = num[s.device] and num[s.device] + 1 or 1
end
function get_wifidev(self, dev)
- if _uci_real:get("wireless", dev) == "wifi-device" then
+ if _uci:get("wireless", dev) == "wifi-device" then
return wifidev(dev)
end
end
local devs = { }
local wfd = { }
- _uci_real:foreach("wireless", "wifi-device",
+ _uci:foreach("wireless", "wifi-device",
function(s) wfd[#wfd+1] = s['.name'] end)
local dev
end
function get_wifinet(self, net)
- local wnet = _wifi_lookup(net)
+ local wnet = _wifi_sid_by_ifname(net)
if wnet then
return wifinet(wnet)
end
function add_wifinet(self, net, options)
if type(options) == "table" and options.device and
- _uci_real:get("wireless", options.device) == "wifi-device"
+ _uci:get("wireless", options.device) == "wifi-device"
then
- local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
+ local wnet = _uci:section("wireless", "wifi-iface", nil, options)
return wifinet(wnet)
end
end
function del_wifinet(self, net)
- local wnet = _wifi_lookup(net)
+ local wnet = _wifi_sid_by_ifname(net)
if wnet then
- _uci_real:delete("wireless", wnet)
+ _uci:delete("wireless", wnet)
return true
end
return false
function get_status_by_route(self, addr, mask)
local _, object
- for _, object in ipairs(_ubus:objects()) do
+ for _, object in ipairs(utl.ubus()) do
local net = object:match("^network%.interface%.(.+)")
if net then
- local s = _ubus:call(object, "status", {})
+ local s = utl.ubus(object, "status", {})
if s and s.route then
local rt
for _, rt in ipairs(s.route) do
function get_status_by_address(self, addr)
local _, object
- for _, object in ipairs(_ubus:objects()) do
+ for _, object in ipairs(utl.ubus()) do
local net = object:match("^network%.interface%.(.+)")
if net then
- local s = _ubus:call(object, "status", {})
+ local s = utl.ubus(object, "status", {})
if s and s['ipv4-address'] then
local a
for _, a in ipairs(s['ipv4-address']) do
end
function get_wannet(self)
- local net = self:get_status_by_route("0.0.0.0", 0)
- return net and network(net)
+ local net, stat = self:get_status_by_route("0.0.0.0", 0)
+ return net and network(net, stat.proto)
end
function get_wandev(self)
end
function get_wan6net(self)
- local net = self:get_status_by_route("::", 0)
- return net and network(net)
+ local net, stat = self:get_status_by_route("::", 0)
+ return net and network(net, stat.proto)
end
function get_wan6dev(self)
return stat and interface(stat.l3_device or stat.device)
end
+function get_switch_topologies(self)
+ return _swtopo
+end
+
function network(name, proto)
if name then
- local p = proto or _uci_real:get("network", name, "proto")
+ local p = proto or _uci:get("network", name, "proto")
local c = p and _protocols[p] or protocol
return c(name)
end
end
function protocol._get(self, opt)
- local v = _uci_real:get("network", self.sid, opt)
+ local v = _uci:get("network", self.sid, opt)
if type(v) == "table" then
return table.concat(v, " ")
end
function protocol._ubus(self, field)
if not _ubusnetcache[self.sid] then
- _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid,
- "status", { })
+ _ubusnetcache[self.sid] = utl.ubus("network.interface.%s" % self.sid,
+ "status", { })
end
if _ubusnetcache[self.sid] and field then
return _ubusnetcache[self.sid][field]
ifname = self:_ubus("device")
end
if not ifname then
- local num = { }
- _uci_real:foreach("wireless", "wifi-iface",
- function(s)
- if s.device then
- num[s.device] = num[s.device]
- and num[s.device] + 1 or 1
-
- local net
- for net in utl.imatch(s.network) do
- if net == self.sid then
- ifname = "%s.network%d" %{ s.device, num[s.device] }
- return false
- end
- end
- end
- end)
+ ifname = _wifi_netid_by_netname(self.sid)
end
return ifname
end
end
function protocol.expires(self)
- local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired"))
- local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime"))
- if a and l then
- l = l - (nxo.sysinfo().uptime - a)
- return l > 0 and l or 0
+ local u = self:_ubus("uptime")
+ local d = self:_ubus("data")
+
+ if type(u) == "number" and type(d) == "table" and
+ type(d.leasetime) == "number"
+ then
+ local r = (d.leasetime - (u % d.leasetime))
+ return r > 0 and r or 0
end
+
return -1
end
function protocol.metric(self)
- return tonumber(_uci_state:get("network", self.sid, "metric")) or 0
+ return self:_ubus("metric") or 0
end
function protocol.ipaddr(self)
return addrs and #addrs > 0 and addrs[1].address
end
+function protocol.ipaddrs(self)
+ local addrs = self:_ubus("ipv4-address")
+ local rv = { }
+
+ if type(addrs) == "table" then
+ local n, addr
+ for n, addr in ipairs(addrs) do
+ rv[#rv+1] = "%s/%d" %{ addr.address, addr.mask }
+ end
+ end
+
+ return rv
+end
+
function protocol.netmask(self)
local addrs = self:_ubus("ipv4-address")
return addrs and #addrs > 0 and
end
end
+function protocol.ip6addrs(self)
+ local addrs = self:_ubus("ipv6-address")
+ local rv = { }
+ local n, addr
+
+ if type(addrs) == "table" then
+ for n, addr in ipairs(addrs) do
+ rv[#rv+1] = "%s/%d" %{ addr.address, addr.mask }
+ end
+ end
+
+ addrs = self:_ubus("ipv6-prefix-assignment")
+
+ if type(addrs) == "table" then
+ for n, addr in ipairs(addrs) do
+ if type(addr["local-address"]) == "table" then
+ rv[#rv+1] = "%s/%d" %{
+ addr["local-address"].address,
+ addr["local-address"].mask
+ }
+ end
+ end
+ end
+
+ return rv
+end
+
function protocol.gw6addr(self)
local _, route
for _, route in ipairs(self:_ubus("route") or { }) do
return dns
end
+function protocol.ip6prefix(self)
+ local prefix = self:_ubus("ipv6-prefix")
+ if prefix and #prefix > 0 then
+ return "%s/%d" %{ prefix[1].address, prefix[1].mask }
+ end
+end
+
function protocol.is_bridge(self)
return (not self:is_virtual() and self:type() == "bridge")
end
if self:is_floating() then
return false
else
- local rv = true
+ local empty = true
if (self:_get("ifname") or ""):match("%S+") then
- rv = false
+ empty = false
end
- _uci_real:foreach("wireless", "wifi-iface",
- function(s)
- local n
- for n in utl.imatch(s.network) do
- if n == self.sid then
- rv = false
- return false
- end
- end
- end)
+ if empty and _wifi_netid_by_netname(self.sid) then
+ empty = false
+ end
- return rv
+ return empty
end
end
ifname = _M:ifnameof(ifname)
if ifname and not self:is_floating() then
-- if its a wifi interface, change its network option
- local wif = _wifi_lookup(ifname)
+ local wif = _wifi_sid_by_ifname(ifname)
if wif then
_append("wireless", wif, "network", self.sid)
ifname = _M:ifnameof(ifname)
if ifname and not self:is_floating() then
-- if its a wireless interface, clear its network option
- local wif = _wifi_lookup(ifname)
+ local wif = _wifi_sid_by_ifname(ifname)
if wif then _filter("wireless", wif, "network", self.sid) end
-- remove the interface
else
local ifn = nil
local num = { }
- for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do
+ for ifn in utl.imatch(_uci:get("network", self.sid, "ifname")) do
ifn = ifn:match("^[^:/]+")
return ifn and interface(ifn, self)
end
- ifn = nil
- _uci_real:foreach("wireless", "wifi-iface",
- function(s)
- if s.device then
- num[s.device] = num[s.device] and num[s.device] + 1 or 1
-
- local net
- for net in utl.imatch(s.network) do
- if net == self.sid then
- ifn = "%s.network%d" %{ s.device, num[s.device] }
- return false
- end
- end
- end
- end)
+ ifn = _wifi_netid_by_netname(self.sid)
return ifn and interface(ifn, self)
end
end
ifaces[#ifaces+1] = nfs[ifn]
end
- local num = { }
local wfs = { }
- _uci_real:foreach("wireless", "wifi-iface",
+ _uci:foreach("wireless", "wifi-iface",
function(s)
if s.device then
- num[s.device] = num[s.device] and num[s.device] + 1 or 1
-
local net
for net in utl.imatch(s.network) do
if net == self.sid then
- ifn = "%s.network%d" %{ s.device, num[s.device] }
- wfs[ifn] = interface(ifn, self)
+ ifn = _wifi_netid_by_sid(s[".name"])
+ if ifn then
+ wfs[ifn] = interface(ifn, self)
+ end
end
end
end
end
end
- local wif = _wifi_lookup(ifname)
+ local wif = _wifi_sid_by_ifname(ifname)
if wif then
local n
- for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do
+ for n in utl.imatch(_uci:get("wireless", wif, "network")) do
if n == self.sid then
return true
end
end
function protocol.adminlink(self)
- return dsp.build_url("admin", "network", "network", self.sid)
+ local stat, dsp = pcall(require, "luci.dispatcher")
+ return stat and dsp.build_url("admin", "network", "network", self.sid)
end
interface = utl.class()
function interface.__init__(self, ifname, network)
- local wif = _wifi_lookup(ifname)
+ local wif = _wifi_sid_by_ifname(ifname)
if wif then
self.wif = wifinet(wif)
- self.ifname = _wifi_state("section", wif, "ifname")
+ self.ifname = self.wif:ifname()
end
self.ifname = self.ifname or ifname
function interface._ubus(self, field)
if not _ubusdevcache[self.ifname] then
- _ubusdevcache[self.ifname] = _ubus:call("network.device", "status",
- { name = self.ifname })
+ _ubusdevcache[self.ifname] = utl.ubus("network.device", "status",
+ { name = self.ifname })
end
if _ubusdevcache[self.ifname] and field then
return _ubusdevcache[self.ifname][field]
end
function interface.mac(self)
- return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper()
+ local mac = self:_ubus("macaddr")
+ return mac and mac:upper()
end
function interface.ipaddrs(self)
function interface.shortname(self)
if self.wif then
- return "%s %q" %{
- self.wif:active_mode(),
- self.wif:active_ssid() or self.wif:active_bssid()
- }
+ return self.wif:shortname()
else
return self.ifname
end
return "%s: %s %q" %{
lng.translate("Wireless Network"),
self.wif:active_mode(),
- self.wif:active_ssid() or self.wif:active_bssid()
+ self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id()
}
else
return "%s: %q" %{ self:get_type_i18n(), self:name() }
elseif x == "switch" then
return lng.translate("Ethernet Switch")
elseif x == "vlan" then
- return lng.translate("VLAN Interface")
+ if _switch[self.ifname] then
+ return lng.translate("Switch VLAN")
+ else
+ return lng.translate("Software VLAN")
+ end
elseif x == "tunnel" then
return lng.translate("Tunnel Interface")
else
wifidev = utl.class()
-function wifidev.__init__(self, dev)
- self.sid = dev
- self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
+function wifidev.__init__(self, name)
+ local t, n = _uci:get("wireless", name)
+ if t == "wifi-device" and n ~= nil then
+ self.sid = n
+ self.iwinfo = _wifi_iwinfo_by_ifname(self.sid, true)
+ end
+ self.sid = self.sid or name
+ self.iwinfo = self.iwinfo or { ifname = self.sid }
end
function wifidev.get(self, opt)
local t = "Generic"
if self.iwinfo.type == "wl" then
t = "Broadcom"
- elseif self.iwinfo.type == "madwifi" then
- t = "Atheros"
end
local m = ""
return (_ubuswificache[self.sid].up == true)
end
- local up = false
- _uci_state:foreach("wireless", "wifi-iface",
- function(s)
- if s.device == self.sid then
- if s.up == "1" then
- up = true
- return false
- end
- end
- end)
-
- return up
+ return false
end
function wifidev.get_wifinet(self, net)
- if _uci_real:get("wireless", net) == "wifi-iface" then
+ if _uci:get("wireless", net) == "wifi-iface" then
return wifinet(net)
else
- local wnet = _wifi_lookup(net)
+ local wnet = _wifi_sid_by_ifname(net)
if wnet then
return wifinet(wnet)
end
function wifidev.get_wifinets(self)
local nets = { }
- _uci_real:foreach("wireless", "wifi-iface",
+ _uci:foreach("wireless", "wifi-iface",
function(s)
if s.device == self.sid then
nets[#nets+1] = wifinet(s['.name'])
options = options or { }
options.device = self.sid
- local wnet = _uci_real:section("wireless", "wifi-iface", nil, options)
+ local wnet = _uci:section("wireless", "wifi-iface", nil, options)
if wnet then
return wifinet(wnet, options)
end
function wifidev.del_wifinet(self, net)
if utl.instanceof(net, wifinet) then
net = net.sid
- elseif _uci_real:get("wireless", net) ~= "wifi-iface" then
- net = _wifi_lookup(net)
+ elseif _uci:get("wireless", net) ~= "wifi-iface" then
+ net = _wifi_sid_by_ifname(net)
end
- if net and _uci_real:get("wireless", net, "device") == self.sid then
- _uci_real:delete("wireless", net)
+ if net and _uci:get("wireless", net, "device") == self.sid then
+ _uci:delete("wireless", net)
return true
end
wifinet = utl.class()
-function wifinet.__init__(self, net, data)
- self.sid = net
+function wifinet.__init__(self, name, data)
+ local sid, netid, radioname, radiostate, netstate
- local num = { }
- local netid
- _uci_real:foreach("wireless", "wifi-iface",
- function(s)
- if s.device then
- num[s.device] = num[s.device] and num[s.device] + 1 or 1
- if s['.name'] == self.sid then
- netid = "%s.network%d" %{ s.device, num[s.device] }
- return false
+ -- lookup state by radio#.network# notation
+ sid = _wifi_sid_by_netid(name)
+ if sid then
+ netid = name
+ radioname, radiostate, netstate = _wifi_state_by_sid(sid)
+ else
+ -- lookup state by ifname (e.g. wlan0)
+ radioname, radiostate, netstate = _wifi_state_by_ifname(name)
+ if radioname and radiostate and netstate then
+ sid = netstate.section
+ netid = _wifi_netid_by_sid(sid)
+ else
+ -- lookup state by uci section id (e.g. cfg053579)
+ radioname, radiostate, netstate = _wifi_state_by_sid(name)
+ if radioname and radiostate and netstate then
+ sid = name
+ netid = _wifi_netid_by_sid(sid)
+ else
+ -- no state available, try to resolve from uci
+ netid, radioname = _wifi_netid_by_sid(name)
+ if netid and radioname then
+ sid = name
end
end
- end)
+ end
+ end
+
+ local iwinfo =
+ (netstate and _wifi_iwinfo_by_ifname(netstate.ifname)) or
+ (radioname and _wifi_iwinfo_by_ifname(radioname)) or
+ { ifname = (netid or sid or name) }
- local dev = _wifi_state("section", self.sid, "ifname") or netid
+ self.sid = sid or name
+ self.wdev = iwinfo.ifname
+ self.iwinfo = iwinfo
+ self.netid = netid
+ self._ubusdata = {
+ radio = radioname,
+ dev = radiostate,
+ net = netstate
+ }
+end
- self.netid = netid
- self.wdev = dev
- self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
- self.iwdata = data or _uci_state:get_all("wireless", self.sid) or
- _uci_real:get_all("wireless", self.sid) or { }
+function wifinet.ubus(self, ...)
+ local n, v = self._ubusdata
+ for n = 1, select('#', ...) do
+ if type(v) == "table" then
+ v = v[select(n, ...)]
+ else
+ return nil
+ end
+ end
+ return v
end
function wifinet.get(self, opt)
end
function wifinet.mode(self)
- return _uci_state:get("wireless", self.sid, "mode") or "ap"
+ return self:ubus("net", "config", "mode") or self:get("mode") or "ap"
end
function wifinet.ssid(self)
- return _uci_state:get("wireless", self.sid, "ssid")
+ return self:ubus("net", "config", "ssid") or self:get("ssid")
end
function wifinet.bssid(self)
- return _uci_state:get("wireless", self.sid, "bssid")
+ return self:ubus("net", "config", "bssid") or self:get("bssid")
end
function wifinet.network(self)
- return _uci_state:get("wifinet", self.sid, "network")
+ local net, networks = nil, { }
+ for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
+ networks[#networks+1] = net
+ end
+ return networks
end
function wifinet.id(self)
end
function wifinet.ifname(self)
- local ifname = self.iwinfo.ifname
+ local ifname = self:ubus("net", "ifname") or self.iwinfo.ifname
if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then
ifname = self.wdev
end
end
function wifinet.get_device(self)
- if self.iwdata.device then
- return wifidev(self.iwdata.device)
- end
+ local dev = self:ubus("radio") or self:get("device")
+ return dev and wifidev(dev) or nil
end
function wifinet.is_up(self)
end
function wifinet.active_mode(self)
- local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap"
+ local m = self.iwinfo.mode or self:ubus("net", "config", "mode") or self:get("mode") or "ap"
if m == "ap" then m = "Master"
elseif m == "sta" then m = "Client"
end
function wifinet.active_ssid(self)
- return _stror(self.iwinfo.ssid, self.iwdata.ssid)
+ return self.iwinfo.ssid or self:ubus("net", "config", "ssid") or self:get("ssid")
end
function wifinet.active_bssid(self)
- return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00"
+ return self.iwinfo.bssid or self:ubus("net", "config", "bssid") or self:get("bssid")
end
function wifinet.active_encryption(self)
end
function wifinet.channel(self)
- return self.iwinfo.channel or
- tonumber(_uci_state:get("wireless", self.iwdata.device, "channel"))
+ return self.iwinfo.channel or self:ubus("dev", "config", "channel") or
+ tonumber(self:get("channel"))
end
function wifinet.signal(self)
end
function wifinet.country(self)
- return self.iwinfo.country or "00"
+ return self.iwinfo.country or self:ubus("dev", "config", "country") or "00"
end
function wifinet.txpower(self)
function wifinet.shortname(self)
return "%s %q" %{
lng.translate(self:active_mode()),
- self:active_ssid() or self:active_bssid()
+ self:active_ssid() or self:active_bssid() or self:id()
}
end
return "%s: %s %q (%s)" %{
lng.translate("Wireless Network"),
lng.translate(self:active_mode()),
- self:active_ssid() or self:active_bssid(),
+ self:active_ssid() or self:active_bssid() or self:id(),
self:ifname()
}
end
function wifinet.adminlink(self)
- return dsp.build_url("admin", "network", "wireless", self.netid)
+ local stat, dsp = pcall(require, "luci.dispatcher")
+ return dsp and dsp.build_url("admin", "network", "wireless", self.netid)
end
function wifinet.get_network(self)
function wifinet.get_networks(self)
local nets = { }
local net
- for net in utl.imatch(tostring(self.iwdata.network)) do
- if _uci_real:get("network", net) == "interface" then
+ for net in utl.imatch(self:ubus("net", "config", "network") or self:get("network")) do
+ if _uci:get("network", net) == "interface" then
nets[#nets+1] = network(net)
end
end