diff --git a/ffh-wifi-offline-ssid/LICENSE b/ffh-wifi-offline-ssid/LICENSE new file mode 100644 index 00000000..7126f014 --- /dev/null +++ b/ffh-wifi-offline-ssid/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2021, Freifunk Hannover +Copyright (c) 2013-2021, Project Gluon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ffh-wifi-offline-ssid/Makefile b/ffh-wifi-offline-ssid/Makefile new file mode 100644 index 00000000..5ada518c --- /dev/null +++ b/ffh-wifi-offline-ssid/Makefile @@ -0,0 +1,22 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ffh-wifi-offline-ssid +PKG_VERSION:=1 +PKG_RELEASE:=1 + +include $(TOPDIR)/../package/gluon.mk + +define Package/$(PKG_NAME) + TITLE:=Changes the SSID to an Offline-SSID on disrupted internet connection + DEPENDS:=+gluon-core +ffh-check-connection +endef + +define Package/$(PKG_NAME)/description + Script to change the SSID to an Offline-SSID when there is no connection to + the internet. This SSID can be generated from the node's hostname with the + first and last part of the node's name or from the MAC address. + The script is being triggered by ffh-check-connection on connection status + changes. +endef + +$(eval $(call BuildPackageGluon,$(PKG_NAME))) diff --git a/ffh-wifi-offline-ssid/README.md b/ffh-wifi-offline-ssid/README.md new file mode 100644 index 00000000..41de8244 --- /dev/null +++ b/ffh-wifi-offline-ssid/README.md @@ -0,0 +1,46 @@ +ffh-wifi-offline-ssid +===================== + +This package adds a script which changes the WLAN SSID on loss of +internet connectivity. It depends on and is being called by +*ffh-check-connection*. + +This ``offline SSID`` can be generated from the node's hostname +with the first and last part of the node name or the MAC address. + +After the connection has been lost for a certain ``threshold`` of +minutes it is being changed to the offline SSID. +Once the connectivity is established it will be changed back to +the default SSID again. + +domain.conf +----------- + +Adapt and add this block to your ``domain.conf``: + +:: + + ffh_wifi_offline_ssid = { + disabled = false, + target_group = 'targets_global', -- the ffh-check-connection target group to perform tests on + threshold = 5, -- the number of minutes after which connectivity is considered lost + prefix = 'Offline_', -- use something short to leave space for the hostname (no '~' allowed!) + suffix = 'hostname', -- generate the SSID with either 'hostname', 'mac' or only the prefix: 'none' + }, + + +Configuration via UCI +--------------------- + +You can configure the offline SSID on the command line with ``uci``. +E.g. disable it with: + +:: + + uci set ffh-wifi-offline-ssid.settings.disabled='1' + +Or set the threshold to three minutes with + +:: + + uci set ffh-wifi-offline-ssid.settings.threshold='3' diff --git a/ffh-wifi-offline-ssid/check_site.lua b/ffh-wifi-offline-ssid/check_site.lua new file mode 100644 index 00000000..ffc7fec3 --- /dev/null +++ b/ffh-wifi-offline-ssid/check_site.lua @@ -0,0 +1,5 @@ +need_boolean({'ffh_wifi_offline_ssid', 'disabled'}, false) +need_string({'ffh_wifi_offline_ssid', 'target_group'}, true) +need_number({'ffh_wifi_offline_ssid', 'threshold'}, false) +need_string({'ffh_wifi_offline_ssid', 'prefix'}, false) +need_one_of({'ffh_wifi_offline_ssid', 'suffix'}, {'hostname', 'mac', 'none'}, false) diff --git a/ffh-wifi-offline-ssid/files/etc/config/ffh-wifi-offline-ssid b/ffh-wifi-offline-ssid/files/etc/config/ffh-wifi-offline-ssid new file mode 100644 index 00000000..c488b640 --- /dev/null +++ b/ffh-wifi-offline-ssid/files/etc/config/ffh-wifi-offline-ssid @@ -0,0 +1 @@ +config settings 'settings' diff --git a/ffh-wifi-offline-ssid/luasrc/lib/gluon/upgrade/600-ffh-wifi-offline-ssid b/ffh-wifi-offline-ssid/luasrc/lib/gluon/upgrade/600-ffh-wifi-offline-ssid new file mode 100755 index 00000000..d387ff26 --- /dev/null +++ b/ffh-wifi-offline-ssid/luasrc/lib/gluon/upgrade/600-ffh-wifi-offline-ssid @@ -0,0 +1,36 @@ +#!/usr/bin/lua + +local site = require 'gluon.site' +local uci = require('simple-uci').cursor() + +if site.ffh_wifi_offline_ssid then + local site_disabled = site.ffh_wifi_offline_ssid.disabled() or '0' + + uci:section('ffh-wifi-offline-ssid', 'settings', 'settings', { + disabled = uci:get('ffh-wifi-offline-ssid', 'settings', 'disabled') or site_disabled, + threshold = site.ffh_wifi_offline_ssid.threshold() or 5, + prefix = site.ffh_wifi_offline_ssid.prefix() or 'Offline_', + suffix = site.ffh_wifi_offline_ssid.suffix() or 'hostname', + }) + + uci:save('ffh-wifi-offline-ssid') + + uci:section('ffh-check-connection', 'script', 'ffh_wifi_offline', { + enabled = true, + interval = 1, + command = 'ffh-wifi-offline-ssid offline', + groups = {site.ffh_wifi_offline_ssid.target_group(),}, + trigger = 'offline', + }) + + uci:section('ffh-check-connection', 'script', 'ffh_wifi_online', { + enabled = true, + interval = 1, + command = 'ffh-wifi-offline-ssid online', + groups = {site.ffh_wifi_offline_ssid.target_group(),}, + onchange = true, + trigger = 'online', + }) + + uci:save('ffh-check-connection') +end diff --git a/ffh-wifi-offline-ssid/luasrc/usr/sbin/ffh-wifi-offline-ssid b/ffh-wifi-offline-ssid/luasrc/usr/sbin/ffh-wifi-offline-ssid new file mode 100644 index 00000000..df748865 --- /dev/null +++ b/ffh-wifi-offline-ssid/luasrc/usr/sbin/ffh-wifi-offline-ssid @@ -0,0 +1,116 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() +local unistd = require 'posix.unistd' +local util = require 'gluon.util' + +local prog_name = 'ffh-wifi-offline-ssid' +local offline_file = '/tmp/ffh-offline-ffh_wifi_offline' + +local disabled = uci:get('ffh-wifi-offline-ssid', 'settings', 'disabled') or false +if disabled then + print(prog_name .. " is disabled. Exiting...") + os.exit(0) +end + +local threshold_mins = tonumber(uci:get(prog_name, 'settings', 'threshold')) or 0 + +local uptime_mins = math.floor(util.get_uptime() / 60) +local offline_mins = uptime +if unistd.access(offline_file) then + offline_mins = uptime - (tonumber(util.readfile(offline_file)) or 0) +end + +if arg[1] == "offline" and offline_mins < threshold_mins then + print((threshold_mins - offline_mins) .. ' minutes remaining until the node is considered offline. Exiting...') + os.exit(0) +end + +local phys = {count = 0} +uci:foreach('wireless', 'wifi-device', function(config) + local phy = util.find_phy(config) + if phy then + phys[config['.name']] = phy + phys['count'] = phys['count'] + 1 + end +end) + +if phys['count'] == 0 then + print('No radios detected. Exiting...') + os.exit(0) +end + +local ssids = {} +uci:foreach('wireless', 'wifi-iface', function(config) + if config['mode'] == 'ap' and config['network'] == 'client' and config['ssid'] then + table.insert(ssids, {ssid = config['ssid'], phy = phys[config['device']]}) + end +end) + +if #ssids == 0 then + print('No client networks active. Exiting...') + os.exit(0) +end + +-- Use something short to leave space for the hostname +-- (no '~' allowed!) +local prefix = uci:get(prog_name, 'settings', 'prefix') or 'Offline_' + +-- Generate the SSID either with 'hostname', 'mac' or only using the prefix +local settings_suffix = uci:get(prog_name, 'settings', 'suffix') or 'hostname' + +local suffix = '' +if settings_suffix == 'hostname' then + local pretty_hostname = require 'pretty_hostname' + suffix = pretty_hostname.get(uci) + -- 32 would be possible as well + if (string.len(suffix) > 30 - string.len(prefix)) then + -- Calculate the length of the first part of the node identifier in the offline-ssid + local half = math.floor((28 - string.len(prefix)) / 2) + -- Jump to this character for the last part of the name + local skip = string.len(suffix) - half + -- Use the first and last part of the nodename for nodes with long name + suffix = string.sub(suffix, 0, half) .. '...' .. string.sub(suffix, skip) + end +elseif settings_suffix == 'mac' then + local sysconfig = require 'gluon.sysconfig' + suffix = sysconfig.primary_mac +end + +local offline_ssid = prefix .. suffix + +local hup_needed = 0 +local ssid_grep = 'grep "^ssid=' +for _, ssid in ipairs(ssids) do + local hostapd = '/var/run/hostapd-' .. ssid.phy .. '.conf' + + if arg[1] == "offline" then + old_ssid = ssid.ssid + new_ssid = offline_ssid + else + old_ssid = offline_ssid + new_ssid = ssid.ssid + end + + if os.execute(ssid_grep .. new_ssid .. '" ' .. hostapd) == 0 then + print('Current SSID "' .. new_ssid .. '" for ' .. ssid.phy .. ' is already correct. Skipping...') + break + end + + -- Confirm that the old SSID was set + if os.execute(ssid_grep .. old_ssid .. '" ' .. hostapd) ~= 0 then + util.log(prog_name .. ': Warning: Neither found SSID "' .. ssid.ssid .. '" nor "' .. offline_ssid .. '" on ' .. ssid.phy .. '.') + end + + local current_ssid = util.trim(util.exec(ssid_grep .. '" ' .. hostapd .. ' | cut -d"=" -f2')) + + util.log(prog_name .. ': Current SSID is "' .. current_ssid .. '". Changing it to "' .. new_ssid .. '"...') + os.execute('sed -i "s~^ssid=' .. current_ssid .. '~ssid=' .. new_ssid .. '~" ' .. hostapd) + hup_needed = 1 +end + +-- Send hup to all hostapd instances to apply the new SSID(s) +if hup_needed == 1 then + print("Applying new SSIDs...") + os.execute('killall -hup hostapd') +end