Browse Source

qcacmn: Handle mlo disconnect while connection is in progress

In case of MLO, when connect is in progress and disconnect is received,
there may be a possibilty that the assoc link's bss peer is deleted
before non-assoc link's connect is still in progress which can lead to
issue in peer setup at DP and FW.
Add fix to handle mlo disconnect while connection is in progress

Change-Id: I550abff439deca19c7ab355cae1fa46db1f0f61b
CRs-Fixed: 3152770
Himanshu Batra 3 years ago
parent
commit
896411a36b

+ 2 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -231,6 +231,7 @@ struct mlo_sta_quiet_status {
  * @copied_conn_req_lock: lock for the original connect request
  * @assoc_rsp: Raw assoc response frame
  * @mlo_csa_param: CSA request parameters for mlo sta
+ * @disconn_req: disconnect req params
  */
 struct wlan_mlo_sta {
 	qdf_bitmap(wlan_connect_req_links, WLAN_UMAC_MLO_MAX_VDEVS);
@@ -246,6 +247,7 @@ struct wlan_mlo_sta {
 	struct element_info assoc_rsp;
 	struct mlo_sta_quiet_status mlo_quiet_status[WLAN_UMAC_MLO_MAX_VDEVS];
 	struct mlo_sta_csa_params mlo_csa_param[WLAN_UMAC_MLO_MAX_VDEVS];
+	struct wlan_cm_disconnect_req *disconn_req;
 };
 
 /*

+ 4 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_main.c

@@ -427,6 +427,10 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
 				}
 				qdf_mem_free(ml_dev->sta_ctx->connect_req);
 			}
+
+			if (ml_dev->sta_ctx->disconn_req)
+				qdf_mem_free(ml_dev->sta_ctx->disconn_req);
+
 			if (ml_dev->sta_ctx->assoc_rsp.ptr)
 				qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr);
 

+ 129 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_sta.c

@@ -199,6 +199,15 @@ mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev,
 /* check back to back connect handling */
 	return QDF_STATUS_SUCCESS;
 }
+
+static QDF_STATUS
+mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev,
+			 enum wlan_cm_source source,
+			 enum wlan_reason_code reason_code,
+			 struct qdf_mac_addr *bssid)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #else
 /**
  * mlo_is_mld_connected - Check whether MLD is connected
@@ -380,6 +389,45 @@ mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev,
 	}
 	return status;
 }
+
+static QDF_STATUS
+mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev,
+			 enum wlan_cm_source source,
+			 enum wlan_reason_code reason_code,
+			 struct qdf_mac_addr *bssid)
+{
+	struct wlan_mlo_dev_context *mlo_dev = vdev->mlo_dev_ctx;
+	struct wlan_mlo_sta *sta_ctx = mlo_dev->sta_ctx;
+	uint8_t i = 0;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (!mlo_dev->wlan_vdev_list[i])
+			continue;
+
+		if (wlan_cm_is_vdev_connecting(mlo_dev->wlan_vdev_list[i])) {
+			if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
+				return QDF_STATUS_SUCCESS;
+
+			if (!sta_ctx->disconn_req)
+				sta_ctx->disconn_req =
+					qdf_mem_malloc(
+					sizeof(struct wlan_cm_disconnect_req));
+
+			if (!sta_ctx->disconn_req)
+				return QDF_STATUS_SUCCESS;
+
+			sta_ctx->disconn_req->vdev_id =
+						wlan_vdev_get_id(vdev);
+			sta_ctx->disconn_req->source = source;
+			sta_ctx->disconn_req->reason_code = reason_code;
+			if (bssid)
+				qdf_copy_macaddr(&sta_ctx->disconn_req->bssid,
+						 bssid);
+			return QDF_STATUS_E_BUSY;
+		}
+	}
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,
@@ -668,6 +716,43 @@ static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg)
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg)
+{
+	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;
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	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;
+}
+
+static QDF_STATUS ml_activate_pend_disconn_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)
@@ -736,6 +821,35 @@ void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
 	}
 }
 
+static inline
+void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev)
+{
+	struct scheduler_msg msg = {0};
+	QDF_STATUS ret;
+
+	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;
+	}
+
+	msg.bodyptr = vdev;
+	msg.callback = ml_activate_pend_disconn_req_cb;
+	msg.flush_callback =
+		ml_activate_pend_disconn_req_flush_cb;
+	ret = mlo_post_disconnect_msg(&msg);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		mlo_err("Failed to post scheduler msg");
+		wlan_objmgr_vdev_release_ref(
+				vdev,
+				WLAN_MLO_MGR_ID);
+		QDF_BUG(0);
+		return;
+	}
+}
+
 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 				 struct wlan_cm_connect_resp *rsp)
 {
@@ -749,6 +863,13 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 		return;
 	}
 
+	if (sta_ctx && sta_ctx->disconn_req) {
+		mlo_debug("Handle pending disocnnect for vdev %d",
+			  wlan_vdev_get_id(vdev));
+		mlo_handle_pending_disconnect(vdev);
+		return;
+	}
+
 	if (wlan_cm_is_vdev_disconnected(vdev)) {
 		if (sta_ctx) {
 			copied_conn_req_lock_acquire(sta_ctx);
@@ -874,6 +995,14 @@ QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
 			sta_ctx->connect_req = NULL;
 		}
 
+		status = mlo_validate_disconn_req(vdev, source,
+						  reason_code, bssid);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlo_debug("Connect in progress, deferring disconnect");
+			mlo_dev_lock_release(mlo_dev_ctx);
+			return status;
+		}
+
 		status = mlo_send_link_disconnect(mlo_dev_ctx, source,
 						  reason_code, bssid);
 		mlo_dev_lock_release(mlo_dev_ctx);