diff --git a/hoodselector/luasrc/usr/sbin/hoodselector b/hoodselector/luasrc/usr/sbin/hoodselector index 41776c3ea73e0671f03cd414527f470134b7268b..f9de6e6068539a6edbcb380c6a30fe488b619a3a 100755 --- a/hoodselector/luasrc/usr/sbin/hoodselector +++ b/hoodselector/luasrc/usr/sbin/hoodselector @@ -133,11 +133,18 @@ local function get_mesh_if(radios) local filtert_if = {} table.insert(filtert_if,(uci:get('fastd', 'mesh_vpn_backbone', 'net'):gsub("%_",'-'):gsub("%-", "%%-"))) for _, radio in ipairs(radios) do - table.insert(filtert_if,(uci:get('wireless', 'ibss_' .. radio, 'ifname'))) + local ifname = uci:get('wireless', 'ibss_' .. radio, 'ifname') + if ifname ~= nil then + table.insert(filtert_if,ifname) + end + ifname = uci:get('wireless', 'mesh_' .. radio, 'ifname') + if ifname ~= nil then + table.insert(filtert_if,ifname) + end end local respondd_if = {} for line in io.popen(string.format("ubus call network.interface dump | jsonfilter -e \"@.interface[@.proto='gluon_mesh' && @.up=true].device\" -e \"@.interface[@.interface='$(cat /lib/gluon/respondd/client.dev 2>/dev/null)' && @.up=true].device\""), "r"):lines() do - -- filter vpn interface + -- filter vpn and wifi interfaces if not filt_if(filtert_if,line) then table.insert(respondd_if,line) end @@ -329,64 +336,127 @@ local function getWifiDevices() return radios end +local function ibss_scan(radio,ifname,ssid,networks) + local wireless_scan = string.format( "iw %s scan", ifname) + local row = {} + row["radio"] = radio + -- loop through each line in the output of iw + for wifiscan in io.popen(wireless_scan, 'r'):lines() do + -- the following line matches a new network in the output of iw + if row["ssid"] ~= nil and ssid ~= nil then + print(row["ssid"].." == "..ssid) + end + if(row["bssid"] ~= nil and row["quality"] ~= nil and row["ssid"] == ssid) then + table.insert(networks, row) + row = {} + row["radio"] = radio + end + + -- get ssid + if wifiscan:match("SSID:") then + row["ssid"] = wifiscan:split(":") + row["ssid"] = row["ssid"][2] + if(row["ssid"] ~= nil) then + row["ssid"] = trim(row["ssid"]) + end + end + + -- get frequency + if wifiscan:match("freq:") then + row["frequency"] = wifiscan:split(":") + row["frequency"] = row["frequency"][2] + if(row["frequency"] ~= nil) then + row["frequency"] = trim(row["frequency"]) + end + end + + -- get bssid + if wifiscan:match("(%w+:%w+:%w+:%w+:%w+:%w+)") then + row["bssid"] = wifiscan:match("(%w+:%w+:%w+:%w+:%w+:%w+)"):upper() + end + + -- get signal strength + if wifiscan:match("signal:") then + row["quality"] = wifiscan:split(" ") + row["quality"] = row["quality"][2]:split(".") + if row["quality"][1]:match("-") then + row["quality"] = row["quality"][1]:split("-") + end + row["quality"] = tonumber(row["quality"][2]:match("(%d%d)")) + end + end + return networks +end + +local function mesh_scan(radio,ifname,meshid,networks) + local wireless_scan = string.format( "iw %s scan", ifname) + local row = {} + row["radio"] = radio + -- loop through each line in the output of iw + for wifiscan in io.popen(wireless_scan, 'r'):lines() do + -- the following line matches a new network in the output of iw + if(row["bssid"] ~= nil and row["quality"] ~= nil and row["ssid"] == meshid) then + table.insert(networks, row) + row = {} + row["radio"] = radio + end + + -- get frequency + if wifiscan:match("freq:") then + row["frequency"] = wifiscan:split(":") + row["frequency"] = row["frequency"][2] + if(row["frequency"] ~= nil) then + row["frequency"] = trim(row["frequency"]) + end + end + + -- get signal strength + if wifiscan:match("signal:") then + row["quality"] = wifiscan:split(" ") + row["quality"] = row["quality"][2]:split(".") + if row["quality"][1]:match("-") then + row["quality"] = row["quality"][1]:split("-") + end + row["quality"] = tonumber(row["quality"][2]:match("(%d%d)")) + end + + -- get mesh-ID(ssid) and hoodbssid + if wifiscan:match("MESH ID:") then + local meshID = wifiscan:split(" ")[3] + if meshID ~= nil then + meshID = meshID:split("_") + if meshID[1] ~= nil then + row["ssid"] = meshID[1].."_" + end + if meshID[2] ~= nil then + if meshID[2]:match("(%w+:%w+:%w+:%w+:%w+:%w+)") then + row["bssid"] = meshID[2]:match("(%w+:%w+:%w+:%w+:%w+:%w+)"):upper() + end + end + end + end + end + return networks +end + + -- Scans for wireless networks and returns a two dimensional array containing -- wireless mesh neigbour networks and their properties. -- The array is sorted descending by signal strength (strongest signal -- first, usually the local signal of the wireless chip of the router) -local function wlan_list_sorted(radios) +local function wlan_list_sorted(radios, mesh_prefix) local networks = {} for _, radio in ipairs(radios) do local ifname = uci:get('wireless', 'ibss_' .. radio, 'ifname') local ssid = uci:get('wireless', 'ibss_' .. radio, 'ssid') if (ifname ~= nil and ssid ~= nil) then - local wireless_scan = string.format( "iw %s scan", ifname) - local row = {} - row["radio"] = radio - -- loop through each line in the output of iw - for wifiscan in io.popen(wireless_scan, 'r'):lines() do - -- the following line matches a new network in the output of iw - if(row["bssid"] ~= nil and row["quality"] ~= nil and row["ssid"] == ssid) then - table.insert(networks, row) - row = {} - row["radio"] = radio - end - - -- get ssid - if wifiscan:match("SSID:") then - row["ssid"] = wifiscan:split(":") - row["ssid"] = row["ssid"][2] - if(row["ssid"] ~= nil) then - row["ssid"] = trim(row["ssid"]) - end - end - - -- get frequency - if wifiscan:match("freq:") then - row["frequency"] = wifiscan:split(":") - row["frequency"] = row["frequency"][2] - if(row["frequency"] ~= nil) then - row["frequency"] = trim(row["frequency"]) - end - end - - -- get bssid - if wifiscan:match("(%w+:%w+:%w+:%w+:%w+:%w+)") then - row["bssid"] = wifiscan:match("(%w+:%w+:%w+:%w+:%w+:%w+)"):upper() - end - - -- get signal strength - if wifiscan:match("signal:") then - row["quality"] = wifiscan:split(" ") - row["quality"] = row["quality"][2]:split(".") - if row["quality"][1]:match("-") then - row["quality"] = row["quality"][1]:split("-") - end - row["quality"] = tonumber(row["quality"][2]:match("(%d%d)")) - end - end - else - log("wireless uci config broken! abort...") - exit(1); + --do ibss scan + networks = ibss_scan(radio,ifname,ssid,networks) + end + ifname = uci:get('wireless', 'mesh_' .. radio, 'ifname') + if (ifname ~= nil and mesh_prefix ~= nil) then + --do mesh scan + networks = mesh_scan(radio,ifname,mesh_prefix,networks) end end @@ -557,17 +627,31 @@ end -- Checks if wireless needs a reconfiguration. Returns true if any of the checks -- passes. Otherwise the method returns false. -local function wireless_reconfiguration_needed(radios, hood_bssid) +local function wireless_reconfiguration_needed(radios, prefix, hood_bssid) + local configure_ibss = false + local configure_mesh = false for _, radio in ipairs(radios) do - if ( uci:get('wireless', 'ibss_' .. radio, 'bssid') ~= hood_bssid ) then - return true + local ifname = uci:get('wireless', 'ibss_' .. radio, 'ifname') + if (ifname ~= nil) then + if ( uci:get('wireless', 'ibss_' .. radio, 'bssid') ~= hood_bssid ) then + configure_ibss = true + end + end + ifname = uci:get('wireless', 'mesh_' .. radio, 'ifname') + if (ifname ~= nil) then + if ( uci:get('wireless', 'mesh_' .. radio, 'mesh_id') ~= prefix..hood_bssid ) then + configure_mesh = true + end end end - return false + if not configure_ibss and not configure_mesh then return 0 end --no changes + if configure_ibss and not configure_mesh then return 1 end --ibss changes + if not configure_ibss and configure_mesh then return 2 end --mesh changes + return 3 --bouth changes end -- Reconfigure wireless -local function wireless_reconfigure(radios, hood_bssid) +local function ibss_reconfigure(radios, hood_bssid) for _, radio in ipairs(radios) do if not ( uci:get('wireless', 'ibss_' .. radio, 'bssid') == hood_bssid ) then uci:section('wireless', 'wifi-iface', 'ibss_' .. radio, { @@ -579,6 +663,18 @@ local function wireless_reconfigure(radios, hood_bssid) uci:commit('wireless') end +local function mesh_reconfigure(radios, meshid) + for _, radio in ipairs(radios) do + if not ( uci:get('wireless', 'mesh_' .. radio, 'mesh_id') == meshid ) then + uci:section('wireless', 'wifi-iface', 'mesh_' .. radio, { + mesh_id = meshid + }) + end + end + uci:save('wireless') + uci:commit('wireless') +end + -- Save selected hood to config to make a restore after a sysupgrade possible local function saveHoodToConfig(hoodname) uci:section('hoodselector', 'settings', 'hoodselector', { @@ -600,7 +696,7 @@ end -- dont restart it before wireless has been reconfigured -- * If wireless needs reconfiguration apply new settings and restart wireless -- * If fastd needed reconfiguration start fastd now -local function set_hoodconfig(hood, radios) +local function set_hoodconfig(hood, prefix, radios) local local_serverlist = getCurrentPeers() local config_changed = false -- Check if VPN needs reconfiguration because in case of reconfiguration we @@ -612,11 +708,18 @@ local function set_hoodconfig(hood, radios) end -- reconfigure wireless - if(wireless_reconfiguration_needed(radios, hood["bssid"])) then + local wifi_reconf = wireless_reconfiguration_needed(radios, prefix, hood["bssid"]) + if(wifi_reconf == 1 or wifi_reconf == 3) then config_changed = true - wireless_reconfigure(radios, hood["bssid"]) + ibss_reconfigure(radios, hood["bssid"]) wireless_restart() - io.stdout:write('Wireless needed reconfiguration. Applied new settings and restarted.\n') + io.stdout:write('IBSS needed reconfiguration. Applied new settings and restarted.\n') + end + if(wifi_reconf == 2 or wifi_reconf == 3) then + config_changed = true + mesh_reconfigure(radios, prefix..hood["bssid"]) + wireless_restart() + io.stdout:write('MESH needed reconfiguration. Applied new settings and restarted.\n') end -- reconfigure fastd @@ -688,7 +791,7 @@ local function getCurrentHood(jhood) return nil end -local function get_batman_mesh_network(sorted_wlan_list, defaultHood) +local function get_batman_mesh_network(sorted_wlan_list, defaultHood, meshprefix) io.stdout:write('Testing neighboring adhoc networks for batman advanced gw connection.\n') io.stdout:write('The following wireless networks have been found:\n') for _, network in pairs(sorted_wlan_list) do @@ -722,12 +825,22 @@ local function get_batman_mesh_network(sorted_wlan_list, defaultHood) -- the settings of the adhoc network if the ap network is still operating os.execute("iw dev client0 del") for _, wireless in pairs(sorted_wlan_list) do - io.stdout:write("Testing "..wireless["bssid"].."...\n") - local ifname = uci:get('wireless', 'ibss_' .. wireless["radio"], 'ifname') - -- leave the current adhoc network - os.execute("iw dev "..ifname.." ibss leave") - -- setup the adhoc network we want to test - os.execute("iw dev "..ifname.." ibss join "..wireless["ssid"].." "..wireless["frequency"].." "..wireless["bssid"]) + if wireless["ssid"] == uci:get('wireless', 'ibss_' .. wireless["radio"], 'ssid') then + io.stdout:write("Testing IBSS "..wireless["bssid"].."...\n") + local ifname = uci:get('wireless', 'ibss_' .. wireless["radio"], 'ifname') + -- leave the current adhoc network + os.execute("iw dev "..ifname.." ibss leave") + -- setup the adhoc network we want to test + os.execute("iw dev "..ifname.." ibss join "..wireless["ssid"].." "..wireless["frequency"].." "..wireless["bssid"]) + end + if wireless["ssid"] == meshprefix then + io.stdout:write("Testing MESH "..wireless["bssid"].."...\n") + local ifname = uci:get('wireless', 'mesh_' .. wireless["radio"], 'ifname') + -- leave the current mesh network + os.execute("iw dev "..ifname.." mesh leave") + -- setup the mesh network we want to test + os.execute("iw dev "..ifname.." mesh join "..meshprefix..wireless["bssid"].." freq "..wireless["frequency"]) + end -- sleep 30 seconds till the connection is fully setup local c = 0; while(not batmanHasGateway()) do @@ -757,11 +870,21 @@ local function get_batman_GW_interface() return nil end -local function get_radio_to_iface(radios,iface) +local function get_radio_to_bssid(radios,iface,jhood) for _, radio in ipairs(radios) do local ifname = uci:get('wireless', 'ibss_' .. radio, 'ifname') if ifname == iface then - return radio + return gethoodByBssid(jhood, uci:get('wireless', 'ibss_' .. radio, 'bssid')) + end + ifname = uci:get('wireless', 'mesh_' .. radio, 'ifname') + if ifname == iface then + local meshid = uci:get('wireless', 'mesh_' .. radio, 'mesh_id') + meshid = meshid:split('_') + if meshid[2] ~= nil then + if meshid[2]:match("(%w+:%w+:%w+:%w+:%w+:%w+)") then + return gethoodByBssid(jhood, meshid[2]:match("(%w+:%w+:%w+:%w+:%w+:%w+)")) + end + end end end return nil @@ -888,6 +1011,21 @@ end -- Get list of wifi devices local radios = getWifiDevices() +local mesh_prefix = nil +for _,radio in ipairs(radios) do + local mesh_id = uci:get('wireless', 'mesh_' .. radio, 'mesh_id') + if mesh_id ~= nil then + mesh_id = mesh_id:split('_') + if mesh_id[1] ~= "" then + mesh_prefix = mesh_id[1].."_" + else + if mesh_id[2] ~= "" then + mesh_prefix = mesh_id[2].."_" + end + end + end +end + -- VPN MODE -- If we have a VPN connection then we will try to get the routers location and -- select the hood coresponding to our location. @@ -901,13 +1039,13 @@ if directVPN() then io.stdout:write('Position found.\n') local geoHood = getHoodByGeo(jhood, geo) if geoHood ~= nil then - set_hoodconfig(geoHood, radios) + set_hoodconfig(geoHood, mesh_prefix, radios) io.stdout:write('Hood set by VPN mode.\n') write_molwm(geoHood,radios) exit(0) end io.stdout:write('No hood has been defined for current position.\n') - set_hoodconfig(defaultHood, radios) + set_hoodconfig(defaultHood, mesh_prefix, radios) io.stdout:write('Defaulthood set.\n') write_molwm(defaultHood,radios) exit(0) @@ -924,15 +1062,12 @@ if batmanHasGateway() then if next(gw_intf) then -- wifi interface - local radio_if = get_radio_to_iface(radios,gw_intf[1]) - if radio_if ~= nil then - local bssidHood = gethoodByBssid(jhood, uci:get('wireless', 'ibss_' .. radio_if, 'bssid')) - if bssidHood ~= nil then - set_hoodconfig(bssidHood, radios) - io.stdout:write('Hood set by batmanHasGateway mode, GW source is wifi\n') - write_molwm(bssidHood,radios) - exit(0) - end + local bssidHood = get_radio_to_bssid(radios,gw_intf[1], jhood) + if bssidHood ~= nil then + set_hoodconfig(bssidHood, mesh_prefix, radios) + io.stdout:write('Hood set by batmanHasGateway mode, GW source is wifi\n') + write_molwm(bssidHood,radios) + exit(0) end -- mesh lan or wan interface @@ -940,9 +1075,9 @@ if batmanHasGateway() then -- if mesh_lan/wan try to get hood by selected bssid of neightbour vpnRouters local neigbourBssid = molw_get_bssid(gw_intf) if neigbourBssid ~= nil then - local bssidHood = gethoodByBssid(jhood, neigbourBssid) + bssidHood = gethoodByBssid(jhood, neigbourBssid) if bssidHood ~= nil then - set_hoodconfig(bssidHood, radios) + set_hoodconfig(bssidHood, mesh_prefix, radios) io.stdout:write('Hood set by batmanHasGateway mode, GW source is mesh on lan/wan\n') molwmtable["md5hash"] = "\"" .. string.format(hash.md5(table.tostring(bssidHood))) .. "\"" molwmtable["hoodname"] = "\"" .. bssidHood["name"] .. "\"" @@ -959,7 +1094,7 @@ if batmanHasGateway() then -- else evtl. set hood by pos. else io.stdout:write("currend configuration are not defined as hood\n") - set_hoodconfig(defaultHood, radios) + set_hoodconfig(defaultHood, mesh_prefix, radios) io.stdout:write('Set defaulthood.\n') write_molwm(defaultHood,radios) end @@ -970,13 +1105,13 @@ end if next(radios) then -- check if there exist a neighboring freifunk batman advanced mesh -- network with an active connection to a batman advanced gateway - local sortedWlanList = wlan_list_sorted(radios) - local meshBSSID = get_batman_mesh_network(sortedWlanList, defaultHood) + local sortedWlanList = wlan_list_sorted(radios, mesh_prefix) + local meshBSSID = get_batman_mesh_network(sortedWlanList, defaultHood, mesh_prefix) if meshBSSID ~= nil then io.stdout:write("Neighoring freifunk batman advanced mesh with BSSID "..meshBSSID.." found\n") local bssidHood = gethoodByBssid(jhood, meshBSSID) if bssidHood ~= nil then - set_hoodconfig(bssidHood, radios) + set_hoodconfig(bssidHood, mesh_prefix, radios) io.stdout:write('Hood set by scan mode\n') write_molwm(bssidHood,radios) exit(0) @@ -986,7 +1121,24 @@ if next(radios) then -- just establish a wireless connection to the mesh without any vpn or vpn_stop() vpn_disable() - wireless_reconfigure(radios, meshBSSID) + local ibss_exsist = false + local mesh_exsist = false + for _,radio in ipairs(radios) do + local ifname = uci:get('wireless', 'ibss_' .. radio, 'ifname') + if (ifname ~= nil) then + ibss_exsist = true + end + ifname = uci:get('wireless', 'mesh_' .. radio, 'ifname') + if (ifname ~= nil) then + mesh_exsist = true + end + end + if ibss_exsist then + ibss_reconfigure(radios, meshBSSID) + end + if mesh_exsist then + mesh_reconfigure(radios, mesh_prefix..meshBSSID) + end wireless_restart() io.stdout:write('Could not select a hood but established a connection via wireless mesh.\n') io.stdout:write('Disabled all connections except connections via wireless mesh.\n') @@ -1002,7 +1154,7 @@ if next(mesh_inf) then if neigbourBssid ~= nil then local bssidHood = gethoodByBssid(jhood, neigbourBssid) if bssidHood ~= nil then - set_hoodconfig(bssidHood, radios) + set_hoodconfig(bssidHood, mesh_prefix, radios) io.stdout:write('Hood set by "Radio less router have mesh lan/wan neigborths"\n') molwmtable["md5hash"] = "\"" .. string.format(hash.md5(table.tostring(bssidHood) )) .. "\"" molwmtable["hoodname"] = "\"" .. bssidHood["name"] .. "\"" @@ -1023,7 +1175,7 @@ if currendHood ~= nil then -- else evtl. set hood by pos. else io.stdout:write("currend configuration are not defined as hood\n") - set_hoodconfig(defaultHood, radios) + set_hoodconfig(defaultHood, mesh_prefix, radios) io.stdout:write('Set defaulthood.\n') write_molwm(defaultHood,radios) end