فهرست منبع

qcacmn: Defer disconnect req when link switch in progress

If link switch is in progress and no other disconnects are
pending in MLO manager sta ctx, save the new disconnect req
and move link switch state to abort. On link switch complete
schedule the pending disconnect in MLO manager.

In the scheduler callback for pending disconnect handling
add NULL check for disconnect request.

Change-Id: I4b144239eb1542cea934478643b6e53b371f2c93
CRs-Fixed: 3608727
Vinod Kumar Pirla 1 سال پیش
والد
کامیت
f161aeba7c

+ 30 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h

@@ -21,6 +21,7 @@
 #define _WLAN_MLO_MGR_LINK_SWITCH_H_
 
 #include <wlan_mlo_mgr_public_structs.h>
+#include <wlan_cm_public_struct.h>
 
 struct wlan_channel;
 
@@ -535,6 +536,27 @@ QDF_STATUS
 mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc,
 				 struct wlan_mlo_link_switch_cnf *cnf_params);
 
+/**
+ * mlo_mgr_link_switch_defer_disconnect_req() - Defer disconnect request from
+ * source other than link switch
+ * @vdev: VDEV object manager
+ * @source: Disconnect requestor
+ * @reason: Reason for disconnect
+ *
+ * If link switch is in progress for @vdev, then queue to disconnect request
+ * received in the MLO dev context and move link switch state to abort and
+ * on completion of link switch schedule pending disconnect requests.
+ *
+ * If link switch is not in progress or already another disconnect in queued in
+ * MLO dev context then reject the disconnect defer request.
+ *
+ * Return: QDF_STATUS.
+ */
+QDF_STATUS
+mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev,
+					 enum wlan_cm_source source,
+					 enum wlan_reason_code reason);
+
 /**
  * mlo_mgr_link_switch_init() - API to initialize link switch
  * @ml_dev: MLO dev context
@@ -707,5 +729,13 @@ mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc,
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
+
+static inline QDF_STATUS
+mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev,
+					 enum wlan_cm_source source,
+					 enum wlan_reason_code reason)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
 #endif
 #endif

+ 17 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_public_api.h

@@ -117,4 +117,21 @@ wlan_mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
 {
 	return mlo_mgr_link_switch_set_mac_addr_resp(vdev, resp_status);
 }
+
+/**
+ * wlan_mlo_mgr_link_switch_defer_disconnect_req() - Defer disconnect requests
+ * from source other than link switch.
+ * @vdev: VDEV object manager
+ * @source: Disconnect requestor
+ * @reason: Reason for disconnect
+ *
+ * Return: QDF_STATUS.
+ */
+static inline QDF_STATUS
+wlan_mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev,
+					      enum wlan_cm_source source,
+					      enum wlan_reason_code reason)
+{
+	return mlo_mgr_link_switch_defer_disconnect_req(vdev, source, reason);
+}
 #endif /* _WLAN_MLO_MGR_PUBLIC_API_H_ */

+ 48 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c

@@ -835,6 +835,10 @@ void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
 	mlo_mgr_link_switch_notify(vdev, req);
 
+	/* Handle any pending disconnect */
+	if (cur_state == MLO_LINK_SWITCH_STATE_ABORT_TRANS)
+		mlo_handle_pending_disconnect(vdev);
+
 	if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) {
 		mlo_debug("Link switch not serialized");
 		mlo_mgr_link_switch_complete(vdev);
@@ -1091,4 +1095,48 @@ mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc,
 
 	return status;
 }
+
+QDF_STATUS
+mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev,
+					 enum wlan_cm_source source,
+					 enum wlan_reason_code reason)
+{
+	struct wlan_mlo_dev_context *mlo_dev_ctx;
+	struct wlan_mlo_sta *sta_ctx;
+
+	if (!mlo_mgr_is_link_switch_in_progress(vdev)) {
+		mlo_info("Link switch not in progress");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+
+	if (!sta_ctx) {
+		mlo_err("sta ctx null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	/* Move current link switch to abort state */
+	mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx);
+
+	if (sta_ctx->disconn_req) {
+		mlo_debug("Pending disconnect from source %d, reason %d",
+			  sta_ctx->disconn_req->source,
+			  sta_ctx->disconn_req->reason_code);
+		return QDF_STATUS_E_ALREADY;
+	}
+
+	sta_ctx->disconn_req =
+			qdf_mem_malloc(sizeof(struct wlan_cm_disconnect_req));
+	if (!sta_ctx->disconn_req)
+		return QDF_STATUS_E_NOMEM;
+
+	sta_ctx->disconn_req->vdev_id = wlan_vdev_get_id(vdev);
+	sta_ctx->disconn_req->source = source;
+	sta_ctx->disconn_req->reason_code = reason;
+
+	mlo_debug("Deferred disconnect source: %d, reason: %d", source, reason);
+	return QDF_STATUS_SUCCESS;
+}
 #endif

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

@@ -1051,12 +1051,17 @@ 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 || !sta_ctx->disconn_req)
+		goto release_ref;
+
 	mlo_disconnect_req(vdev, sta_ctx->disconn_req->source,
 			   sta_ctx->disconn_req->reason_code,
 			   &sta_ctx->disconn_req->bssid, false);
 
 	qdf_mem_free(sta_ctx->disconn_req);
 	sta_ctx->disconn_req = NULL;
+
+release_ref:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
 
 	return QDF_STATUS_SUCCESS;