浏览代码

Revert "Revert "qcacld-3.0: Dump Tx/Rx packets during connection""

This reverts Change-Id I2aec7253511d2ca7b08ca77d858a46f9c01d4e9d

Adding support for dumping 32 tx/rx packets during connection
by reverting above change as "exceeding skb buffer size and
leading to crash" issue is resolved with this change.

Change-Id: I951355776461706bb52eeee0527819377e7b7857
CRs-Fixed: 1097280
Himanshu Agarwal 8 年之前
父节点
当前提交
f65bd4cf8f

+ 59 - 0
core/dp/htt/htt_rx.c

@@ -60,6 +60,7 @@
 #include <asm/barrier.h>
 #include <wma_api.h>
 #endif
+#include <pktlog_ac_fmt.h>
 
 #ifdef HTT_DEBUG_DATA
 #define HTT_PKT_DUMP(x) x
@@ -1996,6 +1997,7 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 	uint8_t offload_ind, frag_ind;
 	uint8_t peer_id;
 	struct htt_host_rx_desc_base *rx_desc;
+	enum rx_pkt_fate status = RX_PKT_FATE_SUCCESS;
 
 	HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0);
 
@@ -2084,6 +2086,15 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 
 		msdu_count--;
 
+		/* calling callback function for packet logging */
+		if (pdev->rx_pkt_dump_cb) {
+			if (qdf_unlikely((*((u_int8_t *)
+				   &rx_desc->fw_desc.u.val)) &
+				   FW_RX_DESC_ANY_ERR_M))
+				status = RX_PKT_FATE_FW_DROP_INVALID;
+			pdev->rx_pkt_dump_cb(msdu, peer_id, status);
+		}
+
 		if (qdf_unlikely((*((u_int8_t *) &rx_desc->fw_desc.u.val)) &
 				    FW_RX_DESC_ANY_ERR_M)) {
 			uint8_t tid =
@@ -3537,3 +3548,51 @@ int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev)
 	return 0;
 }
 #endif /* IPA_OFFLOAD */
+
+/**
+ * htt_register_rx_pkt_dump_callback() - registers callback to
+ *   get rx pkt status and call callback to do rx packet dump
+ *
+ * @pdev: htt pdev handle
+ * @callback: callback to get rx pkt status and
+ *     call callback to do rx packet dump
+ *
+ * This function is used to register the callback to get
+ * rx pkt status and call callback to do rx packet dump
+ *
+ * Return: None
+ *
+ */
+void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev,
+				tp_rx_pkt_dump_cb callback)
+{
+	if (!pdev) {
+		qdf_print("%s: htt pdev is NULL, rx packet status callback register unsuccessful\n",
+						__func__);
+		return;
+	}
+	pdev->rx_pkt_dump_cb = callback;
+}
+
+/**
+ * htt_deregister_rx_pkt_dump_callback() - deregisters callback to
+ *   get rx pkt status and call callback to do rx packet dump
+ *
+ * @pdev: htt pdev handle
+ *
+ * This function is used to deregister the callback to get
+ * rx pkt status and call callback to do rx packet dump
+ *
+ * Return: None
+ *
+ */
+void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev)
+{
+	if (!pdev) {
+		qdf_print("%s: htt pdev is NULL, rx packet status callback deregister unsuccessful\n",
+						__func__);
+		return;
+	}
+	pdev->rx_pkt_dump_cb = NULL;
+}
+

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

@@ -35,6 +35,7 @@
 #include <qdf_atomic.h>         /* qdf_atomic_inc */
 #include <qdf_nbuf.h>           /* qdf_nbuf_t */
 #include <htc_api.h>            /* HTC_PACKET */
+#include <ol_htt_api.h>
 
 #define DEBUG_DMA_DONE
 
@@ -413,6 +414,10 @@ struct htt_pdev_t {
 	qdf_spinlock_t       rx_buff_list_lock;
 	int rx_buff_index;
 #endif
+
+	/* callback function for packetdump */
+	tp_rx_pkt_dump_cb rx_pkt_dump_cb;
+
 	struct mon_channel mon_ch_info;
 };
 

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

@@ -385,5 +385,11 @@ static inline void htt_clear_bundle_stats(struct htt_pdev_t *pdev)
 #endif
 
 void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, uint8_t value);
+typedef void (*tp_rx_pkt_dump_cb)(qdf_nbuf_t msdu, uint8_t peer_id,
+			uint8_t status);
+void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev,
+		tp_rx_pkt_dump_cb ol_rx_pkt_dump_call);
+void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev);
+void ol_rx_pkt_dump_call(qdf_nbuf_t msdu, uint8_t peer_id, uint8_t status);
 
 #endif /* _OL_HTT_API__H_ */

+ 6 - 0
core/dp/ol/inc/ol_txrx_api.h

@@ -60,4 +60,10 @@ enum ol_sec_type {
 	ol_sec_type_types
 };
 
+typedef void (*tp_ol_packetdump_cb)(qdf_nbuf_t netbuf,
+		uint8_t status, uint8_t vdev_id, uint8_t type);
+void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb,
+			tp_ol_packetdump_cb ol_rx_packetdump_cb);
+void ol_deregister_packetdump_callback(void);
+
 #endif /* _OL_TXRX_API__H_ */

+ 46 - 0
core/dp/txrx/ol_rx.c

@@ -58,6 +58,7 @@
 #include <ol_vowext_dbg_defs.h>
 #include <wma.h>
 #include <cds_concurrency.h>
+#include "pktlog_ac_fmt.h"
 
 #include <pld_common.h>
 
@@ -1420,6 +1421,51 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
 	peer->rx_opt_proc(vdev, peer, tid, head_msdu);
 }
 
+/**
+ * ol_rx_pkt_dump_call() - updates status and
+ * calls packetdump callback to log rx packet
+ *
+ * @msdu: rx packet
+ * @peer_id: peer id
+ * @status: status of rx packet
+ *
+ * This function is used to update the status of rx packet
+ * and then calls packetdump callback to log that packet.
+ *
+ * Return: None
+ *
+ */
+void ol_rx_pkt_dump_call(
+	qdf_nbuf_t msdu,
+	uint8_t peer_id,
+	uint8_t status)
+{
+	v_CONTEXT_t vos_context;
+	ol_txrx_pdev_handle pdev;
+	struct ol_txrx_peer_t *peer = NULL;
+
+	vos_context = cds_get_global_context();
+	pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+
+	if (!pdev) {
+		TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+			"%s: pdev is NULL", __func__);
+		return;
+	}
+
+	if (pdev->ol_rx_packetdump_cb) {
+		peer = ol_txrx_peer_find_by_id(pdev, peer_id);
+		if (!peer) {
+			TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+				"%s: peer with peer id %d is NULL", __func__,
+				peer_id);
+			return;
+		}
+		pdev->ol_rx_packetdump_cb(msdu, status, peer->vdev->vdev_id,
+						RX_DATA_PKT);
+	}
+}
+
 /* the msdu_list passed here must be NULL terminated */
 void
 ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev,

+ 1 - 11
core/dp/txrx/ol_tx_desc.c

@@ -92,8 +92,6 @@ static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc)
 }
 #endif
 
-#ifdef CONFIG_HL_SUPPORT
-
 /**
  * ol_tx_desc_vdev_update() - vedv assign.
  * @tx_desc: tx descriptor pointer
@@ -107,15 +105,6 @@ ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc,
 {
 	tx_desc->vdev = vdev;
 }
-#else
-
-static inline void
-ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc,
-		       struct ol_txrx_vdev_t *vdev)
-{
-	return;
-}
-#endif
 
 #ifdef CONFIG_PER_VDEV_TX_DESC_POOL
 
@@ -223,6 +212,7 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev,
 			}
 			ol_tx_desc_sanity_checks(pdev, tx_desc);
 			ol_tx_desc_compute_delay(tx_desc);
+			ol_tx_desc_vdev_update(tx_desc, vdev);
 			qdf_atomic_inc(&tx_desc->ref_cnt);
 		} else {
 			pool->pkt_drop_no_desc++;

+ 66 - 1
core/dp/txrx/ol_tx_send.c

@@ -60,7 +60,7 @@
 #endif
 #include <ol_tx_queue.h>
 #include <ol_txrx.h>
-
+#include <pktlog_ac_fmt.h>
 
 #ifdef TX_CREDIT_RECLAIM_SUPPORT
 
@@ -569,6 +569,13 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
 		tx_desc->status = status;
 		netbuf = tx_desc->netbuf;
 		QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE);
+
+		if (tx_desc->pkt_type != OL_TX_FRM_TSO) {
+			if (pdev->ol_tx_packetdump_cb)
+				pdev->ol_tx_packetdump_cb(netbuf, status,
+					tx_desc->vdev->vdev_id, TX_DATA_PKT);
+		}
+
 		DPTRACE(qdf_dp_trace_ptr(netbuf,
 			QDF_DP_TRACE_FREE_PACKET_PTR_RECORD,
 			qdf_nbuf_data_addr(netbuf),
@@ -791,6 +798,10 @@ ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev,
 	/* Do one shot statistics */
 	TXRX_STATS_UPDATE_TX_STATS(pdev, status, 1, qdf_nbuf_len(netbuf));
 
+	if (pdev->ol_tx_packetdump_cb)
+		pdev->ol_tx_packetdump_cb(netbuf, status,
+			tx_desc->vdev->vdev_id, TX_MGMT_PKT);
+
 	if (OL_TX_DESC_NO_REFS(tx_desc)) {
 		ol_tx_desc_frame_free_nonstd(pdev, tx_desc,
 					     status != htt_tx_status_ok);
@@ -1204,3 +1215,57 @@ ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev,
 }
 
 #endif /* QCA_COMPUTE_TX_DELAY */
+
+/**
+ * ol_register_packetdump_callback() - registers
+ *  tx data packet, tx mgmt. packet and rx data packet
+ *  dump callback handler.
+ *
+ * @ol_tx_packetdump_cb: tx packetdump cb
+ * @ol_rx_packetdump_cb: rx packetdump cb
+ *
+ * This function is used to register tx data pkt, tx mgmt.
+ * pkt and rx data pkt dump callback
+ *
+ * Return: None
+ *
+ */
+void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb,
+					tp_ol_packetdump_cb ol_rx_packetdump_cb)
+{
+	ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+
+	if (!pdev) {
+		TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+				"%s: pdev is NULL", __func__);
+		return;
+	}
+
+	pdev->ol_tx_packetdump_cb = ol_tx_packetdump_cb;
+	pdev->ol_rx_packetdump_cb = ol_rx_packetdump_cb;
+}
+
+/**
+ * ol_deregister_packetdump_callback() - deregidters
+ *  tx data packet, tx mgmt. packet and rx data packet
+ *  dump callback handler
+ *
+ * This function is used to deregidter tx data pkt.,
+ * tx mgmt. pkt and rx data pkt. dump callback
+ *
+ * Return: None
+ *
+ */
+void ol_deregister_packetdump_callback(void)
+{
+	ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+
+	if (!pdev) {
+		TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+				"%s: pdev is NULL", __func__);
+		return;
+	}
+
+	pdev->ol_tx_packetdump_cb = NULL;
+	pdev->ol_rx_packetdump_cb = NULL;
+}

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

@@ -1087,6 +1087,8 @@ ol_txrx_pdev_attach(ol_txrx_soc_handle soc, void *pctrl_pdev,
 	if (!pdev->htt_pdev)
 		goto fail3;
 
+	htt_register_rx_pkt_dump_callback(pdev->htt_pdev,
+			ol_rx_pkt_dump_call);
 	return pdev;
 
 fail3:
@@ -1734,6 +1736,7 @@ void ol_txrx_pdev_detach(void *ppdev, int force)
 		htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc);
 	}
 
+	htt_deregister_rx_pkt_dump_callback(pdev->htt_pdev);
 	ol_tx_deregister_flow_control(pdev);
 	/* Stop the communication between HTT and target at first */
 	htt_detach_target(pdev->htt_pdev);

+ 6 - 2
core/dp/txrx/ol_txrx_types.h

@@ -184,9 +184,9 @@ struct ol_tx_desc_t {
 	 * This field is filled in with the ol_tx_frm_type enum.
 	 */
 	uint8_t pkt_type;
-#if defined(CONFIG_HL_SUPPORT)
+
 	struct ol_txrx_vdev_t *vdev;
-#endif
+
 	void *txq;
 
 #ifdef QCA_SUPPORT_SW_TXRX_ENCAP
@@ -645,6 +645,10 @@ struct ol_txrx_pdev_t {
 		} callbacks[OL_TXRX_MGMT_NUM_TYPES];
 	} tx_mgmt;
 
+	/* packetdump callback functions */
+	tp_ol_packetdump_cb ol_tx_packetdump_cb;
+	tp_ol_packetdump_cb ol_rx_packetdump_cb;
+
 	struct {
 		uint16_t pool_size;
 		uint16_t num_free;

+ 6 - 0
core/hdd/src/wlan_hdd_assoc.c

@@ -62,6 +62,7 @@
 #include <cdp_txrx_flow_ctrl_legacy.h>
 #include <cdp_txrx_peer_ops.h>
 #include <cdp_txrx_misc.h>
+#include <wlan_logging_sock_svc.h>
 
 /* These are needed to recognize WPA and RSN suite types */
 #define HDD_WPA_OUI_SIZE 4
@@ -1538,6 +1539,8 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter,
 
 	hdd_clear_roam_profile_ie(pAdapter);
 	hdd_wmm_init(pAdapter);
+	hdd_info("Invoking packetdump deregistration API");
+	wlan_deregister_txrx_packetdump();
 
 	/* indicate 'disconnect' status to wpa_supplicant... */
 	hdd_send_association_event(dev, pRoamInfo);
@@ -2815,6 +2818,9 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter,
 				       MAC_ADDR_ARRAY(pWextState->req_bssId.bytes),
 				       roamResult, roamStatus);
 
+			hdd_err("Invoking packetdump deregistration API");
+			wlan_deregister_txrx_packetdump();
+
 			/* inform association failure event to nl80211 */
 			if (eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL ==
 			    roamResult) {

+ 5 - 0
core/hdd/src/wlan_hdd_power.c

@@ -76,6 +76,7 @@
 #include "cdp_txrx_flow_ctrl_v2.h"
 #include "pld_common.h"
 #include "wlan_hdd_driver_ops.h"
+#include <wlan_logging_sock_svc.h>
 
 /* Preprocessor definitions and constants */
 #define HDD_SSR_BRING_UP_TIME 30000
@@ -1460,6 +1461,10 @@ QDF_STATUS hdd_wlan_shutdown(void)
 	}
 
 	cds_clear_concurrent_session_count();
+
+	hdd_info("Invoking packetdump deregistration API");
+	wlan_deregister_txrx_packetdump();
+
 	hdd_cleanup_scan_queue(pHddCtx);
 	hdd_ipa_uc_ssr_deinit();
 	hdd_reset_all_adapters(pHddCtx);

+ 1 - 0
core/sme/inc/csr_api.h

@@ -1757,5 +1757,6 @@ static inline void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo
 				tpSirSmeJoinRsp join_rsp)
 {}
 #endif
+void csr_packetdump_timer_stop(void);
 
 #endif

+ 1 - 0
core/sme/inc/csr_internal.h

@@ -1048,6 +1048,7 @@ typedef struct tagCsrRoamStruct {
 	uint32_t deauthRspStatus;
 	uint8_t *pReassocResp;          /* reassociation response from new AP */
 	uint16_t reassocRespLen;        /* length of reassociation response */
+	qdf_mc_timer_t packetdump_timer;
 } tCsrRoamStruct;
 
 #define GET_NEXT_ROAM_ID(pRoamStruct)  (((pRoamStruct)->nextRoamId + 1 == 0) ? \

+ 87 - 0
core/sme/src/csr/csr_api_roam.c

@@ -57,6 +57,7 @@
 #include "cds_concurrency.h"
 #include "sme_nan_datapath.h"
 #include "pld_common.h"
+#include <wlan_logging_sock_svc.h>
 
 #define MAX_PWR_FCC_CHAN_12 8
 #define MAX_PWR_FCC_CHAN_13 2
@@ -85,6 +86,10 @@
 #define MAX_CB_VALUE_IN_INI (2)
 
 #define MAX_SOCIAL_CHANNELS  3
+
+/* packet dump timer duration of 60 secs */
+#define PKT_DUMP_TIMER_DURATION 60
+
 /* Choose the largest possible value that can be accomodates in 8 bit signed */
 /* variable. */
 #define SNR_HACK_BMPS                         (127)
@@ -993,6 +998,58 @@ void csr_set_global_cfgs(tpAniSirGlobal pMac)
 	csr_set_default_dot11_mode(pMac);
 }
 
+/**
+ * csr_packetdump_timer_handler() - packet dump timer
+ * handler
+ * @pv: user data
+ *
+ * This function is used to handle packet dump timer
+ *
+ * Return: None
+ *
+ */
+static void csr_packetdump_timer_handler(void *pv)
+{
+	QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO,
+			"%s Invoking packetdump deregistration API", __func__);
+	wlan_deregister_txrx_packetdump();
+}
+
+/**
+ * csr_packetdump_timer_stop() - stops packet dump timer
+ *
+ * This function is used to stop packet dump timer
+ *
+ * Return: None
+ *
+ */
+void csr_packetdump_timer_stop(void)
+{
+	QDF_STATUS status;
+	tHalHandle hal;
+	tpAniSirGlobal mac;
+	v_CONTEXT_t vos_ctx_ptr;
+
+	/* get the global voss context */
+	vos_ctx_ptr = cds_get_global_context();
+	if (vos_ctx_ptr == NULL) {
+		QDF_ASSERT(0);
+		return;
+	}
+
+	hal = cds_get_context(QDF_MODULE_ID_SME);
+	if (hal == NULL) {
+		QDF_ASSERT(0);
+		return;
+	}
+
+	mac = PMAC_STRUCT(hal);
+	status = qdf_mc_timer_stop(&mac->roam.packetdump_timer);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sms_log(mac, LOGE, FL("cannot stop packetdump timer"));
+	}
+}
+
 QDF_STATUS csr_roam_open(tpAniSirGlobal pMac)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -1019,6 +1076,14 @@ QDF_STATUS csr_roam_open(tpAniSirGlobal pMac)
 					("cannot allocate memory for WaitForKey time out timer"));
 			break;
 		}
+		status = qdf_mc_timer_init(&pMac->roam.packetdump_timer,
+				QDF_TIMER_TYPE_SW, csr_packetdump_timer_handler,
+				pMac);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			sms_log(pMac, LOGE,
+			   FL("cannot allocate memory for packetdump timer"));
+			break;
+		}
 		status =
 			qdf_mc_timer_init(&pMac->roam.tlStatsReqInfo.hTlStatsTimer,
 					  QDF_TIMER_TYPE_SW,
@@ -1043,6 +1108,8 @@ QDF_STATUS csr_roam_close(tpAniSirGlobal pMac)
 	qdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey);
 	qdf_mc_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer);
 	qdf_mc_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer);
+	qdf_mc_timer_stop(&pMac->roam.packetdump_timer);
+	qdf_mc_timer_destroy(&pMac->roam.packetdump_timer);
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -13787,6 +13854,7 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
 	uint8_t ese_config = 0;
 	tpCsrNeighborRoamControlInfo neigh_roam_info;
 	uint32_t value = 0, value1 = 0;
+	QDF_STATUS packetdump_timer_status;
 
 	if (!pSession) {
 		sms_log(pMac, LOGE, FL("  session %d not found "), sessionId);
@@ -14439,6 +14507,25 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
 			csr_join_req = NULL;
 			break;
 		} else {
+			if (pProfile->csrPersona == QDF_STA_MODE) {
+				sms_log(pMac, LOG1,
+				    FL(" Invoking packetdump register API"));
+				wlan_register_txrx_packetdump();
+				packetdump_timer_status =
+					qdf_mc_timer_start(
+					&pMac->roam.packetdump_timer,
+					(PKT_DUMP_TIMER_DURATION *
+					QDF_MC_TIMER_TO_SEC_UNIT)/
+					QDF_MC_TIMER_TO_MS_UNIT);
+				if (!QDF_IS_STATUS_SUCCESS(
+						packetdump_timer_status)) {
+					sms_log(pMac, LOGE,
+					   FL("cannot start packetdump timer"));
+					sms_log(pMac, LOGE,
+					   FL("packetdump_timer_status: %d"),
+					   packetdump_timer_status);
+				}
+			}
 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
 			if (eWNI_SME_JOIN_REQ == messageType) {
 				/* Notify QoS module that join happening */

+ 3 - 0
core/utils/logging/inc/wlan_logging_sock_svc.h

@@ -80,4 +80,7 @@ static inline void wlan_report_log_completion(uint32_t is_fatal,
 
 void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data);
 
+void wlan_deregister_txrx_packetdump(void);
+void wlan_register_txrx_packetdump(void);
+
 #endif /* WLAN_LOGGING_SOCK_SVC_H */

+ 277 - 9
core/utils/logging/src/wlan_logging_sock_svc.c

@@ -37,10 +37,39 @@
 #include <kthread.h>
 #include <qdf_time.h>
 #include <wlan_ptt_sock_svc.h>
-#include "pktlog_ac.h"
 #include <host_diag_core_event.h>
 #include "cds_utils.h"
 #include "host_diag_core_log.h"
+#include "wma.h"
+#include "ol_txrx_api.h"
+#include "csr_api.h"
+#include "wlan_hdd_main.h"
+#include "pktlog_ac.h"
+
+#define MAX_NUM_PKT_LOG 32
+
+/**
+ * struct tx_status - tx status
+ * @tx_status_ok: successfully sent + acked
+ * @tx_status_discard: discard - not sent (congestion control)
+ * @tx_status_no_ack: no_ack - sent, but no ack
+ * @tx_status_download_fail: download_fail -
+ * the host could not deliver the tx frame to the target
+ * @tx_status_peer_del: peer_del - tx completion for
+ * alreay deleted peer used for HL case
+ *
+ * This enum has tx status types
+ */
+enum tx_status {
+	tx_status_ok,
+	tx_status_discard,
+	tx_status_no_ack,
+	tx_status_download_fail,
+	tx_status_peer_del,
+};
+
+static uint8_t gtx_count;
+static uint8_t grx_count;
 
 #define LOGGING_TRACE(level, args ...) \
 	QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args)
@@ -1194,12 +1223,7 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
 	}
 
 	pkt_stats_dump = (struct packet_dump *)pkt_dump;
-	if (pkt_stats_dump)
-		total_stats_len = sizeof(struct ath_pktlog_hdr) +
-					pktlog_hdr->size +
-					sizeof(struct packet_dump);
-	else
-		total_stats_len = sizeof(struct ath_pktlog_hdr) +
+	total_stats_len = sizeof(struct ath_pktlog_hdr) +
 					pktlog_hdr->size;
 
 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
@@ -1224,16 +1248,24 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
 			pktlog_hdr,
 			sizeof(struct ath_pktlog_hdr));
 
-	if (pkt_stats_dump)
+	if (pkt_stats_dump) {
 		qdf_mem_copy(skb_put(ptr,
 				sizeof(struct packet_dump)),
 				pkt_stats_dump,
 				sizeof(struct packet_dump));
+		pktlog_hdr->size -= sizeof(struct packet_dump);
+	}
 
-	qdf_mem_copy(skb_put(ptr,
+	if (data)
+		qdf_mem_copy(skb_put(ptr,
 				pktlog_hdr->size),
 				data, pktlog_hdr->size);
 
+	if (pkt_stats_dump->type == STOP_MONITOR) {
+		wake_up_thread = true;
+		wlan_get_pkt_stats_free_node();
+	}
+
 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
 
 	/* Wakeup logger thread */
@@ -1243,4 +1275,240 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
 	}
 }
 
+/**
+ * driver_hal_status_map() - maps driver to hal
+ * status
+ * @status: status to be mapped
+ *
+ * This function is used to map driver to hal status
+ *
+ * Return: None
+ *
+ */
+static void driver_hal_status_map(uint8_t *status)
+{
+	switch (*status) {
+	case tx_status_ok:
+		*status = TX_PKT_FATE_ACKED;
+		break;
+	case tx_status_discard:
+		*status = TX_PKT_FATE_DRV_DROP_OTHER;
+		break;
+	case tx_status_no_ack:
+		*status = TX_PKT_FATE_SENT;
+		break;
+	case tx_status_download_fail:
+		*status = TX_PKT_FATE_FW_QUEUED;
+		break;
+	default:
+		*status = TX_PKT_FATE_DRV_DROP_OTHER;
+		break;
+	}
+}
+
+
+/*
+ * send_packetdump() - send packet dump
+ * @netbuf: netbuf
+ * @status: status of tx packet
+ * @vdev_id: virtual device id
+ * @type: type of packet
+ *
+ * This function is used to send packet dump to HAL layer
+ * using wlan_pkt_stats_to_logger_thread
+ *
+ * Return: None
+ *
+ */
+static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status,
+				uint8_t vdev_id, uint8_t type)
+{
+	struct ath_pktlog_hdr pktlog_hdr = {0};
+	struct packet_dump pd_hdr = {0};
+	hdd_context_t *hdd_ctx;
+	hdd_adapter_t *adapter;
+	v_CONTEXT_t vos_ctx;
+
+	vos_ctx = cds_get_global_context();
+	if (!vos_ctx)
+		return;
+
+	hdd_ctx = (hdd_context_t *)cds_get_context(QDF_MODULE_ID_HDD);
+	if (!hdd_ctx)
+		return;
+
+	adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+	if (!adapter)
+		return;
+
+	/* Send packet dump only for STA interface */
+	if (adapter->device_mode != QDF_STA_MODE)
+		return;
+
+	pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
+	pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len;
+
+	pd_hdr.status = status;
+	pd_hdr.type = type;
+	pd_hdr.driver_ts = qdf_get_monotonic_boottime();
+
+	if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT))
+		gtx_count++;
+	else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT))
+		grx_count++;
+
+	wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data);
+}
+
+
+/*
+ * send_packetdump_monitor() - sends start/stop packet dump indication
+ * @type: type of packet
+ *
+ * This function is used to indicate HAL layer to start/stop monitoring
+ * of packets
+ *
+ * Return: None
+ *
+ */
+static void send_packetdump_monitor(uint8_t type)
+{
+	struct ath_pktlog_hdr pktlog_hdr = {0};
+	struct packet_dump pd_hdr = {0};
+
+	pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
+	pktlog_hdr.size = sizeof(pd_hdr);
+
+	pd_hdr.type = type;
+
+	LOGGING_TRACE(QDF_TRACE_LEVEL_INFO,
+			"fate Tx-Rx %s: type: %d", __func__, type);
+
+	wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL);
+}
+
+/**
+ * wlan_deregister_txrx_packetdump() - tx/rx packet dump
+ *  deregistration
+ *
+ * This function is used to deregister tx/rx packet dump callbacks
+ * with ol, pe and htt layers
+ *
+ * Return: None
+ *
+ */
+void wlan_deregister_txrx_packetdump(void)
+{
+	if (gtx_count || grx_count) {
+		ol_deregister_packetdump_callback();
+		wma_deregister_packetdump_callback();
+		send_packetdump_monitor(STOP_MONITOR);
+		csr_packetdump_timer_stop();
+
+		gtx_count = 0;
+		grx_count = 0;
+	} else
+		LOGGING_TRACE(QDF_TRACE_LEVEL_INFO,
+			"%s: deregistered packetdump already", __func__);
+}
+
+/*
+ * check_txrx_packetdump_count() - function to check
+ * tx/rx packet dump global counts
+ *
+ * This function is used to check global counts of tx/rx
+ * packet dump functionality.
+ *
+ * Return: 1 if either gtx_count or grx_count reached 32
+ *             0 otherwise
+ *
+ */
+static bool check_txrx_packetdump_count(void)
+{
+	if (gtx_count == MAX_NUM_PKT_LOG ||
+		grx_count == MAX_NUM_PKT_LOG) {
+		LOGGING_TRACE(QDF_TRACE_LEVEL_INFO,
+			"%s gtx_count: %d grx_count: %d deregister packetdump",
+			__func__, gtx_count, grx_count);
+		wlan_deregister_txrx_packetdump();
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * tx_packetdump_cb() - tx packet dump callback
+ * @netbuf: netbuf
+ * @status: status of tx packet
+ * @vdev_id: virtual device id
+ * @type: packet type
+ *
+ * This function is used to send tx packet dump to HAL layer
+ * and deregister packet dump callbacks
+ *
+ * Return: None
+ *
+ */
+static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
+				uint8_t vdev_id, uint8_t type)
+{
+	bool temp;
+
+	temp = check_txrx_packetdump_count();
+	if (temp)
+		return;
+
+	driver_hal_status_map(&status);
+	send_packetdump(netbuf, status, vdev_id, type);
+}
+
+
+/*
+ * rx_packetdump_cb() - rx packet dump callback
+ * @netbuf: netbuf
+ * @status: status of rx packet
+ * @vdev_id: virtual device id
+ * @type: packet type
+ *
+ * This function is used to send rx packet dump to HAL layer
+ * and deregister packet dump callbacks
+ *
+ * Return: None
+ *
+ */
+static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
+				uint8_t vdev_id, uint8_t type)
+{
+	bool temp;
+
+	temp = check_txrx_packetdump_count();
+	if (temp)
+		return;
+
+	send_packetdump(netbuf, status, vdev_id, type);
+}
+
+
+/**
+ * wlan_register_txrx_packetdump() - tx/rx packet dump
+ * registration
+ *
+ * This function is used to register tx/rx packet dump callbacks
+ * with ol, pe and htt layers
+ *
+ * Return: None
+ *
+ */
+void wlan_register_txrx_packetdump(void)
+{
+	ol_register_packetdump_callback(tx_packetdump_cb,
+			rx_packetdump_cb);
+	wma_register_packetdump_callback(tx_packetdump_cb,
+			rx_packetdump_cb);
+	send_packetdump_monitor(START_MONITOR);
+
+	gtx_count = 0;
+	grx_count = 0;
+}
+
 #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */

+ 10 - 0
core/wma/inc/wma.h

@@ -509,6 +509,9 @@ typedef void (*encrypt_decrypt_cb)(struct sir_encrypt_decrypt_rsp_params
 		*encrypt_decrypt_rsp_params);
 
 
+typedef void (*tp_wma_packetdump_cb)(qdf_nbuf_t netbuf,
+			uint8_t status, uint8_t vdev_id, uint8_t type);
+
 /**
  * enum t_wma_drv_type - wma driver type
  * @WMA_DRIVER_TYPE_PRODUCTION: production driver type
@@ -1188,6 +1191,7 @@ struct wmi_desc_t {
 	pWMAAckFnTxComp  ota_post_proc_cb;
 	qdf_nbuf_t	 nbuf;
 	uint32_t	 desc_id;
+	uint8_t vdev_id;
 };
 
 /**
@@ -1600,6 +1604,8 @@ typedef struct {
 					   cds_msg_t *msg);
 	bool fw_timeout_crash;
 	bool sub_20_support;
+	tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb;
+	tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb;
 	tSirLLStatsResults *link_stats_results;
 } t_wma_handle, *tp_wma_handle;
 
@@ -2322,6 +2328,10 @@ QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle,
 
 QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle,
 				uint8_t val);
+void wma_register_packetdump_callback(
+		tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb,
+		tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb);
+void wma_deregister_packetdump_callback(void);
 void wma_update_sta_inactivity_timeout(tp_wma_handle wma,
 		struct sme_sta_inactivity_timeout  *sta_inactivity_timer);
 void wma_peer_set_default_routing(void *scn_handle, uint8_t *peer_macaddr,

+ 1 - 0
core/wma/src/wma_data.c

@@ -2835,6 +2835,7 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
 			status = QDF_STATUS_E_FAILURE;
 		} else {
 			mgmt_param.desc_id = wmi_desc->desc_id;
+			wmi_desc->vdev_id = vdev_id;
 			status = wmi_mgmt_unified_cmd_send(
 					wma_handle->wmi_handle,
 					&mgmt_param);

+ 60 - 0
core/wma/src/wma_mgmt.c

@@ -2508,6 +2508,11 @@ static int wma_process_mgmt_tx_completion(tp_wma_handle wma_handle,
 	if (wmi_desc->nbuf)
 		qdf_nbuf_unmap_single(wma_handle->qdf_dev, wmi_desc->nbuf,
 					  QDF_DMA_TO_DEVICE);
+
+	if (wma_handle->wma_mgmt_tx_packetdump_cb)
+		wma_handle->wma_mgmt_tx_packetdump_cb(wmi_desc->nbuf,
+			QDF_STATUS_SUCCESS, wmi_desc->vdev_id, TX_MGMT_PKT);
+
 	if (wmi_desc->tx_cmpl_cb)
 		wmi_desc->tx_cmpl_cb(wma_handle->mac_context,
 					   wmi_desc->nbuf, 1);
@@ -3323,6 +3328,13 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data,
 		return -EINVAL;
 	}
 
+	if ((mgt_type == IEEE80211_FC0_TYPE_MGT &&
+			mgt_subtype != IEEE80211_FC0_SUBTYPE_BEACON) &&
+			wma_handle->wma_mgmt_rx_packetdump_cb)
+		wma_handle->wma_mgmt_rx_packetdump_cb(rx_pkt->pkt_buf,
+			QDF_STATUS_SUCCESS, rx_pkt->pkt_meta.sessionId,
+			RX_MGMT_PKT);
+
 	wma_handle->mgmt_rx(wma_handle, rx_pkt);
 	return 0;
 }
@@ -3420,3 +3432,51 @@ QDF_STATUS wma_register_mgmt_frm_client(
 
 	return QDF_STATUS_SUCCESS;
 }
+
+/**
+ * wma_register_packetdump_callback() - stores tx and rx mgmt packet dump
+ *   callback handler
+ * @wma_mgmt_tx_packetdump_cb: tx mgmt packetdump cb
+ * @wma_mgmt_rx_packetdump_cb: rx mgmt packetdump cb
+ *
+ * This function is used to store tx and rx mgmt. packet dump callback
+ *
+ * Return: None
+ *
+ */
+void wma_register_packetdump_callback(
+	tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb,
+	tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb)
+{
+	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+
+	if (!wma_handle) {
+		WMA_LOGE("wma handle is NULL");
+		return;
+	}
+
+	wma_handle->wma_mgmt_tx_packetdump_cb = wma_mgmt_tx_packetdump_cb;
+	wma_handle->wma_mgmt_rx_packetdump_cb = wma_mgmt_rx_packetdump_cb;
+}
+
+/**
+ * wma_deregister_packetdump_callback() - removes tx and rx mgmt packet dump
+ *   callback handler
+ *
+ * This function is used to remove tx and rx mgmt. packet dump callback
+ *
+ * Return: None
+ *
+ */
+void wma_deregister_packetdump_callback(void)
+{
+	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+
+	if (!wma_handle) {
+		WMA_LOGE("wma handle is NULL");
+		return;
+	}
+
+	wma_handle->wma_mgmt_tx_packetdump_cb = NULL;
+	wma_handle->wma_mgmt_rx_packetdump_cb = NULL;
+}

+ 106 - 8
uapi/linux/pktlog_ac_fmt.h

@@ -70,6 +70,26 @@ struct ath_pktlog_hdr {
 #endif
 } __ATTRIB_PACK;
 
+/**
+ * enum pkt_type - packet type
+ * @START_MONITOR: indicates parser to start packetdump parsing
+ * @STOP_MONITOR: indicates parser to stop packetdump parsing
+ * @TX_MGMT_PKT: TX management Packet
+ * @TX_DATA_PKT: TX data Packet
+ * @RX_MGMT_PKT: RX management Packet
+ * @RX_DATA_PKT: RX data Packet
+ *
+ * This enum has packet types
+ */
+enum pkt_type {
+	START_MONITOR = 1,
+	STOP_MONITOR,
+	TX_MGMT_PKT,
+	TX_DATA_PKT,
+	RX_MGMT_PKT,
+	RX_DATA_PKT,
+};
+
 #define ATH_PKTLOG_HDR_FLAGS_MASK 0xffff
 #define ATH_PKTLOG_HDR_FLAGS_SHIFT 0
 #define ATH_PKTLOG_HDR_FLAGS_OFFSET 0
@@ -127,17 +147,18 @@ enum {
 
 
 /* Types of packet log events */
-#define PKTLOG_TYPE_TX_CTRL     1
-#define PKTLOG_TYPE_TX_STAT     2
-#define PKTLOG_TYPE_TX_MSDU_ID  3
-#define PKTLOG_TYPE_TX_FRM_HDR  4
-#define PKTLOG_TYPE_RX_STAT     5
-#define PKTLOG_TYPE_RC_FIND     6
-#define PKTLOG_TYPE_RC_UPDATE   7
+#define PKTLOG_TYPE_TX_CTRL      1
+#define PKTLOG_TYPE_TX_STAT      2
+#define PKTLOG_TYPE_TX_MSDU_ID   3
+#define PKTLOG_TYPE_TX_FRM_HDR   4
+#define PKTLOG_TYPE_RX_STAT      5
+#define PKTLOG_TYPE_RC_FIND      6
+#define PKTLOG_TYPE_RC_UPDATE    7
 #define PKTLOG_TYPE_TX_VIRT_ADDR 8
 #define PKTLOG_TYPE_SMART_ANTENNA 9
 #define PKTLOG_TYPE_SW_EVENT     10
-#define PKTLOG_TYPE_MAX          11
+#define PKTLOG_TYPE_PKT_DUMP     11
+#define PKTLOG_TYPE_MAX          12
 
 #define PKTLOG_MAX_TXCTL_WORDS 57       /* +2 words for bitmap */
 #define PKTLOG_MAX_TXSTATUS_WORDS 32
@@ -287,5 +308,82 @@ struct ath_pktlog_buf {
 				sizeof(struct ath_pktlog_hdr)) ? _rd_offset : 0; \
 	} while(0)
 
+/**
+ * enum tx_pkt_fate - tx packet fate
+ * @TX_PKT_FATE_ACKED: Sent over air and ACKed
+ * @TX_PKT_FATE_SENT: Sent over air but not ACKed.
+ * @TX_PKT_FATE_FW_QUEUED: Queued within firmware,
+ * but not yet sent over air
+ * @TX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware as invalid.
+ * E.g. bad source address, bad checksum, or invalid for current state.
+ * @TX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware due
+ * to lack of buffer space
+ * @TX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware for any other
+ * reason. Includes frames that were sent by driver to firmware, but
+ * unaccounted for by firmware.
+ * @TX_PKT_FATE_DRV_QUEUED: Queued within driver, not yet sent to firmware.
+ * @TX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid.
+ * E.g. bad source address, or invalid for current state.
+ * @TX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver due to lack of buffer space
+ * @TX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason.
+ * E.g. out of buffers.
+ *
+ * This enum has packet fate types
+ */
+
+enum tx_pkt_fate {
+	TX_PKT_FATE_ACKED,
+	TX_PKT_FATE_SENT,
+	TX_PKT_FATE_FW_QUEUED,
+	TX_PKT_FATE_FW_DROP_INVALID,
+	TX_PKT_FATE_FW_DROP_NOBUFS,
+	TX_PKT_FATE_FW_DROP_OTHER,
+	TX_PKT_FATE_DRV_QUEUED,
+	TX_PKT_FATE_DRV_DROP_INVALID,
+	TX_PKT_FATE_DRV_DROP_NOBUFS,
+	TX_PKT_FATE_DRV_DROP_OTHER,
+};
+
+/**
+ * enum rx_pkt_fate - rx packet fate
+ * @RX_PKT_FATE_SUCCESS: Valid and delivered to
+ * network stack (e.g., netif_rx()).
+ * @RX_PKT_FATE_FW_QUEUED: Queued within firmware,
+ * but not yet sent to driver.
+ * @RX_PKT_FATE_FW_DROP_FILTER: Dropped by firmware
+ * due to host-programmable filters.
+ * @RX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware
+ * as invalid. E.g. bad checksum, decrypt failed, or invalid for current state.
+ * @RX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware
+ * due to lack of buffer space.
+ * @RX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware
+ * for any other reason.
+ * @RX_PKT_FATE_DRV_QUEUED: Queued within driver,
+ * not yet delivered to network stack.
+ * @RX_PKT_FATE_DRV_DROP_FILTER: Dropped by driver
+ * due to filter rules.
+ * @RX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid.
+ * E.g. not permitted in current state.
+ * @RX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver
+ * due to lack of buffer space.
+ * @RX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason.
+ *
+ * This enum has packet fate types
+ */
+
+enum rx_pkt_fate {
+	RX_PKT_FATE_SUCCESS,
+	RX_PKT_FATE_FW_QUEUED,
+	RX_PKT_FATE_FW_DROP_FILTER,
+	RX_PKT_FATE_FW_DROP_INVALID,
+	RX_PKT_FATE_FW_DROP_NOBUFS,
+	RX_PKT_FATE_FW_DROP_OTHER,
+	RX_PKT_FATE_DRV_QUEUED,
+	RX_PKT_FATE_DRV_DROP_FILTER,
+	RX_PKT_FATE_DRV_DROP_INVALID,
+	RX_PKT_FATE_DRV_DROP_NOBUFS,
+	RX_PKT_FATE_DRV_DROP_OTHER,
+};
+
 #endif /* _PKTLOG_FMT_H_ */
 #endif /* REMOVE_PKT_LOG */