Skip CAC if the driver switches channel to non-DFS

If an AP is started on a DFS channel (or any channels within its
bandwidth require DFS) and DFS is offloaded to the driver, hostapd needs
to wait for CAC to complete. But the driver may not do CAC and just
switches to a non-DFS channel instead. This would result in a failure to
start the AP because hostapd fails to receive a CAC complete event and
cannot finish interface setup.

Skip CAC and complete AP setup in the channel switch event handler for
this case.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Qiwei Cai 2022-11-09 19:46:04 +08:00 committed by Jouni Malinen
parent 080afc03d5
commit b6c38cee93

View file

@ -862,14 +862,16 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int finished) int finished)
{ {
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
int channel, chwidth, is_dfs; int channel, chwidth, is_dfs0, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0; u8 seg0_idx = 0, seg1_idx = 0;
size_t i; size_t i;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, HOSTAPD_LEVEL_INFO,
"driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", "driver %s channel switch: iface->freq=%d, freq=%d, ht=%d, vht_ch=0x%x, "
"he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting", finished ? "had" : "starting",
hapd->iface->freq,
freq, ht, hapd->iconf->ch_switch_vht_config, freq, ht, hapd->iconf->ch_switch_vht_config,
hapd->iconf->ch_switch_he_config, hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_eht_config, offset, hapd->iconf->ch_switch_eht_config, offset,
@ -882,6 +884,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
return; return;
} }
/* Check if any of configured channels require DFS */
is_dfs0 = hostapd_is_dfs_required(hapd->iface);
hapd->iface->freq = freq; hapd->iface->freq = freq;
channel = hostapd_hw_get_channel(hapd, freq); channel = hostapd_hw_get_channel(hapd, freq);
@ -997,11 +1001,11 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hapd->iface->num_hw_features); hapd->iface->num_hw_features);
wpa_msg(hapd->msg_ctx, MSG_INFO, wpa_msg(hapd->msg_ctx, MSG_INFO,
"%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d", "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d is_dfs0=%d dfs=%d",
finished ? WPA_EVENT_CHANNEL_SWITCH : finished ? WPA_EVENT_CHANNEL_SWITCH :
WPA_EVENT_CHANNEL_SWITCH_STARTED, WPA_EVENT_CHANNEL_SWITCH_STARTED,
freq, ht, offset, channel_width_to_string(width), freq, ht, offset, channel_width_to_string(width),
cf1, cf2, is_dfs); cf1, cf2, is_dfs0, is_dfs);
if (!finished) if (!finished)
return; return;
@ -1013,6 +1017,14 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs); "freq=%d dfs=%d", freq, is_dfs);
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
/* Complete AP configuration for the first bring up. */
if (is_dfs0 > 0 &&
hostapd_is_dfs_required(hapd->iface) <= 0 &&
hapd->iface->state != HAPD_IFACE_ENABLED) {
/* Fake a CAC start bit to skip setting channel */
hapd->iface->cac_started = 1;
hostapd_setup_interface_complete(hapd->iface, 0);
}
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs); "freq=%d dfs=%d", freq, is_dfs);
} else if (is_dfs && } else if (is_dfs &&