Quellcode durchsuchen

qcacmn: Fix peer ref counting leak while finding and deleting peer

There are two instances where peer ref counting leak has been observed
1) When DUT-STA is connected to AP1 and if it tries to roam to AP2 or
   to same AP1 then as part of roam sync indication, it needs to delete
   the old peer and create the new peer. Deletion of old peer is
   happening through force delete operation which is No-OP for some of
   the platforms. In such cases, do normal peer delete operation, so
   that peer ref count can be deleted properly.

2) When looking up peer by its associated vdev, driver goes one by one
   all peers and check their associated vdev and compare with given
   vdev. If it doesn't find the match then it returns without releasing
   the reference count.

CRs-Fixed: 2263607
Change-Id: Ibcad72943258e531e29498961d3d7e692fd05b36
Krunal Soni vor 6 Jahren
Ursprung
Commit
304792abd8
3 geänderte Dateien mit 40 neuen und 1 gelöschten Zeilen
  1. 27 0
      dp/inc/cdp_txrx_peer_ops.h
  2. 3 1
      dp/wifi3.0/dp_peer.c
  3. 10 0
      dp/wifi3.0/dp_rx_defrag.c

+ 27 - 0
dp/inc/cdp_txrx_peer_ops.h

@@ -721,4 +721,31 @@ static inline void cdp_peer_detach_force_delete(ol_txrx_soc_handle soc,
 
 	return;
 }
+
+/**
+ * is_cdp_peer_detach_force_delete_supported() - To check if force delete
+ *						 operation is supported
+ * @soc: pointer to SOC handle
+ *
+ * Some of the platforms support force delete operation and some of them
+ * don't. This API returns true if API which handles force delete operation
+ * is registered and false otherwise.
+ *
+ * Return: true if API which handles force delete operation is registered
+ *	   false in all other cases
+ */
+static inline bool
+is_cdp_peer_detach_force_delete_supported(ol_txrx_soc_handle soc)
+{
+	if (!soc || !soc->ops || !soc->ops->peer_ops) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
+			  "%s invalid instance", __func__);
+		return false;
+	}
+
+	if (soc->ops->peer_ops->peer_detach_force_delete)
+		return true;
+
+	return false;
+}
 #endif /* _CDP_TXRX_PEER_H_ */

+ 3 - 1
dp/wifi3.0/dp_peer.c

@@ -1984,8 +1984,10 @@ void *dp_find_peer_by_addr_and_vdev(struct cdp_pdev *pdev_handle,
 	if (!peer)
 		return NULL;
 
-	if (peer->vdev != vdev)
+	if (peer->vdev != vdev) {
+		qdf_atomic_dec(&peer->ref_cnt);
 		return NULL;
+	}
 
 	*local_id = peer->local_id;
 	DP_TRACE(INFO, "peer %pK vdev %pK local id %d", peer, vdev, *local_id);

+ 10 - 0
dp/wifi3.0/dp_rx_defrag.c

@@ -1270,6 +1270,16 @@ void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid)
 	struct dp_rx_reorder_array_elem *rx_reorder_array_elem =
 				peer->rx_tid[tid].array;
 
+	if (!rx_reorder_array_elem) {
+		/*
+		 * if this condition is hit then somebody
+		 * must have reset this pointer to NULL.
+		 * array pointer usually points to base variable
+		 * of TID queue structure: "struct dp_rx_tid"
+		 */
+		QDF_ASSERT(0);
+		return;
+	}
 	/* Free up nbufs */
 	dp_rx_defrag_frames_free(rx_reorder_array_elem->head);