From e36e8a6a3ba5b5fe103b19f6aab9dc1af9a224fa Mon Sep 17 00:00:00 2001 From: Simon Polack Date: Tue, 3 Aug 2021 12:59:44 +0200 Subject: [PATCH] airos-dfs-reset: add airos-dfs-reset Ubiquitis airmax based gear does not fallback to original port after DFS event is over. This tool triggers the fallback automatically by soft-restarting unconditionally, whenever the configured freq differs from the running. Signed-off-by: Simon Polack --- utils/airos-dfs-reset/Makefile | 46 +++++++ utils/airos-dfs-reset/files/airos-dfs-reset | 114 ++++++++++++++++++ .../files/airos-dfs-reset.config | 15 +++ .../files/airos-dfs-reset.init | 18 +++ 4 files changed, 193 insertions(+) create mode 100644 utils/airos-dfs-reset/Makefile create mode 100644 utils/airos-dfs-reset/files/airos-dfs-reset create mode 100644 utils/airos-dfs-reset/files/airos-dfs-reset.config create mode 100644 utils/airos-dfs-reset/files/airos-dfs-reset.init diff --git a/utils/airos-dfs-reset/Makefile b/utils/airos-dfs-reset/Makefile new file mode 100644 index 0000000000..353795f825 --- /dev/null +++ b/utils/airos-dfs-reset/Makefile @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2021 Simon Polack +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=airos-dfs-reset +PKG_VERSION:=1 +PKG_RELEASE:=$(AUTORELEASE) + +PKG_MAINTAINER:=Simon Polack +PKG_LICENSE:=GPL-2.0-only + +include $(INCLUDE_DIR)/package.mk + +define Package/airos-dfs-reset + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Companion app for Ubiquity AirOS to help with DFS + PKGARCH:=all + EXTRA_DEPENDS:=dropbear +endef + +define Package/airos-dfs-reset/description +Companion app for Ubiquity AirOS Gear to enforce fallback to original frequency after DFS event is over. +It works by soft-rebooting if running-frequency doesnt match the configured frequency. +endef + +define Package/airos-dfs-reset/conffiles +/etc/config/airos-dfs-reset +endef + +define Build/Compile +endef + +define Package/airos-dfs-reset/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/airos-dfs-reset.init $(1)/etc/init.d/airos-dfs-reset + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) ./files/airos-dfs-reset $(1)/usr/bin/airos-dfs-reset + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DATA) ./files/airos-dfs-reset.config $(1)/etc/config/airos-dfs-reset +endef + +$(eval $(call BuildPackage,airos-dfs-reset)) diff --git a/utils/airos-dfs-reset/files/airos-dfs-reset b/utils/airos-dfs-reset/files/airos-dfs-reset new file mode 100644 index 0000000000..1d15c9140c --- /dev/null +++ b/utils/airos-dfs-reset/files/airos-dfs-reset @@ -0,0 +1,114 @@ +#!/bin/sh + +. /lib/functions.sh + +log() { + local msg="$1" + logger -t airos-dfs-reset -s "$msg" +} + +rexec() { + local target="$1" + local username="$2" + local password="$3" + local cmd="$4" + raw=$(DROPBEAR_PASSWORD="$password" ssh -y $username@$target "$cmd") + ssh_result=$? +} + +reset_dfs() { + local cmd="/usr/etc/rc.d/rc.softrestart force" + rexec $* "$cmd" +} + +get_running_freq() { + local cmd="iwconfig ath0 | grep Frequency | awk -F ':' '{print \$3}' | awk '{print \$1}' | sed 's/\.//'" + + rexec $* "$cmd" + + # Append zeroes which are then cut to 4, we have to convert GHz into MHz + raw="$raw"000 + + running_freq=${raw:0:4} +} + +get_target_freq() { + local cmd="grep 'radio.1.freq' /tmp/system.cfg | awk -F '=' '{ print \$2}'" + rexec $* "$cmd" + target_freq="$raw" +} + +check_dfs() { + local target="$1" + local username="$2" + local password="$3" + + get_running_freq $target $username $password + if [ "$ssh_result" != 0 ]; then + return + fi + get_target_freq $target $username $password + if [ "$ssh_result" != 0 ]; then + return + fi + log "Running freq: $running_freq - Target freq: $target_freq" + + [ "$running_freq" == "$target_freq" ] +} + + +reset_allowed() { + local daytime_limit="$1" + local start="$(echo $daytime_limit | awk -F '-' '{print $1'})" + local end="$(echo $daytime_limit | awk -F '-' '{print $2'})" + local cur="$(date +%H)" + [ "$cur" -ge "$start" ] && [ "$cur" -le "$end" ] +} + +handle_device() { + local device="$1" + config_get target "$device" target + config_get username "$device" username + config_get password "$device" password + config_get daytime_limit "$device" daytime_limit "0-23" + + ssh_result=0 + + log "Checking Device $device" + + check_dfs $target $username $password + freqmatch=$? + + if [ "$ssh_result" != 0 ]; then + log "ssh exited non-zero - connect timeout?" + return + elif [ "$freqmatch" == 0 ]; then + log "Frequency is matching. No radar event fired" + else + log "Frequency doesnt match. Looks like DFS activity :(" + if reset_allowed $daytime_limit; then + log "Initiating reset" + reset_dfs $target $username $password + log "Waiting $cfg_reset_sleep seconds after reset" + sleep $cfg_reset_sleep + else + log "Resetting is forbidden at this daytime" + fi + fi +} + +main() { + log "started!" + + config_load airos-dfs-reset + config_get cfg_interval general interval 600 + config_get cfg_reset_sleep general reset_sleep 120 + + while :; + do + config_foreach handle_device device + sleep $cfg_interval + done +} + +main diff --git a/utils/airos-dfs-reset/files/airos-dfs-reset.config b/utils/airos-dfs-reset/files/airos-dfs-reset.config new file mode 100644 index 0000000000..c718a525fd --- /dev/null +++ b/utils/airos-dfs-reset/files/airos-dfs-reset.config @@ -0,0 +1,15 @@ +config airos-dfs-reset general + option interval '600' # Check every x seconds + option reset_sleep '120' # Sleep after reset to let routing protocols reconverge + +config device 'sample_ap' # make sure to not use dashes in name + option target '192.168.1.20' + option username 'ubnt' + option password 'ubnt' + option daytime_limit '2-7' # .. from 2:xx to 7:xx reset is allowed + +#config device 'sample_ap1' +# option target '10.31.81.21' +# option username 'ubnt' +# option password '...' +# option daytime_limit '0-23' diff --git a/utils/airos-dfs-reset/files/airos-dfs-reset.init b/utils/airos-dfs-reset/files/airos-dfs-reset.init new file mode 100644 index 0000000000..d75c5b95a6 --- /dev/null +++ b/utils/airos-dfs-reset/files/airos-dfs-reset.init @@ -0,0 +1,18 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=95 +STOP=01 + +start_service() { + procd_open_instance + procd_set_param command /usr/bin/airos-dfs-reset + procd_set_param stdout 0 + procd_set_param stderr 0 + procd_set_param user nobody + procd_close_instance +} + +service_stopped() { + echo "airos-dfs-reset stopped!" +}