Update iface->current_mode when fetching new hw_features

When a CHANNEL_LIST_CHANGED event is received, memory of
iface->hw_features is freed and allocated again with
hostapd_get_hw_features(), but iface->current_mode still refer to the
original memory address, which is not correct since that memory has been
freed. This could happen in cases where the driver provides channel list
updates during the lifetime of the started BSS.

Fix this by updated iface->current_mode to point to the new array of hw
features.

Fixes: 0837863fbc ("AP: Handle 6 GHz AP state machine with NO_IR flags")
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Nijun Gong 2023-07-11 21:21:21 +08:00 committed by Jouni Malinen
parent 07d3c1177b
commit 1085e3bdc6

View file

@ -79,6 +79,9 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
u8 dfs_domain;
enum hostapd_hw_mode mode = HOSTAPD_MODE_IEEE80211ANY;
bool is_6ghz = false;
bool orig_mode_valid = false;
if (hostapd_drv_none(hapd))
return -1;
@ -95,6 +98,20 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
iface->hw_flags = flags;
iface->dfs_domain = dfs_domain;
if (iface->current_mode) {
/*
* Received driver event CHANNEL_LIST_CHANGED when the current
* hw mode is valid. Clear iface->current_mode temporarily as
* the mode instance will be replaced with a new instance and
* the current pointer would be pointing to freed memory.
*/
orig_mode_valid = true;
mode = iface->current_mode->mode;
is_6ghz = mode == HOSTAPD_MODE_IEEE80211A &&
iface->current_mode->num_channels > 0 &&
is_6ghz_freq(iface->current_mode->channels[0].freq);
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;
@ -104,6 +121,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
int dfs_enabled = hapd->iconf->ieee80211h &&
(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
/* Restore orignal mode if possible */
if (orig_mode_valid && feature->mode == mode &&
feature->num_channels > 0 &&
is_6ghz == is_6ghz_freq(feature->channels[0].freq))
iface->current_mode = feature;
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
@ -141,6 +164,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
}
}
if (orig_mode_valid && !iface->current_mode) {
wpa_printf(MSG_ERROR,
"%s: Could not update iface->current_mode",
__func__);
}
return 0;
}