[PATCH 3/8] wifi_stats: hostapd configuration parameters
Iegor Sergieienkov
iegor at nova-labs.com
Thu Aug 27 07:16:20 PDT 2026
Add the configuration parameters for the wifi_stats module:
* wifi_stats_interval - driver polling interval in seconds, 1..3600,
default 1
* wifi_stats_wba_window - aggregation window in seconds, 1..3600,
default 60
* wifi_stats_span - how the aggregation span is determined, either
report (default) or window
* wifi_stats_ewma_weight - exponential weight used by AVG-EXP, 1..9,
default 5
* wifi_stats_wba_enabled - whether to use the WBA Connect-Info format,
default 1
* wifi_stats_metric_<metric>=<algorithm> - per-metric aggregation
algorithm
The metric names are rxbitrate, txbitrate, rssi, frameloss and
frameretry. The algorithms are MIN, MAX, AVG-LIN, AVG-EXP, ACC and NONE;
frameloss and frameretry accept only ACC or NONE. The defaults are MAX
for the two bit rates, AVG-LIN for RSSI, and ACC for the two
counter-derived metrics.
Signed-off-by: Iegor Sergieienkov <iegor at nova-labs.com>
---
hostapd/config_file.c | 116 ++++++++++++++++++++++++++++++++++++++++++
hostapd/hostapd.conf | 71 ++++++++++++++++++++++++++
src/ap/ap_config.c | 8 +++
src/ap/ap_config.h | 15 ++++++
4 files changed, 210 insertions(+)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 6484d6f7d..a6b6cd392 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -24,6 +24,9 @@
#include "ap/wpa_auth.h"
#include "ap/ap_config.h"
#include "config_file.h"
+#ifdef CONFIG_WIFI_STATS
+#include "wifi_stats/wifi_stats.h"
+#endif /* CONFIG_WIFI_STATS */
#ifndef CONFIG_NO_VLAN
@@ -2368,6 +2371,11 @@ static bool get_hexstream(const char *val, struct wpabuf **var,
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_WIFI_STATS
+#define WIFI_STATS_METRIC_PREFIX "wifi_stats_metric_"
+#endif /* CONFIG_WIFI_STATS */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -2505,6 +2513,114 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "config_id") == 0) {
os_free(bss->config_id);
bss->config_id = os_strdup(pos);
+#ifdef CONFIG_WIFI_STATS
+ } else if (os_strcmp(buf, "wifi_stats_interval") == 0) {
+ char *endptr;
+ unsigned long val = strtoul(pos, &endptr, 10);
+ if (endptr == pos || *endptr != '\0' ||
+ val < WIFI_STATS_MIN_INTERVAL || val > WIFI_STATS_MAX_INTERVAL) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wifi_stats_interval '%s' (must be %d-%d)",
+ line, pos, WIFI_STATS_MIN_INTERVAL,
+ WIFI_STATS_MAX_INTERVAL);
+ return 1;
+ }
+ conf->wifi_stats_interval = (unsigned int)val;
+ } else if (os_strcmp(buf, "wifi_stats_wba_window") == 0) {
+ char *endptr;
+ unsigned long val = strtoul(pos, &endptr, 10);
+ if (endptr == pos || *endptr != '\0' ||
+ val < WIFI_STATS_MIN_WINDOW || val > WIFI_STATS_MAX_WINDOW) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wifi_stats_wba_window '%s' (must be %d-%d seconds)",
+ line, pos, WIFI_STATS_MIN_WINDOW,
+ WIFI_STATS_MAX_WINDOW);
+ return 1;
+ }
+ conf->wifi_stats_wba_window = (unsigned int)val;
+ } else if (os_strcmp(buf, "wifi_stats_span") == 0) {
+ wifi_stats_span_mode_t mode =
+ wifi_stats_span_mode_from_str(pos);
+
+ if (mode >= WIFI_STATS_SPAN_COUNT) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wifi_stats_span '%s' (must be report or window)",
+ line, pos);
+ return 1;
+ }
+ conf->wifi_stats_span = mode;
+ } else if (os_strcmp(buf, "wifi_stats_ewma_weight") == 0) {
+ char *endptr;
+ unsigned long val = strtoul(pos, &endptr, 10);
+ if (endptr == pos || *endptr != '\0' ||
+ val < WIFI_STATS_MIN_EWMA_WEIGHT ||
+ val > WIFI_STATS_MAX_EWMA_WEIGHT) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wifi_stats_ewma_weight '%s' (must be %d-%d)",
+ line, pos, WIFI_STATS_MIN_EWMA_WEIGHT,
+ WIFI_STATS_MAX_EWMA_WEIGHT);
+ return 1;
+ }
+ conf->wifi_stats_ewma_weight = (unsigned int)val;
+ } else if (os_strcmp(buf, "wifi_stats_wba_enabled") == 0) {
+ char *endptr;
+ long val = strtol(pos, &endptr, 10);
+ if (endptr == pos || *endptr != '\0' ||
+ (val != 0 && val != 1)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wifi_stats_wba_enabled '%s' (must be 0 or 1)",
+ line, pos);
+ return 1;
+ }
+ conf->wifi_stats_wba_enabled = val;
+ } else if (os_strncmp(buf, WIFI_STATS_METRIC_PREFIX,
+ os_strlen(WIFI_STATS_METRIC_PREFIX)) == 0) {
+ const char *metric_name = buf + os_strlen(WIFI_STATS_METRIC_PREFIX);
+ wifi_stats_metric_type_t metric_idx;
+ wifi_stats_agg_type_t algorithm;
+
+ metric_idx = wifi_stats_metric_type_from_str(metric_name);
+ if (metric_idx >= WIFI_STATS_METRIC_COUNT) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Unknown wifi_stats metric '%s'",
+ line, metric_name);
+ return 1;
+ }
+
+ algorithm = wifi_stats_agg_type_from_str(pos);
+ if (algorithm >= WIFI_STATS_AGG_COUNT) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Unknown algorithm '%s'",
+ line, pos);
+ return 1;
+ }
+
+ if (algorithm != WIFI_STATS_AGG_NONE) {
+ if (algorithm == WIFI_STATS_AGG_ACC &&
+ metric_idx != WIFI_STATS_METRIC_FRAME_LOSS &&
+ metric_idx != WIFI_STATS_METRIC_FRAME_RETRY) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: ACC algorithm only valid for frameloss/frameretry",
+ line);
+ return 1;
+ }
+ if (algorithm != WIFI_STATS_AGG_ACC &&
+ (metric_idx == WIFI_STATS_METRIC_FRAME_LOSS ||
+ metric_idx == WIFI_STATS_METRIC_FRAME_RETRY)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: frameloss/frameretry require ACC or NONE algorithm",
+ line);
+ return 1;
+ }
+ }
+
+ conf->wifi_stats_metrics[metric_idx].configured = 1;
+ conf->wifi_stats_metrics[metric_idx].algorithm = algorithm;
+
+ wpa_printf(MSG_DEBUG,
+ "wifi_stats: Configured metric=%s algorithm=%s",
+ metric_name, pos);
+#endif /* CONFIG_WIFI_STATS */
} else if (os_strcmp(buf, "country_code") == 0) {
if (pos[0] < 'A' || pos[0] > 'Z' ||
pos[1] < 'A' || pos[1] > 'Z') {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 94021d31e..ab927497e 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -3704,3 +3704,74 @@ own_ip_addr=127.0.0.1
#bridge=br-lan
#wpa_key_mgmt=SAE
#bssid=00:03:7f:12:84:85
+
+##### WiFi statistics and WBA Connect-Info ####################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_WIFI_STATS is set while compiling hostapd.
+#
+# When enabled, hostapd polls the driver periodically for per-station link
+# statistics and aggregates them over a sliding window. The aggregated values
+# are reported in the RADIUS Connect-Info attribute using the format defined
+# in draft-grayson-connectinfo-10 (Wireless Broadband Alliance).
+
+# Interval in seconds between driver polls for station statistics.
+# wifi_stats_interval is in 1..3600 range. Default is 1 second.
+#wifi_stats_interval=1
+
+# Length of the aggregation window in seconds. In wifi_stats_span=window mode,
+# samples collected within this window are aggregated into the values
+# reported in Connect-Info, and the window should be longer than
+# wifi_stats_interval; if it is not, aggregation is suppressed and all
+# metrics fall back to reporting instantaneous values. In
+# wifi_stats_span=report mode this value only bounds the accumulation period
+# and does not affect aggregation (see wifi_stats_span below).
+# wifi_stats_wba_window is in 1..3600 range. Default is 60 seconds.
+#wifi_stats_wba_window=60
+
+# How the aggregation span is determined.
+# report - accumulate since the last accounting report was sent, as described
+# in draft-grayson-connectinfo-10 Section 4.2. No sample history is
+# retained. This is the default.
+# window - aggregate over a fixed sliding window of wifi_stats_wba_window
+# seconds, retaining the samples that fall within it.
+# In report mode wifi_stats_wba_window still bounds the accumulation period, so
+# that the reported span stays representable when no accounting server is
+# configured and nothing ever resets it.
+#wifi_stats_span=report
+
+# Exponential weight used by the AVG-EXP algorithm. The smoothing factor is
+# 1/(2^weight), so larger values smooth more heavily, and the weight is what
+# gets reported in place of a time window for AVG-EXP metrics.
+# wifi_stats_ewma_weight is in 1..9 range. Default is 5.
+#wifi_stats_ewma_weight=5
+
+# Whether to use the WBA Connect-Info format in the RADIUS Connect-Info
+# attribute. When disabled, the legacy "CONNECT <rate> Mbps <mode>" format is
+# used instead.
+# 0 = disabled, 1 = enabled (default)
+#wifi_stats_wba_enabled=1
+
+# Per-metric aggregation algorithm:
+# wifi_stats_metric_<metric>=<algorithm>
+#
+# <metric> is one of: rxbitrate, txbitrate, rssi, frameloss, frameretry
+#
+# <algorithm> is one of:
+# MIN - minimum value within the window
+# MAX - maximum value within the window
+# AVG-LIN - linear (arithmetic mean) average within the window
+# AVG-EXP - exponentially weighted moving average
+# ACC - accumulated percentage derived from driver counter deltas
+# NONE - no aggregation; report the most recent value
+#
+# The frameloss and frameretry metrics are derived from driver counters and
+# accept only ACC or NONE. The other metrics accept any algorithm except ACC.
+#
+# AVG-EXP reports its weight rather than a time window, so wifi_stats_wba_window
+# does not appear in the output for a metric using it.
+#
+# Defaults: rxbitrate=MAX, txbitrate=MAX, rssi=AVG-LIN, frameloss=ACC,
+# frameretry=ACC
+#wifi_stats_metric_rssi=AVG-LIN
+#wifi_stats_metric_frameloss=ACC
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 4e7d44da1..ad067a92c 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -318,6 +318,14 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->disable_mcs15_rx = true;
+#ifdef CONFIG_WIFI_STATS
+ conf->wifi_stats_interval = WIFI_STATS_DEFAULT_INTERVAL;
+ conf->wifi_stats_wba_window = WIFI_STATS_DEFAULT_WINDOW;
+ conf->wifi_stats_wba_enabled = 1;
+ conf->wifi_stats_ewma_weight = WIFI_STATS_DEFAULT_EWMA_WEIGHT;
+ conf->wifi_stats_span = WIFI_STATS_SPAN_REPORT;
+#endif /* CONFIG_WIFI_STATS */
+
return conf;
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 563639e76..feb095ecf 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -19,6 +19,9 @@
#include "wps/wps.h"
#include "fst/fst.h"
#include "vlan.h"
+#ifdef CONFIG_WIFI_STATS
+#include "wifi_stats/wifi_stats.h"
+#endif /* CONFIG_WIFI_STATS */
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
@@ -1333,6 +1336,18 @@ struct hostapd_config {
int min_power;
} afc;
#endif /* CONFIG_AFC */
+
+#ifdef CONFIG_WIFI_STATS
+ unsigned int wifi_stats_interval;
+ unsigned int wifi_stats_wba_window;
+ unsigned int wifi_stats_ewma_weight;
+ wifi_stats_span_mode_t wifi_stats_span;
+ int wifi_stats_wba_enabled;
+ struct wifi_stats_metric_config {
+ int configured;
+ wifi_stats_agg_type_t algorithm;
+ } wifi_stats_metrics[WIFI_STATS_METRIC_COUNT];
+#endif /* CONFIG_WIFI_STATS */
};
--
2.43.0
More information about the Hostap
mailing list