qcacmn: deliver RX data to stack evev if no peer found

Deliver RX data to stack even if no peer found, this is
needed for LFR roaming case like eapol data.

Change-Id: Ic81f29993fb4542847bd076042a13de6e9f18173
CRs-Fixed: 2468082
diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c
index 21bc8e0..ca23a47 100644
--- a/dp/wifi3.0/dp_rx.c
+++ b/dp/wifi3.0/dp_rx.c
@@ -1512,6 +1512,96 @@
 #endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */
 
 /**
+ * dp_is_special_data() - check is the pkt special like eapol, dhcp, etc
+ *
+ * @nbuf: pkt skb pointer
+ *
+ * Return: true if matched, false if not
+ */
+static inline
+bool dp_is_special_data(qdf_nbuf_t nbuf)
+{
+	if (qdf_nbuf_is_ipv4_arp_pkt(nbuf) ||
+	    qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) ||
+	    qdf_nbuf_is_ipv4_eapol_pkt(nbuf) ||
+	    qdf_nbuf_is_ipv6_dhcp_pkt(nbuf))
+		return true;
+	else
+		return false;
+}
+
+#ifdef DP_RX_PKT_NO_PEER_DELIVER
+/**
+ * dp_rx_deliver_to_stack_no_peer() - try deliver rx data even if
+ *				      no corresbonding peer found
+ * @soc: core txrx main context
+ * @nbuf: pkt skb pointer
+ *
+ * This function will try to deliver some RX special frames to stack
+ * even there is no peer matched found. for instance, LFR case, some
+ * eapol data will be sent to host before peer_map done.
+ *
+ * Return: None
+ */
+static inline
+void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf)
+{
+	uint32_t peer_mdata;
+	uint16_t peer_id;
+	uint8_t vdev_id;
+	struct dp_vdev *vdev;
+	uint32_t l2_hdr_offset = 0;
+	uint16_t msdu_len = 0;
+	uint32_t pkt_len = 0;
+	uint8_t *rx_tlv_hdr;
+
+	peer_mdata =  QDF_NBUF_CB_RX_PEER_ID(nbuf);
+
+	peer_id = DP_PEER_METADATA_PEER_ID_GET(peer_mdata);
+	if (peer_id > soc->max_peers)
+		goto deliver_fail;
+
+	vdev_id = DP_PEER_METADATA_ID_GET(peer_mdata);
+	vdev = dp_get_vdev_from_soc_vdev_id_wifi3(soc, vdev_id);
+	if (!vdev || !vdev->osif_rx)
+		goto deliver_fail;
+
+	rx_tlv_hdr = qdf_nbuf_data(nbuf);
+	l2_hdr_offset =
+		hal_rx_msdu_end_l3_hdr_padding_get(rx_tlv_hdr);
+
+	msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf);
+	pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN;
+
+	qdf_nbuf_set_pktlen(nbuf, pkt_len);
+	qdf_nbuf_pull_head(nbuf,
+			   RX_PKT_TLVS_LEN +
+			   l2_hdr_offset);
+
+	/* only allow special frames */
+	if (!dp_is_special_data(nbuf))
+		goto deliver_fail;
+
+	vdev->osif_rx(vdev->osif_vdev, nbuf);
+	DP_STATS_INC(soc, rx.err.pkt_delivered_no_peer, 1);
+	return;
+
+deliver_fail:
+	DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer, 1,
+			 QDF_NBUF_CB_RX_PKT_LEN(nbuf));
+	qdf_nbuf_free(nbuf);
+}
+#else
+static inline
+void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf)
+{
+	DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer, 1,
+			 QDF_NBUF_CB_RX_PKT_LEN(nbuf));
+	qdf_nbuf_free(nbuf);
+}
+#endif
+
+/**
  * dp_rx_process() - Brain of the Rx processing functionality
  *		     Called from the bottom half (tasklet/NET_RX_SOFTIRQ)
  * @soc: core txrx main context
@@ -1825,9 +1915,7 @@
 		if (qdf_likely(peer)) {
 			vdev = peer->vdev;
 		} else {
-			DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer, 1,
-					 QDF_NBUF_CB_RX_PKT_LEN(nbuf));
-			qdf_nbuf_free(nbuf);
+			dp_rx_deliver_to_stack_no_peer(soc, nbuf);
 			nbuf = next;
 			continue;
 		}
diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c
index 1cdd289..39f27fd 100644
--- a/dp/wifi3.0/dp_stats.c
+++ b/dp/wifi3.0/dp_stats.c
@@ -5098,6 +5098,8 @@
 			       pdev->soc->stats.rx.err.invalid_sa_da_idx);
 		DP_PRINT_STATS("defrag peer uninit %u",
 			       pdev->soc->stats.rx.err.defrag_peer_uninit);
+		DP_PRINT_STATS("pkts delivered no peer %u",
+			       pdev->soc->stats.rx.err.pkt_delivered_no_peer);
 
 		DP_PRINT_STATS("Reo Statistics");
 		DP_PRINT_STATS("rbm error: %u msdus",
@@ -5560,6 +5562,8 @@
 		       soc->stats.rx.err.invalid_sa_da_idx);
 	DP_PRINT_STATS("Defrag peer uninit = %d",
 		       soc->stats.rx.err.defrag_peer_uninit);
+	DP_PRINT_STATS("Pkts delivered no peer = %d",
+		       soc->stats.rx.err.pkt_delivered_no_peer);
 	DP_PRINT_STATS("Invalid Pdev = %d",
 		       soc->stats.rx.err.invalid_pdev);
 	DP_PRINT_STATS("Invalid Peer = %d",
diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h
index 445dd4d..c9cac73 100644
--- a/dp/wifi3.0/dp_types.h
+++ b/dp/wifi3.0/dp_types.h
@@ -690,6 +690,8 @@
 			/* Invalid PDEV error count */
 			uint32_t invalid_pdev;
 
+			/* Packets delivered to stack that no related peer */
+			uint32_t pkt_delivered_no_peer;
 			/* Defrag peer uninit error count */
 			uint32_t defrag_peer_uninit;
 			/* Invalid sa_idx or da_idx*/