Browse Source

qcacmn: WAR to drop MPDU with incorrect sw_peer_id

In certain scenarios where AP sends OFDMA TCP packet to
multiple STAs in HE80 mode in poor RSSI conditions, it has been
observed that host in STA gets in to null_q_descr handling case and
rxtlv doesn't carry correct sw_peer_id. Due to this,
driver can't find correct peer from table and ends up sending deauth
frame to handle invalid peer case. The TA is valid and host is able to
find the peer using the TA.

Apply workaround by detecting this special case and drop the frame.

CRs-Fixed: 2367420
Change-Id: I0cbdbb8e9976e739c959062261fc1c946e446d63
Krunal Soni 6 years ago
parent
commit
53add6504b
3 changed files with 72 additions and 4 deletions
  1. 3 0
      dp/wifi3.0/dp_main.c
  2. 67 4
      dp/wifi3.0/dp_rx_err.c
  3. 2 0
      dp/wifi3.0/dp_types.h

+ 3 - 0
dp/wifi3.0/dp_main.c

@@ -8506,6 +8506,9 @@ static void dp_txrx_path_stats(struct dp_soc *soc)
 			       pdev->stats.rx.err.mic_err);
 		DP_TRACE_STATS(INFO_HIGH, "Invalid peer on rx path: %u",
 			       pdev->soc->stats.rx.err.rx_invalid_peer.num);
+		DP_TRACE_STATS(INFO_HIGH, "sw_peer_id invalid %u",
+			       pdev->soc->stats.rx.err.rx_invalid_peer_id.num);
+
 
 		DP_TRACE_STATS(INFO_HIGH, "Reo Statistics");
 		DP_TRACE_STATS(INFO_HIGH, "rbm error: %u msdus",

+ 67 - 4
dp/wifi3.0/dp_rx_err.c

@@ -564,6 +564,64 @@ free_nbuf:
 	return;
 }
 
+#ifdef QCA_WIFI_QCA6390
+/**
+ * dp_rx_null_q_handle_invalid_peer_id_exception() - to find exception
+ * @soc: pointer to dp_soc struct
+ * @pool_id: Pool id to find dp_pdev
+ * @rx_tlv_hdr: TLV header of received packet
+ * @nbuf: SKB
+ *
+ * In certain types of packets if peer_id is not correct then
+ * driver may not be able find. Try finding peer by addr_2 of
+ * received MPDU. If you find the peer then most likely sw_peer_id &
+ * ast_idx is corrupted.
+ *
+ * Return: True if you find the peer by addr_2 of received MPDU else false
+ */
+static bool
+dp_rx_null_q_handle_invalid_peer_id_exception(struct dp_soc *soc,
+					      uint8_t pool_id,
+					      uint8_t *rx_tlv_hdr,
+					      qdf_nbuf_t nbuf)
+{
+	uint8_t local_id;
+	struct dp_peer *peer = NULL;
+	uint8_t *rx_pkt_hdr = hal_rx_pkt_hdr_get(rx_tlv_hdr);
+	struct dp_pdev *pdev = soc->pdev_list[pool_id];
+	struct ieee80211_frame *wh = (struct ieee80211_frame *)rx_pkt_hdr;
+
+	/*
+	 * WAR- In certain types of packets if peer_id is not correct then
+	 * driver may not be able find. Try finding peer by addr_2 of
+	 * received MPDU
+	 */
+	if (wh)
+		peer = dp_find_peer_by_addr((struct cdp_pdev *)pdev,
+					    wh->i_addr2, &local_id);
+	if (peer) {
+		dp_err("MPDU sw_peer_id & ast_idx is corrupted");
+		hal_rx_dump_pkt_tlvs(soc->hal_soc, rx_tlv_hdr,
+				     QDF_TRACE_LEVEL_INFO);
+		DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer_id,
+				 1, qdf_nbuf_len(nbuf));
+		qdf_nbuf_free(nbuf);
+
+		return true;
+	}
+	return false;
+}
+#else
+static inline bool
+dp_rx_null_q_handle_invalid_peer_id_exception(struct dp_soc *soc,
+					      uint8_t pool_id,
+					      uint8_t *rx_tlv_hdr,
+					      qdf_nbuf_t nbuf)
+{
+	return false;
+}
+#endif
+
 /**
  * dp_rx_null_q_desc_handle() - Function to handle NULL Queue
  *                              descriptor violation on either a
@@ -604,14 +662,14 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf,
 	msdu_len = hal_rx_msdu_start_msdu_len_get(rx_tlv_hdr);
 	pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN;
 
-	QDF_TRACE_ERROR_RL(QDF_MODULE_ID_DP,
-			   "Len %d Extn list %pK ",
-			   (uint32_t)qdf_nbuf_len(nbuf),
-			   qdf_nbuf_get_ext_list(nbuf));
 	/* Set length in nbuf */
 	if (!qdf_nbuf_get_ext_list(nbuf))
 		qdf_nbuf_set_pktlen(nbuf, pkt_len);
 
+	QDF_TRACE_ERROR_RL(QDF_MODULE_ID_DP,
+			   "Len %d Extn list %pK ",
+			   (uint32_t)qdf_nbuf_len(nbuf),
+			   qdf_nbuf_get_ext_list(nbuf));
 	/*
 	 * Check if DMA completed -- msdu_done is the last bit
 	 * to be written
@@ -626,6 +684,11 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf,
 		qdf_assert(0);
 	}
 
+	if (!peer &&
+	    dp_rx_null_q_handle_invalid_peer_id_exception(soc, pool_id,
+							  rx_tlv_hdr, nbuf))
+		return;
+
 	if (!peer) {
 		bool mpdu_done = false;
 		struct dp_pdev *pdev = soc->pdev_list[pool_id];

+ 2 - 0
dp/wifi3.0/dp_types.h

@@ -609,6 +609,8 @@ struct dp_soc_stats {
 			uint32_t invalid_pdev;
 			/* Invalid PEER Error count */
 			struct cdp_pkt_info rx_invalid_peer;
+			/* Invalid PEER ID count */
+			struct cdp_pkt_info rx_invalid_peer_id;
 			/* HAL ring access Fail error count */
 			uint32_t hal_ring_access_fail;
 			/* RX DMA error count */