X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=modules%2Fluci-base%2Fluasrc%2Fmodel%2Fnetwork.lua;h=9ea8e369daf735d58806dd231008b9524d8bdca6;hb=898b8a9904f597be38eb7e80201ee958bab65668;hp=20e1032760c4d8d5eaf831b634a401c457159ae8;hpb=1cb3adb619bdd876867f4c4da615ea850464e711;p=project%2Fluci.git diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua index 20e103276..9ea8e369d 100644 --- a/modules/luci-base/luasrc/model/network.lua +++ b/modules/luci-base/luasrc/model/network.lua @@ -1,27 +1,26 @@ -- Copyright 2009-2015 Jo-Philipp Wich -- Licensed to the public under the Apache License 2.0. -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 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" } @@ -29,12 +28,12 @@ protocol = utl.class() local _protocols = { } -local _interfaces, _bridge, _switch, _tunnel +local _interfaces, _bridge, _switch, _tunnel, _swtopo local _ubusnetcache, _ubusdevcache, _ubuswificache -local _uci_real, _uci_state +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 @@ -44,9 +43,9 @@ function _filter(c, s, o, r) 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 @@ -55,16 +54,16 @@ function _filter(c, s, o, r) 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 @@ -73,7 +72,7 @@ function _append(c, s, o, a) 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 @@ -82,7 +81,7 @@ function _append(c, s, o, a) end end l[#l+1] = a - _uci_real:set(c, s, o, l) + _uci:set(c, s, o, l) end end @@ -95,15 +94,67 @@ function _stror(s1, s2) 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 @@ -117,72 +168,113 @@ function _wifi_iface(x) return false end -function _wifi_state(key, val, field) - local radio, radiostate, ifc, ifcstate - - if not next(_ubuswificache) then - _ubuswificache = utl.ubus("network.wireless", "status", {}) or {} +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 + } - -- 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 @@ -200,18 +292,17 @@ function _iface_ignore(x) 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 = { } _ubusnetcache = { } _ubusdevcache = { } @@ -221,13 +312,12 @@ function init(cursor) 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, @@ -237,11 +327,6 @@ function init(cursor) 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 @@ -277,17 +362,90 @@ function init(cursor) 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) @@ -345,7 +503,7 @@ end 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 @@ -360,7 +518,7 @@ function add_network(self, n, options) 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 @@ -369,7 +527,7 @@ function get_networks(self) local nets = { } local nls = { } - _uci_real:foreach("network", "interface", + _uci:foreach("network", "interface", function(s) nls[s['.name']] = network(s['.name']) end) @@ -383,18 +541,18 @@ function get_networks(self) 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 = { } @@ -404,10 +562,10 @@ function del_network(self, n) 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 @@ -417,31 +575,31 @@ 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 = { } @@ -453,12 +611,12 @@ function rename_network(self, old, new) 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 @@ -468,78 +626,61 @@ function get_interface(self, i) 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) @@ -551,7 +692,7 @@ function get_interfaces(self) -- 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 @@ -572,7 +713,7 @@ function ignore_interface(self, x) 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 @@ -581,7 +722,7 @@ function get_wifidevs(self) 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 @@ -593,7 +734,7 @@ function get_wifidevs(self) 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 @@ -601,17 +742,17 @@ 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 @@ -662,8 +803,8 @@ function get_status_by_address(self, addr) 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) @@ -672,8 +813,8 @@ 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) @@ -681,10 +822,14 @@ 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 @@ -695,7 +840,7 @@ function protocol.__init__(self, name) 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 @@ -729,22 +874,7 @@ function protocol.ifname(self) 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 @@ -779,17 +909,21 @@ function protocol.uptime(self) 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) @@ -797,6 +931,20 @@ 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 @@ -835,6 +983,33 @@ function protocol.ip6addr(self) 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 @@ -855,6 +1030,13 @@ function protocol.dns6addrs(self) 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 @@ -879,24 +1061,17 @@ function protocol.is_empty(self) 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 @@ -904,7 +1079,7 @@ function protocol.add_interface(self, ifname) 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) @@ -919,7 +1094,7 @@ function protocol.del_interface(self, ifname) 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 @@ -937,25 +1112,11 @@ function protocol.get_interface(self) 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 @@ -975,18 +1136,17 @@ function protocol.get_interfaces(self) 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 @@ -1017,10 +1177,10 @@ function protocol.contains_interface(self, ifname) 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 @@ -1032,17 +1192,18 @@ function protocol.contains_interface(self, ifname) 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 @@ -1066,7 +1227,8 @@ function interface.name(self) 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) @@ -1095,10 +1257,7 @@ end 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 @@ -1109,7 +1268,7 @@ function interface.get_i18n(self) 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() } @@ -1125,7 +1284,11 @@ function interface.get_type_i18n(self) 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 @@ -1228,9 +1391,14 @@ end 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) @@ -1258,8 +1426,6 @@ function wifidev.get_i18n(self) local t = "Generic" if self.iwinfo.type == "wl" then t = "Broadcom" - elseif self.iwinfo.type == "madwifi" then - t = "Atheros" end local m = "" @@ -1278,25 +1444,14 @@ function wifidev.is_up(self) 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 @@ -1306,7 +1461,7 @@ 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']) @@ -1320,7 +1475,7 @@ function wifidev.add_wifinet(self, options) 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 @@ -1329,12 +1484,12 @@ 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 @@ -1344,29 +1499,62 @@ 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 dev = _wifi_state("section", self.sid, "ifname") or netid + 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) } - 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 { } + self.sid = sid or name + self.wdev = iwinfo.ifname + self.iwinfo = iwinfo + self.netid = netid + self._ubusdata = { + radio = radioname, + dev = radiostate, + net = netstate + } +end + +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) @@ -1378,19 +1566,23 @@ function wifinet.set(self, opt, val) 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) @@ -1402,7 +1594,7 @@ function wifinet.name(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 @@ -1410,9 +1602,8 @@ function wifinet.ifname(self) 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) @@ -1421,7 +1612,7 @@ function wifinet.is_up(self) end function wifinet.active_mode(self) - local m = _stror(self.iwdata.mode, self.iwinfo.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" @@ -1438,11 +1629,11 @@ function wifinet.active_mode_i18n(self) end function wifinet.active_ssid(self) - return _stror(self.iwdata.ssid, self.iwinfo.ssid) + return self.iwinfo.ssid or self:ubus("net", "config", "ssid") or self:get("ssid") end function wifinet.active_bssid(self) - return _stror(self.iwdata.bssid, self.iwinfo.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) @@ -1469,8 +1660,8 @@ function wifinet.bitrate(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) @@ -1482,7 +1673,7 @@ function wifinet.noise(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) @@ -1524,7 +1715,7 @@ end 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 @@ -1532,13 +1723,14 @@ function wifinet.get_i18n(self) 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) @@ -1548,8 +1740,8 @@ end 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