From 974da2640ae4a970a8fd54c0ef1303c3578a89b1 Mon Sep 17 00:00:00 2001 From: Chaithanya Garrepalli Date: Thu, 22 Feb 2018 20:32:19 +0530 Subject: [PATCH] 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 --- dp/wifi3.0/dp_peer.c | 11 +++++++++-- dp/wifi3.0/dp_peer.h | 29 ++++++++++++++++++++++++++--- dp/wifi3.0/dp_rx.c | 40 +++++++++++++++++----------------------- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index ce3021fb130e..ff1fdc85a14a 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/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++) { diff --git a/dp/wifi3.0/dp_peer.h b/dp/wifi3.0/dp_peer.h index b12f94734f90..cfb2ce1dca12 100644 --- a/dp/wifi3.0/dp_peer.h +++ b/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); diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index c4df96800ec3..82f5a2d1c9bd 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/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,