From 44bd807fa7c579ee85a241823f9e74b0fae2a03d Mon Sep 17 00:00:00 2001 From: Amir Patel Date: Mon, 5 Aug 2019 11:36:17 +0530 Subject: [PATCH] qcacmn: Fix memleak in m_copy mode 1. Assign correct first msdu payload 2. Reset mpdu fcs ok bitmap upon reception of next ppdu 3. Free rx_ppdu_buf_q in error cases Change-Id: I4f2e687d51d1e10693adc9cfcdee49190ba6815c CRs-Fixed: 2502889 --- dp/wifi3.0/dp_main.c | 15 +++++++++++++-- dp/wifi3.0/dp_rx_mon_status.c | 34 ++++++++++++++++++++++++++++++++-- hal/wifi3.0/hal_generic_api.h | 4 ++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index cdeb8620de..b1b13beb2c 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3881,6 +3881,7 @@ static void dp_pdev_deinit(struct cdp_pdev *txrx_pdev, int force) dp_tx_ppdu_stats_detach(pdev); qdf_nbuf_free(pdev->sojourn_buf); + qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q); dp_cal_client_detach(&pdev->cal_client_ctx); @@ -7360,6 +7361,13 @@ dp_pdev_tid_stats_osif_drop(struct cdp_pdev *pdev, uint32_t val) dp_pdev->stats.tid_stats.osif_drop += val; } +static inline void +dp_pdev_disable_mcopy_code(struct dp_pdev *pdev) +{ + pdev->mcopy_mode = 0; + qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q); +} + /* * dp_config_debug_sniffer()- API to enable/disable debug sniffer * @pdev_handle: DP_PDEV handle @@ -7379,7 +7387,9 @@ dp_config_debug_sniffer(struct cdp_pdev *pdev_handle, int val) switch (val) { case 0: pdev->tx_sniffer_enable = 0; - pdev->mcopy_mode = 0; + if (pdev->mcopy_mode) + dp_pdev_disable_mcopy_code(pdev); + pdev->monitor_configured = false; if (!pdev->pktlog_ppdu_stats && !pdev->enhanced_stats_en && @@ -7402,7 +7412,8 @@ dp_config_debug_sniffer(struct cdp_pdev *pdev_handle, int val) case 1: pdev->tx_sniffer_enable = 1; - pdev->mcopy_mode = 0; + if (pdev->mcopy_mode) + dp_pdev_disable_mcopy_code(pdev); pdev->monitor_configured = false; if (!pdev->pktlog_ppdu_stats) diff --git a/dp/wifi3.0/dp_rx_mon_status.c b/dp/wifi3.0/dp_rx_mon_status.c index ddad46782c..070363906b 100644 --- a/dp/wifi3.0/dp_rx_mon_status.c +++ b/dp/wifi3.0/dp_rx_mon_status.c @@ -548,6 +548,9 @@ dp_rx_get_fcs_ok_msdu(struct dp_pdev *pdev, qdf_nbuf_t status_nbuf = NULL; unsigned long *fcs_ok_bitmap; + if (qdf_unlikely(qdf_nbuf_is_queue_empty(&pdev->rx_ppdu_buf_q))) + return NULL; + /* Obtain fcs_ok passed index from bitmap * this index is used to get fcs passed first msdu payload */ @@ -557,7 +560,10 @@ dp_rx_get_fcs_ok_msdu(struct dp_pdev *pdev, mpdu_fcs_ok = qdf_find_first_bit(fcs_ok_bitmap, HAL_RX_MAX_MPDU); - if (mpdu_fcs_ok >= HAL_RX_MAX_MPDU) + if (qdf_unlikely(mpdu_fcs_ok >= HAL_RX_MAX_MPDU)) + goto end; + + if (qdf_unlikely(!ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf)) goto end; /* Get status buffer by indexing mpdu_fcs_ok index @@ -565,15 +571,26 @@ dp_rx_get_fcs_ok_msdu(struct dp_pdev *pdev, * and clone the buffer */ status_nbuf = ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf; + ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf = NULL; + /* Take ref of status nbuf as this nbuf is to be * freeed by upper layer. */ qdf_nbuf_ref(status_nbuf); + ppdu_info->fcs_ok_msdu_info.first_msdu_payload = + ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].first_msdu_payload; + ppdu_info->fcs_ok_msdu_info.payload_len = + ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].payload_len; + end: /* Free the ppdu status buffer queue */ qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q); + qdf_mem_zero(&ppdu_info->ppdu_msdu_info, + (ppdu_info->com_info.mpdu_cnt_fcs_ok + + ppdu_info->com_info.mpdu_cnt_fcs_err) + * sizeof(struct hal_rx_msdu_payload_info)); return status_nbuf; } @@ -582,6 +599,13 @@ dp_rx_handle_ppdu_status_buf(struct dp_pdev *pdev, struct hal_rx_ppdu_info *ppdu_info, qdf_nbuf_t status_nbuf) { + qdf_nbuf_t dropnbuf; + + if (qdf_nbuf_queue_len(&pdev->rx_ppdu_buf_q) > + HAL_RX_MAX_MPDU) { + dropnbuf = qdf_nbuf_queue_remove(&pdev->rx_ppdu_buf_q); + qdf_nbuf_free(dropnbuf); + } qdf_nbuf_queue_add(&pdev->rx_ppdu_buf_q, status_nbuf); } /** @@ -615,7 +639,6 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, size = (ppdu_info->fcs_ok_msdu_info.first_msdu_payload - qdf_nbuf_data(nbuf)); - ppdu_info->fcs_ok_msdu_info.first_msdu_payload = NULL; if (qdf_nbuf_pull_head(nbuf, size) == NULL) return QDF_STATUS_SUCCESS; @@ -627,6 +650,7 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, return QDF_STATUS_SUCCESS; } + ppdu_info->fcs_ok_msdu_info.first_msdu_payload = NULL; nbuf_data = (uint32_t *)qdf_nbuf_data(nbuf); *nbuf_data = pdev->ppdu_info.com_info.ppdu_id; /* only retain RX MSDU payload in the skb */ @@ -667,6 +691,12 @@ dp_rx_process_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, * and devliver fcs_ok msdu buffer */ if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) { + if (qdf_unlikely(ppdu_info->com_info.mpdu_cnt != + (ppdu_info->com_info.mpdu_cnt_fcs_ok + + ppdu_info->com_info.mpdu_cnt_fcs_err))) { + qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q); + return; + } /* Get rx ppdu status buffer having fcs ok msdu */ status_nbuf = dp_rx_get_fcs_ok_msdu(pdev, ppdu_info); if (status_nbuf) { diff --git a/hal/wifi3.0/hal_generic_api.h b/hal/wifi3.0/hal_generic_api.h index e3e04e0cbf..514abd7ea1 100644 --- a/hal/wifi3.0/hal_generic_api.h +++ b/hal/wifi3.0/hal_generic_api.h @@ -444,12 +444,16 @@ hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo, /* If last ppdu_id doesn't match new ppdu_id, * 1. reset mpdu_cnt * 2. update last_ppdu_id with new + * 3. reset mpdu fcs bitmap */ if (com_info->ppdu_id != com_info->last_ppdu_id) { com_info->mpdu_cnt = 0; com_info->last_ppdu_id = com_info->ppdu_id; com_info->num_users = 0; + qdf_mem_zero(&com_info->mpdu_fcs_ok_bitmap, + HAL_RX_NUM_WORDS_PER_PPDU_BITMAP * + sizeof(com_info->mpdu_fcs_ok_bitmap[0])); } break; }