From b6c38cee93e312635576d47fea87b86c78e553b8 Mon Sep 17 00:00:00 2001 From: Qiwei Cai Date: Wed, 9 Nov 2022 19:46:04 +0800 Subject: [PATCH] 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 --- src/ap/drv_callbacks.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index a673fae09..19a3afcb8 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -862,14 +862,16 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, int finished) { #ifdef NEED_AP_MLME - int channel, chwidth, is_dfs; + int channel, chwidth, is_dfs0, is_dfs; u8 seg0_idx = 0, seg1_idx = 0; size_t i; hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 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", + hapd->iface->freq, freq, ht, hapd->iconf->ch_switch_vht_config, hapd->iconf->ch_switch_he_config, 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; } + /* Check if any of configured channels require DFS */ + is_dfs0 = hostapd_is_dfs_required(hapd->iface); hapd->iface->freq = 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); 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 : WPA_EVENT_CHANNEL_SWITCH_STARTED, freq, ht, offset, channel_width_to_string(width), - cf1, cf2, is_dfs); + cf1, cf2, is_dfs0, is_dfs); if (!finished) 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 "freq=%d dfs=%d", freq, is_dfs); } 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 "freq=%d dfs=%d", freq, is_dfs); } else if (is_dfs &&