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

Raja Mani raja.mani at oss.qualcomm.com
Sat Nov 15 05:47:14 PST 2025



On 10/17/2025 7:35 PM, Benjamin Berg wrote:
> 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)

I hope, the intention here is to move the survey data for the matching
frequency. Shouldn't it be done this way ?

	if (new_chan->freq != old_chan->freq)
		continue;

> +				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",




More information about the Hostap mailing list