From b0dab9088798419de7e10fa9c4e4fa0504a49bc9 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 21 Jan 2022 21:27:39 +0100 Subject: [PATCH] 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 --- CMakeLists.txt | 2 +- local_node.c | 3 + main.c | 1 + measurement.c | 112 +++++++++++++++++++++++++ openwrt/usteer/files/etc/config/usteer | 3 + openwrt/usteer/files/etc/init.d/usteer | 1 + remote.c | 2 + sta.c | 2 + ubus.c | 1 + usteer.h | 32 +++++++ 10 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 measurement.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e22b7ae..6344aab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) +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) ADD_DEFINITIONS(${NL_CFLAGS}) diff --git a/local_node.c b/local_node.c index e69ec21..25387ab 100644 --- a/local_node.c +++ b/local_node.c @@ -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_state_reset(ln); usteer_sta_node_cleanup(&ln->node); + usteer_measurement_report_node_cleanup(&ln->node); uloop_timeout_cancel(&ln->update); uloop_timeout_cancel(&ln->bss_tm_queries_timeout); 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); kvlist_init(&ln->node_info, kvlist_blob_len); INIT_LIST_HEAD(&node->sta_info); + INIT_LIST_HEAD(&node->measurements); ln->bss_tm_queries_timeout.cb = usteer_local_node_process_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)); usteer_local_node_state_reset(ln); usteer_sta_node_cleanup(&ln->node); + usteer_measurement_report_node_cleanup(&ln->node); uloop_timeout_cancel(&ln->update); ubus_unsubscribe(ubus_ctx, &ln->ev, ln->obj_id); return; diff --git a/main.c b/main.c index d8fdbf0..37053d3 100644 --- a/main.c +++ b/main.c @@ -86,6 +86,7 @@ void usteer_init_defaults(void) config.sta_block_timeout = 30 * 1000; config.local_sta_timeout = 120 * 1000; + config.measurement_report_timeout = 120 * 1000; config.local_sta_update = 1 * 1000; config.max_retry_band = 5; config.max_neighbor_reports = 8; diff --git a/measurement.c b/measurement.c new file mode 100644 index 0000000..c1b5ab4 --- /dev/null +++ b/measurement.c @@ -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 + */ + +#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; +} diff --git a/openwrt/usteer/files/etc/config/usteer b/openwrt/usteer/files/etc/config/usteer index 92e9443..fb27fd9 100644 --- a/openwrt/usteer/files/etc/config/usteer +++ b/openwrt/usteer/files/etc/config/usteer @@ -26,6 +26,9 @@ config usteer # Maximum amount of time (ms) a local unconnected station is tracked #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) #option local_sta_update 1000 diff --git a/openwrt/usteer/files/etc/init.d/usteer b/openwrt/usteer/files/etc/init.d/usteer index 921cccb..29a43a2 100755 --- a/openwrt/usteer/files/etc/init.d/usteer +++ b/openwrt/usteer/files/etc/init.d/usteer @@ -76,6 +76,7 @@ uci_usteer() { debug_level \ sta_block_timeout local_sta_timeout local_sta_update \ max_neighbor_reports max_retry_band seen_policy_timeout \ + measurement_report_timeout \ load_balancing_threshold band_steering_threshold \ remote_update_interval remote_node_timeout\ min_connect_snr min_snr min_snr_kick_delay signal_diff_threshold \ diff --git a/remote.c b/remote.c index bad5f8b..f000e68 100644 --- a/remote.c +++ b/remote.c @@ -210,6 +210,7 @@ remote_node_free(struct usteer_remote_node *node) list_del(&node->list); list_del(&node->host_list); usteer_sta_node_cleanup(&node->node); + usteer_measurement_report_node_cleanup(&node->node); free(node); 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->host = host; INIT_LIST_HEAD(&node->node.sta_info); + INIT_LIST_HEAD(&node->node.measurements); list_add_tail(&node->list, &remote_nodes); list_add_tail(&node->host_list, &host->nodes); diff --git a/sta.c b/sta.c index 2868a67..af4f17e 100644 --- a/sta.c +++ b/sta.c @@ -35,6 +35,7 @@ usteer_sta_del(struct sta *sta) MAC_ADDR_DATA(sta->addr)); avl_delete(&stations, &sta->avl); + usteer_measurement_report_sta_cleanup(sta); free(sta); } @@ -140,6 +141,7 @@ usteer_sta_get(const uint8_t *addr, bool create) sta->avl.key = sta->addr; avl_insert(&stations, &sta->avl); INIT_LIST_HEAD(&sta->nodes); + INIT_LIST_HEAD(&sta->measurements); return sta; } diff --git a/ubus.c b/ubus.c index 6960464..bb4e4d2 100644 --- a/ubus.c +++ b/ubus.c @@ -149,6 +149,7 @@ struct cfg_item { _cfg(U32, max_neighbor_reports), \ _cfg(U32, max_retry_band), \ _cfg(U32, seen_policy_timeout), \ + _cfg(U32, measurement_report_timeout), \ _cfg(U32, load_balancing_threshold), \ _cfg(U32, band_steering_threshold), \ _cfg(U32, remote_update_interval), \ diff --git a/usteer.h b/usteer.h index 0ad9499..2f74a01 100644 --- a/usteer.h +++ b/usteer.h @@ -73,6 +73,7 @@ struct usteer_remote_host; struct usteer_node { struct avl_node avl; struct list_head sta_info; + struct list_head measurements; enum usteer_node_type type; @@ -155,6 +156,7 @@ struct usteer_config { uint32_t max_retry_band; uint32_t seen_policy_timeout; + uint32_t measurement_report_timeout; bool assoc_steering; @@ -254,6 +256,7 @@ struct sta_info { struct sta { struct avl_node avl; struct list_head nodes; + struct list_head measurements; uint8_t seen_2ghz : 1; uint8_t seen_5ghz : 1; @@ -263,6 +266,27 @@ struct sta { 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 usteer_config config; 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_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 -- 2.30.2