Переглянути джерело

qcacmn: Modify MLO disconnect handling

Modify MLO disconnect handling to issue disconnect on all links in
parallel
Also modify connect resp to accommodate ml info in connect resp

Change-Id: I57575c6ce7c8ebff7770f862dc81e7dfd20aa42d
Himanshu Batra 3 роки тому
батько
коміт
b21d96305e

+ 3 - 7
os_if/linux/mlme/src/osif_cm_connect_rsp.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2015, 2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -635,6 +636,7 @@ static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev,
 		assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev);
 		if (!assoc_vdev)
 			return;
+		qdf_mem_copy(&resp, rsp, sizeof(struct wlan_cm_connect_resp));
 		tmp_osif_priv  = wlan_vdev_get_ospriv(assoc_vdev);
 		freq = vdev->vdev_mlme.bss_chan->ch_freq;
 		wlan_vdev_get_bss_peer_mac(assoc_vdev, &macaddr);
@@ -649,19 +651,13 @@ static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev,
 		}
 		qdf_mem_copy(resp.bssid.bytes, macaddr.bytes,
 			     QDF_MAC_ADDR_SIZE);
-		qdf_mem_copy(resp.ssid.ssid, rsp->ssid.ssid,
-			     rsp->ssid.length);
-		resp.ssid.length = rsp->ssid.length;
 		resp.freq = freq;
-		resp.connect_status = rsp->connect_status;
-		resp.reason = rsp->reason;
-		resp.status_code = rsp->status_code;
 		resp.connect_ies.assoc_req.ptr = rsp->connect_ies.assoc_req.ptr;
 		resp.connect_ies.assoc_req.len = rsp->connect_ies.assoc_req.len;
 		resp.connect_ies.assoc_rsp.ptr = rsp->connect_ies.assoc_rsp.ptr;
 		resp.connect_ies.assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
 		if (osif_update_connect_results(tmp_osif_priv->wdev->netdev, bss,
-						&resp, vdev))
+						&resp, assoc_vdev))
 			osif_connect_bss(tmp_osif_priv->wdev->netdev, bss, &resp);
 	}
 }

+ 24 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -442,6 +443,7 @@ cm_inform_blm_disconnect_complete(struct wlan_objmgr_vdev *vdev,
 	wlan_blm_update_bssid_connect_params(pdev, resp->req.req.bssid,
 					     BLM_AP_DISCONNECTED);
 }
+
 #else
 static inline void
 cm_inform_blm_disconnect_complete(struct wlan_objmgr_vdev *vdev,
@@ -449,6 +451,27 @@ cm_inform_blm_disconnect_complete(struct wlan_objmgr_vdev *vdev,
 {}
 #endif
 
+#ifdef WLAN_FEATURE_11BE_MLO
+#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+static inline void
+cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
+{
+	wlan_vdev_mlme_feat_ext2_cap_clear(vdev, WLAN_VDEV_FEXT2_MLO);
+}
+#else /*WLAN_FEATURE_11BE_MLO_ADV_FEATURE*/
+static inline void
+cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
+{
+	if (mlo_is_mld_sta(vdev) && ucfg_mlo_is_mld_disconnected(vdev))
+		ucfg_mlo_mld_clear_mlo_cap(vdev);
+}
+#endif /*WLAN_FEATURE_11BE_MLO_ADV_FEATURE*/
+#else /*WLAN_FEATURE_11BE_MLO*/
+static inline void
+cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
+{ }
+#endif /*WLAN_FEATURE_11BE_MLO*/
+
 QDF_STATUS cm_notify_disconnect_complete(struct cnx_mgr *cm_ctx,
 					 struct wlan_cm_discon_rsp *resp)
 {
@@ -457,7 +480,7 @@ QDF_STATUS cm_notify_disconnect_complete(struct cnx_mgr *cm_ctx,
 	mlme_cm_osif_disconnect_complete(cm_ctx->vdev, resp);
 	cm_if_mgr_inform_disconnect_complete(cm_ctx->vdev);
 	cm_inform_blm_disconnect_complete(cm_ctx->vdev, resp);
-	wlan_vdev_mlme_feat_ext2_cap_clear(cm_ctx->vdev, WLAN_VDEV_FEXT2_MLO);
+	cm_clear_vdev_mlo_cap(cm_ctx->vdev);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 10 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_sta.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -121,6 +122,15 @@ bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev);
  * Return: true if mld is disconnected, false otherwise
  */
 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_mlo_mld_clear_mlo_cap - Clear MLO cap for all vdevs in MLD
+ *
+ * @vdev: pointer to vdev
+ *
+ * Return: None
+ */
+void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev);
 #endif
 
 /*

+ 258 - 206
umac/mlo_mgr/src/wlan_mlo_mgr_sta.c

@@ -26,6 +26,7 @@
 #include <wlan_cm_api.h>
 #include <wlan_mlo_mgr_cmn.h>
 #include <wlan_scan_api.h>
+#include <scheduler_api.h>
 
 #ifdef WLAN_FEATURE_11BE_MLO
 /**
@@ -195,6 +196,29 @@ bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
 	return mlo_is_mld_disconnected(vdev);
 }
 
+static inline
+void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
+	uint8_t i = 0;
+
+	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
+		return;
+
+	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (!mlo_dev_ctx->wlan_vdev_list[i])
+			continue;
+		wlan_vdev_mlme_feat_ext2_cap_clear(
+				mlo_dev_ctx->wlan_vdev_list[i],
+				WLAN_VDEV_FEXT2_MLO);
+	}
+}
+
+void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
+{
+	mlo_mld_clear_mlo_cap(vdev);
+}
+
 static void
 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev,
 					     struct wlan_cm_connect_req *req)
@@ -500,39 +524,117 @@ mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx,
 	}
 }
 
+static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
+
+	if (!vdev) {
+		mlme_err("Null input vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
+		       REASON_UNSPEC_FAILURE, NULL);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
+
+	if (!vdev) {
+		mlme_err("Null input vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+static inline
+QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
+{
+	return scheduler_post_message(
+			QDF_MODULE_ID_SYS,
+			QDF_MODULE_ID_SYS,
+			QDF_MODULE_ID_SYS,
+			msg);
+}
+#else
+static inline
+QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
+{
+	return scheduler_post_message(
+			QDF_MODULE_ID_MLME,
+			QDF_MODULE_ID_MLME,
+			QDF_MODULE_ID_MLME,
+			msg);
+}
+#endif
+
+static inline
+void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
+					 struct wlan_cm_connect_resp *rsp)
+{
+	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
+	struct wlan_mlo_sta *sta_ctx = NULL;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS ret;
+
+	if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
+		sta_ctx = mlo_dev_ctx->sta_ctx;
+		if (sta_ctx->orig_conn_req) {
+			mlo_free_connect_ies(
+				sta_ctx->orig_conn_req);
+			qdf_mem_free(sta_ctx->orig_conn_req);
+			sta_ctx->orig_conn_req = NULL;
+		}
+	} else {
+		mlo_update_connected_links(vdev, 0);
+		if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
+		    rsp->reason == CM_HW_MODE_FAILURE ||
+		    rsp->reason == CM_SER_FAILURE) {
+			ret = wlan_objmgr_vdev_try_get_ref(
+					vdev, WLAN_MLO_MGR_ID);
+			if (QDF_IS_STATUS_ERROR(ret)) {
+				mlo_err("Failed to get ref vdev_id %d",
+					wlan_vdev_get_id(vdev));
+				return;
+			}
+			/* Since these failures happen in same context. use
+			 * scheduler to avoid deadlock by deferring context
+			 */
+			msg.bodyptr = vdev;
+			msg.callback = ml_activate_disconnect_req_sched_cb;
+			msg.flush_callback =
+				ml_activate_disconnect_req_flush_cb;
+			mlo_post_disconnect_msg(&msg);
+			if (QDF_IS_STATUS_ERROR(ret)) {
+				wlan_objmgr_vdev_release_ref(
+						vdev,
+						WLAN_MLO_MGR_ID);
+				return;
+			}
+		} else {
+			mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
+				       REASON_UNSPEC_FAILURE, NULL);
+		}
+	}
+}
+
 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 				 struct wlan_cm_connect_resp *rsp)
 {
 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
-	struct wlan_mlo_sta *sta_ctx = NULL;
 
 	if (mlo_dev_ctx) {
 		mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
 		if (wlan_cm_is_vdev_disconnected(vdev)) {
-			// Connect Failure
-			if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
-				sta_ctx = mlo_dev_ctx->sta_ctx;
-				if (sta_ctx->orig_conn_req) {
-					mlo_free_connect_ies(
-							sta_ctx->orig_conn_req);
-					qdf_mem_free(sta_ctx->orig_conn_req);
-					sta_ctx->orig_conn_req = NULL;
-				}
-				return;
-			} else {
-				mlo_update_connected_links(vdev, 0);
-				if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
-				    rsp->reason == CM_HW_MODE_FAILURE ||
-				    rsp->reason == CM_SER_FAILURE)
-					mlo_disconnect_no_lock(
-						vdev, CM_OSIF_DISCONNECT,
-						REASON_UNSPEC_FAILURE, NULL);
-				else
-					mlo_disconnect(
-						vdev, CM_OSIF_DISCONNECT,
-						REASON_UNSPEC_FAILURE, NULL);
-				return;
-			}
+			mlo_handle_sta_link_connect_failure(vdev, rsp);
+			return;
 		} else if (!wlan_cm_is_vdev_connected(vdev)) {
 			/* If vdev is not in disconnected or connected state,
 			 * then the event is received due to connect req being
@@ -569,32 +671,6 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 	}
 }
 
-/*
- * mlo_get_connected_link_vdev - API to get 1st connected link vdev
- *
- * @mlo_dev_ctx: mlo dev ctx
- *
- * Return: 1st connected link vdev in ML dev, NULL if none of the link vdev
- * is connected
- */
-static struct wlan_objmgr_vdev
-*mlo_get_connected_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
-{
-	uint8_t i = 0;
-
-	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)) &&
-		    wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]))
-			return mlo_dev_ctx->wlan_vdev_list[i];
-	}
-
-	return NULL;
-}
-
 /**
  * mlo_send_link_disconnect- Issue the disconnect request on MLD links
  *
@@ -605,7 +681,6 @@ static struct wlan_objmgr_vdev
  *
  * Return: QDF_STATUS
  */
-#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
 static QDF_STATUS
 mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
 			 enum wlan_cm_source source,
@@ -630,6 +705,16 @@ mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * mlo_send_link_disconnect- Issue sync the disconnect request on MLD links
+ *
+ * @mlo_dev_ctx: pointer to mlo dev context
+ * @source: disconnect source
+ * @reason_code: disconnect reason
+ * @bssid: bssid of AP to disconnect, can be null if not known
+ *
+ * Return: QDF_STATUS
+ */
 static QDF_STATUS
 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
 			      enum wlan_cm_source source,
@@ -652,68 +737,6 @@ mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
 				source, reason_code);
 	return QDF_STATUS_SUCCESS;
 }
-#else
-static QDF_STATUS
-mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
-			 enum wlan_cm_source source,
-			 enum wlan_reason_code reason_code,
-			 struct qdf_mac_addr *bssid)
-{
-	uint8_t i = 0;
-	QDF_STATUS status = QDF_STATUS_E_ALREADY;
-
-	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
-		if (!mlo_dev_ctx->wlan_vdev_list[i])
-			continue;
-
-		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
-			if (wlan_cm_is_vdev_connecting(
-					mlo_dev_ctx->wlan_vdev_list[i]) ||
-			    wlan_cm_is_vdev_disconnecting(
-					mlo_dev_ctx->wlan_vdev_list[i]) ||
-			    wlan_cm_is_vdev_roaming(
-					mlo_dev_ctx->wlan_vdev_list[i])) {
-				wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
-						   source, reason_code, NULL);
-				return QDF_STATUS_SUCCESS;
-			}
-		}
-	}
-
-	return status;
-}
-
-static QDF_STATUS
-mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
-			      enum wlan_cm_source source,
-			      enum wlan_reason_code reason_code,
-			      struct qdf_mac_addr *bssid)
-{
-	uint8_t i = 0;
-	QDF_STATUS status = QDF_STATUS_E_ALREADY;
-
-	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
-		if (!mlo_dev_ctx->wlan_vdev_list[i])
-			continue;
-
-		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
-			if (wlan_cm_is_vdev_connecting(
-					mlo_dev_ctx->wlan_vdev_list[i]) ||
-			    wlan_cm_is_vdev_disconnecting(
-					mlo_dev_ctx->wlan_vdev_list[i]) ||
-			    wlan_cm_is_vdev_roaming(
-				mlo_dev_ctx->wlan_vdev_list[i])) {
-				wlan_cm_disconnect_sync(
-					mlo_dev_ctx->wlan_vdev_list[i],
-					source, reason_code);
-				return QDF_STATUS_SUCCESS;
-			}
-		}
-	}
-
-	return status;
-}
-#endif
 
 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
 					 enum wlan_cm_source source,
@@ -721,7 +744,6 @@ static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
 					 struct qdf_mac_addr *bssid)
 {
 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
-	struct wlan_objmgr_vdev *tmp_vdev = vdev;
 	struct wlan_mlo_sta *sta_ctx = NULL;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
@@ -744,22 +766,6 @@ static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
 
 		status = mlo_send_link_disconnect(mlo_dev_ctx, source,
 						  reason_code, bssid);
-
-		if (QDF_IS_STATUS_SUCCESS(status))
-			return status;
-
-		tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
-		if (tmp_vdev) {
-			status = wlan_cm_disconnect(tmp_vdev, source,
-						    reason_code, NULL);
-			return status;
-		}
-		tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
-		if (tmp_vdev) {
-			status = wlan_cm_disconnect(tmp_vdev, source,
-						    reason_code, NULL);
-			return status;
-		}
 	}
 
 	return status;
@@ -770,11 +776,14 @@ QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
 			  enum wlan_reason_code reason_code,
 			  struct qdf_mac_addr *bssid)
 {
-	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
-	struct wlan_objmgr_vdev *tmp_vdev = NULL;
+	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
 	struct wlan_mlo_sta *sta_ctx = NULL;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
+	if (!vdev)
+		return QDF_STATUS_E_FAILURE;
+
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	if (mlo_dev_ctx)
 		sta_ctx = mlo_dev_ctx->sta_ctx;
 	if (sta_ctx && sta_ctx->orig_conn_req) {
@@ -793,26 +802,6 @@ QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
 
 		status = mlo_send_link_disconnect(mlo_dev_ctx, source,
 						  reason_code, bssid);
-
-		if (QDF_IS_STATUS_SUCCESS(status)) {
-			mlo_dev_lock_release(mlo_dev_ctx);
-			return status;
-		}
-
-		tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
-		if (tmp_vdev) {
-			status = wlan_cm_disconnect(tmp_vdev, source,
-						    reason_code, NULL);
-			mlo_dev_lock_release(mlo_dev_ctx);
-			return status;
-		}
-		tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
-		if (tmp_vdev) {
-			status = wlan_cm_disconnect(tmp_vdev, source,
-						    reason_code, NULL);
-			mlo_dev_lock_release(mlo_dev_ctx);
-			return status;
-		}
 		mlo_dev_lock_release(mlo_dev_ctx);
 		return status;
 	}
@@ -825,11 +814,14 @@ QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
 			       enum wlan_reason_code reason_code,
 			       struct qdf_mac_addr *bssid)
 {
-	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
-	struct wlan_objmgr_vdev *tmp_vdev = NULL;
+	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
 	struct wlan_mlo_sta *sta_ctx = NULL;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
+	if (!vdev)
+		return QDF_STATUS_E_FAILURE;
+
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	if (mlo_dev_ctx)
 		sta_ctx = mlo_dev_ctx->sta_ctx;
 	if (sta_ctx && sta_ctx->orig_conn_req) {
@@ -848,21 +840,6 @@ QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
 		status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source,
 						       reason_code, bssid);
 
-		if (QDF_IS_STATUS_SUCCESS(status))
-			return status;
-
-		tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
-		if (tmp_vdev) {
-			status = wlan_cm_disconnect_sync(tmp_vdev, source,
-							 reason_code);
-			return status;
-		}
-		tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
-		if (tmp_vdev) {
-			status = wlan_cm_disconnect_sync(tmp_vdev, source,
-							 reason_code);
-			return status;
-		}
 		return status;
 	}
 	return wlan_cm_disconnect_sync(vdev, source,
@@ -911,42 +888,120 @@ void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
 static
 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
 				struct wlan_cm_discon_rsp *resp)
+{ }
+#endif
+
+static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg)
 {
-	struct wlan_objmgr_vdev *assoc_vdev = NULL;
-	enum wlan_cm_source source;
-	enum wlan_reason_code reason_code;
+	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
+	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
+	struct wlan_mlo_sta *sta_ctx = NULL;
+
+	if (!vdev) {
+		mlme_err("Null input vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	if (!mlo_dev_ctx) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlo_connect(vdev, sta_ctx->connect_req);
+	mlo_free_connect_ies(sta_ctx->connect_req);
+	qdf_mem_free(sta_ctx->connect_req);
+	sta_ctx->connect_req = NULL;
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
+
+	if (!vdev) {
+		mlme_err("Null input vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+static inline
+void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
+{ }
+#else
+static inline
+void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
+	struct wlan_objmgr_vdev *tmp_vdev;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS ret;
+	struct wlan_mlo_sta *sta_ctx = NULL;
 	uint8_t i = 0;
+	struct mlo_partner_info partner_info;
+	struct mlo_link_info partner_link_info;
 
-	mlo_dev_lock_acquire(mlo_dev_ctx);
-	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
-		if (!mlo_dev_ctx->wlan_vdev_list[i])
-			continue;
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	ret = wlan_objmgr_vdev_try_get_ref(
+			vdev,
+			WLAN_MLO_MGR_ID);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		mlo_free_connect_ies(sta_ctx->connect_req);
+		qdf_mem_free(sta_ctx->connect_req);
+		sta_ctx->connect_req = NULL;
+		return;
+	}
+	msg.bodyptr = vdev;
+	msg.callback = ml_activate_connect_req_sched_cb;
+	msg.flush_callback = ml_activate_connect_req_flush_cb;
+
+	ret = scheduler_post_message(QDF_MODULE_ID_MLME,
+				     QDF_MODULE_ID_MLME,
+				     QDF_MODULE_ID_MLME, &msg);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		mlo_free_connect_ies(sta_ctx->connect_req);
+		qdf_mem_free(sta_ctx->connect_req);
+		sta_ctx->connect_req = NULL;
+		wlan_objmgr_vdev_release_ref(vdev,
+					     WLAN_MLO_MGR_ID);
+		return;
+	}
 
-		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
-			if (wlan_cm_is_vdev_connected(
-					mlo_dev_ctx->wlan_vdev_list[i])) {
-				if (wlan_vdev_mlme_is_mlo_link_vdev(
-					mlo_dev_ctx->wlan_vdev_list[i])) {
-					source = resp->req.req.source;
-					reason_code = resp->req.req.reason_code;
-					wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
-							   source, reason_code, NULL);
-					mlo_dev_lock_release(mlo_dev_ctx);
-					return;
-				}
+	if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) {
+		partner_info = sta_ctx->connect_req->ml_parnter_info;
+		wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO);
+		mlo_clear_connect_req_links_bmap(vdev);
+		mlo_update_connect_req_links(vdev, 1);
+		for (i = 0; i < partner_info.num_partner_links; i++) {
+			partner_link_info = partner_info.partner_link_info[i];
+			tmp_vdev = mlo_get_ml_vdev_by_mac(
+					vdev,
+					&partner_link_info.link_addr);
+			if (tmp_vdev) {
+				mlo_update_connect_req_links(tmp_vdev, 1);
+				wlan_vdev_mlme_feat_ext2_cap_set(
+						tmp_vdev, WLAN_VDEV_FEXT2_MLO);
+				wlan_vdev_mlme_feat_ext2_cap_set(
+						tmp_vdev,
+						WLAN_VDEV_FEXT2_MLO_STA_LINK);
+				wlan_vdev_set_link_id(
+					tmp_vdev,
+					partner_link_info.link_id);
 			}
 		}
 	}
-	assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
-	if (assoc_vdev && wlan_cm_is_vdev_connected(assoc_vdev)) {
-		source = resp->req.req.source;
-		reason_code = resp->req.req.reason_code;
-		wlan_cm_disconnect(assoc_vdev,
-				   source, reason_code, NULL);
-		mlo_dev_lock_release(mlo_dev_ctx);
-		return;
-	}
-	mlo_dev_lock_release(mlo_dev_ctx);
 }
 #endif
 
@@ -955,6 +1010,7 @@ void mlo_sta_link_disconn_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 = NULL;
 
 	if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
 		return;
@@ -967,15 +1023,11 @@ void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
 		return;
 
 	mlo_update_connected_links(vdev, 0);
-	if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
+	if (mlo_is_mld_disconnected(vdev)) {
 		if (sta_ctx->connect_req) {
-			mlo_connect(mlo_get_assoc_link_vdev(mlo_dev_ctx),
-				    sta_ctx->connect_req);
-			mlo_free_connect_ies(sta_ctx->connect_req);
-			qdf_mem_free(sta_ctx->connect_req);
-			sta_ctx->connect_req = NULL;
+			assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
+			mlo_sta_link_handle_pending_connect(assoc_vdev);
 		}
-		return;
 	}
 
 	mlo_handle_disconnect_resp(mlo_dev_ctx, resp);