[PATCH 4/8] wifi_stats: Integration into hostapd

Iegor Sergieienkov iegor at nova-labs.com
Thu Aug 27 07:16:21 PDT 2026


Create the wifi_stats context for each interface in
hostapd_setup_interface(), apply the configured parameters to it, and
start the collection timer. The context is freed in
hostapd_interface_deinit().

The configuration is re-applied when the interface is reloaded so that
changes to the wifi_stats_* parameters take effect without restarting
hostapd. A metric whose directive has been removed reverts to its
default rather than keeping the previously configured algorithm.

Per-station state is released in ap_free_sta() so that a station
reassociating within the aggregation span does not inherit statistics
collected during its previous association. A station that reassociates
while its struct sta_info is still present keeps its state, which matches
the lifetime of the RADIUS accounting session.

Signed-off-by: Iegor Sergieienkov <iegor at nova-labs.com>
---
 src/ap/hostapd.c  | 73 +++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/hostapd.h  |  8 ++++++
 src/ap/sta_info.c |  6 +++-
 3 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 12384e792..cc2a95944 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -23,6 +23,9 @@
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "fst/fst.h"
+#ifdef CONFIG_WIFI_STATS
+#include "wifi_stats/wifi_stats.h"
+#endif /* CONFIG_WIFI_STATS */
 #include "hostapd.h"
 #include "authsrv.h"
 #include "sta_info.h"
@@ -60,6 +63,9 @@
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+#ifdef CONFIG_WIFI_STATS
+static void hostapd_reload_wifi_stats_config(struct hostapd_iface *iface);
+#endif /* CONFIG_WIFI_STATS */
 #ifdef CONFIG_WEP
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
 static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
@@ -300,6 +306,9 @@ int hostapd_reload_config(struct hostapd_iface *iface)
 		hostapd_clear_old(iface);
 		for (j = 0; j < iface->num_bss; j++)
 			hostapd_reload_bss(iface->bss[j]);
+#ifdef CONFIG_WIFI_STATS
+		hostapd_reload_wifi_stats_config(iface);
+#endif /* CONFIG_WIFI_STATS */
 		return 0;
 	}
 
@@ -377,6 +386,9 @@ int hostapd_reload_config(struct hostapd_iface *iface)
 	iface->conf = newconf;
 	hostapd_config_free(oldconf);
 
+#ifdef CONFIG_WIFI_STATS
+	hostapd_reload_wifi_stats_config(iface);
+#endif /* CONFIG_WIFI_STATS */
 
 	return 0;
 }
@@ -2977,6 +2989,42 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
 }
 
 
+#ifdef CONFIG_WIFI_STATS
+static void hostapd_reload_wifi_stats_config(struct hostapd_iface *iface)
+{
+	int i;
+
+	if (!iface || !iface->wifi_stats || !iface->conf)
+		return;
+
+	wifi_stats_set_params(iface->wifi_stats,
+			      iface->conf->wifi_stats_interval,
+			      iface->conf->wifi_stats_wba_window);
+	wifi_stats_set_span_mode(iface->wifi_stats,
+				 iface->conf->wifi_stats_span);
+	wifi_stats_set_ewma_weight(iface->wifi_stats,
+				   iface->conf->wifi_stats_ewma_weight);
+
+	for (i = 0; i < WIFI_STATS_METRIC_COUNT; i++) {
+		wifi_stats_agg_type_t algorithm;
+
+		if (iface->conf->wifi_stats_metrics[i].configured)
+			algorithm = iface->conf->wifi_stats_metrics[i].algorithm;
+		else
+			algorithm = wifi_stats_default_algorithm(i);
+		wifi_stats_set_metric_config(iface->wifi_stats, i, algorithm);
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "wifi_stats: Applied config (interval=%u window=%u span=%s weight=%u)",
+		   iface->conf->wifi_stats_interval,
+		   iface->conf->wifi_stats_wba_window,
+		   wifi_stats_span_mode_to_str(iface->conf->wifi_stats_span),
+		   iface->conf->wifi_stats_ewma_weight);
+}
+#endif /* CONFIG_WIFI_STATS */
+
+
 /**
  * hostapd_setup_interface - Setup of an interface
  * @iface: Pointer to interface data.
@@ -3006,6 +3054,20 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
 		return -1;
 	}
 
+#ifdef CONFIG_WIFI_STATS
+	if (!iface->wifi_stats)
+		iface->wifi_stats = wifi_stats_init();
+	if (!iface->wifi_stats) {
+		wpa_printf(MSG_WARNING,
+			   "wifi_stats: failed to allocate context, continuing without stats");
+	} else {
+		hostapd_reload_wifi_stats_config(iface);
+		if (wifi_stats_start_timer(iface->wifi_stats, iface) != 0)
+			wpa_printf(MSG_WARNING,
+				   "wifi_stats: Failed to start timer");
+	}
+#endif /* CONFIG_WIFI_STATS */
+
 	return 0;
 }
 
@@ -3107,6 +3169,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
 	hostapd_stop_setup_timers(iface);
 	eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
 #endif /* NEED_AP_MLME */
+
+#ifdef CONFIG_WIFI_STATS
+	if (iface->wifi_stats) {
+		wifi_stats_deinit(iface->wifi_stats);
+		iface->wifi_stats = NULL;
+	}
+#endif /* CONFIG_WIFI_STATS */
 }
 
 
@@ -3717,6 +3786,10 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
 	for (j = 0; j < hapd_iface->num_bss; j++)
 		hostapd_reload_bss(hapd_iface->bss[j]);
 
+#ifdef CONFIG_WIFI_STATS
+	hostapd_reload_wifi_stats_config(hapd_iface);
+#endif /* CONFIG_WIFI_STATS */
+
 	return 0;
 }
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 0c3ea700f..0949f34f0 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -40,6 +40,10 @@ struct rsn_pmksa_cache_entry;
 struct mesh_conf;
 #endif /* CONFIG_MESH */
 
+#ifdef CONFIG_WIFI_STATS
+struct wifi_stats_ctx;
+#endif /* CONFIG_WIFI_STATS */
+
 #ifdef CONFIG_CTRL_IFACE_UDP
 #define CTRL_IFACE_COOKIE_LEN 8
 #endif /* CONFIG_CTRL_IFACE_UDP */
@@ -795,6 +799,10 @@ struct hostapd_iface {
 		bool data_valid;
 	} afc;
 #endif /* CONFIG_AFC */
+
+#ifdef CONFIG_WIFI_STATS
+	struct wifi_stats_ctx *wifi_stats;
+#endif /* CONFIG_WIFI_STATS */
 };
 
 /* hostapd.c */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 40d941cef..a1c499199 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -39,6 +39,9 @@
 #include "sta_info.h"
 #include "vlan.h"
 #include "wps_hostapd.h"
+#ifdef CONFIG_WIFI_STATS
+#include "wifi_stats/wifi_stats.h"
+#endif /* CONFIG_WIFI_STATS */
 #include "robust_av.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
@@ -526,7 +529,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 #endif /* CONFIG_PASN */
 
 #ifdef CONFIG_WIFI_STATS
-	sta->wifi_stats = NULL;
+	if (hapd->iface && hapd->iface->wifi_stats)
+		wifi_stats_forget_sta(hapd->iface->wifi_stats, sta->addr);
 #endif /* CONFIG_WIFI_STATS */
 
 	os_free(sta->ifname_wds);
-- 
2.43.0




More information about the Hostap mailing list