qcacld-2.0: Monitor mode - Populate MCS/VHT info in Radiotap Header

In LL Monitor mode path obtain MCS/VHT information
from rx ppdu start descriptor and update the
Radiotap header fields

Change-Id: I8b10f3885ced9a55fdb634a663f9b3d5227a50dc
CRs-Fixed: 2182487
diff --git a/CORE/CLD_TXRX/HTT/htt_rx.c b/CORE/CLD_TXRX/HTT/htt_rx.c
index a34d5df..bf44d23 100644
--- a/CORE/CLD_TXRX/HTT/htt_rx.c
+++ b/CORE/CLD_TXRX/HTT/htt_rx.c
@@ -1598,15 +1598,81 @@
 }
 
 /**
- * htt_get_radiotap_rx_status() - Update information about the rx status, which
- * is used later for radiotap updation.
+ * get_ht_vht_info_ll() - get ht/vht information
+ * @rx_desc: pointer to PPDU start
+ * @rx_status: pointer to mon_rx_status.
+ *
+ * This function retrieve MCS/VHT info by parsing preamble,
+ * vht_sig_a1 and vht_sig_a2, which follows ieee80211 spec.
+ *
+ * Return: None.
+ */
+static void get_ht_vht_info_ll(struct rx_ppdu_start rx_desc,
+                              struct mon_rx_status *rx_status)
+{
+	uint8_t preamble_type =
+		(uint8_t)rx_desc.preamble_type;
+	uint32_t ht_sig_vht_sig_a_1 = rx_desc.ht_sig_vht_sig_a_1;
+	uint32_t ht_sig_vht_sig_a_2 = rx_desc.ht_sig_vht_sig_a_2;
+	switch (preamble_type) {
+	case 8:
+	case 9:
+		rx_status->mcs_info.valid = 1;
+		rx_status->vht_info.valid = 0;
+		rx_status->mcs_info.mcs = ht_sig_vht_sig_a_1 & 0x7f;
+		rx_status->nr_ant = rx_status->mcs_info.mcs >> 3;
+		rx_status->mcs_info.bw = (ht_sig_vht_sig_a_1 >> 7) & 0x1;
+		rx_status->mcs_info.smoothing = ht_sig_vht_sig_a_2 & 0x1;
+		rx_status->mcs_info.not_sounding =
+			(ht_sig_vht_sig_a_2 >> 1) & 0x1;
+		rx_status->mcs_info.aggregation =
+			(ht_sig_vht_sig_a_2 >> 3) & 0x1;
+		rx_status->mcs_info.stbc = (ht_sig_vht_sig_a_2 >> 4) & 0x3;
+		rx_status->mcs_info.fec = (ht_sig_vht_sig_a_2 >> 6) & 0x1;
+		rx_status->mcs_info.sgi = (ht_sig_vht_sig_a_2 >> 7) & 0x1;
+		rx_status->mcs_info.ness = (ht_sig_vht_sig_a_2 >> 8) & 0x3;
+		break;
+	case 0x0c: /* VHT w/o TxBF */
+	case 0x0d: /* VHT w/ TxBF */
+		rx_status->vht_info.valid = 1;
+		rx_status->mcs_info.valid = 0;
+		rx_status->vht_info.bw = ht_sig_vht_sig_a_1 & 0x3;
+		rx_status->vht_info.stbc = (ht_sig_vht_sig_a_1 >> 3) & 0x1;
+		/* Currently only handle SU case */
+		rx_status->vht_info.gid = (ht_sig_vht_sig_a_1 >> 4) & 0x3f;
+		rx_status->vht_info.nss = (ht_sig_vht_sig_a_1 >> 10) & 0x7;
+		rx_status->nr_ant = (ht_sig_vht_sig_a_1 >> 10) & 0x7;
+		rx_status->vht_info.paid = (ht_sig_vht_sig_a_1 >> 13) & 0x1ff;
+		rx_status->vht_info.txps_forbidden =
+			(ht_sig_vht_sig_a_1 >> 22) & 0x1;
+		rx_status->vht_info.sgi = ht_sig_vht_sig_a_2 & 0x1;
+		rx_status->vht_info.sgi_disambiguation =
+			(ht_sig_vht_sig_a_2 >> 1) & 0x1;
+		rx_status->vht_info.coding = (ht_sig_vht_sig_a_2 >> 2) & 0x1;
+		rx_status->vht_info.ldpc_extra_symbol =
+			(ht_sig_vht_sig_a_2 >> 3) & 0x1;
+		rx_status->vht_info.mcs = (ht_sig_vht_sig_a_2 >> 4) & 0xf;
+		rx_status->vht_info.beamformed =
+			(ht_sig_vht_sig_a_2 >> 8) & 0x1;
+		break;
+	default:
+		rx_status->mcs_info.valid = 0;
+		rx_status->vht_info.valid = 0;
+		rx_status->nr_ant = 1;
+		break;
+	}
+}
+
+/**
+ * htt_get_radiotap_rx_status_ll() - Update information about the rx status,
+ * which is used later for radiotap updation.
  * @rx_desc: Pointer to struct htt_host_rx_desc_base
  * @rx_status: Return variable updated with rx_status
  *
  * Return: None
  */
-void htt_get_radiotap_rx_status(struct htt_host_rx_desc_base *rx_desc, struct
-		       mon_rx_status *rx_status)
+void htt_get_radiotap_rx_status_ll(struct htt_host_rx_desc_base *rx_desc,
+			struct mon_rx_status *rx_status)
 {
 	uint16_t channel_flags = 0;
 
@@ -1620,8 +1686,11 @@
 	rx_status->chan_flags = channel_flags;
 	rx_status->ant_signal_db = rx_desc->ppdu_start.rssi_comb;
 	rx_status->nr_ant = get_nr_antenna(rx_desc);
+	get_ht_vht_info_ll(rx_desc->ppdu_start, rx_status);
 }
 
+struct mon_rx_status g_ll_rx_status;
+
 /**
  * htt_rx_mon_amsdu_rx_in_order_pop_ll() - Monitor mode HTT Rx in order pop
  * function
@@ -1699,13 +1768,17 @@
 		 * Make the netbuf's data pointer point to the payload rather
 		 * than the descriptor.
 		 */
-		rx_status.chan = (uint16_t)ch_freq;
-		htt_get_radiotap_rx_status(rx_desc, &rx_status);
+		if(rx_desc->attention.first_mpdu) {
+			memset(&rx_status, 0, sizeof(struct mon_rx_status));
+			rx_status.chan = (uint16_t)ch_freq;
+			htt_get_radiotap_rx_status_ll(rx_desc, &rx_status);
+			memcpy(&g_ll_rx_status,&rx_status,sizeof(struct mon_rx_status));
+		}
 		/*
 		 * 250 bytes of RX_STD_DESC size should be sufficient for
 		 * radiotap.
 		 */
-		adf_nbuf_update_radiotap(&rx_status, msdu,
+		adf_nbuf_update_radiotap(&g_ll_rx_status, msdu,
 						  HTT_RX_STD_DESC_RESERVATION);
 		amsdu_len = HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET(*(msg_word
 								  + 1));