Explorar o código

qcacld-3.0: Store cdp peer setup/delete history

Any MLD peer setup call to cdp shall happen only after
clearing the existing MLD peer otherwise the MLD peer's
VDEV reference is lost on recreation. This leads to
VDEV reference leak.

Add history to track the peer setup and destroy sequence,
to understand the CP peer create/destroy sequence when
any such leak happens.

Change-Id: If338bc26e086490a3cc2bb4de32efa6a762ee0e6
CRs-Fixed: 3736548
(cherry picked from commit 1f2aba85c0bdefaa30f5a442ce215d9257be5e1c)
Vinod Kumar Pirla hai 1 ano
pai
achega
31ca035f37

+ 2 - 0
components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c

@@ -29,6 +29,7 @@
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include <include/wlan_pdev_mlme.h>
 #include "wlan_pdev_mlme_api.h"
+#include <wlan_psoc_mlme_api.h>
 #include "wlan_vdev_mgr_tgt_if_tx_api.h"
 #include "wlan_policy_mgr_public_struct.h"
 #include "spatial_reuse_api.h"
@@ -107,6 +108,7 @@ QDF_STATUS ucfg_mlme_psoc_open(struct wlan_objmgr_psoc *psoc)
 void ucfg_mlme_psoc_close(struct wlan_objmgr_psoc *psoc)
 {
 	/* Clear the MLME CFG Structure */
+	wlan_mlme_psoc_flush_peer_trans_history(psoc);
 }
 
 QDF_STATUS ucfg_mlme_pdev_open(struct wlan_objmgr_pdev *pdev)

+ 13 - 0
core/mac/src/pe/lim/lim_assoc_utils.c

@@ -322,10 +322,16 @@ QDF_STATUS lim_del_peer_info(struct mac_context *mac,
 	uint16_t i;
 	uint32_t  bitmap = 1 << CDP_PEER_DELETE_NO_SPECIAL;
 	bool peer_unmap_conf_support_enabled;
+	struct wlan_objmgr_peer *peer;
+	struct wlan_objmgr_psoc *psoc;
 
 	peer_unmap_conf_support_enabled =
 				cdp_cfg_get_peer_unmap_conf_support(soc);
 
+	psoc = wlan_vdev_get_psoc(pe_session->vdev);
+	if (!psoc)
+		return QDF_STATUS_E_FAILURE;
+
 	for (i = 0; i < pe_session->dph.dphHashTable.size; i++) {
 		tpDphHashNode sta_ds;
 
@@ -334,6 +340,13 @@ QDF_STATUS lim_del_peer_info(struct mac_context *mac,
 		if (!sta_ds)
 			continue;
 
+		peer = wlan_objmgr_get_peer_by_mac(psoc, sta_ds->staAddr,
+						   WLAN_LEGACY_MAC_ID);
+		if (peer) {
+			wma_peer_tbl_trans_add_entry(peer, false, NULL);
+			wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
+		}
+
 		cdp_peer_teardown(soc, pe_session->vdev_id, sta_ds->staAddr);
 		if (peer_unmap_conf_support_enabled)
 			cdp_peer_delete_sync(soc, pe_session->vdev_id,

+ 23 - 0
core/wma/inc/wma.h

@@ -1767,6 +1767,29 @@ QDF_STATUS wma_peer_unmap_conf_cb(uint8_t vdev_id,
 bool wma_objmgr_peer_exist(tp_wma_handle wma,
 			   uint8_t *peer_addr, uint8_t *peer_vdev_id);
 
+#ifdef WLAN_FEATURE_PEER_TRANS_HIST
+/**
+ * wma_peer_tbl_trans_add_entry() - Add peer transition to peer history
+ * @peer: Object manager peer pointer
+ * @is_create: Set to %true if @peer is getting created
+ * @peer_info: Info of peer setup on @peer create,
+ *               %NULL if @is_create is %false.
+ *
+ * Adds new entry to peer history about the transition of peer in the system.
+ * The APIs has to be called to keep record of create and delete of peer.
+ *
+ * Returns: void
+ */
+void wma_peer_tbl_trans_add_entry(struct wlan_objmgr_peer *peer, bool is_create,
+				  struct cdp_peer_setup_info *peer_info);
+#else
+static inline void
+wma_peer_tbl_trans_add_entry(struct wlan_objmgr_peer *peer, bool is_create,
+			     struct cdp_peer_setup_info *peer_info)
+{
+}
+#endif
+
 /**
  * wma_get_cca_stats() - send request to fw to get CCA
  * @wmi_hdl: wma handle

+ 152 - 50
core/wma/src/wma_dev_if.c

@@ -115,6 +115,7 @@
 #include "wlan_fwol_ucfg_api.h"
 #include "wlan_vdev_mgr_utils_api.h"
 #include "target_if.h"
+#include <wlan_psoc_mlme_api.h>
 
 /*
  * FW only supports 8 clients in SAP/GO mode for D3 WoW feature
@@ -1645,6 +1646,71 @@ bool wma_objmgr_peer_exist(tp_wma_handle wma,
 	return true;
 }
 
+#ifdef WLAN_FEATURE_PEER_TRANS_HIST
+void wma_peer_tbl_trans_add_entry(struct wlan_objmgr_peer *peer, bool is_create,
+				  struct cdp_peer_setup_info *peer_info)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_peer_tbl_trans_entry *peer_trans_entry;
+	uint8_t *peer_mac, *peer_mld;
+
+	vdev = wlan_peer_get_vdev(peer);
+	if (!vdev)
+		return;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc)
+		return;
+
+	peer_trans_entry = qdf_mem_malloc(sizeof(*peer_trans_entry));
+	if (!peer_trans_entry)
+		return;
+
+	peer_trans_entry->ts = qdf_get_log_timestamp();
+	peer_trans_entry->vdev_id = wlan_vdev_get_id(vdev);
+	peer_trans_entry->opmode = wlan_vdev_mlme_get_opmode(vdev);
+
+	peer_mac = wlan_peer_get_macaddr(peer);
+	peer_mld = wlan_peer_mlme_get_mldaddr(peer);
+	qdf_ether_addr_copy(&peer_trans_entry->peer_addr.bytes[0], peer_mac);
+	if (peer_mld) {
+		qdf_ether_addr_copy(&peer_trans_entry->peer_mld_addr.bytes[0],
+				    peer_mld);
+	}
+
+	peer_trans_entry->is_mlo = wlan_vdev_mlme_is_mlo_vdev(vdev);
+	peer_trans_entry->is_mlo_link = wlan_vdev_mlme_is_mlo_link_vdev(vdev);
+
+	if (wlan_cm_is_vdev_roam_sync_inprogress(vdev)) {
+		peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_ROAM;
+		peer_trans_entry->auth_status =
+				wlan_cm_check_mlo_roam_auth_status(vdev);
+		peer_trans_entry->num_roam_links = mlo_mgr_num_roam_links(vdev);
+	} else if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev)) {
+		peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_LINK_SWITCH;
+	} else if (is_create) {
+		peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_CONNECT;
+	} else {
+		peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_DISCONNECT;
+	}
+
+	if (is_create) {
+		peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_CREATE;
+		peer_trans_entry->is_primary = peer_info->is_primary_link;
+		peer_trans_entry->is_first_link = peer_info->is_first_link;
+	} else {
+		peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_DESTROY;
+	}
+
+	status = wlan_mlme_psoc_peer_tbl_trans_add_entry(psoc,
+							 peer_trans_entry);
+	if (QDF_IS_STATUS_ERROR(status))
+		qdf_mem_free(peer_trans_entry);
+}
+#endif
+
 /**
  * wma_remove_peer() - remove peer information from host driver and fw
  * @wma: wma handle
@@ -1669,6 +1735,7 @@ QDF_STATUS wma_remove_peer(tp_wma_handle wma, uint8_t *mac_addr,
 	uint8_t peer_vdev_id;
 	struct peer_delete_cmd_params del_param = {0};
 	struct wma_txrx_node *iface;
+	struct wlan_objmgr_peer *peer;
 
 	if (vdev_id >= WLAN_MAX_VDEVS) {
 		wma_err("Invalid vdev_id %d", vdev_id);
@@ -1690,19 +1757,25 @@ QDF_STATUS wma_remove_peer(tp_wma_handle wma, uint8_t *mac_addr,
 		return QDF_STATUS_E_INVAL;
 	}
 
-	if (!wma_objmgr_peer_exist(wma, peer_addr, &peer_vdev_id)) {
+	peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_addr,
+					   WLAN_LEGACY_WMA_ID);
+	if (!peer) {
 		wma_err("peer doesn't exist peer_addr "QDF_MAC_ADDR_FMT" vdevid %d peer_count %d",
 			 QDF_MAC_ADDR_REF(peer_addr), vdev_id,
 			 iface->peer_count);
 		return QDF_STATUS_E_INVAL;
 	}
 
+	peer_vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer));
 	if (peer_vdev_id != vdev_id) {
 		wma_err("peer "QDF_MAC_ADDR_FMT" is on vdev id %d but delete req on vdevid %d peer_count %d",
 			 QDF_MAC_ADDR_REF(peer_addr), peer_vdev_id, vdev_id,
 			 iface->peer_count);
+		wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID);
 		return QDF_STATUS_E_INVAL;
 	}
+
+	wma_peer_tbl_trans_add_entry(peer, false, NULL);
 	peer_unmap_conf_support_enabled =
 				cdp_cfg_get_peer_unmap_conf_support(soc);
 
@@ -1767,6 +1840,7 @@ peer_detach:
 			cdp_peer_delete(soc, vdev_id, peer_addr, bitmap);
 	}
 
+	wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID);
 	wlan_release_peer_key_wakelock(wma->pdev, peer_mac);
 	wma_remove_objmgr_peer(wma, iface->vdev, peer_mac);
 
@@ -2125,70 +2199,75 @@ QDF_STATUS wma_add_peer(tp_wma_handle wma,
 }
 
 #ifdef WLAN_FEATURE_11BE_MLO
+static void wma_peer_setup_fill_info(struct wlan_objmgr_psoc *psoc,
+				     struct wlan_objmgr_peer *peer,
+				     struct cdp_peer_setup_info *peer_info)
+{
+	uint8_t vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer));
+
+	peer_info->mld_peer_mac = wlan_peer_mlme_get_mldaddr(peer);
+	if (MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) &&
+	    wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) {
+		peer_info->is_first_link = true;
+		peer_info->is_primary_link = false;
+	} else if (wlan_cm_is_roam_sync_in_progress(psoc, vdev_id) &&
+		   wlan_vdev_mlme_get_is_mlo_vdev(psoc, vdev_id)) {
+		if (mlo_get_single_link_ml_roaming(psoc, vdev_id)) {
+			peer_info->is_first_link = true;
+			peer_info->is_primary_link = true;
+		} else {
+			peer_info->is_first_link = false;
+			peer_info->is_primary_link = true;
+		}
+	} else {
+		peer_info->is_first_link = wlan_peer_mlme_is_assoc_peer(peer);
+		peer_info->is_primary_link = peer_info->is_first_link;
+	}
+}
+
 /**
  * wma_cdp_peer_setup() - provide mlo information to cdp_peer_setup
- * @wma: wma handle
  * @dp_soc: dp soc
  * @vdev_id: vdev id
- * @peer_addr: peer mac addr
+ * @peer: Object manager peer pointer
+ * @peer_info: Peer setup info
  *
  * Return: VOID
  */
-static void wma_cdp_peer_setup(tp_wma_handle wma,
-			       ol_txrx_soc_handle dp_soc,
-			       uint8_t vdev_id,
-			       uint8_t *peer_addr)
+static void wma_cdp_peer_setup(ol_txrx_soc_handle dp_soc,
+			       uint8_t vdev_id, struct wlan_objmgr_peer *peer,
+			       struct cdp_peer_setup_info *peer_info)
 {
-	struct cdp_peer_setup_info peer_info;
-	uint8_t *mld_mac;
-	struct wlan_objmgr_peer *obj_peer = NULL;
+	uint8_t *mld_mac, *peer_addr;
 
-	obj_peer = wlan_objmgr_get_peer_by_mac(wma->psoc,
-					       peer_addr,
-					       WLAN_LEGACY_WMA_ID);
-	if (!obj_peer) {
-		wma_err("Invalid obj_peer");
-		return;
-	}
-
-	mld_mac = wlan_peer_mlme_get_mldaddr(obj_peer);
+	peer_addr = wlan_peer_get_macaddr(peer);
+	mld_mac = peer_info->mld_peer_mac;
 
 	if (!mld_mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mld_mac)) {
 		cdp_peer_setup(dp_soc, vdev_id, peer_addr, NULL);
-		wlan_objmgr_peer_release_ref(obj_peer, WLAN_LEGACY_WMA_ID);
 		return;
 	}
 
-	qdf_mem_zero(&peer_info, sizeof(peer_info));
-
-	peer_info.mld_peer_mac = mld_mac;
-	if (MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id) &&
-	    wlan_vdev_mlme_get_is_mlo_link(wma->psoc, vdev_id)) {
-		peer_info.is_first_link = 1;
-		peer_info.is_primary_link = 0;
-	} else if (wlan_cm_is_roam_sync_in_progress(wma->psoc, vdev_id) &&
-		   wlan_vdev_mlme_get_is_mlo_vdev(wma->psoc, vdev_id)) {
-		if (mlo_get_single_link_ml_roaming(wma->psoc, vdev_id)) {
-			peer_info.is_first_link = 1;
-			peer_info.is_primary_link = 1;
-		} else {
-			peer_info.is_first_link = 0;
-			peer_info.is_primary_link = 1;
-		}
-	} else {
-		peer_info.is_first_link = wlan_peer_mlme_is_assoc_peer(obj_peer);
-		peer_info.is_primary_link = peer_info.is_first_link;
-	}
-
-	cdp_peer_setup(dp_soc, vdev_id, peer_addr, &peer_info);
-	wlan_objmgr_peer_release_ref(obj_peer, WLAN_LEGACY_WMA_ID);
+	cdp_peer_setup(dp_soc, vdev_id, peer_addr, peer_info);
 }
 #else
-static void wma_cdp_peer_setup(tp_wma_handle wma,
-			       ol_txrx_soc_handle dp_soc,
-			       uint8_t vdev_id,
-			       uint8_t *peer_addr)
+static inline void
+wma_peer_setup_fill_info(struct wlan_objmgr_psoc *psoc,
+			 struct wlan_objmgr_peer *peer,
+			 struct cdp_peer_setup_info *peer_info)
+{
+	peer_info->mld_peer_mac = NULL;
+	peer_info->is_first_link = false;
+	peer_info->is_primary_link = false;
+}
+
+static void wma_cdp_peer_setup(ol_txrx_soc_handle dp_soc,
+			       uint8_t vdev_id, struct wlan_objmgr_peer *peer,
+			       struct cdp_peer_setup_info *peer_info)
 {
+	uint8_t *peer_addr;
+
+	peer_addr = wlan_peer_get_macaddr(peer);
 	cdp_peer_setup(dp_soc, vdev_id, peer_addr, NULL);
 }
 #endif
@@ -2201,6 +2280,8 @@ QDF_STATUS wma_create_peer(tp_wma_handle wma,
 {
 	void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC);
 	QDF_STATUS status;
+	struct wlan_objmgr_peer *obj_peer;
+	struct cdp_peer_setup_info peer_info = {0};
 
 	if (!dp_soc)
 		return QDF_STATUS_E_FAILURE;
@@ -2209,8 +2290,17 @@ QDF_STATUS wma_create_peer(tp_wma_handle wma,
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
+	obj_peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_addr,
+					       WLAN_LEGACY_WMA_ID);
+	if (!obj_peer)
+		return QDF_STATUS_E_FAILURE;
+
 	wma_increment_peer_count(wma, vdev_id);
-	wma_cdp_peer_setup(wma, dp_soc, vdev_id, peer_addr);
+
+	wma_peer_setup_fill_info(wma->psoc, obj_peer, &peer_info);
+	wma_peer_tbl_trans_add_entry(obj_peer, true, &peer_info);
+	wma_cdp_peer_setup(dp_soc, vdev_id, obj_peer, &peer_info);
+	wlan_objmgr_peer_release_ref(obj_peer, WLAN_LEGACY_WMA_ID);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -3501,6 +3591,8 @@ int wma_peer_create_confirm_handler(void *handle, uint8_t *evt_param_info,
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	int ret = -EINVAL;
 	uint8_t req_msg_type;
+	struct wlan_objmgr_peer *peer;
+	struct cdp_peer_setup_info peer_info = {0};
 
 	param_buf = (WMI_PEER_CREATE_CONF_EVENTID_param_tlvs *)evt_param_info;
 	if (!param_buf) {
@@ -3552,8 +3644,18 @@ int wma_peer_create_confirm_handler(void *handle, uint8_t *evt_param_info,
 			goto fail;
 		}
 
-		wma_cdp_peer_setup(wma, dp_soc, peer_create_rsp->vdev_id,
-				   peer_mac.bytes);
+		peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_mac.bytes,
+						   WLAN_LEGACY_WMA_ID);
+		if (!peer) {
+			status = QDF_STATUS_E_FAILURE;
+			goto fail;
+		}
+
+		wma_peer_setup_fill_info(wma->psoc, peer, &peer_info);
+		wma_peer_tbl_trans_add_entry(peer, true, &peer_info);
+		wma_cdp_peer_setup(dp_soc, peer_create_rsp->vdev_id,
+				   peer, &peer_info);
+		wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID);
 
 		status = QDF_STATUS_SUCCESS;
 		ret = 0;