[PATCH 2/2] AP: Keep channel survey over regulatory changes

Benjamin Berg benjamin at sipsolutions.net
Fri Oct 17 07:05:04 PDT 2025


From: Benjamin Berg <benjamin.berg at intel.com>

When updatig the HW modes after a regulatory change, the internal lists
for the current survey would be lost, resulting in a crash when fetching
the survey results later on. This can happen if the regulatory changes
because of the ACS scan.

Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
Reviewed-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/ap/hw_features.c | 58 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 55 insertions(+), 3 deletions(-)

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 1f80bdd240..29edb2dd58 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -71,6 +71,47 @@ static char * dfs_info(struct hostapd_channel_data *chan)
 }
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
+static void move_survey_data(struct hostapd_channel_data *new_chan,
+			     struct hostapd_channel_data *old_chan)
+{
+	struct freq_survey *survey, *tmp;
+
+	/* Copy the survey list from old to new channel */
+	if (old_chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED) {
+		dl_list_init(&new_chan->survey_list);
+		dl_list_for_each_safe(survey, tmp, &old_chan->survey_list,
+				      struct freq_survey, list) {
+			dl_list_del(&survey->list);
+			dl_list_add(&new_chan->survey_list,
+				    &survey->list);
+		}
+		new_chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
+	}
+}
+
+static void move_hw_mode_data(struct hostapd_hw_modes *new_feature,
+			      struct hostapd_hw_modes *old_feature)
+{
+	int i, j;
+
+	for (i = 0; i < new_feature->num_channels; i++) {
+		struct hostapd_channel_data *new_chan;
+		struct hostapd_channel_data *old_chan;
+
+		new_chan = &new_feature->channels[i];
+
+		for (j = 0; j < old_feature->num_channels; j++) {
+			old_chan = &old_feature->channels[j];
+
+			if (new_chan->freq == old_chan->freq)
+				continue;
+
+			move_survey_data(new_chan, old_chan);
+
+			break;
+		}
+	}
+}
 
 int hostapd_get_hw_features(struct hostapd_iface *iface)
 {
@@ -113,9 +154,6 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
 		is_6ghz = iface->current_mode->is_6ghz;
 		iface->current_mode = NULL;
 	}
-	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
-	iface->hw_features = modes;
-	iface->num_hw_features = num_modes;
 
 	for (i = 0; i < num_modes; i++) {
 		struct hostapd_hw_modes *feature = &modes[i];
@@ -163,8 +201,22 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
 				   feature->channels[j].max_tx_power,
 				   dfs ? dfs_info(&feature->channels[j]) : "");
 		}
+
+		/* Move any old data that should be kept */
+		for (j = 0; j < iface->num_hw_features; j++) {
+			struct hostapd_hw_modes *old_feature =
+				&iface->hw_features[j];
+			if (feature->mode != old_feature->mode)
+				continue;
+
+			move_hw_mode_data(feature, old_feature);
+		}
 	}
 
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = modes;
+	iface->num_hw_features = num_modes;
+
 	if (orig_mode_valid && !iface->current_mode) {
 		wpa_printf(MSG_ERROR,
 			   "%s: Could not update iface->current_mode",
-- 
2.51.0




More information about the Hostap mailing list