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 <pkushwah@codeaurora.org>
This commit is contained in:
Purushottam Kushwaha 2020-11-27 15:53:33 +05:30 committed by Jouni Malinen
parent b4a41abad4
commit 74818ca63f
3 changed files with 53 additions and 1 deletions

View 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");
}

View 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;

View 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 ||