]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Skip CAC if the driver switches channel to non-DFS
authorQiwei Cai <quic_qcai@quicinc.com>
Wed, 9 Nov 2022 11:46:04 +0000 (19:46 +0800)
committerJouni Malinen <j@w1.fi>
Wed, 23 Nov 2022 16:32:46 +0000 (18:32 +0200)
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>
src/ap/drv_callbacks.c

index a673fae09c93a0fc831b5e4458f179c43c861a85..19a3afcb8d7a306cb569f31a703ba844e2afd3ff 100644 (file)
@@ -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 &&