band-steering: add band-steering component
This adds a new band-steering component to usteer. With band-steering enabled, usteer will attempt to move clients with a consistently good SNR / signal from 2.4 GHz to the 5 GHz band. In contrast to existing policies usteer tracks, band-steering is non-invasive and will not lead to forceful connection termination. Signed-off-by: David Bauer <mail@david-bauer.net>
This commit is contained in:
@@ -24,7 +24,7 @@ IF(NOT HAVE_PCAP_H)
|
||||
MESSAGE(FATAL_ERROR "pcap/pcap.h is not found")
|
||||
ENDIF()
|
||||
|
||||
SET(SOURCES main.c local_node.c node.c sta.c policy.c ubus.c remote.c parse.c netifd.c timeout.c event.c measurement.c)
|
||||
SET(SOURCES main.c local_node.c node.c sta.c policy.c ubus.c remote.c parse.c netifd.c timeout.c event.c measurement.c band_steering.c)
|
||||
|
||||
IF(NL_CFLAGS)
|
||||
ADD_DEFINITIONS(${NL_CFLAGS})
|
||||
|
98
band_steering.c
Normal file
98
band_steering.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2022 David Bauer <mail@david-bauer.net>
|
||||
*/
|
||||
|
||||
#include "usteer.h"
|
||||
#include "node.h"
|
||||
|
||||
void usteer_band_steering_sta_update(struct sta_info *si)
|
||||
{
|
||||
if (si->signal < usteer_snr_to_signal(si->node, config.band_steering_min_snr))
|
||||
si->band_steering.below_snr = true;
|
||||
}
|
||||
|
||||
bool usteer_band_steering_is_target(struct usteer_local_node *ln, struct usteer_node *node)
|
||||
{
|
||||
if (&ln->node == node)
|
||||
return false;
|
||||
|
||||
if (strcmp(ln->node.ssid, node->ssid))
|
||||
return false;
|
||||
|
||||
if (node->freq < 4000)
|
||||
return false;
|
||||
|
||||
if (!usteer_policy_node_below_max_assoc(node))
|
||||
return false;
|
||||
|
||||
/* ToDo: Skip nodes with active load-kick */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool usteer_band_steering_has_target_iface(struct usteer_local_node *ln)
|
||||
{
|
||||
struct usteer_node *node;
|
||||
|
||||
for_each_local_node(node) {
|
||||
if (usteer_band_steering_is_target(ln, node))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void usteer_band_steering_perform_steer(struct usteer_local_node *ln)
|
||||
{
|
||||
unsigned int min_count = DIV_ROUND_UP(config.band_steering_interval, config.local_sta_update);
|
||||
struct sta_info *si;
|
||||
|
||||
if (!config.band_steering_interval)
|
||||
return;
|
||||
|
||||
/* Band-Steering is only available on 2.4 GHz interfaces */
|
||||
if (ln->node.freq > 4000)
|
||||
return;
|
||||
|
||||
/* Check if we have an interface we can steer to */
|
||||
if (!usteer_band_steering_has_target_iface(ln))
|
||||
return;
|
||||
|
||||
/* Only steer every interval */
|
||||
if (ln->band_steering_interval < min_count) {
|
||||
ln->band_steering_interval++;
|
||||
return;
|
||||
}
|
||||
|
||||
ln->band_steering_interval = 0;
|
||||
|
||||
list_for_each_entry(si, &ln->node.sta_info, node_list) {
|
||||
if (si->connected != STA_CONNECTED)
|
||||
continue;
|
||||
|
||||
/* Skip clients with insufficient SNR-state */
|
||||
if (si->band_steering.below_snr) {
|
||||
si->band_steering.below_snr = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (si->bss_transition)
|
||||
usteer_ubus_band_steering_request(si);
|
||||
|
||||
si->band_steering.below_snr = false;
|
||||
}
|
||||
}
|
@@ -642,6 +642,7 @@ usteer_local_node_update(struct uloop_timeout *timeout)
|
||||
usteer_local_node_state_reset(ln);
|
||||
uloop_timeout_set(&ln->req_timer, 1);
|
||||
usteer_local_node_kick(ln);
|
||||
usteer_band_steering_perform_steer(ln);
|
||||
uloop_timeout_set(timeout, config.local_sta_update);
|
||||
}
|
||||
|
||||
|
3
main.c
3
main.c
@@ -99,6 +99,9 @@ void usteer_init_defaults(void)
|
||||
|
||||
config.steer_reject_timeout = 60000;
|
||||
|
||||
config.band_steering_interval = 120000;
|
||||
config.band_steering_min_snr = -60;
|
||||
|
||||
config.roam_kick_delay = 10000;
|
||||
config.roam_process_timeout = 5 * 1000;
|
||||
config.roam_scan_tries = 3;
|
||||
|
2
node.h
2
node.h
@@ -59,6 +59,8 @@ struct usteer_local_node {
|
||||
|
||||
int beacon_interval;
|
||||
|
||||
uint16_t band_steering_interval;
|
||||
|
||||
struct {
|
||||
bool present;
|
||||
struct uloop_timeout update;
|
||||
|
@@ -117,6 +117,14 @@ config usteer
|
||||
# Reason code on client kick based on channel load (default: WLAN_REASON_DISASSOC_AP_BUSY)
|
||||
#option load_kick_reason_code 5
|
||||
|
||||
# Attempting to steer clients to a higher frequency-band every n ms.
|
||||
# A value of 0 disabled band-steering.
|
||||
#option band_steering_interval 120000
|
||||
|
||||
# Minimal SNR or absolute signal a device has to maintain over band_steering_interval to be
|
||||
# steered to a higher frequency band
|
||||
#option band_steering_min_snr -60
|
||||
|
||||
# Script to run after bringing up a node
|
||||
#option node_up_script ''
|
||||
|
||||
|
@@ -85,6 +85,7 @@ uci_usteer() {
|
||||
roam_kick_delay roam_scan_tries roam_scan_timeout \
|
||||
roam_scan_snr roam_scan_interval \
|
||||
roam_trigger_snr roam_trigger_interval \
|
||||
band_steering_interval band_steering_min_snr \
|
||||
load_kick_threshold load_kick_delay load_kick_min_clients \
|
||||
load_kick_reason_code
|
||||
do
|
||||
|
4
sta.c
4
sta.c
@@ -160,8 +160,10 @@ usteer_sta_info_update(struct sta_info *si, int signal, bool avg)
|
||||
if (si->connected == STA_CONNECTED && si->signal != NO_SIGNAL && !avg)
|
||||
signal = NO_SIGNAL;
|
||||
|
||||
if (signal != NO_SIGNAL)
|
||||
if (signal != NO_SIGNAL) {
|
||||
si->signal = signal;
|
||||
usteer_band_steering_sta_update(si);
|
||||
}
|
||||
|
||||
si->seen = current_time;
|
||||
|
||||
|
27
ubus.c
27
ubus.c
@@ -181,6 +181,8 @@ struct cfg_item {
|
||||
_cfg(U32, load_kick_delay), \
|
||||
_cfg(U32, load_kick_min_clients), \
|
||||
_cfg(U32, load_kick_reason_code), \
|
||||
_cfg(U32, band_steering_interval), \
|
||||
_cfg(I32, band_steering_min_snr), \
|
||||
_cfg(ARRAY_CB, interfaces), \
|
||||
_cfg(STRING_CB, node_up_script), \
|
||||
_cfg(ARRAY_CB, event_log_types), \
|
||||
@@ -654,6 +656,31 @@ int usteer_ubus_bss_transition_request(struct sta_info *si,
|
||||
return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
|
||||
}
|
||||
|
||||
int usteer_ubus_band_steering_request(struct sta_info *si)
|
||||
{
|
||||
struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
|
||||
struct usteer_node *node;
|
||||
void *c;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
|
||||
blobmsg_add_u32(&b, "dialog_token", 0);
|
||||
blobmsg_add_u8(&b, "disassociation_imminent", false);
|
||||
blobmsg_add_u8(&b, "abridged", false);
|
||||
blobmsg_add_u32(&b, "validity_period", 100);
|
||||
|
||||
c = blobmsg_open_array(&b, "neighbors");
|
||||
for_each_local_node(node) {
|
||||
if (!usteer_band_steering_is_target(ln, node))
|
||||
continue;
|
||||
|
||||
usteer_add_nr_entry(si->node, node);
|
||||
}
|
||||
blobmsg_close_array(&b, c);
|
||||
|
||||
return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
|
||||
}
|
||||
|
||||
int usteer_ubus_notify_client_disassoc(struct sta_info *si)
|
||||
{
|
||||
struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
|
||||
|
12
usteer.h
12
usteer.h
@@ -188,6 +188,9 @@ struct usteer_config {
|
||||
|
||||
uint32_t roam_kick_delay;
|
||||
|
||||
uint32_t band_steering_interval;
|
||||
int32_t band_steering_min_snr;
|
||||
|
||||
uint32_t initial_connect_delay;
|
||||
|
||||
bool load_kick_enabled;
|
||||
@@ -253,6 +256,10 @@ struct sta_info {
|
||||
uint64_t timestamp;
|
||||
} bss_transition_response;
|
||||
|
||||
struct {
|
||||
bool below_snr;
|
||||
} band_steering;
|
||||
|
||||
uint64_t kick_time;
|
||||
|
||||
int kick_count;
|
||||
@@ -318,10 +325,15 @@ int usteer_local_node_get_beacon_interval(struct usteer_local_node *ln);
|
||||
|
||||
bool usteer_policy_node_below_max_assoc(struct usteer_node *node);
|
||||
|
||||
void usteer_band_steering_perform_steer(struct usteer_local_node *ln);
|
||||
void usteer_band_steering_sta_update(struct sta_info *si);
|
||||
bool usteer_band_steering_is_target(struct usteer_local_node *ln, struct usteer_node *node);
|
||||
|
||||
void usteer_ubus_init(struct ubus_context *ctx);
|
||||
void usteer_ubus_kick_client(struct sta_info *si);
|
||||
int usteer_ubus_trigger_client_scan(struct sta_info *si);
|
||||
int usteer_ubus_notify_client_disassoc(struct sta_info *si);
|
||||
int usteer_ubus_band_steering_request(struct sta_info *si);
|
||||
int usteer_ubus_bss_transition_request(struct sta_info *si,
|
||||
uint8_t dialog_token,
|
||||
bool disassoc_imminent,
|
||||
|
Reference in New Issue
Block a user