Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

roamguide: add package #185

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions net/roamguide/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=roamguide
PKG_VERSION:=0.0.4
PKG_RELEASE:=$(GLUON_BRANCH)

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(TOPDIR)/../package/gluon.mk

define Package/roamguide
SECTION:=net
CATEGORY:=Network
DEPENDS:=+micrond
TITLE:=Helps your client to search for a better AP and have a nice roam experience.
endef

define Package/roamguide/description
Helps your client to search for a better AP and have a nice roam experience.
endef

define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef

define Build/Compile
endef

define Package/roamguide/install
$(CP) ./files/* $(1)
endef

$(eval $(call BuildPackage,roamguide))
47 changes: 47 additions & 0 deletions net/roamguide/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
ROAM-Guide
----------

Helps your clients to search for a better AP and to have a nice roaming experience.

The roaming guide runs as a cronjob every minute on your ap and verifies that clients
have an acceptable TQ towards the AP. If that isn't the case it will deauth the client
by stating that the AP is full, enabling the client to look for an alternative AP.

This is happening in three definable stages depending on the TQ of the client.
When a client has decided to come back after the ban-time it will not be bothered
again unless it depletes to the next TQ level or it has been kicked $stage times.
For every stage the client is guided, the ban time will be increased. So by default
the first stage has a bantime of 500ms, the second 2775ms and the third 10000ms.

When a client is away for some definable time or is below the first stages TQ,
it will be forgotten, and the guiding will be re-enable.

Configuration
-------------

In '/etc/config/roamguide' the following default configuration is available,
to activate it you need to set enabled to '1'.

config roamguide
option device "client0" # wireless AP device we like to guide
list signal '-60' # first penality level, in dBm
list signal '-77' # second penality level, in dBm
list signal '-85' # final penality level. in dBm
option bantime_base '500' # on the first level ban for 500ms
option bantime_factor '2375' # on the second one for 2775ms,
# and in the final 10000ms
option forget_time '600' # Forget about a client after 10s
option enabled '0' # set to '1' to enable this profile

This module creates a cronjob calling /usr/bin/roamguide once a minute.
If you want to make roamguide more reactive (but also stress your device) you can add some more cron jobs with sleep timers in /usr/lib/micron.d/root:

* * * * * sleep 20 & /usr/bin/roamguide
* * * * * sleep 40 & /usr/bin/roamguide

### Testing tools

This will show you the stats, where you are connected to on your client:

watch -d -n0,5 iw dev $(ip -o -4 route show to default | awk '{print $5}') station dump

11 changes: 11 additions & 0 deletions net/roamguide/files/etc/config/roamguide
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# repeat the following for every wireless AP device you like to guide.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would prefer a solution where this package detects itself if there is a single-band or a dual-band device, which in the latter case would need two sections for client0 and client1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened an issue here: sargon/gluon-sargon#14

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue is said to be fixed in sargon/gluon-sargon@c9539a0 (though it just creates both and fails silently on single band devices).

config roamguide
option device "client0" # wireless AP device we like to guide
list signal '-60' # first penality level
list signal '-77' # second penality level
list signal '-85' # final penality level
option bantime_base '500' # on the first level ban for 500ms
option bantime_factor '2375' # on the second one for 2775ms,
# and in the final 10000ms
option forget_time '600' # Forget about a client after 10s
option enabled '1' # set to '0' to disable this profile
106 changes: 106 additions & 0 deletions net/roamguide/files/usr/bin/roamguide
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/sh

. /lib/functions.sh

LOCK="/tmp/roamguide.lock"

try_lock(){
mkdir "$LOCK" || echo "Already running!"
trap "rm $LOCK" EXIT
}

wifi_kick(){
local dev="$1" ; shift
local mac="$1" ; shift
local bantime="$1" ; shift
ubus call hostapd.${dev} del_client '{ "addr" : "'${mac}'", "reason" : "assoc toomany", "ban_time" : '${bantime}' }'
}

count_file(){
echo "/tmp/roam-${1}-${2}"
}

count_get(){
local fn=$(count_file $@)
if [ -e "$fn" ] ; then
touch "$fn"
cat $fn
else
echo 0
fi
}

count_inc(){
expr $(count_get $@) + 1 > $(count_file $@)
}

count_dec(){
$(expr $(count_get $@) - 1) > $(count_file $@)
}

count_rm(){
local fn=$(count_file $@)
if [ -e $fn ] ; then
logger -s -t roamguide "forget" $@
rm $fn
fi
}

count_cleanup() {
local device="$1" ; shift
local current_time=$(date +%s)
for file in $(find /tmp -maxdepth 1 -name "roam-${device}-*" -type f ); do
[ "$(expr "$current_time" - $(date +%s -r $file))" -gt "$forget_time" ] && rm $file
done
}

client_macs() {
local dev="$1"
iw dev "${dev}" station dump | grep Station | sed -e 's/^[^ ]\+ \([0-9a-z:]*\) .*/\1/'
}

client_tq() {
local dev="$1"
local mac="$2"
iw dev "${dev}" station get "${mac}" | grep "signal avg" | xargs | cut -d' ' -f 3
}

roamguide() {
local s="$1"
config_get_bool enabled "$s" 'enabled' 0
[ $enabled -ne 0 ] || return 0

config_get device "$s" device
config_get forget_time "$s" forget_time 600
config_get bantime_base "$s" bantime_base 500
config_get bantime_factor "$s" bantime_factor 2375

for mac in $(client_macs "${device}") ; do
tq=$(client_tq "${device}" "${mac}")
level=1
config_list_foreach "$s" signal roamlevel "${tq}" "${device}" "${mac}"
done
count_cleanup ${device}
}

roamlevel(){
local roam_tq="$1" ; shift
local tq="$1" ; shift
local device="$1" ; shift
local mac="$1" ; shift
if [ ${tq} -le ${roam_tq} ]; then
mac_count=$(count_get "${device}" "${mac}")
if [ $mac_count -lt $level ] ; then
count_inc ${device} ${mac}
local bantime=$(expr $bantime_base + $(expr $mac_count \* $mac_count) \* $bantime_factor)
logger -s -t roamguide "${device}: ban ${mac} ${tq}dBm for ${bantime}ms"
wifi_kick "${device}" "${mac}" "${bantime}"
break # quits config_list_foreach
fi
fi
level=$(expr $level + 1)
}

try_lock
config_load 'roamguide'
config_foreach roamguide 'roamguide'
13 changes: 13 additions & 0 deletions net/roamguide/files/usr/bin/roamguide-loop
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

LOCK="/tmp/roamguide-loop.lock"

try_lock(){
mkdir "$LOCK" || echo "Already running!"
trap "rmdir $LOCK" EXIT
}

/sbin/logread -f -e '\<hostapd\>.*\<associated\>' |\
while read line ; do
/usr/bin/roamguide
done
1 change: 1 addition & 0 deletions net/roamguide/files/usr/lib/micron.d/roamguide
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* * * * * /usr/bin/roamguide
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New line is missing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.