Jelajahi Sumber

qcacmn: Handle invalid decap type during rx mon tlv processing

- Handle scenario where decap type may be invalid when
  buff address tlv is received.
- Add check for min number of frags during restitch process.
- Minor fixes during rx mon tlv processing.

Change-Id: I0120d97e297701362183189e29c1d5df91affdc1
CRs-Fixed: 3216050
Jeevan Kukkalli 3 tahun lalu
induk
melakukan
e0231b2771

+ 2 - 0
dp/inc/cdp_txrx_mon_struct.h

@@ -380,6 +380,7 @@ enum cdp_mon_phyrx_abort_reason_code {
  * @mon_rx_desc_invalid: rx_desc invalid count
  * @mpdu_ppdu_id_mismatch_drop: mpdu's ppdu id did not match destination
  *  ring ppdu id
+ * @mpdu_decap_type_invalid: mpdu decap type invalid count
  * @rx_undecoded_count: Received undecoded frame count
  * @rx_undecoded_error: Rx undecoded errors
  * @rx_hdr_not_received: Rx HDR not received for MPDU
@@ -425,6 +426,7 @@ struct cdp_pdev_mon_stats {
 	uint32_t mon_rx_desc_invalid;
 	uint32_t mon_nbuf_sanity_err;
 	uint32_t mpdu_ppdu_id_mismatch_drop;
+	uint32_t mpdu_decap_type_invalid;
 #ifdef QCA_UNDECODED_METADATA_SUPPORT
 	uint32_t rx_undecoded_count;
 	uint32_t rx_undecoded_error[CDP_PHYRX_ERR_MAX];

+ 3 - 0
dp/wifi3.0/monitor/2.0/dp_mon_2.0.h

@@ -37,6 +37,9 @@
 #define DP_MON_MSDU_LOGGING 0
 #define DP_MON_MPDU_LOGGING 1
 
+#define DP_MON_DECAP_FORMAT_INVALID 0xff
+#define DP_MON_MIN_FRAGS_FOR_RESTITCH 2
+
 /* monitor frame filter modes */
 enum dp_mon_frm_filter_mode {
 	/* mode filter pass */

+ 40 - 9
dp/wifi3.0/monitor/2.0/dp_rx_mon_2.0.c

@@ -391,7 +391,7 @@ dp_rx_mon_process_ppdu_info(struct dp_pdev *pdev,
 				status = dp_lite_mon_rx_mpdu_process(pdev, ppdu_info,
 								     mpdu, mpdu_idx, user);
 				if (status != QDF_STATUS_SUCCESS) {
-					qdf_nbuf_free(mpdu);
+					dp_mon_free_parent_nbuf(mon_pdev, mpdu);
 					continue;
 				}
 			} else {
@@ -401,8 +401,12 @@ dp_rx_mon_process_ppdu_info(struct dp_pdev *pdev,
 						continue;
 					}
 
-					dp_rx_mon_handle_full_mon(pdev,
-								  ppdu_info, mpdu);
+					status = dp_rx_mon_handle_full_mon(pdev,
+									   ppdu_info, mpdu);
+					if (status != QDF_STATUS_SUCCESS) {
+						dp_mon_free_parent_nbuf(mon_pdev, mpdu);
+						continue;
+					}
 				} else {
 					dp_mon_free_parent_nbuf(mon_pdev, mpdu);
 					continue;
@@ -519,7 +523,7 @@ dp_rx_mon_add_ppdu_info_to_wq(struct dp_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 
-void
+QDF_STATUS
 dp_rx_mon_handle_full_mon(struct dp_pdev *pdev,
 			  struct hal_rx_ppdu_info *ppdu_info,
 			  qdf_nbuf_t mpdu)
@@ -557,7 +561,13 @@ dp_rx_mon_handle_full_mon(struct dp_pdev *pdev,
 		qdf_nbuf_trim_add_frag_size(mpdu,
 					    qdf_nbuf_get_nr_frags(mpdu) - 1,
 					    -HAL_RX_FCS_LEN, 0);
-		return;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	num_frags = qdf_nbuf_get_nr_frags(mpdu);
+	if (qdf_unlikely(num_frags < DP_MON_MIN_FRAGS_FOR_RESTITCH)) {
+		dp_mon_debug("not enough frags(%d) for restitch", num_frags);
+		return QDF_STATUS_E_FAILURE;
 	}
 
 	l2_hdr_offset = DP_RX_MON_NONRAW_L2_HDR_PAD_BYTE;
@@ -824,6 +834,8 @@ dp_rx_mon_handle_full_mon(struct dp_pdev *pdev,
 			msdu_cur = qdf_nbuf_queue_next(msdu_cur);
 		}
 	}
+
+	return QDF_STATUS_SUCCESS;
 }
 
 /**
@@ -978,6 +990,10 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 			}
 			ppdu_info->mpdu_info[ppdu_info->user_id].mpdu_start_received = true;
 			ppdu_info->mpdu_info[user_id].first_rx_hdr_rcvd = true;
+			/* initialize decap type to invalid, this will be set to appropriate
+			 * value once the mpdu start tlv is received
+			 */
+			ppdu_info->mpdu_info[user_id].decap_type = DP_MON_DECAP_FORMAT_INVALID;
 		} else {
 			if (ppdu_info->mpdu_info[user_id].decap_type ==
 					HAL_HW_RX_DECAP_FORMAT_RAW) {
@@ -1056,6 +1072,18 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 			return num_buf_reaped;
 		}
 
+		if (mpdu_info->decap_type == DP_MON_DECAP_FORMAT_INVALID) {
+			/* decap type is invalid, drop the frame */
+			mon_pdev->rx_mon_stats.mpdu_decap_type_invalid++;
+			DP_STATS_INC(mon_soc, frag_free, 1);
+			mon_pdev->rx_mon_stats.parent_buf_free++;
+			qdf_frag_free(addr);
+			qdf_nbuf_free(nbuf);
+			/* we have freed the nbuf mark the q entry null */
+			ppdu_info->mpdu_q[user_id][mpdu_idx] = NULL;
+			return num_buf_reaped;
+		}
+
 		tmp_nbuf = qdf_get_nbuf_valid_frag(nbuf);
 
 		if (!tmp_nbuf) {
@@ -1132,6 +1160,8 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 		/* update msdu metadata at last buffer of msdu in MPDU */
 		nbuf = ppdu_info->mpdu_q[user_id][mpdu_idx];
 		if (!nbuf) {
+			/* reset msdu info for next msdu for same user */
+			qdf_mem_zero(msdu_info, sizeof(*msdu_info));
 			dp_mon_err(" <%d> nbuf is NULL, return user: %d mpdu_idx: %d", __LINE__, user_id, mpdu_idx);
 			break;
 		}
@@ -1157,7 +1187,7 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 		dp_rx_mon_pf_tag_to_buf_headroom_2_0(nbuf, ppdu_info, pdev,
 						     soc);
 		/* reset msdu info for next msdu for same user */
-		qdf_mem_zero(msdu_info, sizeof(msdu_info));
+		qdf_mem_zero(msdu_info, sizeof(*msdu_info));
 
 		/* If flow classification is enabled,
 		 * update cce_metadata and fse_metadata
@@ -1185,6 +1215,8 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 		mpdu_info = &ppdu_info->mpdu_info[user_id];
 		nbuf = ppdu_info->mpdu_q[user_id][mpdu_idx];
 		if (!nbuf) {
+			/* reset mpdu info for next mpdu for same user */
+			qdf_mem_zero(mpdu_info, sizeof(*mpdu_info));
 			dp_mon_err(" <%d> nbuf is NULL, return user: %d mpdu_idx: %d", __LINE__, user_id, mpdu_idx);
 			break;
 		}
@@ -1197,10 +1229,9 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 		mpdu_meta->full_pkt = mpdu_info->full_pkt;
 		mpdu_meta->truncated = mpdu_info->truncated;
 
-		num_frags = qdf_nbuf_get_nr_frags(nbuf);
 		ppdu_info->mpdu_q[user_id][mpdu_idx] = nbuf;
-		/* reset msdu info for next msdu for same user */
-		qdf_mem_zero(mpdu_info, sizeof(mpdu_info));
+		/* reset mpdu info for next mpdu for same user */
+		qdf_mem_zero(mpdu_info, sizeof(*mpdu_info));
 		ppdu_info->mpdu_info[ppdu_info->user_id].mpdu_start_received = false;
 		ppdu_info->mpdu_count[user_id]++;
 	}

+ 3 - 1
dp/wifi3.0/monitor/2.0/dp_rx_mon_2.0.h

@@ -171,8 +171,10 @@ static inline void dp_rx_mon_process_ppdu(void *context)
  * @pdev: DP pdev
  * @ppdu_info: PPDU info
  * @mpdu: mpdu buf
+ *
+ * Return: SUCCESS or Failure
  */
-void
+QDF_STATUS
 dp_rx_mon_handle_full_mon(struct dp_pdev *pdev,
 			  struct hal_rx_ppdu_info *ppdu_info,
 			  qdf_nbuf_t mpdu);

+ 2 - 0
dp/wifi3.0/monitor/dp_mon.c

@@ -872,6 +872,8 @@ dp_print_pdev_rx_mon_stats(struct dp_pdev *pdev)
 		       rx_mon_stats->dest_ppdu_drop);
 	DP_PRINT_STATS("mpdu_ppdu_id_mismatch_drop = %u",
 		       rx_mon_stats->mpdu_ppdu_id_mismatch_drop);
+	DP_PRINT_STATS("mpdu_decap_type_invalid = %u",
+		       rx_mon_stats->mpdu_decap_type_invalid);
 	stat_ring_ppdu_ids =
 		(uint32_t *)qdf_mem_malloc(sizeof(uint32_t) * MAX_PPDU_ID_HIST);
 	dest_ring_ppdu_ids =