Procházet zdrojové kódy

qcacmn: Fix race condition of mlo disconnect/connect

Currently, link vdev is triggered to connect process
after assoc vdev connects successfully in function
mlo_send_link_connect. If osif_cm_disconnect_sync is
invoked during assoc vdev connection, the disconnect
command for link vdev is dropped since it is in INIT
state. Then it only queues the disconnect command for
assoc vdev. After link vdev connects successfully, it
process the disconnect command for assoc vdev, and F/W
assert happens because deleting assoc peer before link
peer.

To resolve the issue, invoking wlan_cm_disconnect with
source CM_MLO_LINK_VDEV_DISCONNECT for each link vdev
in function cm_disconnect_start for assoc vdev.

Change-Id: Id0d0607d4374ed48513f15e5e3f5dfe499087935
CRs-Fixed: 3346737
Paul Zhang před 2 roky
rodič
revize
a4660a051d

+ 4 - 4
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -228,10 +228,6 @@ static QDF_STATUS cm_ser_disconnect_req(struct wlan_objmgr_pdev *pdev,
 	cmd.cmd_timeout_duration = DISCONNECT_TIMEOUT;
 	cmd.vdev = cm_ctx->vdev;
 	cmd.is_blocking = cm_ser_get_blocking_cmd();
-	if (wlan_vdev_mlme_is_link_sta_vdev(cmd.vdev)) {
-		mlme_debug("Set link dev disconnect cmd as high priority");
-		cmd.is_high_priority = true;
-	}
 
 	ser_cmd_status = wlan_serialization_request(&cmd);
 	switch (ser_cmd_status) {
@@ -325,6 +321,10 @@ QDF_STATUS cm_disconnect_start(struct cnx_mgr *cm_ctx,
 		cm_send_disconnect_resp(cm_ctx, req->cm_id);
 		return QDF_STATUS_E_INVAL;
 	}
+
+	if (wlan_vdev_mlme_is_mlo_vdev(cm_ctx->vdev))
+		mlo_internal_disconnect_links(cm_ctx->vdev);
+
 	cm_vdev_scan_cancel(pdev, cm_ctx->vdev);
 	mlme_cm_disconnect_start_ind(cm_ctx->vdev, &req->req);
 	cm_if_mgr_inform_disconnect_start(cm_ctx->vdev);

+ 13 - 31
umac/mlo_mgr/src/wlan_mlo_mgr_sta.c

@@ -820,17 +820,12 @@ static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg)
 
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	sta_ctx = mlo_dev_ctx->sta_ctx;
-	if (sta_ctx->disconn_req) {
-		mlo_disconnect(vdev, sta_ctx->disconn_req->source,
-			       sta_ctx->disconn_req->reason_code,
-			       &sta_ctx->disconn_req->bssid);
-		qdf_mem_free(sta_ctx->disconn_req);
-		sta_ctx->disconn_req = NULL;
-	} else {
-		mlo_disconnect(vdev, CM_MLME_DISCONNECT,
-			       REASON_DEAUTH_NETWORK_LEAVING,
-			       NULL);
-	}
+	mlo_disconnect(vdev, sta_ctx->disconn_req->source,
+		       sta_ctx->disconn_req->reason_code,
+		       &sta_ctx->disconn_req->bssid);
+
+	qdf_mem_free(sta_ctx->disconn_req);
+	sta_ctx->disconn_req = NULL;
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
 
 	return QDF_STATUS_SUCCESS;
@@ -959,7 +954,6 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 {
 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
 	struct wlan_mlo_sta *sta_ctx = NULL;
-	struct wlan_objmgr_vdev *assoc_vdev;
 
 	if (mlo_dev_ctx) {
 		sta_ctx = mlo_dev_ctx->sta_ctx;
@@ -975,18 +969,6 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 		return;
 	}
 
-	assoc_vdev = mlo_get_assoc_link_vdev(vdev->mlo_dev_ctx);
-	if (assoc_vdev && QDF_IS_STATUS_SUCCESS(rsp->connect_status) &&
-	    !wlan_cm_is_vdev_connected(assoc_vdev)) {
-		mlo_debug("Handle pending disconnect for vdev %d",
-			  wlan_vdev_get_id(vdev));
-		if (assoc_vdev != vdev)
-			mlo_disconnect(vdev, CM_MLME_DISCONNECT,
-				       REASON_DEAUTH_NETWORK_LEAVING,
-				       NULL);
-		return;
-	}
-
 	if (wlan_cm_is_vdev_disconnected(vdev))
 		mlo_free_copied_conn_req(sta_ctx);
 
@@ -1048,19 +1030,19 @@ mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
 			      enum wlan_reason_code reason_code,
 			      struct qdf_mac_addr *bssid)
 {
-	uint8_t i = 0;
+	uint8_t i;
 	struct wlan_objmgr_vdev *assoc_vdev =
 			mlo_get_assoc_link_vdev(mlo_dev_ctx);
 
 	if (!assoc_vdev)
 		return QDF_STATUS_E_FAILURE;
 
-	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
 		if (!mlo_dev_ctx->wlan_vdev_list[i])
 			continue;
 
 		if (mlo_dev_ctx->wlan_vdev_list[i] !=
-				mlo_get_assoc_link_vdev(mlo_dev_ctx))
+		    mlo_get_assoc_link_vdev(mlo_dev_ctx))
 			wlan_cm_disconnect_sync(mlo_dev_ctx->wlan_vdev_list[i],
 						source, reason_code);
 	}
@@ -1829,11 +1811,11 @@ void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev)
 
 	mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
 	for (i =  0; i < vdev_count; i++) {
-		if (qdf_test_bit(i, sta_ctx->wlan_connected_links) &&
-		    wlan_vdev_list[i] !=
-		    mlo_get_assoc_link_vdev(mlo_dev_ctx))
+		if (wlan_vdev_list[i] != mlo_get_assoc_link_vdev(mlo_dev_ctx) &&
+		    (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) ||
+		     wlan_cm_is_vdev_connecting(wlan_vdev_list[i])))
 			wlan_cm_disconnect(wlan_vdev_list[i],
-					   CM_INTERNAL_DISCONNECT,
+					   CM_MLO_LINK_VDEV_DISCONNECT,
 					   REASON_UNSPEC_FAILURE,
 					   NULL);
 		mlo_release_vdev_ref(wlan_vdev_list[i]);