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:

committed by
Madan Koyyalamudi

parent
eddc343b43
commit
08c3b4d0b8
@@ -2347,7 +2347,8 @@ cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
|
|||||||
* @cm_ctx: connection manager context
|
* @cm_ctx: connection manager context
|
||||||
* @cm_id: cm id
|
* @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
|
* 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)
|
if (prefix != CONNECT_REQ_PREFIX)
|
||||||
return is_reassoc;
|
return is_reassoc;
|
||||||
|
|
||||||
cm_req_lock_acquire(cm_ctx);
|
|
||||||
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
||||||
while (cur_node) {
|
while (cur_node) {
|
||||||
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_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->cm_id == cm_id) {
|
||||||
if (cm_req->connect_req.req.reassoc_in_non_connected)
|
if (cm_req->connect_req.req.reassoc_in_non_connected)
|
||||||
is_reassoc = true;
|
is_reassoc = true;
|
||||||
cm_req_lock_release(cm_ctx);
|
|
||||||
return is_reassoc;
|
return is_reassoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_node = next_node;
|
cur_node = next_node;
|
||||||
next_node = NULL;
|
next_node = NULL;
|
||||||
}
|
}
|
||||||
cm_req_lock_release(cm_ctx);
|
|
||||||
|
|
||||||
return is_reassoc;
|
return is_reassoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
|
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;
|
enum wlan_cm_sm_state sm_state;
|
||||||
|
|
||||||
@@ -2398,13 +2397,19 @@ QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
|
|||||||
* kernel flags
|
* kernel flags
|
||||||
*/
|
*/
|
||||||
if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
|
if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
|
||||||
sm_state == WLAN_CM_S_INIT &&
|
sm_state == WLAN_CM_S_INIT) {
|
||||||
cm_is_connect_id_reassoc_in_non_connected(cm_ctx, resp->cm_id)) {
|
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;
|
resp->send_disconnect = true;
|
||||||
mlme_debug(CM_PREFIX_FMT "Set send disconnect to true to indicate disconnect instead of connect resp",
|
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),
|
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
|
||||||
resp->cm_id));
|
resp->cm_id));
|
||||||
}
|
}
|
||||||
|
if (acquire_lock)
|
||||||
|
cm_req_lock_release(cm_ctx);
|
||||||
|
}
|
||||||
mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
|
mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
|
||||||
cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
|
cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
|
||||||
resp->connect_status);
|
resp->connect_status);
|
||||||
@@ -2446,7 +2451,7 @@ QDF_STATUS cm_connect_complete(struct cnx_mgr *cm_ctx,
|
|||||||
send_ind = false;
|
send_ind = false;
|
||||||
|
|
||||||
if (send_ind)
|
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 */
|
/* Update scan entry in case connect is success or fails with bssid */
|
||||||
if (!qdf_is_macaddr_zero(&resp->bssid)) {
|
if (!qdf_is_macaddr_zero(&resp->bssid)) {
|
||||||
|
@@ -226,13 +226,16 @@ QDF_STATUS cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
|
|||||||
* connect response notification
|
* connect response notification
|
||||||
* @cm_ctx: connection manager context
|
* @cm_ctx: connection manager context
|
||||||
* @resp: connection complete resp.
|
* @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
|
* This API would be called after connection completion resp from VDEV mgr
|
||||||
*
|
*
|
||||||
* Return: QDF status
|
* Return: QDF status
|
||||||
*/
|
*/
|
||||||
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
|
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
|
* cm_connect_complete() - This API would be called after connect complete
|
||||||
* request from the serialization.
|
* request from the serialization.
|
||||||
|
@@ -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 */
|
/* Get bssid and ssid and freq for the cm id from the req list */
|
||||||
cm_fill_connect_resp_from_req(resp, cm_req);
|
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);
|
qdf_mem_free(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user