qcacld-3.0: Fix race condition between connect and disconnect

Scenario: In case of STA + STA, NB/SB issues disconnection for
vdev 0 when vdev 1 is in connecting state.

As connection is blocking serialization command and it can try
multiple candidates and can take upto 30+ sec, there is a
chance that disconnect may get timeout and is followed by
vdev delete from osif. This can lead to vdev delete sent
without vdev down/stop and bss peer delete for vdev 0.

So abort connection when trying for candidate if any of the
vdev is waiting for disconnect, to avoid disconnect timeout.

Change-Id: I876550532524767e811c9fd03e85e16d6a90b940
CRs-Fixed: 3049934
This commit is contained in:
abhinav kumar 2021-09-30 13:55:08 +05:30 • committed by Madan Koyyalamudi
commit 2033fd4633
2 changed files with 55 additions and 2 deletions

View file

@ -8471,6 +8471,11 @@ QDF_STATUS csr_roam_disconnect(struct mac_context *mac_ctx, uint32_t session_id,
|| CSR_IS_CONN_NDI(&session->connectedProfile)) {
status = csr_roam_issue_disassociate_cmd(mac_ctx, session_id,
reason, mac_reason);
} else if (csr_is_deauth_disassoc_already_active(mac_ctx, session_id,
session->connectedProfile.bssid)) {
/* Return success if Disconnect is already in progress */
sme_debug("Disconnect already in queue return success");
status = QDF_STATUS_SUCCESS;
} else if (session->scan_info.profile) {
mac_ctx->roam.roamSession[session_id].connectState =
eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING;
@ -8670,6 +8675,37 @@ bool is_disconnect_pending(struct mac_context *pmac, uint8_t vdev_id)
return disconnect_cmd_exist;
}
bool is_disconnect_pending_on_other_vdev(struct mac_context *pmac,
uint8_t vdev_id)
{
tListElem *entry = NULL;
tListElem *next_entry = NULL;
tSmeCmd *command = NULL;
bool disconnect_cmd_exist = false;
entry = csr_nonscan_pending_ll_peek_head(pmac, LL_ACCESS_NOLOCK);
while (entry) {
next_entry = csr_nonscan_pending_ll_next(pmac, entry,
LL_ACCESS_NOLOCK);
command = GET_BASE_ADDR(entry, tSmeCmd, Link);
/*
* check if any other vdev NB disconnect or SB disconnect
* (eSmeCommandWmStatusChange) is pending
*/
if (command && (CSR_IS_DISCONNECT_COMMAND(command) ||
command->command == eSmeCommandWmStatusChange) &&
command->vdev_id != vdev_id) {
sme_debug("disconnect is pending on vdev:%d, cmd:%d",
command->vdev_id, command->command);
disconnect_cmd_exist = true;
break;
}
entry = next_entry;
}
return disconnect_cmd_exist;
}
#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
static void
csr_clear_other_bss_sae_single_pmk_entry(struct mac_context *mac,
@ -8789,7 +8825,7 @@ static void csr_roam_join_rsp_processor(struct mac_context *mac,
struct csr_roam_connectedinfo *prev_connect_info;
struct wlan_crypto_pmksa *pmksa;
uint32_t len = 0, roamId = 0, reason_code = 0;
bool is_dis_pending;
bool is_dis_pending, is_dis_pending_on_other_vdev;
bool use_same_bss = false;
uint8_t max_retry_count = 1;
bool retry_same_bss = false;
@ -8893,6 +8929,9 @@ static void csr_roam_join_rsp_processor(struct mac_context *mac,
reason_code);
is_dis_pending = is_disconnect_pending(mac, session_ptr->sessionId);
is_dis_pending_on_other_vdev =
is_disconnect_pending_on_other_vdev(mac,
session_ptr->sessionId);
is_time_allowed =
csr_is_time_allowed_for_connect_attempt(pCommand,
session_ptr->vdev_id);
@ -8901,7 +8940,7 @@ static void csr_roam_join_rsp_processor(struct mac_context *mac,
* if userspace has issued disconnection or we have reached mac tries or
* max time, driver should not continue for next connection.
*/
if (is_dis_pending || !is_time_allowed ||
if (is_dis_pending || is_dis_pending_on_other_vdev || !is_time_allowed ||
session_ptr->join_bssid_count >= CSR_MAX_BSSID_COUNT)
attempt_next_bss = false;
@ -9017,6 +9056,9 @@ static void csr_roam_join_rsp_processor(struct mac_context *mac,
if (is_dis_pending)
sme_err("disconnect is pending, complete roam");
if (is_dis_pending_on_other_vdev)
sme_err("disconnect is pending on other vdev, complete roam");
if (!is_time_allowed)
sme_err("time can exceed the active timeout for connection attempt");

View file

@ -974,6 +974,17 @@ csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle,
bool is_disconnect_pending(struct mac_context *mac_ctx,
uint8_t sessionid);
/**
* is_disconnect_pending_on_other_vdev() - To check whether a disconnect req
* is pending on any other vdev or not
* @mac_tx: mac context
* @sessionid: session id
*
* Return true if disconnect is pending on any other vdev
*/
bool is_disconnect_pending_on_other_vdev(struct mac_context *mac_ctx,
uint8_t sessionid);
QDF_STATUS
csr_roam_prepare_bss_config_from_profile(struct mac_context *mac_ctx,
struct csr_roam_profile *profile,