airos-dfs-reset: add airos-dfs-reset
authorSimon Polack <redacted>
Tue, 3 Aug 2021 10:59:44 +0000 (12:59 +0200)
committerPolynomdivision <redacted>
Mon, 23 Aug 2021 09:40:33 +0000 (11:40 +0200)
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 <redacted>
utils/airos-dfs-reset/Makefile [new file with mode: 0644]
utils/airos-dfs-reset/files/airos-dfs-reset [new file with mode: 0644]
utils/airos-dfs-reset/files/airos-dfs-reset.config [new file with mode: 0644]
utils/airos-dfs-reset/files/airos-dfs-reset.init [new file with mode: 0644]

diff --git a/utils/airos-dfs-reset/Makefile b/utils/airos-dfs-reset/Makefile
new file mode 100644 (file)
index 0000000..353795f
--- /dev/null
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2021 Simon Polack <spolack+git@@mailbox.org>
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=airos-dfs-reset
+PKG_VERSION:=1
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_MAINTAINER:=Simon Polack <spolack+git@mailbox.org>
+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 (file)
index 0000000..1d15c91
--- /dev/null
@@ -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 (file)
index 0000000..c718a52
--- /dev/null
@@ -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 (file)
index 0000000..d75c5b9
--- /dev/null
@@ -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!"
+}
git clone https://git.99rst.org/PROJECT