qcacld-3.0: Fix race condition when disconnecting

Fix one more scenario which is not covered by the change
Ib6a30057469d60efcc905d97b5234ea5a0e097a8

For some timing issue, HDD conn state is set to disconnecting
after hdd_association_completion_handler is called. So
hddDisconInProgress is not set and disconnect_comp_var will not
be completed in hdd_association_completion_handler.

To fix this issue, QDF_STATUS_CMD_NOT_QUEUED should be set only
when scan for ssid is in progress, with pSession->scan_info.profile
we can check if scan for ssid is in progress. So set
QDF_STATUS_CMD_NOT_QUEUED only when pSession->scan_info.profile
is set.

Also if disconnect from LIM was already in progress (i.e.
csr_is_conn_state_connected and
csr_is_roam_command_waiting_for_session are false and
pSession->scan_info.profile is set), return failure and wait for
WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS ms for the disconnect
to be completed.

Change-Id: Ib490021775a39614646f8e518860c878cc0fdaae
CRs-Fixed: 2564992
This commit is contained in:
Min Liu 2019-11-12 15:53:27 +08:00 • committed by nshrivas
commit 818395d83e
2 changed files with 17 additions and 23 deletions

View file

@ -20810,31 +20810,25 @@ int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason)
status = sme_roam_disconnect(mac_handle,
adapter->vdev_id, reason);
if ((QDF_STATUS_CMD_NOT_QUEUED == status) &&
prev_conn_state != eConnectionState_Connecting) {
hdd_debug("status = %d, already disconnected", status);
result = 0;
/*
* Wait here instead of returning directly. This will block the
* next connect command and allow processing of the disconnect
* in SME else we might hit some race conditions leading to SME
* and HDD out of sync. As disconnect is already in progress,
* wait here for 1 sec instead of 5 sec.
*/
wait_time = WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS;
} else if (QDF_STATUS_CMD_NOT_QUEUED == status) {
if (QDF_STATUS_CMD_NOT_QUEUED == status &&
prev_conn_state == eConnectionState_Connecting) {
/*
* Wait here instead of returning directly, this will block the
* next connect command and allow processing of the scan for
* ssid and the previous connect command in CSR. Else we might
* hit some race conditions leading to SME and HDD out of sync.
* ssid and the previous connect command in CSR.
*/
hdd_debug("Already disconnected or connect was in sme/roam pending list and removed by disconnect");
} else if (0 != status) {
hdd_err("csr_roam_disconnect failure, status: %d", (int)status);
sta_ctx->sta_debug_state = status;
result = -EINVAL;
goto disconnected;
hdd_debug("CSR is not in connected state but scan for SSID is in progress, wait for scan to be aborted or completed.");
} else if (QDF_IS_STATUS_ERROR(status)) {
hdd_debug("status = %d, already disconnect in progress or SME is disconencted OR connect removed from pending queue",
status);
/*
* Wait here instead of returning directly. This will block the
* next connect command and allow processing of the disconnect
* in SME. As disconnect is already in progress, wait here for
* WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS instead of
* SME_DISCONNECT_TIMEOUT.
*/
wait_time = WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS;
}
wait_for_disconnect:
rc = wait_for_completion_timeout(&adapter->disconnect_comp_var,
@ -20844,7 +20838,6 @@ wait_for_disconnect:
hdd_err("Failed to disconnect, timed out");
result = -ETIMEDOUT;
}
disconnected:
hdd_conn_set_connection_state(adapter, eConnectionState_NotConnected);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
/* Sending disconnect event to userspace for kernel version < 3.11

View file

@ -9010,7 +9010,7 @@ QDF_STATUS csr_roam_issue_stop_bss_cmd(struct mac_context *mac, uint32_t session
QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessionId,
eCsrRoamDisconnectReason reason)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
QDF_STATUS status = QDF_STATUS_E_FAILURE;
struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId);
if (!pSession) {
@ -9026,7 +9026,7 @@ QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessio
sme_debug("called");
status = csr_roam_issue_disassociate_cmd(mac, sessionId,
reason);
} else {
} else if (pSession->scan_info.profile) {
mac->roam.roamSession[sessionId].connectState =
eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING;
csr_scan_abort_mac_scan(mac, sessionId, INVAL_SCAN_ID);
@ -9034,6 +9034,7 @@ QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessio
sme_debug("Disconnect cmd not queued, Roam command is not present return with status: %d",
status);
}
return status;
}