Browse Source

qcacmn: Enhancements for link switch connect

Introduce following for link switch disconnect:
    1) Connect request source.
    2) Connect request reason.

If the set MAC address response for new link is successful, post
connection on new link and transition the link switch state to
connecting. If the status of connection is successful, update
the state to link switch complete or else directly go for
deserializing link switch command and posting response to FW.

Based on the final state of link switch at the time of sending
FW response, send the appropirate status of link switch and reset
the state of link switch to idle post FW notify.

Don't unlink BSS incase of failure in connection.

Don't indicate connect results to userspace.

As we are already in serialization due to link switch,
don't serialize/deserialize connection command if it
is due to link switch.

Incase of race condition between link switch connect and
userspace connect/disconnect always abort link switch connect.

Change-Id: Ie350b52021c36802b82d6cb5f6f441fe1bd10458
CRs-Fixed: 3556529
Vinod Kumar Pirla 2 years ago
parent
commit
35ea97c560

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

@@ -1047,7 +1047,8 @@ static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev,
 static inline
 bool osif_cm_is_unlink_bss_required(struct wlan_cm_connect_resp *rsp)
 {
-	if (QDF_IS_STATUS_SUCCESS(rsp->connect_status))
+	if (QDF_IS_STATUS_SUCCESS(rsp->connect_status) ||
+	    rsp->cm_id & CM_ID_LSWITCH_BIT)
 		return false;
 
 	if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
@@ -1107,7 +1108,7 @@ QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev,
 	osif_check_and_unlink_bss(vdev, rsp);
 
 	status = osif_validate_connect_and_reset_src_id(osif_priv, rsp);
-	if (QDF_IS_STATUS_ERROR(status)) {
+	if (QDF_IS_STATUS_ERROR(status) || rsp->cm_id & CM_ID_LSWITCH_BIT) {
 		osif_cm_connect_comp_ind(vdev, rsp, OSIF_NOT_HANDLED);
 		return status;
 	}

+ 28 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -38,6 +38,7 @@
 #ifdef WLAN_FEATURE_11BE_MLO
 #include <wlan_mlo_mgr_peer.h>
 #endif
+#include <wlan_mlo_mgr_link_switch.h>
 #include <wlan_mlo_mgr_sta.h>
 #include "wlan_mlo_mgr_op.h"
 #include <wlan_objmgr_vdev_obj.h>
@@ -1660,6 +1661,14 @@ cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
 			   cm_state_substate);
 	}
 
+	/* Reject any link switch connect request while in non-init state */
+	if (cm_req->req.source == CM_MLO_LINK_SWITCH_CONNECT) {
+		mlme_info(CM_PREFIX_FMT "Ignore disconnect req from source %d state %d",
+			  CM_PREFIX_REF(vdev_id, cm_req->cm_id),
+			  cm_req->req.source, cm_state_substate);
+		return QDF_STATUS_E_INVAL;
+	}
+
 	switch (cm_state_substate) {
 	case WLAN_CM_S_ROAMING:
 		/* for FW roam/LFR3 remove the req from the list */
@@ -1796,7 +1805,18 @@ QDF_STATUS cm_connect_start(struct cnx_mgr *cm_ctx,
 		return QDF_STATUS_SUCCESS;
 	}
 
-	status = cm_ser_connect_req(pdev, cm_ctx, cm_req);
+	if (cm_req->req.source == CM_MLO_LINK_SWITCH_CONNECT) {
+		/* The error handling has to be different here.not corresponds
+		 * to connect req serialization now.
+		 */
+		status = cm_sm_deliver_event_sync(cm_ctx,
+						  WLAN_CM_SM_EV_CONNECT_ACTIVE,
+						  sizeof(wlan_cm_id),
+						  &cm_req->cm_id);
+	} else {
+		status = cm_ser_connect_req(pdev, cm_ctx, cm_req);
+	}
+
 	if (QDF_IS_STATUS_ERROR(status)) {
 		reason = CM_SER_FAILURE;
 		goto connect_err;
@@ -2757,7 +2777,7 @@ QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
 					  resp->connect_status);
 	cm_inform_dlm_connect_complete(cm_ctx->vdev, resp);
 	if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
-	    sm_state == WLAN_CM_S_INIT)
+	    sm_state == WLAN_CM_S_INIT && !(resp->cm_id & CM_ID_LSWITCH_BIT))
 		cm_clear_vdev_mlo_cap(cm_ctx->vdev);
 
 	return QDF_STATUS_SUCCESS;
@@ -2819,6 +2839,12 @@ QDF_STATUS cm_connect_complete(struct cnx_mgr *cm_ctx,
 				 resp->cm_id));
 	cm_remove_cmd(cm_ctx, &resp->cm_id);
 
+	if (resp->cm_id & CM_ID_LSWITCH_BIT) {
+		cm_reset_active_cm_id(cm_ctx->vdev, resp->cm_id);
+		mlo_mgr_link_switch_connect_done(cm_ctx->vdev,
+						 resp->connect_status);
+	}
+
 	return QDF_STATUS_SUCCESS;
 }
 

+ 11 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_util.c

@@ -36,6 +36,7 @@ static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) {
 	case CM_OSIF_CONNECT:
 	case CM_OSIF_CFG_CONNECT:
 	case CM_MLO_LINK_VDEV_CONNECT:
+	case CM_MLO_LINK_SWITCH_CONNECT:
 		return CONNECT_REQ_PREFIX;
 	case CM_ROAMING_HOST:
 	case CM_ROAMING_FW:
@@ -59,7 +60,8 @@ wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source)
 	cm_id = (cm_id & CM_ID_MASK);
 	cm_id = CM_ID_SET_VDEV_ID(cm_id, vdev_id);
 	cm_id = (cm_id | prefix);
-	if (source == CM_MLO_LINK_SWITCH_DISCONNECT)
+	if (source == CM_MLO_LINK_SWITCH_DISCONNECT ||
+	    source == CM_MLO_LINK_SWITCH_CONNECT)
 		cm_id |= CM_ID_LSWITCH_BIT;
 
 	return cm_id;
@@ -597,6 +599,14 @@ cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
 	cm_fill_connect_resp_from_req(cm_ctx->vdev, resp, cm_req);
 
 	cm_notify_connect_complete(cm_ctx, resp, 0);
+
+	/* For link switch connect request, notify MLO mgr */
+	if (resp->cm_id & CM_ID_LSWITCH_BIT) {
+		cm_reset_active_cm_id(cm_ctx->vdev, resp->cm_id);
+		mlo_mgr_link_switch_connect_done(cm_ctx->vdev,
+						 resp->connect_status);
+	}
+
 	qdf_mem_free(resp);
 }
 

+ 2 - 0
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h

@@ -156,6 +156,7 @@ struct wlan_fils_con_info {
  * @CM_MLO_LINK_VDEV_DISCONNECT: Disconnect req for ML link
  * @CM_MLO_LINK_VDEV_CONNECT: Connect req for ML link
  * @CM_MLO_ROAM_INTERNAL_DISCONNECT: Disconnect req triggered for mlo roaming
+ * @CM_MLO_LINK_SWITCH_CONNECT: Connect req triggered for mlo link switch
  * @CM_MLO_LINK_SWITCH_DISCONNECT: Disconnect req triggered for mlo link switch
  * @CM_SOURCE_MAX: max value of connection manager source
  * @CM_SOURCE_INVALID: Invalid connection manager req source
@@ -177,6 +178,7 @@ enum wlan_cm_source {
 	CM_MLO_LINK_VDEV_DISCONNECT,
 	CM_MLO_LINK_VDEV_CONNECT,
 	CM_MLO_ROAM_INTERNAL_DISCONNECT,
+	CM_MLO_LINK_SWITCH_CONNECT,
 	CM_MLO_LINK_SWITCH_DISCONNECT,
 	CM_SOURCE_MAX,
 	CM_SOURCE_INVALID = CM_SOURCE_MAX,

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

@@ -296,6 +296,33 @@ QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
 						 uint8_t resp_status);
 
+/**
+ * mlo_mgr_link_switch_start_connect() - Start link switch connect on new link
+ * @vdev: VDEV pointer.
+ *
+ * Call the API to initiate connection for link switch post successful set mac
+ * address on @vdev.
+ *
+ * Return:QDF_STATUS
+ */
+QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlo_mgr_link_switch_connect_done() - Link switch connect done indication.
+ * @vdev: VDEV object manager
+ * @status: Status of connect request.
+ *
+ * The callback from connection manager with connect response.
+ * If the response is failure, don't change the state of link switch.
+ * If the response if success, set link switch state to
+ * MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS.
+ * Finally call remove link switch cmd from serialization.
+ *
+ * Return: void
+ */
+void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
+				      QDF_STATUS status);
+
 /**
  * mlo_mgr_link_switch_init_state() - Set the current state of link switch
  * to init state.
@@ -489,6 +516,18 @@ mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_E_NOSUPPORT;
 }
 
+static inline QDF_STATUS
+mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline void
+mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
+				 QDF_STATUS status)
+{
+}
+
 static inline QDF_STATUS
 mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev)
 {

+ 80 - 79
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -483,6 +483,85 @@ struct wlan_link_force_context {
 	struct ml_link_force_state force_state;
 };
 
+#if defined(UMAC_SUPPORT_MLNAWDS) || defined(MESH_MODE_SUPPORT)
+/**
+ * struct mlnawds_config - MLO NAWDS configuration
+ * @caps: Bandwidth & NSS capabilities to be configured on NAWDS peer
+ * @puncture_bitmap: puncture bitmap to be configured on NAWDS peer
+ * @mac: MAC address of the NAWDS peer to which the caps & puncture bitmap is
+ * to be configured.
+ */
+struct mlnawds_config {
+	uint64_t caps;
+	uint16_t puncture_bitmap;
+	uint8_t  mac[QDF_MAC_ADDR_SIZE];
+};
+#endif
+
+/**
+ * struct mlo_link_info - ML link info
+ * @link_addr: link mac address
+ * @link_id: link index
+ * @is_bridge : Bridge peer or not
+ * @chan_freq: Operating channel frequency
+ * @nawds_config: peer's NAWDS configurarion
+ * @vdev_id: VDEV ID
+ * @mesh_config: peer's MESH configurarion
+ * @link_status_flags: Current status of link
+ * @ap_link_addr: Associated link BSSID
+ * @link_chan_info: Associated link channel info
+ */
+struct mlo_link_info {
+	struct qdf_mac_addr link_addr;
+	uint8_t link_id;
+	bool is_bridge;
+	uint16_t chan_freq;
+#ifdef UMAC_SUPPORT_MLNAWDS
+	struct mlnawds_config nawds_config;
+#endif
+	uint8_t vdev_id;
+#ifdef MESH_MODE_SUPPORT
+	struct mlnawds_config mesh_config;
+#endif
+#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+	uint8_t link_status_flags;
+	struct qdf_mac_addr ap_link_addr;
+	struct wlan_channel *link_chan_info;
+#endif
+};
+
+/**
+ * struct mlo_nstr_info - MLO NSTR capability info
+ * @link_id: Lind Id
+ * @nstr_lp_present: Flag for NSTR link pair presence
+ * @nstr_bmp_size: NSTR Bitmap Size
+ * @nstr_lp_bitmap: NSTR link pair bitmap of link_id
+ */
+struct mlo_nstr_info {
+	uint8_t link_id;
+	bool nstr_lp_present;
+	uint8_t nstr_bmp_size;
+	uint16_t nstr_lp_bitmap;
+};
+
+/**
+ * struct mlo_partner_info - mlo partner link info
+ * @num_partner_links: no. of partner links
+ * @partner_link_info: per partner link info
+ * @t2lm_enable_val: enum wlan_t2lm_enable
+ * @nstr_info: NSTR Capability info
+ * @num_nstr_info_links: No. of links for which NSTR info is present
+ */
+struct mlo_partner_info {
+	uint8_t num_partner_links;
+	struct mlo_link_info partner_link_info[WLAN_UMAC_MLO_MAX_VDEVS];
+#ifdef WLAN_FEATURE_11BE
+	enum wlan_t2lm_enable t2lm_enable_val;
+	struct mlo_nstr_info nstr_info[WLAN_UMAC_MLO_MAX_VDEVS];
+	uint8_t num_nstr_info_links;
+#endif
+};
+
 /*
  * struct wlan_mlo_sta - MLO sta additional info
  * @wlan_connect_req_links: list of vdevs selected for connection with the MLAP
@@ -527,6 +606,7 @@ struct wlan_mlo_sta {
 #ifdef WLAN_FEATURE_11BE_MLO
 	struct ml_link_state_cmd_info ml_link_state;
 	struct wlan_t2lm_context copied_t2lm_ie_assoc_rsp;
+	struct mlo_partner_info ml_partner_info;
 #endif
 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
 	struct wlan_link_force_context link_force_ctx;
@@ -580,53 +660,6 @@ struct mlo_vdev_link_mac_info {
 	struct qdf_mac_addr link_mac_addr;
 };
 
-#if defined(UMAC_SUPPORT_MLNAWDS) || defined(MESH_MODE_SUPPORT)
-/**
- * struct mlnawds_config - MLO NAWDS configuration
- * @caps: Bandwidth & NSS capabilities to be configured on NAWDS peer
- * @puncture_bitmap: puncture bitmap to be configured on NAWDS peer
- * @mac: MAC address of the NAWDS peer to which the caps & puncture bitmap is
- * to be configured.
- */
-struct mlnawds_config {
-	uint64_t caps;
-	uint16_t puncture_bitmap;
-	uint8_t  mac[QDF_MAC_ADDR_SIZE];
-};
-#endif
-
-/**
- * struct mlo_link_info - ML link info
- * @link_addr: link mac address
- * @link_id: link index
- * @is_bridge : Bridge peer or not
- * @chan_freq: Operating channel frequency
- * @nawds_config: peer's NAWDS configurarion
- * @vdev_id: VDEV ID
- * @mesh_config: peer's MESH configurarion
- * @link_status_flags: Current status of link
- * @ap_link_addr: Associated link BSSID
- * @link_chan_info: Associated link channel info
- */
-struct mlo_link_info {
-	struct qdf_mac_addr link_addr;
-	uint8_t link_id;
-	bool is_bridge;
-	uint16_t chan_freq;
-#ifdef UMAC_SUPPORT_MLNAWDS
-	struct mlnawds_config nawds_config;
-#endif
-	uint8_t vdev_id;
-#ifdef MESH_MODE_SUPPORT
-	struct mlnawds_config mesh_config;
-#endif
-#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
-	uint8_t link_status_flags;
-	struct qdf_mac_addr ap_link_addr;
-	struct wlan_channel *link_chan_info;
-#endif
-};
-
 /**
  * struct wlan_mlo_link_mac_update: VDEV to link MAC address list
  * @num_mac_update: Number of mac address
@@ -821,20 +854,6 @@ struct wlan_mlo_mld_cap {
 		 reserved:3;
 };
 
-/**
- * struct mlo_nstr_info - MLO NSTR capability info
- * @link_id: Lind Id
- * @nstr_lp_present: Flag for NSTR link pair presence
- * @nstr_bmp_size: NSTR Bitmap Size
- * @nstr_lp_bitmap: NSTR link pair bitmap of link_id
- */
-struct mlo_nstr_info {
-	uint8_t link_id;
-	bool nstr_lp_present;
-	uint8_t nstr_bmp_size;
-	uint16_t nstr_lp_bitmap;
-};
-
 /**
  * struct wlan_mlo_peer_context - MLO peer context
  *
@@ -914,24 +933,6 @@ struct wlan_mlo_peer_context {
 	bool primary_umac_migration_in_progress;
 };
 
-/**
- * struct mlo_partner_info - mlo partner link info
- * @num_partner_links: no. of partner links
- * @partner_link_info: per partner link info
- * @t2lm_enable_val: enum wlan_t2lm_enable
- * @nstr_info: NSTR Capability info
- * @num_nstr_info_links: No. of links for which NSTR info is present
- */
-struct mlo_partner_info {
-	uint8_t num_partner_links;
-	struct mlo_link_info partner_link_info[WLAN_UMAC_MLO_MAX_VDEVS];
-#ifdef WLAN_FEATURE_11BE
-	enum wlan_t2lm_enable t2lm_enable_val;
-	struct mlo_nstr_info nstr_info[WLAN_UMAC_MLO_MAX_VDEVS];
-	uint8_t num_nstr_info_links;
-#endif
-};
-
 /**
  * struct mlo_probereq_info - mlo probe req link info
  * @mlid: MLID requested in the probe req

+ 79 - 1
umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c

@@ -512,8 +512,86 @@ QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
 							req->new_ieee_link_id,
 							req->vdev_id);
 
+	mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
+	status = mlo_mgr_link_switch_start_connect(vdev);
+
+	return status;
+}
+
+QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS status = QDF_STATUS_E_INVAL;
+	struct wlan_cm_connect_req conn_req = {0};
+	struct mlo_link_info *mlo_link_info;
+	uint8_t *vdev_mac;
+	struct wlan_mlo_sta *sta_ctx;
+	struct wlan_mlo_link_switch_req *req =
+					&vdev->mlo_dev_ctx->link_ctx->last_req;
+
+	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
+
+	mlo_link_info =
+		mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id);
+
+	if (!mlo_link_info) {
+		mlo_err("New link ID not found");
+		goto out;
+	}
+
+	vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev);
+	if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr,
+				  (struct qdf_mac_addr *)vdev_mac)) {
+		mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT,
+			QDF_MAC_ADDR_REF(vdev_mac),
+			QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes));
+		goto out;
+	}
+
+	wlan_vdev_set_link_id(vdev, req->new_ieee_link_id);
+	copied_conn_req_lock_acquire(sta_ctx);
+	if (sta_ctx->copied_conn_req) {
+		qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req,
+			     sizeof(struct wlan_cm_connect_req));
+	} else {
+		copied_conn_req_lock_release(sta_ctx);
+		goto out;
+	}
+	copied_conn_req_lock_release(sta_ctx);
+
+	conn_req.vdev_id = wlan_vdev_get_id(vdev);
+	conn_req.source = CM_MLO_LINK_SWITCH_CONNECT;
+	qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr);
+	mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req);
+	conn_req.crypto.auth_type = 0;
+	conn_req.ml_parnter_info = sta_ctx->ml_partner_info;
+	status = wlan_cm_start_connect(vdev, &conn_req);
+	if (QDF_IS_STATUS_SUCCESS(status))
+		mlo_update_connected_links(vdev, 1);
+
+	wlan_cm_free_connect_req_param(&conn_req);
+
+out:
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlo_err("VDEV %d link switch connect request failed",
+			wlan_vdev_get_id(vdev));
+		mlo_mgr_remove_link_switch_cmd(vdev);
+	}
+
+	return status;
+}
+
+void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
+				      QDF_STATUS status)
+{
+	struct wlan_mlo_link_switch_req *req;
+
+	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
+	if (QDF_IS_STATUS_SUCCESS(status))
+		mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
+	else
+		mlo_err("VDEV %d link switch connect failed", req->vdev_id);
+
 	mlo_mgr_remove_link_switch_cmd(vdev);
-	return QDF_STATUS_SUCCESS;
 }
 
 static QDF_STATUS

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

@@ -1219,6 +1219,11 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 		return;
 	}
 
+	if (rsp->cm_id & CM_ID_LSWITCH_BIT) {
+		mlo_info("Skip for link switch connect request");
+		return;
+	}
+
 	if (mlo_sta_ignore_link_connect_fail(vdev))
 		return;
 
@@ -1254,6 +1259,7 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 				qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
 					     rsp->connect_ies.assoc_rsp.ptr,
 					     rsp->connect_ies.assoc_rsp.len);
+			sta_ctx->ml_partner_info = rsp->ml_parnter_info;
 			/* Update connected_links_bmap for all vdev taking
 			 * part in association
 			 */

+ 2 - 0
wmi/src/wmi_unified_11be_tlv.c

@@ -310,6 +310,8 @@ uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr,
 			req->mlo_params.nstr_bitmap_present;
 	mlo_params->mlo_flags.nstr_bitmap_size =
 			req->mlo_params.nstr_bitmap_size;
+	mlo_params->mlo_flags.mlo_link_switch =
+			req->mlo_params.link_switch_in_progress;
 	mlo_params->nstr_indication_bitmap =
 		req->mlo_params.nstr_indication_bitmap;