Merge pull request #990 from freifunk-ffm/christf_get_mesh_interfaces

gluon-core: add function to gluon.util that returns all active mesh-devices
This commit is contained in:
Matthias Schiffer 2016-12-23 00:56:42 +01:00 committed by GitHub
commit 2ddf77fc81

View File

@ -1,25 +1,25 @@
-- Writes all lines from the file input to the file output except those starting with prefix -- Writes all lines from the file input to the file output except those starting with prefix
-- Doesn't close the output file, but returns the file object -- Doesn't close the output file, but returns the file object
local function do_filter_prefix(input, output, prefix) local function do_filter_prefix(input, output, prefix)
local f = io.open(output, 'w+') local f = io.open(output, 'w+')
local l = prefix:len() local l = prefix:len()
for line in io.lines(input) do for line in io.lines(input) do
if line:sub(1, l) ~= prefix then if line:sub(1, l) ~= prefix then
f:write(line, '\n') f:write(line, '\n')
end end
end end
return f return f
end end
local function escape_args(ret, arg0, ...) local function escape_args(ret, arg0, ...)
if not arg0 then if not arg0 then
return ret return ret
end end
return escape_args(ret .. "'" .. string.gsub(arg0, "'", "'\\''") .. "' ", ...) return escape_args(ret .. "'" .. string.gsub(arg0, "'", "'\\''") .. "' ", ...)
end end
@ -38,79 +38,88 @@ local uci = require('luci.model.uci').cursor()
local lutil = require 'luci.util' local lutil = require 'luci.util'
local fs = require 'nixio.fs' local fs = require 'nixio.fs'
module 'gluon.util' module 'gluon.util'
function exec(...) function exec(...)
return os.execute(escape_args('', 'exec', ...)) return os.execute(escape_args('', 'exec', ...))
end end
-- Removes all lines starting with a prefix from a file, optionally adding a new one -- Removes all lines starting with a prefix from a file, optionally adding a new one
function replace_prefix(file, prefix, add) function replace_prefix(file, prefix, add)
local tmp = file .. '.tmp' local tmp = file .. '.tmp'
local f = do_filter_prefix(file, tmp, prefix) local f = do_filter_prefix(file, tmp, prefix)
if add then if add then
f:write(add) f:write(add)
end end
f:close() f:close()
os.rename(tmp, file) os.rename(tmp, file)
end end
function readline(fd) function readline(fd)
local line = fd:read('*l') local line = fd:read('*l')
fd:close() fd:close()
return line return line
end end
function lock(file) function lock(file)
exec('lock', file) exec('lock', file)
end end
function unlock(file) function unlock(file)
exec('lock', '-u', file) exec('lock', '-u', file)
end end
function node_id() function node_id()
return string.gsub(sysconfig.primary_mac, ':', '') return string.gsub(sysconfig.primary_mac, ':', '')
end end
function get_mesh_devices(uconn)
local dump = uconn:call("network.interface", "dump", {})
local devices = {}
for _, interface in ipairs(dump.interface) do
if ( (interface.proto == "gluon_mesh") and interface.up ) then
table.insert(devices, interface.device)
end
end
return devices
end
local function find_phy_by_path(path) local function find_phy_by_path(path)
for phy in fs.glob('/sys/devices/' .. path .. '/ieee80211/phy*') do for phy in fs.glob('/sys/devices/' .. path .. '/ieee80211/phy*') do
return phy:match('([^/]+)$') return phy:match('([^/]+)$')
end end
end end
local function find_phy_by_macaddr(macaddr) local function find_phy_by_macaddr(macaddr)
local addr = macaddr:lower() local addr = macaddr:lower()
for file in fs.glob('/sys/class/ieee80211/*/macaddress') do for file in fs.glob('/sys/class/ieee80211/*/macaddress') do
if lutil.trim(fs.readfile(file)) == addr then if lutil.trim(fs.readfile(file)) == addr then
return file:match('([^/]+)/macaddress$') return file:match('([^/]+)/macaddress$')
end end
end end
end end
local function find_phy(radio) local function find_phy(radio)
local config = uci:get_all('wireless', radio) local config = uci:get_all('wireless', radio)
if not config or config.type ~= 'mac80211' then if not config or config.type ~= 'mac80211' then
return nil return nil
elseif config.path then elseif config.path then
return find_phy_by_path(config.path) return find_phy_by_path(config.path)
elseif config.macaddr then elseif config.macaddr then
return find_phy_by_macaddr(config.macaddr) return find_phy_by_macaddr(config.macaddr)
else else
return nil return nil
end end
end end
local function get_addresses(radio) local function get_addresses(radio)
local phy = find_phy(radio) local phy = find_phy(radio)
if not phy then if not phy then
return function() end return function() end
end end
return io.lines('/sys/class/ieee80211/' .. phy .. '/addresses') return io.lines('/sys/class/ieee80211/' .. phy .. '/addresses')
end end
-- Generates a (hopefully) unique MAC address -- Generates a (hopefully) unique MAC address
@ -126,70 +135,70 @@ end
-- 6: ibss1 -- 6: ibss1
-- 7: wan_radio1 (private WLAN); mesh VPN -- 7: wan_radio1 (private WLAN); mesh VPN
function generate_mac(i) function generate_mac(i)
if i > 7 or i < 0 then return nil end -- max allowed id (0b111) if i > 7 or i < 0 then return nil end -- max allowed id (0b111)
local hashed = string.sub(hash.md5(sysconfig.primary_mac), 0, 12) local hashed = string.sub(hash.md5(sysconfig.primary_mac), 0, 12)
local m1, m2, m3, m4, m5, m6 = string.match(hashed, '(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)') local m1, m2, m3, m4, m5, m6 = string.match(hashed, '(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)')
m1 = tonumber(m1, 16) m1 = tonumber(m1, 16)
m6 = tonumber(m6, 16) m6 = tonumber(m6, 16)
m1 = nixio.bit.bor(m1, 0x02) -- set locally administered bit m1 = nixio.bit.bor(m1, 0x02) -- set locally administered bit
m1 = nixio.bit.band(m1, 0xFE) -- unset the multicast bit m1 = nixio.bit.band(m1, 0xFE) -- unset the multicast bit
-- It's necessary that the first 45 bits of the MAC address don't -- It's necessary that the first 45 bits of the MAC address don't
-- vary on a single hardware interface, since some chips are using -- vary on a single hardware interface, since some chips are using
-- a hardware MAC filter. (e.g 'rt305x') -- a hardware MAC filter. (e.g 'rt305x')
m6 = nixio.bit.band(m6, 0xF8) -- zero the last three bits (space needed for counting) m6 = nixio.bit.band(m6, 0xF8) -- zero the last three bits (space needed for counting)
m6 = m6 + i -- add virtual interface id m6 = m6 + i -- add virtual interface id
return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6) return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6)
end end
local function get_wlan_mac_from_driver(radio, vif) local function get_wlan_mac_from_driver(radio, vif)
local primary = sysconfig.primary_mac:lower() local primary = sysconfig.primary_mac:lower()
local i = 1 local i = 1
for addr in get_addresses(radio) do for addr in get_addresses(radio) do
if addr:lower() ~= primary then if addr:lower() ~= primary then
if i == vif then if i == vif then
return addr return addr
end end
i = i + 1 i = i + 1
end end
end end
end end
function get_wlan_mac(radio, index, vif) function get_wlan_mac(radio, index, vif)
local addr = get_wlan_mac_from_driver(radio, vif) local addr = get_wlan_mac_from_driver(radio, vif)
if addr then if addr then
return addr return addr
end end
return generate_mac(4*(index-1) + (vif-1)) return generate_mac(4*(index-1) + (vif-1))
end end
-- Iterate over all radios defined in UCI calling -- Iterate over all radios defined in UCI calling
-- f(radio, index, site.wifiX) for each radio found while passing -- f(radio, index, site.wifiX) for each radio found while passing
-- site.wifi24 for 2.4 GHz devices and site.wifi5 for 5 GHz ones. -- site.wifi24 for 2.4 GHz devices and site.wifi5 for 5 GHz ones.
function iterate_radios(f) function iterate_radios(f)
local radios = {} local radios = {}
uci:foreach('wireless', 'wifi-device', uci:foreach('wireless', 'wifi-device',
function(s) function(s)
table.insert(radios, s['.name']) table.insert(radios, s['.name'])
end end
) )
for index, radio in ipairs(radios) do for index, radio in ipairs(radios) do
local hwmode = uci:get('wireless', radio, 'hwmode') local hwmode = uci:get('wireless', radio, 'hwmode')
if hwmode == '11g' or hwmode == '11ng' then if hwmode == '11g' or hwmode == '11ng' then
f(radio, index, site.wifi24) f(radio, index, site.wifi24)
elseif hwmode == '11a' or hwmode == '11na' then elseif hwmode == '11a' or hwmode == '11na' then
f(radio, index, site.wifi5) f(radio, index, site.wifi5)
end end
end end
end end