From adfe908a35cd4ed7a2cd61e89e609a907a9c0e0d Mon Sep 17 00:00:00 2001 From: Mohit Khanna Date: Fri, 17 Nov 2017 13:11:17 -0800 Subject: [PATCH] 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 --- dp/inc/cdp_txrx_mob_def.h | 20 ++++++++++++++ dp/inc/cdp_txrx_ops.h | 4 +++ dp/inc/cdp_txrx_peer_ops.h | 53 ++++++++++++++++++++++++++++++++++++++ dp/wifi3.0/dp_main.c | 26 +++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/dp/inc/cdp_txrx_mob_def.h b/dp/inc/cdp_txrx_mob_def.h index d9907ea91204..2bb08a7d570e 100644 --- a/dp/inc/cdp_txrx_mob_def.h +++ b/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 diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 08dcdd28b6af..057415558259 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/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, diff --git a/dp/inc/cdp_txrx_peer_ops.h b/dp/inc/cdp_txrx_peer_ops.h index bf60331ec438..c10abb6bd9fa 100644 --- a/dp/inc/cdp_txrx_peer_ops.h +++ b/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 diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 1bc57fdd35fa..a26b0f653312 100644 --- a/dp/wifi3.0/dp_main.c +++ b/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,