浏览代码

qcacld-3.0: Add HTT datapath changes to handle monitor mode

Make special handling for monitor mode operation. Take care to handle
amsdu packets in which case firmware marks the last_frag in msdu_info
field. These MSDUs of AMSDU are stiched using frags_list of skb and
handed over to network stack.
Also take care to extract and update the radiotap header to head of
the packet.

Change-Id: I4ed9696175e63884b5db682a2a4c4df504a7fb20
CRs-Fixed: 963060
Manjunathappa Prakash 9 年之前
父节点
当前提交
b757372528

+ 3 - 0
core/cds/src/cds_api.c

@@ -1588,6 +1588,9 @@ QDF_STATUS cds_get_vdev_types(enum tQDF_ADAPTER_MODE mode, uint32_t *type,
 	case QDF_IBSS_MODE:
 		*type = WMI_VDEV_TYPE_IBSS;
 		break;
+	case QDF_MONITOR_MODE:
+		*type = WMI_VDEV_TYPE_MONITOR;
+		break;
 	default:
 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
 			  "Invalid device mode %d", mode);

+ 2 - 0
core/cds/src/cds_concurrency.c

@@ -3394,6 +3394,7 @@ void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode)
 	case QDF_P2P_GO_MODE:
 	case QDF_SAP_MODE:
 	case QDF_IBSS_MODE:
+	case QDF_MONITOR_MODE:
 		hdd_ctx->concurrency_mode |= (1 << mode);
 		hdd_ctx->no_of_open_sessions[mode]++;
 		break;
@@ -3428,6 +3429,7 @@ void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode)
 	case QDF_P2P_CLIENT_MODE:
 	case QDF_P2P_GO_MODE:
 	case QDF_SAP_MODE:
+	case QDF_MONITOR_MODE:
 		hdd_ctx->no_of_open_sessions[mode]--;
 		if (!(hdd_ctx->no_of_open_sessions[mode]))
 			hdd_ctx->concurrency_mode &= (~(1 << mode));

+ 13 - 0
core/dp/htt/htt_h2t.c

@@ -51,6 +51,7 @@
 #include <ol_htt_tx_api.h>
 
 #include <htt_internal.h>
+#include <cds_concurrency.h>
 
 #define HTT_MSG_BUF_SIZE(msg_bytes) \
 	((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING)
@@ -356,6 +357,18 @@ A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev)
 	enable_ppdu_start = 0;
 	enable_ppdu_end = 0;
 #endif
+	if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) {
+		enable_ctrl_data  = 1;
+		enable_mgmt_data  = 1;
+		enable_null_data  = 1;
+		enable_phy_data   = 1;
+		enable_hdr        = 1;
+		enable_ppdu_start = 1;
+		enable_ppdu_end   = 1;
+		/* Disable ASPM for monitor mode */
+		qdf_print("Monitor mode is enabled\n");
+	}
+
 	HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, enable_hdr);
 	HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1);
 	HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, enable_ppdu_start);

+ 1 - 0
core/dp/htt/htt_internal.h

@@ -331,6 +331,7 @@ static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc)
  * rounded up to a cache line size.
  */
 #define HTT_RX_BUF_SIZE 1920
+#define MAX_RX_PAYLOAD_SZ (HTT_RX_BUF_SIZE - RX_STD_DESC_SIZE)
 /*
  * DMA_MAP expects the buffer to be an integral number of cache lines.
  * Rather than checking the actual cache line size, this code makes a

+ 476 - 2
core/dp/htt/htt_rx.c

@@ -53,12 +53,20 @@
 
 #include <cds_ieee80211_common.h>   /* ieee80211_frame, ieee80211_qoscntl */
 #include <cds_ieee80211_defines.h>  /* ieee80211_rx_status */
+#include <cds_utils.h>
+#include <cds_concurrency.h>
 
 #ifdef DEBUG_DMA_DONE
 #include <asm/barrier.h>
 #include <wma_api.h>
 #endif
 
+#ifdef HTT_DEBUG_DATA
+#define HTT_PKT_DUMP(x) x
+#else
+#define HTT_PKT_DUMP(x) /* no-op */
+#endif
+
 /* AR9888v1 WORKAROUND for EV#112367 */
 /* FIX THIS - remove this WAR when the bug is fixed */
 #define PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR
@@ -1151,8 +1159,313 @@ htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev,
 	return 0;
 }
 
-extern void
-dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len);
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#if HTT_PADDR64
+#define NEXT_FIELD_OFFSET_IN32 2
+#else /* ! HTT_PADDR64 */
+#define NEXT_FIELD_OFFSET_IN32 1
+#endif /* HTT_PADDR64 */
+
+/**
+ * htt_mon_rx_handle_amsdu_packet() - Handle consecutive fragments of amsdu
+ * @msdu: pointer to first msdu of amsdu
+ * @pdev: Handle to htt_pdev_handle
+ * @msg_word: Input and output variable, so pointer to HTT msg pointer
+ * @amsdu_len: remaining length of all N-1 msdu msdu's
+ *
+ * This function handles the (N-1) msdu's of amsdu, N'th msdu is already
+ * handled by calling function. N-1 msdu's are tied using frags_list.
+ * msdu_info field updated by FW indicates if this is last msdu. All the
+ * msdu's before last msdu will be of MAX payload.
+ *
+ * Return: 1 on success and 0 on failure.
+ */
+int htt_mon_rx_handle_amsdu_packet(qdf_nbuf_t msdu, htt_pdev_handle pdev,
+				   uint32_t **msg_word, uint32_t amsdu_len)
+{
+	qdf_nbuf_t frag_nbuf;
+	qdf_nbuf_t prev_frag_nbuf;
+	uint32_t len;
+	uint32_t last_frag;
+
+	*msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS;
+	frag_nbuf = htt_rx_in_order_netbuf_pop(pdev,
+				HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(**msg_word));
+	if (qdf_unlikely(NULL == frag_nbuf)) {
+		qdf_print("%s: netbuf pop failed!\n", __func__);
+		return 0;
+	}
+	last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)*msg_word)->
+		msdu_info;
+	qdf_nbuf_append_ext_list(msdu, frag_nbuf, amsdu_len);
+	qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE);
+	qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE);
+	/* For msdu's other than parent will not have htt_host_rx_desc_base */
+	len = MIN(amsdu_len, HTT_RX_BUF_SIZE);
+	amsdu_len -= len;
+	qdf_nbuf_trim_tail(frag_nbuf, HTT_RX_BUF_SIZE - len);
+
+	HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX,
+					QDF_TRACE_LEVEL_FATAL,
+					qdf_nbuf_data(frag_nbuf),
+					qdf_nbuf_len(frag_nbuf)));
+	prev_frag_nbuf = frag_nbuf;
+	while (!last_frag) {
+		*msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS;
+		frag_nbuf = htt_rx_in_order_netbuf_pop(pdev,
+				HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(**msg_word));
+		last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)
+			     *msg_word)->msdu_info;
+
+		if (qdf_unlikely(NULL == frag_nbuf)) {
+			qdf_print("%s: netbuf pop failed!\n", __func__);
+			prev_frag_nbuf->next = NULL;
+			return 0;
+		}
+		qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE);
+		qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE);
+
+		len = MIN(amsdu_len, HTT_RX_BUF_SIZE);
+		amsdu_len -= len;
+		qdf_nbuf_trim_tail(frag_nbuf, HTT_RX_BUF_SIZE - len);
+		HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX,
+						QDF_TRACE_LEVEL_FATAL,
+						qdf_nbuf_data(frag_nbuf),
+						qdf_nbuf_len(frag_nbuf)));
+
+		qdf_nbuf_set_next(prev_frag_nbuf, frag_nbuf);
+		prev_frag_nbuf = frag_nbuf;
+	}
+	qdf_nbuf_set_next(prev_frag_nbuf, NULL);
+	return 1;
+}
+
+/**
+ * htt_mon_rx_get_phy_info() - Get rate interms of 500Kbps.
+ * @rx_desc: Pointer to struct htt_host_rx_desc_base
+ * @rx_status: Return variable updated with phy_info in rx_status
+ *
+ * If l_sig_rate_select is 0:
+ * 0x8: OFDM 48 Mbps
+ * 0x9: OFDM 24 Mbps
+ * 0xA: OFDM 12 Mbps
+ * 0xB: OFDM 6 Mbps
+ * 0xC: OFDM 54 Mbps
+ * 0xD: OFDM 36 Mbps
+ * 0xE: OFDM 18 Mbps
+ * 0xF: OFDM 9 Mbps
+ * If l_sig_rate_select is 1:
+ * 0x8: CCK 11 Mbps long preamble
+ * 0x9: CCK 5.5 Mbps long preamble
+ * 0xA: CCK 2 Mbps long preamble
+ * 0xB: CCK 1 Mbps long preamble
+ * 0xC: CCK 11 Mbps short preamble
+ * 0xD: CCK 5.5 Mbps short preamble
+ * 0xE: CCK 2 Mbps short preamble
+ *
+ * Return: None
+ */
+static void htt_mon_rx_get_phy_info(struct htt_host_rx_desc_base *rx_desc,
+				    struct mon_rx_status *rx_status)
+{
+#define SHORT_PREAMBLE 1
+#define LONG_PREAMBLE  0
+	char rate = 0x0;
+	uint8_t preamble = SHORT_PREAMBLE;
+	uint8_t preamble_type = rx_desc->ppdu_start.preamble_type;
+	uint8_t mcs = 0, nss = 0, sgi = 0, bw = 0, beamformed = 0;
+	uint16_t vht_flags = 0;
+	uint32_t l_sig_rate_select = rx_desc->ppdu_start.l_sig_rate_select;
+	uint32_t l_sig_rate = rx_desc->ppdu_start.l_sig_rate;
+	bool is_stbc = 0, ldpc = 0;
+
+	if (l_sig_rate_select == 0) {
+		switch (l_sig_rate) {
+		case 0x8:
+			rate = 0x60;
+			break;
+		case 0x9:
+			rate = 0x30;
+			break;
+		case 0xA:
+			rate = 0x18;
+			break;
+		case 0xB:
+			rate = 0x0c;
+			break;
+		case 0xC:
+			rate = 0x6c;
+			break;
+		case 0xD:
+			rate = 0x48;
+			break;
+		case 0xE:
+			rate = 0x24;
+			break;
+		case 0xF:
+			rate = 0x12;
+			break;
+		default:
+			break;
+		}
+	} else if (l_sig_rate_select == 1) {
+		switch (l_sig_rate) {
+		case 0x8:
+			rate = 0x16;
+			preamble = LONG_PREAMBLE;
+			break;
+		case 0x9:
+			rate = 0x0B;
+			preamble = LONG_PREAMBLE;
+			break;
+		case 0xA:
+			rate = 0x04;
+			preamble = LONG_PREAMBLE;
+			break;
+		case 0xB:
+			rate = 0x02;
+			preamble = LONG_PREAMBLE;
+			break;
+		case 0xC:
+			rate = 0x16;
+			break;
+		case 0xD:
+			rate = 0x0B;
+			break;
+		case 0xE:
+			rate = 0x04;
+			break;
+		default:
+			break;
+		}
+	} else {
+		qdf_print("Invalid rate info\n");
+	}
+
+	switch (preamble_type) {
+	case 8:
+		is_stbc = ((VHT_SIG_A_2(rx_desc) >> 4) & 3);
+		/* fallthrough */
+	case 9:
+		vht_flags = 1;
+		sgi = (VHT_SIG_A_2(rx_desc) >> 7) & 0x01;
+		bw = (VHT_SIG_A_1(rx_desc) >> 7) & 0x01;
+		mcs = (VHT_SIG_A_1(rx_desc) & 0x7f);
+		nss = mcs>>3;
+		beamformed =
+			(VHT_SIG_A_2(rx_desc) >> 8) & 0x1;
+		break;
+	case 0x0c:
+		vht_flags = 1;
+		is_stbc = (VHT_SIG_A_2(rx_desc) >> 3) & 1;
+		ldpc = (VHT_SIG_A_2(rx_desc) >> 2) & 1;
+		/* fallthrough */
+	case 0x0d:
+	{
+		uint8_t gid_in_sig = ((VHT_SIG_A_1(rx_desc) >> 4) & 0x3f);
+
+		vht_flags = 1;
+		sgi = VHT_SIG_A_2(rx_desc) & 0x01;
+		bw = (VHT_SIG_A_1(rx_desc) & 0x03);
+		if (gid_in_sig == 0 || gid_in_sig == 63) {
+			/* SU case */
+			mcs = (VHT_SIG_A_2(rx_desc) >> 4) &
+				0xf;
+			nss = (VHT_SIG_A_1(rx_desc) >> 10) &
+				0x7;
+		} else {
+			/* SU case */
+			uint8_t sta_user_pos =
+				(uint8_t)((rx_desc->ppdu_start.reserved_4a >> 8)
+					  & 0x3);
+			mcs = (rx_desc->ppdu_start.vht_sig_b >> 16);
+			if (bw >= 2)
+				mcs >>= 3;
+			else if (bw > 0)
+				mcs >>= 1;
+			mcs &= 0xf;
+			nss = (((VHT_SIG_A_1(rx_desc) >> 10) +
+				sta_user_pos * 3) & 0x7);
+		}
+		beamformed = (VHT_SIG_A_2(rx_desc) >> 8) & 0x1;
+	}
+		/* fallthrough */
+	default:
+		break;
+	}
+
+	rx_status->mcs = mcs;
+	rx_status->nr_ant = nss;
+	rx_status->is_stbc = is_stbc;
+	rx_status->sgi = sgi;
+	rx_status->ldpc = ldpc;
+	rx_status->beamformed = beamformed;
+	rx_status->vht_flag_values3[0] = mcs << 0x4;
+	rx_status->rate = rate;
+	rx_status->vht_flags = vht_flags;
+	rx_status->rtap_flags |= ((preamble == SHORT_PREAMBLE) ? BIT(1) : 0);
+	rx_status->vht_flag_values2 = 0x01 < bw;
+}
+
+/**
+ * htt_mon_rx_get_rtap_flags() - Get radiotap flags
+ * @rx_desc: Pointer to struct htt_host_rx_desc_base
+ *
+ * Return: Bitmapped radiotap flags.
+ */
+static uint8_t htt_mon_rx_get_rtap_flags(struct htt_host_rx_desc_base *rx_desc)
+{
+	uint8_t rtap_flags = 0;
+
+	/* WEP40 || WEP104 || WEP128 */
+	if (rx_desc->mpdu_start.encrypt_type == 0 ||
+	    rx_desc->mpdu_start.encrypt_type == 1 ||
+	    rx_desc->mpdu_start.encrypt_type == 3)
+		rtap_flags |= BIT(2);
+
+	/* IEEE80211_RADIOTAP_F_FRAG */
+	if (rx_desc->attention.fragment)
+		rtap_flags |= BIT(3);
+
+	/* IEEE80211_RADIOTAP_F_FCS */
+	rtap_flags |= BIT(4);
+
+	/* IEEE80211_RADIOTAP_F_BADFCS */
+	if (rx_desc->mpdu_end.fcs_err)
+		rtap_flags |= BIT(6);
+
+	return rtap_flags;
+}
+
+/**
+ * htt_rx_mon_get_rx_status() - 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_rx_mon_get_rx_status(htt_pdev_handle pdev,
+			      struct htt_host_rx_desc_base *rx_desc,
+			      struct mon_rx_status *rx_status)
+{
+	uint16_t channel_flags = 0;
+	struct mon_channel *ch_info = &pdev->mon_ch_info;
+
+	rx_status->tsft = (u_int64_t)TSF_TIMESTAMP(rx_desc);
+	rx_status->chan_freq = ch_info->ch_freq;
+	rx_status->chan_num = ch_info->ch_num;
+	htt_mon_rx_get_phy_info(rx_desc, rx_status);
+	rx_status->rtap_flags |= htt_mon_rx_get_rtap_flags(rx_desc);
+	channel_flags |= rx_desc->ppdu_start.l_sig_rate_select ?
+		IEEE80211_CHAN_CCK : IEEE80211_CHAN_OFDM;
+	channel_flags |=
+		(cds_chan_to_band(ch_info->ch_num) == CDS_BAND_2GHZ ?
+		IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
+
+	rx_status->chan_flags = channel_flags;
+	rx_status->ant_signal_db = rx_desc->ppdu_start.rssi_comb;
+}
 
 #ifdef RX_HASH_DEBUG
 #define HTT_RX_CHECK_MSDU_COUNT(msdu_count) HTT_ASSERT_ALWAYS(msdu_count)
@@ -1160,6 +1473,164 @@ dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len);
 #define HTT_RX_CHECK_MSDU_COUNT(msdu_count)     /* no-op */
 #endif
 
+/**
+ * htt_rx_mon_amsdu_rx_in_order_pop_ll() - Monitor mode HTT Rx in order pop
+ * function
+ * @pdev: Handle to htt_pdev_handle
+ * @rx_ind_msg: In order indication message.
+ * @head_msdu: Return variable pointing to head msdu.
+ * @tail_msdu: Return variable pointing to tail msdu.
+ *
+ * This function pops the msdu based on paddr:length of inorder indication
+ * message.
+ *
+ * Return: 1 for success, 0 on failure.
+ */
+int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
+					qdf_nbuf_t rx_ind_msg,
+					qdf_nbuf_t *head_msdu,
+					qdf_nbuf_t *tail_msdu)
+{
+	qdf_nbuf_t msdu, next;
+	uint8_t *rx_ind_data;
+	uint32_t *msg_word;
+	uint32_t msdu_count;
+	struct htt_host_rx_desc_base *rx_desc;
+	struct mon_rx_status rx_status = {0};
+	uint32_t amsdu_len;
+	uint32_t len;
+	uint32_t last_frag;
+
+	HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0);
+
+	rx_ind_data = qdf_nbuf_data(rx_ind_msg);
+	msg_word = (uint32_t *)rx_ind_data;
+
+	HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX,
+					QDF_TRACE_LEVEL_FATAL,
+					(void *)rx_ind_data,
+					(int)qdf_nbuf_len(rx_ind_msg)));
+
+	/* Get the total number of MSDUs */
+	msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1));
+	HTT_RX_CHECK_MSDU_COUNT(msdu_count);
+
+	msg_word = (uint32_t *)(rx_ind_data +
+				 HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES);
+
+	(*head_msdu) = msdu = htt_rx_in_order_netbuf_pop(pdev,
+				HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*msg_word));
+
+	if (qdf_unlikely(NULL == msdu)) {
+		qdf_print("%s: netbuf pop failed!\n", __func__);
+		*tail_msdu = NULL;
+		return 0;
+	}
+	while (msdu_count > 0) {
+
+		msdu_count--;
+		/*
+		 * Set the netbuf length to be the entire buffer length
+		 * initially, so the unmap will unmap the entire buffer.
+		 */
+		qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE);
+		qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE);
+
+		/*
+		 * cache consistency has been taken care of by the
+		 * qdf_nbuf_unmap
+		 */
+		rx_desc = htt_rx_desc(msdu);
+		HTT_PKT_DUMP(htt_print_rx_desc(rx_desc));
+		/*
+		 * Make the netbuf's data pointer point to the payload rather
+		 * than the descriptor.
+		 */
+		htt_rx_mon_get_rx_status(pdev, rx_desc, &rx_status);
+		/*
+		 * 350 bytes of RX_STD_DESC size should be sufficient for
+		 * radiotap.
+		 */
+		qdf_nbuf_update_radiotap(&rx_status, msdu,
+						  HTT_RX_STD_DESC_RESERVATION);
+		amsdu_len = HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET(*(msg_word +
+						NEXT_FIELD_OFFSET_IN32));
+
+		/*
+		 * MAX_RX_PAYLOAD_SZ when we have AMSDU packet. amsdu_len in
+		 * which case is the total length of sum of all AMSDU's
+		 */
+		len = MIN(amsdu_len, MAX_RX_PAYLOAD_SZ);
+		amsdu_len -= len;
+		qdf_nbuf_trim_tail(msdu,
+			   HTT_RX_BUF_SIZE -
+			   (RX_STD_DESC_SIZE + len));
+
+
+		HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX,
+						QDF_TRACE_LEVEL_FATAL,
+						qdf_nbuf_data(msdu),
+						qdf_nbuf_len(msdu)));
+		last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)
+			     msg_word)->msdu_info;
+
+#undef NEXT_FIELD_OFFSET_IN32
+		/* Handle amsdu packet */
+		if (!last_frag) {
+			/*
+			 * For AMSDU packet msdu->len is sum of all the msdu's
+			 * length, msdu->data_len is sum of length's of
+			 * remaining msdu's other than parent.
+			 */
+			if (!htt_mon_rx_handle_amsdu_packet(msdu, pdev,
+							    &msg_word,
+							    amsdu_len)) {
+				qdf_print("%s: failed to handle amsdu packet\n",
+					     __func__);
+				return 0;
+			}
+		}
+		/* check if this is the last msdu */
+		if (msdu_count) {
+			msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS;
+			next = htt_rx_in_order_netbuf_pop(pdev,
+				HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*msg_word));
+			if (qdf_unlikely(NULL == next)) {
+				qdf_print("%s: netbuf pop failed!\n",
+					     __func__);
+				*tail_msdu = NULL;
+				return 0;
+			}
+			qdf_nbuf_set_next(msdu, next);
+			msdu = next;
+		} else {
+			*tail_msdu = msdu;
+			qdf_nbuf_set_next(msdu, NULL);
+		}
+	}
+
+	return 1;
+}
+
+/**
+ * htt_rx_mon_note_capture_channel() - Make note of channel to update in
+ * radiotap
+ * @pdev: handle to htt_pdev
+ * @mon_ch: capture channel number.
+ *
+ * Return: None
+ */
+void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch)
+{
+	struct mon_channel *ch_info = &pdev->mon_ch_info;
+
+	ch_info->ch_num = mon_ch;
+	ch_info->ch_freq = cds_chan_to_freq(mon_ch);
+}
+
+extern void
+dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len);
+
 /* Return values: 1 - success, 0 - failure */
 int
 htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
@@ -2231,6 +2702,9 @@ int htt_rx_attach(struct htt_pdev_t *pdev)
 		htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_ll;
 	}
 
+	if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
+		htt_rx_amsdu_pop = htt_rx_mon_amsdu_rx_in_order_pop_ll;
+
 	htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_ll;
 	htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_ll;
 	htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_ll;

+ 11 - 0
core/dp/htt/htt_types.h

@@ -211,6 +211,16 @@ struct msdu_ext_desc_t {
 };
 #endif  /* defined(HELIUMPLUS_PADDR64) */
 
+/**
+ * struct mon_channel
+ * @ch_num: Monitor mode capture channel number
+ * @ch_freq: channel frequency.
+ */
+struct mon_channel {
+	uint32_t ch_num;
+	uint32_t ch_freq;
+};
+
 struct htt_pdev_t {
 	ol_pdev_handle ctrl_pdev;
 	ol_txrx_pdev_handle txrx_pdev;
@@ -385,6 +395,7 @@ struct htt_pdev_t {
 	struct rx_buf_debug *rx_buff_list;
 	int rx_buff_index;
 #endif
+	struct mon_channel mon_ch_info;
 };
 
 #define HTT_EPID_GET(_htt_pdev_hdl)  \

+ 10 - 0
core/dp/htt/rx_desc.h

@@ -257,6 +257,12 @@ struct rx_ppdu_start {
 	uint32_t service:16, /* [15:0] */
 		reserved_9:16; /* [31:16] */
 };
+
+#define VHT_SIG_A_1(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_ah_sig_a_1)
+#define VHT_SIG_A_2(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_ah_sig_a_2)
+#define TSF_TIMESTAMP(rx_desc) \
+((rx_desc)->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32)
+
 struct rx_location_info {
 	volatile
 	uint32_t rtt_fac_legacy:14, /* [13:0] */
@@ -469,6 +475,10 @@ struct rx_ppdu_start {
 		reserved_9:16; /* [31:16] */
 };
 
+#define VHT_SIG_A_1(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_a_1)
+#define VHT_SIG_A_2(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_a_2)
+
+#define TSF_TIMESTAMP(rx_desc) ((rx_desc)->ppdu_end.tsf_timestamp)
 
 struct rx_mpdu_start {
 	volatile

+ 3 - 0
core/dp/ol/inc/ol_htt_api.h

@@ -362,4 +362,7 @@ static inline void htt_ipa_uc_detach(struct htt_pdev_t *pdev)
 }
 #endif /* IPA_OFFLOAD */
 
+void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch);
+
+void ol_htt_mon_note_chan(ol_txrx_pdev_handle pdev, int mon_ch);
 #endif /* _OL_HTT_API__H_ */

+ 16 - 1
core/dp/txrx/ol_rx.c

@@ -57,6 +57,7 @@
 #include <ipv6_defs.h>          /* IPv6 header defs */
 #include <ol_vowext_dbg_defs.h>
 #include <wma.h>
+#include <cds_concurrency.h>
 
 #ifdef HTT_RX_RESTORE
 #if  defined(CONFIG_CNSS)
@@ -1243,7 +1244,10 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
 	qdf_nbuf_t head_msdu, tail_msdu = NULL;
 
 	if (pdev) {
-		peer = ol_txrx_peer_find_by_id(pdev, peer_id);
+		if (qdf_unlikely(QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()))
+			peer = pdev->self_peer;
+		else
+			peer = ol_txrx_peer_find_by_id(pdev, peer_id);
 		htt_pdev = pdev->htt_pdev;
 	} else {
 		TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
@@ -1374,6 +1378,17 @@ ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev,
 	htt_rx_msdu_buff_replenish(htt_pdev);
 }
 
+/**
+ * ol_htt_mon_note_chan() - Update monitor channel information
+ * @pdev:  handle to the physical device
+ * @mon_ch: Monitor channel
+ *
+ * Return: None
+ */
+void ol_htt_mon_note_chan(ol_txrx_pdev_handle pdev, int mon_ch)
+{
+	htt_rx_mon_note_capture_channel(pdev->htt_pdev, mon_ch);
+}
 
 #ifdef NEVERDEFINED
 /**

+ 9 - 0
core/dp/txrx/ol_txrx.c

@@ -1569,6 +1569,15 @@ ol_txrx_peer_attach(ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr)
 #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI
 	peer->rssi_dbm = HTT_RSSI_INVALID;
 #endif
+	if ((QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) &&
+	    !pdev->self_peer) {
+		pdev->self_peer = peer;
+		/*
+		 * No Tx in monitor mode, otherwise results in target assert.
+		 * Setting disable_intrabss_fwd to true
+		 */
+		ol_vdev_rx_set_intrabss_fwd(vdev, true);
+	}
 
 	ol_txrx_local_peer_id_alloc(pdev, peer);
 

+ 1 - 0
core/dp/txrx/ol_txrx_types.h

@@ -767,6 +767,7 @@ struct ol_txrx_pdev_t {
 		void *lro_data;
 		void (*lro_flush_cb)(void *);
 	} lro_info;
+	struct ol_txrx_peer_t *self_peer;
 };
 
 struct ol_txrx_ocb_chan_info {

+ 1 - 2
core/wma/src/wma_scan_roam.c

@@ -51,6 +51,7 @@
 #include "qdf_types.h"
 #include "qdf_mem.h"
 #include "ol_txrx_peer_find.h"
+#include "ol_htt_api.h"
 
 #include "wma_types.h"
 #include "lim_api.h"
@@ -97,8 +98,6 @@ enum extscan_report_events_type {
 #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION (5 * 1000) /* in msec */
 #endif
 
-void ol_cfg_update_mon_chan(ol_txrx_pdev_handle pdev, int mon_ch,
-			    int mon_ch_freq);
 /**
  * wma_set_p2p_scan_info() - set p2p scan info in wma handle
  * @wma_handle: wma handle