Browse Source

qcacmn: Add peer APIs to get and release peer ref

The existing peer API cdp_peer_find_by_add does not maintain any peer
references. So a peer which is returned by the API may get deleted in a
different context. This may lead to access to a already deleted memory.

Fix the issue by introducing new APIs "peer_get_ref" and
"peer_release_ref" which make sure the peer is valid until it is
"released" (peer_release_ref is called).

Change-Id: Id04d13bc6a1b8a55c1ae9246077f64ffb86de3d8
CRs-Fixed: 2146742
Mohit Khanna 7 years ago
parent
commit
adfe908a35
4 changed files with 103 additions and 0 deletions
  1. 20 0
      dp/inc/cdp_txrx_mob_def.h
  2. 4 0
      dp/inc/cdp_txrx_ops.h
  3. 53 0
      dp/inc/cdp_txrx_peer_ops.h
  4. 26 0
      dp/wifi3.0/dp_main.c

+ 20 - 0
dp/inc/cdp_txrx_mob_def.h

@@ -187,6 +187,26 @@ enum ol_tx_spec {
 	OL_TX_SPEC_NO_FREE = 0x20,      /* give to cb rather than free */
 };
 
+/**
+ * @enum peer_debug_id_type: debug ids to track peer get_ref and release_ref
+ * @brief Unique peer debug IDs to track the callers. Each new usage can add to
+ *        this enum list to create a new "PEER_DEBUG_ID_".
+ * @PEER_DEBUG_ID_OL_INTERNAL: debug id for OL internal usage
+ * @PEER_DEBUG_ID_WMA_PKT_DROP: debug id for wma_is_pkt_drop_candidate API
+ * @PEER_DEBUG_ID_WMA_ADDBA_REQ: debug id for ADDBA request
+ * @PEER_DEBUG_ID_WMA_DELBA_REQ: debug id for DELBA request
+ * @PEER_DEBUG_ID_LIM_SEND_ADDBA_RESP: debug id for send ADDBA response
+ * @PEER_DEBUG_ID_MAX: debug id MAX
+ */
+enum peer_debug_id_type {
+	PEER_DEBUG_ID_OL_INTERNAL = 0,
+	PEER_DEBUG_ID_WMA_PKT_DROP = 1,
+	PEER_DEBUG_ID_WMA_ADDBA_REQ = 2,
+	PEER_DEBUG_ID_WMA_DELBA_REQ = 3,
+	PEER_DEBUG_ID_LIM_SEND_ADDBA_RESP = 4,
+	PEER_DEBUG_ID_MAX
+};
+
 /**
  * struct ol_txrx_desc_type - txrx descriptor type
  * @sta_id: sta id

+ 4 - 0
dp/inc/cdp_txrx_ops.h

@@ -905,6 +905,10 @@ struct cdp_peer_ops {
 	QDF_STATUS (*change_peer_state)(uint8_t sta_id,
 			enum ol_txrx_peer_state sta_state,
 			bool roam_synch_in_progress);
+	void * (*peer_get_ref_by_addr)(struct cdp_pdev *pdev,
+				       u8 *peer_addr, uint8_t *peer_id,
+				       enum peer_debug_id_type debug_id);
+	void (*peer_release_ref)(void *peer, enum peer_debug_id_type debug_id);
 	void * (*find_peer_by_addr)(struct cdp_pdev *pdev,
 			uint8_t *peer_addr, uint8_t *peer_id);
 	void * (*find_peer_by_addr_and_vdev)(struct cdp_pdev *pdev,

+ 53 - 0
dp/inc/cdp_txrx_peer_ops.h

@@ -145,6 +145,59 @@ cdp_peer_remove_for_vdev(ol_txrx_soc_handle soc,
 	return;
 }
 
+/**
+ * cdp_peer_get_ref_by_addr() - Find peer by peer mac address and inc peer ref
+ * @soc - data path soc handle
+ * @pdev - data path device instance
+ * @peer_addr - peer mac address
+ * @peer_id - local peer id with target mac address
+ * @debug_id - debug_id to track caller
+ *
+ * To release the peer ref, cdp_peer_release_ref needs to be called.
+ *
+ * Return: peer instance void pointer
+ *         NULL cannot find target peer
+ */
+static inline void
+*cdp_peer_get_ref_by_addr(ol_txrx_soc_handle soc, struct cdp_pdev *pdev,
+			  u8 *peer_addr, u8 *peer_id,
+			  enum peer_debug_id_type debug_id)
+{
+	if (!soc || !soc->ops || !soc->ops->peer_ops) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
+			  "%s invalid instance", __func__);
+		return NULL;
+	}
+
+	if (soc->ops->peer_ops->peer_get_ref_by_addr)
+		return soc->ops->peer_ops->peer_get_ref_by_addr(
+			pdev, peer_addr, peer_id, debug_id);
+
+	return NULL;
+}
+
+/**
+ * cdp_peer_release_ref() - Release peer reference
+ * @soc - data path soc handle
+ * @peer - peer pointer
+ * @debug_id - debug_id to track caller
+ *
+ * Return:void
+ */
+static inline void
+cdp_peer_release_ref(ol_txrx_soc_handle soc, void *peer,
+		     enum peer_debug_id_type debug_id)
+{
+	if (!soc || !soc->ops || !soc->ops->peer_ops) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
+			  "%s invalid instance", __func__);
+		return;
+	}
+
+	if (soc->ops->peer_ops->peer_release_ref)
+		soc->ops->peer_ops->peer_release_ref(peer, debug_id);
+}
+
 /**
  * cdp_peer_find_by_addr() - Find peer by peer mac address
  * @soc - data path soc handle

+ 26 - 0
dp/wifi3.0/dp_main.c

@@ -5642,11 +5642,37 @@ static struct cdp_cfg_ops dp_ops_cfg = {
 	/* WIFI 3.0 DP NOT IMPLEMENTED YET */
 };
 
+/*
+ * dp_wrapper_peer_get_ref_by_addr - wrapper function to get to peer
+ * @dev: physical device instance
+ * @peer_mac_addr: peer mac address
+ * @local_id: local id for the peer
+ * @debug_id: to track enum peer access
+
+ * Return: peer instance pointer
+ */
+static inline void *
+dp_wrapper_peer_get_ref_by_addr(struct cdp_pdev *dev, u8 *peer_mac_addr,
+				u8 *local_id,
+				enum peer_debug_id_type debug_id)
+{
+	/*
+	 * Currently this function does not implement the "get ref"
+	 * functionality and is mapped to dp_find_peer_by_addr which does not
+	 * increment the peer ref count. So the peer state is uncertain after
+	 * calling this API. The functionality needs to be implemented.
+	 * Accordingly the corresponding release_ref function is NULL.
+	 */
+	return dp_find_peer_by_addr(dev, peer_mac_addr, local_id);
+}
+
 static struct cdp_peer_ops dp_ops_peer = {
 	.register_peer = dp_register_peer,
 	.clear_peer = dp_clear_peer,
 	.find_peer_by_addr = dp_find_peer_by_addr,
 	.find_peer_by_addr_and_vdev = dp_find_peer_by_addr_and_vdev,
+	.peer_get_ref_by_addr = dp_wrapper_peer_get_ref_by_addr,
+	.peer_release_ref = NULL,
 	.local_peer_id = dp_local_peer_id,
 	.peer_find_by_local_id = dp_peer_find_by_local_id,
 	.peer_state_update = dp_peer_state_update,