]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Update hw_mode when CSA finishes
authorNijun Gong <quic_ngong@quicinc.com>
Mon, 10 Jul 2023 13:19:29 +0000 (21:19 +0800)
committerJouni Malinen <j@w1.fi>
Wed, 30 Aug 2023 13:37:37 +0000 (16:37 +0300)
The driver might decide to change the operating band on its own, e.g.,
when trying to use a single channel in AP + AP case. A CSA event will be
notified to hostapd to update the channel/frequency, but hw_mode did not
get updated accordingly.

This may cause hostapd interface restarting to fail, e.g., with control
interface DISABLE / ENABLE commands at configured_fixed_chan_to_freq(),
because of the mismatch between conf->channel and conf->hw_mode.

Update hw_mode right after channel change to fix this.

Signed-off-by: ngong <quic_ngong@quicinc.com>
src/ap/drv_callbacks.c
src/ap/hw_features.c
src/ap/hw_features.h

index 5bc8402dbf82bf3769edcb63c4b9ce0383cc44c3..0516213f44f3583ec791a69de59df6ebe99bbad6 100644 (file)
@@ -1085,6 +1085,12 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
                break;
        }
 
+       /* The operating channel changed when CSA finished, so need to update
+        * hw_mode for all following operations to cover the cases where the
+        * driver changed the operating band. */
+       if (finished && hostapd_csa_update_hwmode(hapd->iface))
+               return;
+
        switch (hapd->iface->current_mode->mode) {
        case HOSTAPD_MODE_IEEE80211A:
                if (cf1 == 5935)
index 2fcc437d3709024e3190479a1c614c24d07ec231..9edbb5ae214d00d92b903cbd2404f8654fe91033 100644 (file)
@@ -1079,14 +1079,14 @@ static bool skip_mode(struct hostapd_iface *iface,
 }
 
 
-void hostapd_determine_mode(struct hostapd_iface *iface)
+int hostapd_determine_mode(struct hostapd_iface *iface)
 {
        int i;
        enum hostapd_hw_mode target_mode;
 
        if (iface->current_mode ||
            iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
-               return;
+               return 0;
 
        if (iface->freq < 4000)
                target_mode = HOSTAPD_MODE_IEEE80211G;
@@ -1109,8 +1109,11 @@ void hostapd_determine_mode(struct hostapd_iface *iface)
                }
        }
 
-       if (!iface->current_mode)
-               wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
+       if (!iface->current_mode) {
+               wpa_printf(MSG_ERROR, "ACS/CSA: Cannot decide mode");
+               return -1;
+       }
+       return 0;
 }
 
 
@@ -1215,6 +1218,25 @@ out:
 }
 
 
+/**
+ * hostapd_csa_update_hwmode - Update hardware mode
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, < 0 on failure
+ *
+ * Update hardware mode when the operating channel changed because of CSA.
+ */
+int hostapd_csa_update_hwmode(struct hostapd_iface *iface)
+{
+       if (!iface || !iface->conf)
+               return -1;
+
+       iface->current_mode = NULL;
+       iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
+
+       return hostapd_determine_mode(iface);
+}
+
+
 /**
  * hostapd_select_hw_mode - Select the hardware mode
  * @iface: Pointer to interface data.
index 092941f77a2e0fd1933eb5ee34ddcdc40a08c1c7..c682c6d20b817c6ba68be348c1b3c46e5f9be7ce 100644 (file)
@@ -15,6 +15,7 @@
 void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
                              size_t num_hw_features);
 int hostapd_get_hw_features(struct hostapd_iface *iface);
+int hostapd_csa_update_hwmode(struct hostapd_iface *iface);
 int hostapd_acs_completed(struct hostapd_iface *iface, int err);
 int hostapd_select_hw_mode(struct hostapd_iface *iface);
 const char * hostapd_hw_mode_txt(int mode);
@@ -28,7 +29,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
 void hostapd_stop_setup_timers(struct hostapd_iface *iface);
 int hostapd_hw_skip_mode(struct hostapd_iface *iface,
                         struct hostapd_hw_modes *mode);
-void hostapd_determine_mode(struct hostapd_iface *iface);
+int hostapd_determine_mode(struct hostapd_iface *iface);
 #else /* NEED_AP_MLME */
 static inline void
 hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -41,6 +42,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
        return -1;
 }
 
+static inline int hostapd_csa_update_hwmode(struct hostapd_iface *iface)
+{
+       return 0;
+}
+
 static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
 {
        return -1;
@@ -92,8 +98,9 @@ static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
        return 0;
 }
 
-static inline void hostapd_determine_mode(struct hostapd_iface *iface)
+static inline int hostapd_determine_mode(struct hostapd_iface *iface)
 {
+       return 0;
 }
 
 #endif /* NEED_AP_MLME */