qcacmn: Fix dead lock in connection completion handler

Connection completion handler is called from two scenarios.
Scenario 1: Called via connection flush with lock held
cm_disconnect_complete()-->
cm_flush_pending_request() acquired lock here-->
cm_handle_connect_flush()-->
cm_notify_connect_complete()

Scenario 2: Called via connection response without lock held

In first scenario, cm_notify_connect_complete() calls
cm_is_connect_id_reassoc_in_non_connected() to check if connect
request is a reassoc req and received in not connected state.
This function tries to auqire same lock which leads to dead lock.

To fix this issue, check if cm_notify_connect_complete() is called
with lock held or not. If not, acquire lock and call
cm_is_connect_id_reassoc_in_non_connected().

This prevents dead lock in scenario 1 and allows calling
cm_is_connect_id_reassoc_in_non_connected() with lock held for
scenario 2.

CRs-Fixed: 3351119
Change-Id: I192090777cb2cf0d604e2670a317aaf6f320d086
This commit is contained in:
Shreedhar Parande
2022-12-10 15:54:24 +05:30
committed by Madan Koyyalamudi
parent eddc343b43
commit 08c3b4d0b8
3 changed files with 22 additions and 14 deletions

View File

@@ -2347,7 +2347,8 @@ cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
* @cm_ctx: connection manager context
* @cm_id: cm id
*
* If connect req is a reassoc req and received in not connected state
* If connect req is a reassoc req and received in not connected state.
* Caller should take cm_ctx lock.
*
* Return: bool
*/
@@ -2362,7 +2363,6 @@ static bool cm_is_connect_id_reassoc_in_non_connected(struct cnx_mgr *cm_ctx,
if (prefix != CONNECT_REQ_PREFIX)
return is_reassoc;
cm_req_lock_acquire(cm_ctx);
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
while (cur_node) {
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
@@ -2371,20 +2371,19 @@ static bool cm_is_connect_id_reassoc_in_non_connected(struct cnx_mgr *cm_ctx,
if (cm_req->cm_id == cm_id) {
if (cm_req->connect_req.req.reassoc_in_non_connected)
is_reassoc = true;
cm_req_lock_release(cm_ctx);
return is_reassoc;
}
cur_node = next_node;
next_node = NULL;
}
cm_req_lock_release(cm_ctx);
return is_reassoc;
}
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
struct wlan_cm_connect_resp *resp)
struct wlan_cm_connect_resp *resp,
bool acquire_lock)
{
enum wlan_cm_sm_state sm_state;
@@ -2398,13 +2397,19 @@ QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
* kernel flags
*/
if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
sm_state == WLAN_CM_S_INIT &&
cm_is_connect_id_reassoc_in_non_connected(cm_ctx, resp->cm_id)) {
sm_state == WLAN_CM_S_INIT) {
if (acquire_lock)
cm_req_lock_acquire(cm_ctx);
if (cm_is_connect_id_reassoc_in_non_connected(cm_ctx,
resp->cm_id)) {
resp->send_disconnect = true;
mlme_debug(CM_PREFIX_FMT "Set send disconnect to true to indicate disconnect instead of connect resp",
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
resp->cm_id));
}
if (acquire_lock)
cm_req_lock_release(cm_ctx);
}
mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
resp->connect_status);
@@ -2446,7 +2451,7 @@ QDF_STATUS cm_connect_complete(struct cnx_mgr *cm_ctx,
send_ind = false;
if (send_ind)
cm_notify_connect_complete(cm_ctx, resp);
cm_notify_connect_complete(cm_ctx, resp, 1);
/* Update scan entry in case connect is success or fails with bssid */
if (!qdf_is_macaddr_zero(&resp->bssid)) {

View File

@@ -226,13 +226,16 @@ QDF_STATUS cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
* connect response notification
* @cm_ctx: connection manager context
* @resp: connection complete resp.
* @acquire_lock: Flag to indicate whether this function needs
* cm_ctx lock or not.
*
* This API would be called after connection completion resp from VDEV mgr
*
* Return: QDF status
*/
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
struct wlan_cm_connect_resp *resp);
struct wlan_cm_connect_resp *resp,
bool acquire_lock);
/**
* cm_connect_complete() - This API would be called after connect complete
* request from the serialization.

View File

@@ -503,7 +503,7 @@ cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
/* Get bssid and ssid and freq for the cm id from the req list */
cm_fill_connect_resp_from_req(resp, cm_req);
cm_notify_connect_complete(cm_ctx, resp);
cm_notify_connect_complete(cm_ctx, resp, 0);
qdf_mem_free(resp);
}