From 74818ca63f7ec9f9ad7c588772172393c7271b1a Mon Sep 17 00:00:00 2001 From: Purushottam Kushwaha Date: Fri, 27 Nov 2020 15:53:33 +0530 Subject: [PATCH] Process QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH after NL80211_CMD_ROAM 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 --- src/drivers/driver_nl80211.c | 6 +++++ src/drivers/driver_nl80211.h | 6 +++++ src/drivers/driver_nl80211_event.c | 42 +++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 448c404f3..64544e09d 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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"); } diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 4009545fa..08e82dfa9 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -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; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 3af13f410..982bd5673 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -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 ||