]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Process QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH after NL80211_CMD_ROAM
authorPurushottam Kushwaha <pkushwah@codeaurora.org>
Fri, 27 Nov 2020 10:23:33 +0000 (15:53 +0530)
committerJouni Malinen <j@w1.fi>
Mon, 21 Dec 2020 20:57:42 +0000 (22:57 +0200)
NL80211_CMD_ROAM indication is scheduled via a kernel work queue, while
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH is a vendor event from the
driver. Thus, a race condition can exist wherein the vendor event is
received prior to the NL80211_CMD_ROAM indication.

The processing of this vendor event depends on the NL80211_CMD_ROAM
indication to update the roamed BSS/BSSID information and thus the out
of sequence processing of these events would result in not updating the
right BSS information.

This commit adds a workaround to hold the pending
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH event for up to 100 ms in
case NL80211_CMD_ROAM is not received first.

Signed-off-by: Purushottam Kushwaha <pkushwah@codeaurora.org>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_event.c

index 448c404f303b7035f2f78b76db31da8093137b6e..64544e09d4c0332690e98c12680be869b0c40dbb 100644 (file)
@@ -2986,6 +2986,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                os_free(drv->iface_ext_capa[i].ext_capa_mask);
        }
        os_free(drv->first_bss);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+       os_free(drv->pending_roam_data);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
        os_free(drv);
 }
 
@@ -6187,6 +6190,9 @@ skip_auth_type:
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
        } else {
+#ifdef CONFIG_DRIVER_NL80211_QCA
+               drv->roam_indication_done = false;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
                wpa_printf(MSG_DEBUG,
                           "nl80211: Connect request send successfully");
        }
index 4009545fa2d97ccb67a2aced35a53e0ce3cd6a9b..08e82dfa970a3a25f4201f320472b1b4b34d8bce 100644 (file)
@@ -221,6 +221,12 @@ struct wpa_driver_nl80211_data {
         * (NL80211_CMD_VENDOR). 0 if no pending scan request.
         */
        int last_scan_cmd;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+       bool roam_indication_done;
+       u8 *pending_roam_data;
+       size_t pending_roam_data_len;
+       struct os_reltime pending_roam_ind_time;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
 };
 
 struct nl_msg;
index 3af13f4109695f90970aa9b82bd9f65e16505711..982bd56734d9d33a5c1d5e8c13da5c0ed570361d 100644 (file)
@@ -2072,6 +2072,27 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void
+qca_nl80211_key_mgmt_auth_handler(struct wpa_driver_nl80211_data *drv,
+                                 const u8 *data, size_t len)
+{
+       if (!drv->roam_indication_done) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Pending roam indication, delay processing roam+auth vendor event");
+               os_get_reltime(&drv->pending_roam_ind_time);
+
+               os_free(drv->pending_roam_data);
+               drv->pending_roam_data = os_memdup(data, len);
+               if (!drv->pending_roam_data)
+                       return;
+               drv->pending_roam_data_len = len;
+               return;
+       }
+       drv->roam_indication_done = false;
+       qca_nl80211_key_mgmt_auth(drv, data, len);
+}
+
+
 static void qca_nl80211_dfs_offload_radar_event(
        struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
 {
@@ -2329,7 +2350,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
                qca_nl80211_avoid_freq(drv, data, len);
                break;
        case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
-               qca_nl80211_key_mgmt_auth(drv, data, len);
+               qca_nl80211_key_mgmt_auth_handler(drv, data, len);
                break;
        case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
                qca_nl80211_acs_select_ch(drv, data, len);
@@ -2721,17 +2742,36 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
                   cmd, nl80211_command_to_string(cmd), bss->ifname);
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
        if (cmd == NL80211_CMD_ROAM &&
            (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+               if (drv->pending_roam_data) {
+                       struct os_reltime now, age;
+
+                       os_get_reltime(&now);
+                       os_reltime_sub(&now, &drv->pending_roam_ind_time, &age);
+                       if (age.sec == 0 && age.usec < 100000) {
+                               wpa_printf(MSG_DEBUG,
+                                          "nl80211: Process pending roam+auth vendor event");
+                               qca_nl80211_key_mgmt_auth(
+                                       drv, drv->pending_roam_data,
+                                       drv->pending_roam_data_len);
+                       }
+                       os_free(drv->pending_roam_data);
+                       drv->pending_roam_data = NULL;
+                       return;
+               }
                /*
                 * Device will use roam+auth vendor event to indicate
                 * roaming, so ignore the regular roam event.
                 */
+               drv->roam_indication_done = true;
                wpa_printf(MSG_DEBUG,
                           "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
                           cmd);
                return;
        }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
 
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||