measurement: add handling of measurements

Add logic for saving measurement-reports from STAs.

This commit does not yet save the measurement-reports received from
clients but adds the necessary code to do so. Currently the codes can
only handle beacon-reports, but link measurements can be added to it in
the future.

It also adds the new config-key measurement_report_timeout which
controls how long measurements are saved upon they are received by a
STA.

Signed-off-by: David Bauer <mail@david-bauer.net>
This commit is contained in:
David Bauer
2022-01-21 21:27:39 +01:00
parent 76ccae62df
commit b0dab90887
10 changed files with 158 additions and 1 deletions

View File

@@ -24,7 +24,7 @@ IF(NOT HAVE_PCAP_H)
MESSAGE(FATAL_ERROR "pcap/pcap.h is not found") MESSAGE(FATAL_ERROR "pcap/pcap.h is not found")
ENDIF() 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) 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)
IF(NL_CFLAGS) IF(NL_CFLAGS)
ADD_DEFINITIONS(${NL_CFLAGS}) ADD_DEFINITIONS(${NL_CFLAGS})

View File

@@ -71,6 +71,7 @@ usteer_free_node(struct ubus_context *ctx, struct usteer_local_node *ln)
usteer_local_node_pending_bss_tm_free(ln); usteer_local_node_pending_bss_tm_free(ln);
usteer_local_node_state_reset(ln); usteer_local_node_state_reset(ln);
usteer_sta_node_cleanup(&ln->node); usteer_sta_node_cleanup(&ln->node);
usteer_measurement_report_node_cleanup(&ln->node);
uloop_timeout_cancel(&ln->update); uloop_timeout_cancel(&ln->update);
uloop_timeout_cancel(&ln->bss_tm_queries_timeout); uloop_timeout_cancel(&ln->bss_tm_queries_timeout);
avl_delete(&local_nodes, &ln->node.avl); avl_delete(&local_nodes, &ln->node.avl);
@@ -578,6 +579,7 @@ usteer_get_node(struct ubus_context *ctx, const char *name)
avl_insert(&local_nodes, &node->avl); avl_insert(&local_nodes, &node->avl);
kvlist_init(&ln->node_info, kvlist_blob_len); kvlist_init(&ln->node_info, kvlist_blob_len);
INIT_LIST_HEAD(&node->sta_info); INIT_LIST_HEAD(&node->sta_info);
INIT_LIST_HEAD(&node->measurements);
ln->bss_tm_queries_timeout.cb = usteer_local_node_process_bss_tm_queries; ln->bss_tm_queries_timeout.cb = usteer_local_node_process_bss_tm_queries;
INIT_LIST_HEAD(&ln->bss_tm_queries); INIT_LIST_HEAD(&ln->bss_tm_queries);
@@ -623,6 +625,7 @@ usteer_check_node_enabled(struct usteer_local_node *ln)
MSG(INFO, "Disconnecting from local node %s\n", usteer_node_name(&ln->node)); MSG(INFO, "Disconnecting from local node %s\n", usteer_node_name(&ln->node));
usteer_local_node_state_reset(ln); usteer_local_node_state_reset(ln);
usteer_sta_node_cleanup(&ln->node); usteer_sta_node_cleanup(&ln->node);
usteer_measurement_report_node_cleanup(&ln->node);
uloop_timeout_cancel(&ln->update); uloop_timeout_cancel(&ln->update);
ubus_unsubscribe(ubus_ctx, &ln->ev, ln->obj_id); ubus_unsubscribe(ubus_ctx, &ln->ev, ln->obj_id);
return; return;

1
main.c
View File

@@ -86,6 +86,7 @@ void usteer_init_defaults(void)
config.sta_block_timeout = 30 * 1000; config.sta_block_timeout = 30 * 1000;
config.local_sta_timeout = 120 * 1000; config.local_sta_timeout = 120 * 1000;
config.measurement_report_timeout = 120 * 1000;
config.local_sta_update = 1 * 1000; config.local_sta_update = 1 * 1000;
config.max_retry_band = 5; config.max_retry_band = 5;
config.max_neighbor_reports = 8; config.max_neighbor_reports = 8;

112
measurement.c Normal file
View File

@@ -0,0 +1,112 @@
/*
* 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) 2021 David Bauer <mail@david-bauer.net>
*/
#include "usteer.h"
LIST_HEAD(measurements);
static struct usteer_timeout_queue tq;
void
usteer_measurement_report_node_cleanup(struct usteer_node *node)
{
struct usteer_measurement_report *mr, *tmp;
list_for_each_entry_safe(mr, tmp, &node->measurements, node_list)
usteer_measurement_report_del(mr);
}
void
usteer_measurement_report_sta_cleanup(struct sta *sta)
{
struct usteer_measurement_report *mr, *tmp;
list_for_each_entry_safe(mr, tmp, &sta->measurements, sta_list)
usteer_measurement_report_del(mr);
}
struct usteer_measurement_report *
usteer_measurement_report_get(struct sta *sta, struct usteer_node *node, bool create)
{
struct usteer_measurement_report *mr;
list_for_each_entry(mr, &sta->measurements, sta_list) {
if (mr->node == node)
return mr;
}
if (!create)
return NULL;
mr = calloc(1, sizeof(*mr));
if (!mr)
return NULL;
/* Set node & add to nodes list */
mr->node = node;
list_add(&mr->node_list, &node->measurements);
/* Set sta & add to STAs list */
mr->sta = sta;
list_add(&mr->sta_list, &sta->measurements);
/* Add to Measurement list */
list_add(&mr->list, &measurements);
/* Set measurement expiration */
usteer_timeout_set(&tq, &mr->timeout, config.measurement_report_timeout);
return mr;
}
struct usteer_measurement_report *
usteer_measurement_report_add_beacon_report(struct sta *sta, struct usteer_node *node,
struct usteer_beacon_report *br, uint64_t timestamp)
{
struct usteer_measurement_report *mr = usteer_measurement_report_get(sta, node, true);
if (!mr)
return NULL;
mr->timestamp = timestamp;
memcpy(&mr->beacon_report, br, sizeof(*br));
return mr;
}
void
usteer_measurement_report_del(struct usteer_measurement_report *mr)
{
usteer_timeout_cancel(&tq, &mr->timeout);
list_del(&mr->node_list);
list_del(&mr->sta_list);
list_del(&mr->list);
free(mr);
}
static void
usteer_measurement_timeout(struct usteer_timeout_queue *q, struct usteer_timeout *t)
{
struct usteer_measurement_report *mr = container_of(t, struct usteer_measurement_report, timeout);
usteer_measurement_report_del(mr);
}
static void __usteer_init usteer_measurement_init(void)
{
usteer_timeout_init(&tq);
tq.cb = usteer_measurement_timeout;
}

View File

@@ -26,6 +26,9 @@ config usteer
# Maximum amount of time (ms) a local unconnected station is tracked # Maximum amount of time (ms) a local unconnected station is tracked
#option local_sta_timeout 120000 #option local_sta_timeout 120000
# Maximum amount of time (ms) a measurement report is stored
#option measurement_report_timeout 120000
# Local station information update interval (ms) # Local station information update interval (ms)
#option local_sta_update 1000 #option local_sta_update 1000

View File

@@ -76,6 +76,7 @@ uci_usteer() {
debug_level \ debug_level \
sta_block_timeout local_sta_timeout local_sta_update \ sta_block_timeout local_sta_timeout local_sta_update \
max_neighbor_reports max_retry_band seen_policy_timeout \ max_neighbor_reports max_retry_band seen_policy_timeout \
measurement_report_timeout \
load_balancing_threshold band_steering_threshold \ load_balancing_threshold band_steering_threshold \
remote_update_interval remote_node_timeout\ remote_update_interval remote_node_timeout\
min_connect_snr min_snr min_snr_kick_delay signal_diff_threshold \ min_connect_snr min_snr min_snr_kick_delay signal_diff_threshold \

View File

@@ -210,6 +210,7 @@ remote_node_free(struct usteer_remote_node *node)
list_del(&node->list); list_del(&node->list);
list_del(&node->host_list); list_del(&node->host_list);
usteer_sta_node_cleanup(&node->node); usteer_sta_node_cleanup(&node->node);
usteer_measurement_report_node_cleanup(&node->node);
free(node); free(node);
if (!list_empty(&host->nodes)) if (!list_empty(&host->nodes))
@@ -264,6 +265,7 @@ interface_get_node(struct usteer_remote_host *host, const char *name)
node->name = buf + addr_len + 1; node->name = buf + addr_len + 1;
node->host = host; node->host = host;
INIT_LIST_HEAD(&node->node.sta_info); INIT_LIST_HEAD(&node->node.sta_info);
INIT_LIST_HEAD(&node->node.measurements);
list_add_tail(&node->list, &remote_nodes); list_add_tail(&node->list, &remote_nodes);
list_add_tail(&node->host_list, &host->nodes); list_add_tail(&node->host_list, &host->nodes);

2
sta.c
View File

@@ -35,6 +35,7 @@ usteer_sta_del(struct sta *sta)
MAC_ADDR_DATA(sta->addr)); MAC_ADDR_DATA(sta->addr));
avl_delete(&stations, &sta->avl); avl_delete(&stations, &sta->avl);
usteer_measurement_report_sta_cleanup(sta);
free(sta); free(sta);
} }
@@ -140,6 +141,7 @@ usteer_sta_get(const uint8_t *addr, bool create)
sta->avl.key = sta->addr; sta->avl.key = sta->addr;
avl_insert(&stations, &sta->avl); avl_insert(&stations, &sta->avl);
INIT_LIST_HEAD(&sta->nodes); INIT_LIST_HEAD(&sta->nodes);
INIT_LIST_HEAD(&sta->measurements);
return sta; return sta;
} }

1
ubus.c
View File

@@ -149,6 +149,7 @@ struct cfg_item {
_cfg(U32, max_neighbor_reports), \ _cfg(U32, max_neighbor_reports), \
_cfg(U32, max_retry_band), \ _cfg(U32, max_retry_band), \
_cfg(U32, seen_policy_timeout), \ _cfg(U32, seen_policy_timeout), \
_cfg(U32, measurement_report_timeout), \
_cfg(U32, load_balancing_threshold), \ _cfg(U32, load_balancing_threshold), \
_cfg(U32, band_steering_threshold), \ _cfg(U32, band_steering_threshold), \
_cfg(U32, remote_update_interval), \ _cfg(U32, remote_update_interval), \

View File

@@ -73,6 +73,7 @@ struct usteer_remote_host;
struct usteer_node { struct usteer_node {
struct avl_node avl; struct avl_node avl;
struct list_head sta_info; struct list_head sta_info;
struct list_head measurements;
enum usteer_node_type type; enum usteer_node_type type;
@@ -155,6 +156,7 @@ struct usteer_config {
uint32_t max_retry_band; uint32_t max_retry_band;
uint32_t seen_policy_timeout; uint32_t seen_policy_timeout;
uint32_t measurement_report_timeout;
bool assoc_steering; bool assoc_steering;
@@ -254,6 +256,7 @@ struct sta_info {
struct sta { struct sta {
struct avl_node avl; struct avl_node avl;
struct list_head nodes; struct list_head nodes;
struct list_head measurements;
uint8_t seen_2ghz : 1; uint8_t seen_2ghz : 1;
uint8_t seen_5ghz : 1; uint8_t seen_5ghz : 1;
@@ -263,6 +266,27 @@ struct sta {
uint8_t rrm; uint8_t rrm;
}; };
struct usteer_beacon_report {
uint8_t rcpi;
uint8_t rsni;
};
struct usteer_measurement_report {
struct usteer_timeout timeout;
struct list_head list;
struct usteer_node *node;
struct list_head node_list;
struct sta *sta;
struct list_head sta_list;
uint64_t timestamp;
struct usteer_beacon_report beacon_report;
};
extern struct ubus_context *ubus_ctx; extern struct ubus_context *ubus_ctx;
extern struct usteer_config config; extern struct usteer_config config;
extern struct list_head node_handlers; extern struct list_head node_handlers;
@@ -335,4 +359,12 @@ void usteer_run_hook(const char *name, const char *arg);
void usteer_dump_node(struct blob_buf *buf, struct usteer_node *node); void usteer_dump_node(struct blob_buf *buf, struct usteer_node *node);
void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host); void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host);
struct usteer_measurement_report * usteer_measurement_report_get(struct sta *sta, struct usteer_node *node, bool create);
void usteer_measurement_report_node_cleanup(struct usteer_node *node);
void usteer_measurement_report_sta_cleanup(struct sta *sta);
void usteer_measurement_report_del(struct usteer_measurement_report *mr);
struct usteer_measurement_report *
usteer_measurement_report_add_beacon_report(struct sta *sta, struct usteer_node *node, struct usteer_beacon_report *br, uint64_t timestamp);
#endif #endif