Browse Source

qca-wifi: Tx capture stability fixes

1) Avoid removing wrong nbuf from queue
   In corner case, the current flow can remove first nbuf instead of
   actual nbuf from queue, this can lead to having the actual pointer
   stored at two array indexs.

2) tsf wraparound handling for mgmt frame

3) Mpdu tried is higher than ba_sisze
   mpdus[] is allocated with ba_size, it is observed that mpdu_tried
   is higher than ba_size, which can lead to buffer overlow.
   Added the check of ba_size along with mpdu_tried.

To avoid it, copied nbuf in the corner case, and left the actual nbuf
in the xretries queue.

Change-Id: Ifa57eaf62cf50aa2c356a6d1f41ef4b7283be52e
CRs-Fixed: 2643848
Srinivas Pitla 5 years ago
parent
commit
d0aafa3624
1 changed files with 62 additions and 8 deletions
  1. 62 8
      dp/wifi3.0/dp_tx_capture.c

+ 62 - 8
dp/wifi3.0/dp_tx_capture.c

@@ -1053,6 +1053,7 @@ static void  dp_iterate_free_peer_msdu_q(void *pdev_hdl)
 							continue;
 							continue;
 						qdf_nbuf_free(
 						qdf_nbuf_free(
 							ppdu_desc->mpdus[i]);
 							ppdu_desc->mpdus[i]);
+						ppdu_desc->mpdus[i] = NULL;
 					}
 					}
 					qdf_mem_free(ppdu_desc->mpdus);
 					qdf_mem_free(ppdu_desc->mpdus);
 					ppdu_desc->mpdus = NULL;
 					ppdu_desc->mpdus = NULL;
@@ -2152,6 +2153,50 @@ void dp_send_data_to_stack(struct dp_pdev *pdev,
 		dp_gen_ack_rx_frame(pdev, &tx_capture_info);
 		dp_gen_ack_rx_frame(pdev, &tx_capture_info);
 }
 }
 
 
+static qdf_nbuf_t dp_tx_mon_get_next_mpdu(
+	struct cdp_tx_completion_ppdu *xretry_ppdu,
+	qdf_nbuf_t mpdu_nbuf)
+{
+	qdf_nbuf_t next_nbuf = NULL;
+	qdf_nbuf_queue_t temp_xretries;
+
+	if (mpdu_nbuf != qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q)) {
+		next_nbuf = qdf_nbuf_queue_next(mpdu_nbuf);
+		/* Initialize temp list */
+		qdf_nbuf_queue_init(&temp_xretries);
+		/* Move entries into temp list till the mpdu_nbuf is found */
+		while ((qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q)) &&
+		       (mpdu_nbuf !=
+				qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q))) {
+			qdf_nbuf_queue_add(&temp_xretries,
+				qdf_nbuf_queue_remove(&xretry_ppdu->mpdu_q));
+		}
+		if ((qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q)) &&
+		    (mpdu_nbuf == qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q))) {
+			/* Remove mpdu_nbuf from queue */
+			qdf_nbuf_queue_remove(&xretry_ppdu->mpdu_q);
+			/* Add remaining nbufs into temp queue */
+			qdf_nbuf_queue_append(&temp_xretries,
+					      &xretry_ppdu->mpdu_q);
+			/* Reinit xretry_ppdu->mpdu_q */
+			qdf_nbuf_queue_init(&xretry_ppdu->mpdu_q);
+			/* append all the entries into original queue */
+			qdf_nbuf_queue_append(&xretry_ppdu->mpdu_q,
+					      &temp_xretries);
+		} else {
+			QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE,
+				  QDF_TRACE_LEVEL_FATAL,
+				  "%s: This is buggy scenario, did not find nbuf in queue ",
+				  __func__);
+		}
+	} else {
+		qdf_nbuf_queue_remove(&xretry_ppdu->mpdu_q);
+		next_nbuf = qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q);
+	}
+
+	return next_nbuf;
+}
+
 static void
 static void
 dp_tx_mon_proc_xretries(struct dp_pdev *pdev, struct dp_peer *peer,
 dp_tx_mon_proc_xretries(struct dp_pdev *pdev, struct dp_peer *peer,
 			uint16_t tid)
 			uint16_t tid)
@@ -2187,7 +2232,8 @@ dp_tx_mon_proc_xretries(struct dp_pdev *pdev, struct dp_peer *peer,
 			mpdu_tried = ppdu_desc->user[0].mpdu_tried_ucast +
 			mpdu_tried = ppdu_desc->user[0].mpdu_tried_ucast +
 			ppdu_desc->user[0].mpdu_tried_mcast;
 			ppdu_desc->user[0].mpdu_tried_mcast;
 			mpdu_nbuf = qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q);
 			mpdu_nbuf = qdf_nbuf_queue_first(&xretry_ppdu->mpdu_q);
-			for (i = 0; (mpdu_tried > 0) && mpdu_nbuf; i++) {
+			for (i = 0; (i < ppdu_desc->user[0].ba_size) &&
+				(mpdu_tried > 0) && (mpdu_nbuf); i++) {
 				if (!(SEQ_BIT(ppdu_desc->user[0].enq_bitmap,
 				if (!(SEQ_BIT(ppdu_desc->user[0].enq_bitmap,
 				    i)))
 				    i)))
 					continue;
 					continue;
@@ -2214,11 +2260,13 @@ dp_tx_mon_proc_xretries(struct dp_pdev *pdev, struct dp_peer *peer,
 				ppdu_desc->pending_retries--;
 				ppdu_desc->pending_retries--;
 				if (ptr_msdu_info->transmit_cnt == 0) {
 				if (ptr_msdu_info->transmit_cnt == 0) {
 					ppdu_desc->mpdus[seq_no - start_seq] =
 					ppdu_desc->mpdus[seq_no - start_seq] =
-						mpdu_nbuf;
-					qdf_nbuf_queue_remove(
-						&xretry_ppdu->mpdu_q);
-					mpdu_nbuf = qdf_nbuf_queue_first(
-						&xretry_ppdu->mpdu_q);
+							mpdu_nbuf;
+					/*
+					 * This API removes mpdu_nbuf from q and
+					 * returns next mpdu from the queue
+					 */
+					mpdu_nbuf = dp_tx_mon_get_next_mpdu(
+							xretry_ppdu, mpdu_nbuf);
 				} else {
 				} else {
 					ppdu_desc->mpdus[seq_no - start_seq] =
 					ppdu_desc->mpdus[seq_no - start_seq] =
 					qdf_nbuf_copy_expand_fraglist(
 					qdf_nbuf_copy_expand_fraglist(
@@ -2599,6 +2647,7 @@ dp_check_mgmt_ctrl_ppdu(struct dp_pdev *pdev,
 	uint32_t ppdu_id;
 	uint32_t ppdu_id;
 	size_t head_size;
 	size_t head_size;
 	uint32_t status = 1;
 	uint32_t status = 1;
+	uint32_t tsf_delta;
 
 
 	ppdu_desc = (struct cdp_tx_completion_ppdu *)
 	ppdu_desc = (struct cdp_tx_completion_ppdu *)
 		qdf_nbuf_data(nbuf_ppdu_desc);
 		qdf_nbuf_data(nbuf_ppdu_desc);
@@ -2682,8 +2731,13 @@ get_mgmt_pkt_from_queue:
 			if (is_sgen_pkt) {
 			if (is_sgen_pkt) {
 				start_tsf = (ppdu_desc->ppdu_start_timestamp &
 				start_tsf = (ppdu_desc->ppdu_start_timestamp &
 					     LOWER_32_MASK);
 					     LOWER_32_MASK);
-				if (ptr_comp_info->tx_tsf <
-				     (start_tsf + MAX_MGMT_ENQ_DELAY)) {
+
+				if (start_tsf > ptr_comp_info->tx_tsf)
+					tsf_delta = start_tsf - ptr_comp_info->tx_tsf;
+				else
+					tsf_delta = ptr_comp_info->tx_tsf - start_tsf;
+
+				if (tsf_delta > MAX_MGMT_ENQ_DELAY) {
 					/*
 					/*
 					 * free the older mgmt buffer from
 					 * free the older mgmt buffer from
 					 * the queue and get new mgmt buffer
 					 * the queue and get new mgmt buffer