Quellcode durchsuchen

qcacmn: Avoid reference of peer object after peer_teardown

In API dp_peer_find_by_id return NULL if delete_in_progress
bit is set, this will avoid referencing peer memory which will
be free in peer_unmap event asynchronously.

Change-Id: Ieab559b9274a886809a9baa9bb348d348e924625
CRs-fixed: 2194265
Chaithanya Garrepalli vor 7 Jahren
Ursprung
Commit
974da2640a
3 geänderte Dateien mit 52 neuen und 28 gelöschten Zeilen
  1. 9 2
      dp/wifi3.0/dp_peer.c
  2. 26 3
      dp/wifi3.0/dp_peer.h
  3. 17 23
      dp/wifi3.0/dp_rx.c

+ 9 - 2
dp/wifi3.0/dp_peer.c

@@ -914,6 +914,8 @@ static inline struct dp_peer *dp_peer_find_add_id(struct dp_soc *soc,
 			   qdf_atomic_read(&peer->ref_cnt));
 		soc->peer_id_to_obj_map[peer_id] = peer;
 
+		qdf_assert_always(!peer->delete_in_progress);
+
 		if (dp_peer_find_add_id_to_obj(peer, peer_id)) {
 			/* TBDXXX: assert for now */
 			QDF_ASSERT(0);
@@ -994,7 +996,8 @@ dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id)
 	struct dp_peer *peer;
 	struct dp_soc *soc = (struct dp_soc *)soc_handle;
 	uint8_t i;
-	peer = dp_peer_find_by_id(soc, peer_id);
+
+	peer = __dp_peer_find_by_id(soc, peer_id);
 
 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH,
 		"peer_unmap_event (soc:%pK) peer_id %d peer %pK\n",
@@ -1005,8 +1008,12 @@ dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id)
 	 * If the peer ID is for a vdev, then the peer pointer stored
 	 * in peer_id_to_obj_map will be NULL.
 	 */
-	if (!peer)
+	if (!peer) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			"%s: Received unmap event for invalid peer_id"
+			" %u\n", __func__, peer_id);
 		return;
+	}
 
 	soc->peer_id_to_obj_map[peer_id] = NULL;
 	for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) {

+ 26 - 3
dp/wifi3.0/dp_peer.h

@@ -23,9 +23,8 @@
 #include "dp_types.h"
 
 #define DP_INVALID_PEER_ID 0xffff
-
 /**
- * dp_peer_find_by_id() - Returns peer object given the peer id
+ * __dp_peer_find_by_id() - Returns peer object given the peer id
  *
  * @soc		: core DP soc context
  * @peer_id	: peer id from peer object can be retrieved
@@ -33,7 +32,7 @@
  * Return: struct dp_peer*: Pointer to DP peer object
  */
 static inline struct dp_peer *
-dp_peer_find_by_id(struct dp_soc *soc,
+__dp_peer_find_by_id(struct dp_soc *soc,
 		   uint16_t peer_id)
 {
 	struct dp_peer *peer;
@@ -53,6 +52,30 @@ dp_peer_find_by_id(struct dp_soc *soc,
 	return peer;
 }
 
+/**
+ * dp_peer_find_by_id() - Returns peer object given the peer id
+ *                        if delete_in_progress in not set for peer
+ *
+ * @soc		: core DP soc context
+ * @peer_id	: peer id from peer object can be retrieved
+ *
+ * Return: struct dp_peer*: Pointer to DP peer object
+ */
+static inline struct dp_peer *
+dp_peer_find_by_id(struct dp_soc *soc,
+		   uint16_t peer_id)
+{
+	struct dp_peer *peer;
+
+	peer = __dp_peer_find_by_id (soc, peer_id);
+
+	if (peer && peer->delete_in_progress) {
+		return NULL;
+	}
+
+	return peer;
+}
+
 void dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id,
 	uint16_t hw_peer_id, uint8_t vdev_id, uint8_t *peer_mac_addr);
 void dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id);

+ 17 - 23
dp/wifi3.0/dp_rx.c

@@ -317,12 +317,6 @@ dp_get_vdev_from_peer(struct dp_soc *soc,
 	}
 	return vdev;
 }
-/*
- * In case of LFR, this is an empty inline function
- */
-static inline void dp_rx_peer_validity_check(struct dp_peer *peer)
-{
-}
 #else
 static inline struct dp_vdev *
 dp_get_vdev_from_peer(struct dp_soc *soc,
@@ -340,14 +334,6 @@ dp_get_vdev_from_peer(struct dp_soc *soc,
 		return peer->vdev;
 	}
 }
-
-/*
- * Assert if PEER is NULL
- */
-static inline void dp_rx_peer_validity_check(struct dp_peer *peer)
-{
-	qdf_assert_always(peer);
-}
 #endif
 
 /**
@@ -723,6 +709,10 @@ uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t mpdu)
 				dp_rx_mon_deliver(soc, i,
 						pdev->invalid_peer_head_msdu,
 						pdev->invalid_peer_tail_msdu);
+
+				pdev->invalid_peer_head_msdu = NULL;
+				pdev->invalid_peer_tail_msdu = NULL;
+
 				return 0;
 			}
 		}
@@ -1332,8 +1322,20 @@ done:
 			deliver_list_tail = NULL;
 		}
 
-		if (qdf_likely(peer != NULL))
+		if (qdf_likely(peer != NULL)) {
 			vdev = peer->vdev;
+		} else {
+			qdf_nbuf_free(nbuf);
+			nbuf = next;
+			continue;
+		}
+
+		if (qdf_unlikely(vdev == NULL)) {
+			qdf_nbuf_free(nbuf);
+			nbuf = next;
+			DP_STATS_INC(soc, rx.err.invalid_vdev, 1);
+			continue;
+		}
 
 		/*
 		 * Check if DMA completed -- msdu_done is the last bit
@@ -1387,14 +1389,6 @@ done:
 			}
 		}
 
-		/*
-		 * This is a redundant sanity check, Ideally peer
-		 * should never be NULL here. if for any reason it
-		 * is NULL we will assert.
-		 * Do nothing for LFR case.
-		 */
-		dp_rx_peer_validity_check(peer);
-
 		if (!dp_wds_rx_policy_check(rx_tlv_hdr, vdev, peer,
 					hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr))) {
 			QDF_TRACE(QDF_MODULE_ID_DP,