Jelajahi Sumber

qcacmn: Implement reassoc framework

This change processes Duplicate Assoc req from MLO Station
This would reuse old link peers and populate assoc req IEs.

This will fail, if Assoc link is not same as previous,
and number of links are not same as previous assoc req
processing.

Change-Id: I6a8c412b0bc484e8eb64ca794e54e080c391f7f8
CRs-Fixed: 3465223
Srinivas Pitla 3 tahun lalu
induk
melakukan
ca2acbe6bc

+ 14 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h

@@ -278,6 +278,20 @@ mlo_mlme_peer_process_auth(struct mlpeer_auth_params *auth_param)
 }
 #endif
 
+/**
+ * mlo_mlme_peer_reassoc() - Reassoc mlo peer
+ * @vdev: Object manager vdev
+ * @ml_peer: MLO peer context
+ * @addr: Peer addr
+ * @frm_buf: Frame buffer for IE processing
+ *
+ * Return: void
+ */
+void mlo_mlme_peer_reassoc(struct wlan_objmgr_vdev *vdev,
+			   struct wlan_mlo_peer_context *ml_peer,
+			   struct qdf_mac_addr *addr,
+			   qdf_nbuf_t frm_buf);
+
 /**
  * mlo_get_link_vdev_ix() - Get index of link VDEV in MLD
  * @mldev: ML device context

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

@@ -48,6 +48,7 @@ struct ctxt_switch_mgr {
  * @MLO_PEER_DEAUTH:  Initiate Deauth for ML connection
  * @MLO_PEER_PENDING_AUTH:  Initiate process of pending auth
  * @MLO_BRIDGE_PEER_CREATE:   Bridge peer create
+ * @MLO_PEER_REASSOC:  Partner peer reassoc
  */
 enum mlo_msg_type {
 	MLO_PEER_CREATE,
@@ -57,6 +58,7 @@ enum mlo_msg_type {
 	MLO_PEER_DEAUTH,
 	MLO_PEER_PENDING_AUTH,
 	MLO_BRIDGE_PEER_CREATE,
+	MLO_PEER_REASSOC,
 };
 
 /*

+ 53 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_peer.h

@@ -183,6 +183,18 @@ bool mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer,
 bool wlan_mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer,
 				 struct wlan_objmgr_peer *peer);
 
+/**
+ * wlan_mlo_peer_is_link_peer() - check whether the peer is link peer
+ * @ml_peer: MLO peer
+ * @peer: Link peer
+ *
+ * This function checks whether the peer is link peer of MLO peer
+ *
+ * Return: true, if it is link peer
+ */
+bool wlan_mlo_peer_is_link_peer(struct wlan_mlo_peer_context *ml_peer,
+				struct wlan_objmgr_peer *peer);
+
 /**
  * wlan_mlo_partner_peer_assoc_post() - Notify partner peer assoc
  * @assoc_peer: Link peer
@@ -248,6 +260,23 @@ QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev,
 				qdf_nbuf_t frm_buf,
 				uint16_t aid);
 
+/**
+ * wlan_mlo_peer_asreq() - MLO peer process assoc req
+ * @vdev: Link VDEV
+ * @link_peer: Link peer
+ * @ml_info: ML links info
+ * @frm_buf: Assoc req buffer
+ *
+ * This function process assoc req on existing MLO peer and notifies other
+ * partner peers to process assoc request
+ *
+ * Return: SUCCESS, if MLO peer is successfully processed
+ */
+QDF_STATUS wlan_mlo_peer_asreq(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_objmgr_peer *link_peer,
+			       struct mlo_partner_info *ml_info,
+			       qdf_nbuf_t frm_buf);
+
 /**
  * mlo_peer_cleanup() - Free MLO peer
  * @ml_peer: MLO peer
@@ -302,6 +331,20 @@ QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer,
 				     struct wlan_objmgr_peer *peer,
 				     qdf_nbuf_t frm_buf);
 
+/**
+ * wlan_mlo_link_asresp_attach() - MLO link peer assoc resp attach
+ * @ml_peer: MLO peer
+ * @peer: Link peer
+ * @frm_buf: Assoc resp buffer of non-assoc link
+ *
+ * This function attaches assoc resp of link peer to MLO peer
+ *
+ * Return: SUCCESS, if peer is successfully attached to MLO peer
+ */
+QDF_STATUS wlan_mlo_link_asresp_attach(struct wlan_mlo_peer_context *ml_peer,
+				       struct wlan_objmgr_peer *peer,
+				       qdf_nbuf_t frm_buf);
+
 /**
  * wlan_mlo_link_peer_delete() - MLO link peer delete
  * @peer: Link peer
@@ -663,6 +706,16 @@ mlo_peer_free_auth_param(struct mlpeer_auth_params *auth_params)
  */
 bool wlan_mlo_partner_peer_delete_is_allowed(struct wlan_objmgr_peer *src_peer);
 
+/**
+ * wlan_mlo_validate_reassocreq() - Checks MLO peer reassoc processing
+ * @ml_peer: ML peer
+ *
+ * This function checks whether Reassoc from MLO peer is processed successfully
+ *
+ * Return: SUCCESS, if Reassoc processing is done
+ */
+QDF_STATUS wlan_mlo_validate_reassocreq(struct wlan_mlo_peer_context *ml_peer);
+
 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
 /**
  * wlan_objmgr_mlo_update_primary_info() - Update is_primary flag

+ 7 - 1
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -607,6 +607,7 @@ struct wlan_mlo_mld_cap {
  * @peer_list: list of peers on the MLO link
  * @link_peer_cnt: Number of link peers attached
  * @max_links: Max links for this ML peer
+ * @link_asresp_cnt: Number of reassoc resp generated
  * @mlo_peer_id: unique ID for the peer
  * @peer_mld_addr: MAC address of MLD link
  * @mlo_ie: MLO IE struct
@@ -632,6 +633,7 @@ struct wlan_mlo_peer_context {
 	struct wlan_mlo_link_peer_entry peer_list[MAX_MLO_LINK_PEERS];
 	uint8_t link_peer_cnt;
 	uint8_t max_links;
+	uint8_t link_asresp_cnt;
 	uint32_t mlo_peer_id;
 	struct qdf_mac_addr peer_mld_addr;
 	uint8_t *mlo_ie;
@@ -803,6 +805,7 @@ struct mlo_tgt_partner_info {
  * @mlo_mlme_ext_peer_process_auth: Callback to process pending auth
  * @mlo_mlme_ext_handle_sta_csa_param: Callback to handle sta csa param
  * @mlo_mlme_ext_sta_op_class:
+ * @mlo_mlme_ext_peer_reassoc: Callback to process reassoc
  */
 struct mlo_mlme_ext_ops {
 	QDF_STATUS (*mlo_mlme_ext_validate_conn_req)(
@@ -838,7 +841,10 @@ struct mlo_mlme_ext_ops {
 	QDF_STATUS (*mlo_mlme_ext_sta_op_class)(
 			struct vdev_mlme_obj *vdev_mlme,
 			uint8_t *ml_ie);
-
+	QDF_STATUS (*mlo_mlme_ext_peer_reassoc)(struct wlan_objmgr_vdev *vdev,
+					struct wlan_mlo_peer_context *ml_peer,
+					struct qdf_mac_addr *addr,
+					qdf_nbuf_t frm_buf);
 };
 
 /* maximum size of vdev bitmap array for MLO link set active command */

+ 15 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c

@@ -299,6 +299,21 @@ void mlo_mlme_peer_process_auth(struct mlpeer_auth_params *auth_param)
 }
 #endif
 
+void mlo_mlme_peer_reassoc(struct wlan_objmgr_vdev *vdev,
+			   struct wlan_mlo_peer_context *ml_peer,
+			   struct qdf_mac_addr *addr,
+			   qdf_nbuf_t frm_buf)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
+	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc)
+		return;
+
+	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc(vdev, ml_peer, addr,
+						     frm_buf);
+}
+
 uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *ml_dev,
 			     struct wlan_objmgr_vdev *vdev)
 {

+ 31 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_msgq.c

@@ -92,6 +92,17 @@ QDF_STATUS mlo_msgq_post(enum mlo_msg_type type,
 		mlo_mlme_peer_process_auth(peer_auth->auth_params);
 		break;
 
+	case MLO_PEER_REASSOC:
+		peer_create = (struct peer_create_notif_s *)payload;
+		mlo_mlme_peer_reassoc(peer_create->vdev_link,
+				      peer_create->ml_peer, &peer_create->addr,
+				      peer_create->frm_buf);
+		qdf_nbuf_free(peer_create->frm_buf);
+		wlan_mlo_peer_release_ref(peer_create->ml_peer);
+		wlan_objmgr_vdev_release_ref(peer_create->vdev_link,
+					     WLAN_MLO_MGR_ID);
+		break;
+
 	default:
 		break;
 	}
@@ -225,6 +236,15 @@ QDF_STATUS mlo_msgq_post(enum mlo_msg_type type,
 		peer_auth->auth_params = peer_auth_l->auth_params;
 		break;
 
+	case MLO_PEER_REASSOC:
+		peer_create = &msg->m.peer_create;
+		peer_create_l = (struct peer_create_notif_s *)payload;
+		peer_create->frm_buf = peer_create_l->frm_buf;
+		peer_create->ml_peer = peer_create_l->ml_peer;
+		peer_create->vdev_link = peer_create_l->vdev_link;
+		qdf_copy_macaddr(&peer_create->addr, &peer_create_l->addr);
+		break;
+
 	default:
 		break;
 	}
@@ -304,6 +324,17 @@ static void mlo_msgq_msg_process_hdlr(struct mlo_ctxt_switch_msg_s *msg)
 		mlo_mlme_peer_process_auth(peer_auth->auth_params);
 		break;
 
+	case MLO_PEER_REASSOC:
+		peer_create = &msg->m.peer_create;
+		mlo_mlme_peer_reassoc(peer_create->vdev_link,
+				      peer_create->ml_peer, &peer_create->addr,
+				      peer_create->frm_buf);
+		qdf_nbuf_free(peer_create->frm_buf);
+		wlan_mlo_peer_release_ref(peer_create->ml_peer);
+		wlan_objmgr_vdev_release_ref(peer_create->vdev_link,
+					     WLAN_MLO_MGR_ID);
+		break;
+
 	default:
 		break;
 	}

+ 279 - 1
umac/mlo_mgr/src/wlan_mlo_mgr_peer.c

@@ -75,6 +75,54 @@ static void mlo_partner_peer_create_post(struct wlan_mlo_dev_context *ml_dev,
 	}
 }
 
+static void mlo_partner_peer_reassoc_post(struct wlan_mlo_dev_context *ml_dev,
+					  struct wlan_objmgr_vdev *vdev_link,
+					  struct wlan_mlo_peer_context *ml_peer,
+					  qdf_nbuf_t frm_buf,
+					  struct mlo_partner_info *ml_info)
+{
+	struct peer_create_notif_s peer_create;
+	QDF_STATUS status;
+	uint8_t i;
+	uint8_t link_id;
+
+	if (wlan_objmgr_vdev_try_get_ref(vdev_link, WLAN_MLO_MGR_ID) ==
+							QDF_STATUS_SUCCESS) {
+		peer_create.vdev_link = vdev_link;
+	} else {
+		mlo_err("VDEV is not in created state");
+		return;
+	}
+
+	wlan_mlo_peer_get_ref(ml_peer);
+	peer_create.ml_peer = ml_peer;
+	link_id = wlan_vdev_get_link_id(vdev_link);
+	for (i = 0; i < ml_info->num_partner_links; i++) {
+		if (link_id != ml_info->partner_link_info[i].link_id)
+			continue;
+
+		qdf_copy_macaddr(&peer_create.addr,
+				 &ml_info->partner_link_info[i].link_addr);
+		break;
+	}
+
+	status = mlo_peer_create_get_frm_buf(ml_peer, &peer_create, frm_buf);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wlan_mlo_peer_release_ref(ml_peer);
+		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
+		mlo_err("nbuf clone is failed");
+		return;
+	}
+
+	status = mlo_msgq_post(MLO_PEER_REASSOC, ml_dev, &peer_create);
+	if (status != QDF_STATUS_SUCCESS) {
+		qdf_nbuf_free(frm_buf);
+		wlan_mlo_peer_release_ref(ml_peer);
+		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
+	}
+}
+
 static void mlo_link_peer_assoc_notify(struct wlan_mlo_dev_context *ml_dev,
 				       struct wlan_objmgr_peer *peer)
 {
@@ -242,7 +290,7 @@ bool mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer,
 
 	peer_entry = &ml_peer->peer_list[0];
 
-	if (peer_entry->link_peer != peer)
+	if (peer_entry->link_peer == peer)
 		is_assoc_peer = true;
 
 	return is_assoc_peer;
@@ -265,6 +313,34 @@ bool wlan_mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer,
 	return is_assoc_peer;
 }
 
+bool wlan_mlo_peer_is_link_peer(struct wlan_mlo_peer_context *ml_peer,
+				struct wlan_objmgr_peer *peer)
+{
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	bool is_link_peer = false;
+	uint16_t i;
+
+	if (!ml_peer || !peer)
+		return is_link_peer;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		peer_entry = &ml_peer->peer_list[i];
+		if (!peer_entry->link_peer)
+			continue;
+
+		if (peer == peer_entry->link_peer) {
+			is_link_peer = true;
+			break;
+		}
+	}
+
+	mlo_peer_lock_release(ml_peer);
+
+	return is_link_peer;
+}
+
 void wlan_mlo_partner_peer_assoc_post(struct wlan_objmgr_peer *assoc_peer)
 {
 	struct wlan_mlo_dev_context *ml_dev;
@@ -1029,6 +1105,128 @@ wlan_mlo_get_bridge_peer_psoc_id(struct wlan_objmgr_vdev *vdev,
 }
 #endif
 
+QDF_STATUS wlan_mlo_peer_asreq(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_objmgr_peer *link_peer,
+			       struct mlo_partner_info *ml_info,
+			       qdf_nbuf_t frm_buf)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_mlo_peer_context *ml_peer = NULL;
+	struct wlan_objmgr_vdev *link_vdevs[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL };
+	struct wlan_objmgr_vdev *vdev_link;
+	QDF_STATUS status;
+	uint16_t i;
+	uint16_t j;
+	uint16_t link_count;
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	struct wlan_objmgr_peer *iter_peer;
+
+	/* get ML VDEV from VDEV */
+	ml_dev = vdev->mlo_dev_ctx;
+	if (!ml_dev) {
+		mlo_err("ML dev ctx is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	ml_peer = link_peer->mlo_peer_ctx;
+	if (!ml_peer) {
+		mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " ML peer is NULL",
+			ml_dev->mld_id,
+			QDF_MAC_ADDR_REF(link_peer->mldaddr));
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!wlan_mlo_peer_is_assoc_peer(ml_peer, link_peer)) {
+		mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT "Assoc req received on non-assoc peer" QDF_MAC_ADDR_FMT,
+			ml_dev->mld_id,
+			QDF_MAC_ADDR_REF(link_peer->mldaddr),
+			QDF_MAC_ADDR_REF(link_peer->macaddr));
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = mlo_dev_get_link_vdevs(vdev, ml_dev,
+					ml_info, link_vdevs);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " get link vdevs failed",
+			ml_dev->mld_id,
+			QDF_MAC_ADDR_REF(link_peer->mldaddr));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* If ML peer state is not in Assoc done state, drop REASSOC req */
+	if (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE) {
+		mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " invalid state %d",
+			ml_dev->mld_id,
+			QDF_MAC_ADDR_REF(link_peer->mldaddr),
+			ml_peer->mlpeer_state);
+
+		mlo_dev_release_link_vdevs(link_vdevs);
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	link_count = 0;
+	for (j = 0; j < ml_peer->max_links; j++) {
+		peer_entry = &ml_peer->peer_list[j];
+		iter_peer = peer_entry->link_peer;
+		if (!iter_peer)
+			continue;
+
+		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+			vdev_link = link_vdevs[i];
+			if (!vdev_link)
+				continue;
+
+			if (vdev_link != wlan_peer_get_vdev(iter_peer))
+				continue;
+
+			link_count++;
+			break;
+		}
+	}
+	if (link_count != ml_peer->link_peer_cnt) {
+		mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " incorrect link peers",
+			ml_dev->mld_id,
+			QDF_MAC_ADDR_REF(link_peer->mldaddr));
+		mlo_dev_release_link_vdevs(link_vdevs);
+
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* Notify other vdevs about assoc req */
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev_link = link_vdevs[i];
+		if (!vdev_link)
+			continue;
+
+		if (vdev_link == vdev)
+			continue;
+
+		mlo_partner_peer_reassoc_post(ml_dev, vdev_link,
+					      ml_peer, frm_buf, ml_info);
+	}
+
+	mlo_dev_release_link_vdevs(link_vdevs);
+
+	if (QDF_IS_STATUS_ERROR(wlan_mlo_validate_reassocreq(ml_peer))) {
+		mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " reassoc proc is failed %pK",
+			 ml_dev->mld_id,
+			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
+			 ml_peer);
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " reassoc handled %pK",
+		 ml_dev->mld_id,
+		 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
+		 ml_peer);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev,
 				struct wlan_objmgr_peer *link_peer,
 				struct mlo_partner_info *ml_info,
@@ -1404,6 +1602,52 @@ QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer,
 	return status;
 }
 
+QDF_STATUS wlan_mlo_link_asresp_attach(struct wlan_mlo_peer_context *ml_peer,
+				       struct wlan_objmgr_peer *peer,
+				       qdf_nbuf_t frm_buf)
+{
+	uint16_t i;
+	struct wlan_mlo_link_peer_entry *peer_entry;
+
+	if (!ml_peer) {
+		mlo_err(" ml peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!peer) {
+		ml_peer->link_asresp_cnt++;
+		mlo_err(" ml peer or link peer pointer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	mlo_peer_lock_acquire(ml_peer);
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		peer_entry = &ml_peer->peer_list[i];
+		if (!peer_entry->link_peer)
+			continue;
+
+		if (peer == peer_entry->link_peer) {
+			ml_peer->link_asresp_cnt++;
+			/* Free previous assoc resp buffer */
+			if (peer_entry->assoc_rsp_buf) {
+				qdf_nbuf_free(peer_entry->assoc_rsp_buf);
+				peer_entry->assoc_rsp_buf = NULL;
+			}
+
+			if (frm_buf)
+				peer_entry->assoc_rsp_buf = frm_buf;
+			else
+				peer_entry->assoc_rsp_buf = NULL;
+
+			break;
+		}
+	}
+
+	mlo_peer_lock_release(ml_peer);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_mlo_link_peer_delete(struct wlan_objmgr_peer *peer)
 {
 	struct wlan_mlo_peer_context *ml_peer;
@@ -1745,3 +1989,37 @@ bool wlan_mlo_partner_peer_delete_is_allowed(struct wlan_objmgr_peer *src_peer)
 	return true;
 }
 #endif
+
+QDF_STATUS wlan_mlo_validate_reassocreq(struct wlan_mlo_peer_context *ml_peer)
+{
+	uint16_t i;
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!ml_peer) {
+		mlo_err(" ml peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		peer_entry = &ml_peer->peer_list[i];
+		if (!peer_entry->link_peer)
+			continue;
+
+		/* Check non-assoc link peer Assoc resp buf is valid
+		 * (exclude bridge peer)
+		 */
+		if (i && !peer_entry->assoc_rsp_buf &&
+		    (wlan_peer_get_peer_type(peer_entry->link_peer) !=
+						WLAN_PEER_MLO_BRIDGE)) {
+			status = QDF_STATUS_E_FAILURE;
+			break;
+		}
+	}
+
+	mlo_peer_lock_release(ml_peer);
+
+	return status;
+}