Browse Source

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
Amir Patel 5 years ago
parent
commit
44bd807fa7
3 changed files with 49 additions and 4 deletions
  1. 13 2
      dp/wifi3.0/dp_main.c
  2. 32 2
      dp/wifi3.0/dp_rx_mon_status.c
  3. 4 0
      hal/wifi3.0/hal_generic_api.h

+ 13 - 2
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)

+ 32 - 2
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) {

+ 4 - 0
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;
 	}