summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-06-01 23:03:34 -0700
committerLinux Build Service Account <lnxbuild@localhost>2019-06-01 23:03:34 -0700
commit3c316fb43ebffd16b407f8a2cf9f52e2800d2b18 (patch)
treea1a0c60d92ebc70b878bb3cf5dcae4c60a44218f
parente634d1741b5ee45ecde55af2df3d803aa70382a1 (diff)
parentab9f60b51d5e33daaaf95bff8fa07ce604a18223 (diff)
Merge ab9f60b51d5e33daaaf95bff8fa07ce604a18223 on remote branch
Change-Id: I1f2ce847514a862506ba913d901cf4247ec2d03c
-rw-r--r--Kbuild7
-rw-r--r--core/cds/inc/cds_api.h23
-rw-r--r--core/cds/inc/cds_sched.h151
-rw-r--r--core/cds/src/cds_api.c36
-rw-r--r--core/cds/src/cds_concurrency.c15
-rw-r--r--core/cds/src/cds_sched.c410
-rw-r--r--core/dp/htt/htt_rx.c49
-rw-r--r--core/dp/htt/htt_t2h.c14
-rw-r--r--core/dp/ol/inc/ol_cfg.h8
-rw-r--r--core/dp/ol/inc/ol_htt_api.h6
-rw-r--r--core/dp/ol/inc/ol_htt_rx_api.h6
-rw-r--r--core/dp/ol/inc/ol_txrx_htt_api.h6
-rw-r--r--core/dp/ol/inc/ol_txrx_osif_api.h19
-rw-r--r--core/dp/txrx/ol_cfg.c35
-rw-r--r--core/dp/txrx/ol_rx.c43
-rw-r--r--core/dp/txrx/ol_rx_defrag.c41
-rw-r--r--core/dp/txrx/ol_tx_send.c260
-rw-r--r--core/dp/txrx/ol_txrx.c825
-rw-r--r--core/dp/txrx/ol_txrx.h5
-rw-r--r--core/dp/txrx/ol_txrx_flow_control.c13
-rw-r--r--core/dp/txrx/ol_txrx_types.h25
-rw-r--r--core/hdd/inc/wlan_hdd_cfg.h46
-rw-r--r--core/hdd/inc/wlan_hdd_main.h81
-rw-r--r--core/hdd/inc/wlan_hdd_tx_rx.h32
-rw-r--r--core/hdd/src/wlan_hdd_cfg.c35
-rw-r--r--core/hdd/src/wlan_hdd_cfg80211.c26
-rw-r--r--core/hdd/src/wlan_hdd_driver_ops.c3
-rw-r--r--core/hdd/src/wlan_hdd_main.c199
-rw-r--r--core/hdd/src/wlan_hdd_p2p.c18
-rw-r--r--core/hdd/src/wlan_hdd_power.c40
-rw-r--r--core/hdd/src/wlan_hdd_stats.c16
-rw-r--r--core/hdd/src/wlan_hdd_tx_rx.c38
-rw-r--r--core/mac/inc/qwlan_version.h4
-rw-r--r--core/mac/src/pe/include/lim_session.h6
-rw-r--r--core/mac/src/pe/lim/lim_api.c3
-rw-r--r--core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c129
-rw-r--r--core/mac/src/pe/lim/lim_process_mlm_req_messages.c13
-rw-r--r--core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c24
-rw-r--r--core/mac/src/pe/lim/lim_session.c38
-rw-r--r--core/mac/src/pe/lim/lim_utils.c18
-rw-r--r--core/mac/src/pe/lim/lim_utils.h10
-rw-r--r--core/sap/src/sap_api_link_cntl.c24
-rw-r--r--core/sme/inc/csr_api.h2
-rw-r--r--core/sme/src/common/sme_api.c3
-rw-r--r--core/sme/src/csr/csr_api_roam.c2
-rw-r--r--core/sme/src/csr/csr_api_scan.c53
-rw-r--r--core/utils/logging/src/wlan_logging_sock_svc.c6
-rw-r--r--core/utils/pktlog/pktlog_internal.c3
-rw-r--r--core/wma/inc/wma.h3
-rw-r--r--core/wma/inc/wma_internal.h10
-rw-r--r--core/wma/src/wma_dev_if.c53
-rw-r--r--core/wma/src/wma_main.c23
-rw-r--r--core/wma/src/wma_mgmt.c316
-rw-r--r--core/wma/src/wma_scan_roam.c39
-rw-r--r--core/wma/src/wma_utils.c48
55 files changed, 3062 insertions, 299 deletions
diff --git a/Kbuild b/Kbuild
index cfa13e139986..39f0e177480b 100644
--- a/Kbuild
+++ b/Kbuild
@@ -184,6 +184,9 @@ ifeq ($(KERNEL_BUILD), 0)
#Flag to enable offload packets feature
CONFIG_WLAN_OFFLOAD_PACKETS := y
+ #Flag to enable packet capture mode
+ CONFIG_WLAN_FEATURE_PKT_CAPTURE := y
+
#enable TSF get feature
CONFIG_WLAN_SYNC_TSF := y
#Enable DSRC feature
@@ -1316,6 +1319,10 @@ ifeq ($(CONFIG_WLAN_FEATURE_FILS),y)
CDEFINES += -DWLAN_FEATURE_FILS_SK
endif
+ifeq ($(CONFIG_WLAN_FEATURE_PKT_CAPTURE),y)
+CDEFINES += -DWLAN_FEATURE_PKT_CAPTURE
+endif
+
ifeq ($(CONFIG_CNSS), y)
ifeq ($(CONFIG_CNSS_SDIO), y)
CDEFINES += -DCONFIG_PLD_SDIO_CNSS
diff --git a/core/cds/inc/cds_api.h b/core/cds/inc/cds_api.h
index 2f08babd8582..a83ead34cf01 100644
--- a/core/cds/inc/cds_api.h
+++ b/core/cds/inc/cds_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -582,4 +582,25 @@ QDF_STATUS cds_register_mode_change_cb(send_mode_change_event_cb callback);
* Return: QDF_STATUS
*/
QDF_STATUS cds_deregister_mode_change_cb(void);
+
+/**
+ * cds_get_pktcap_mode_enable() - get pktcap mode enable/disable
+ *
+ * Get the pktcap mode enable/disable from ini
+ *
+ * Return: 0 - disable, 1 - enable
+ */
+bool cds_get_pktcap_mode_enable(void);
+
+/**
+ * cds_get_pktcapture_mode() - get pktcapture mode value
+ *
+ * Get the pktcapture mode value from hdd context
+ *
+ * Return: 0 - disable
+ * 1 - Mgmt packets
+ * 2 - Data packets
+ * 3 - Both Mgmt and Data packets
+ */
+uint8_t cds_get_pktcapture_mode(void);
#endif /* if !defined __CDS_API_H */
diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h
index 6b5f7a7841df..24e3b624115f 100644
--- a/core/cds/inc/cds_sched.h
+++ b/core/cds/inc/cds_sched.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -79,8 +79,19 @@
#define CDS_MAX_OL_RX_PKT 4000
#endif
+/*
+** Maximum number of cds messages to be allocated for
+** OL MON thread.
+*/
+#define CDS_MAX_OL_MON_PKT 4000
+
typedef void (*cds_ol_rx_thread_cb)(void *context, void *rxpkt, uint16_t staid);
+typedef void (*cds_ol_mon_thread_cb)(
+ void *context, void *monpkt,
+ uint8_t vdev_id, uint8_t tid,
+ uint8_t status, bool pkt_format);
+
typedef int (*send_mode_change_event_cb)(void);
/*
@@ -114,6 +125,31 @@ struct cds_ol_rx_pkt {
};
/*
+** CDS message wrapper for mon data from TXRX
+*/
+struct cds_ol_mon_pkt {
+ struct list_head list;
+ void *context;
+
+ /* mon skb */
+ void *monpkt;
+
+ /* vdev id to which this packet is destined */
+ uint8_t vdev_id;
+
+ uint8_t tid;
+
+ /* Tx packet status */
+ uint8_t status;
+
+ /* 0 = 802.3 format , 1 = 802.11 format */
+ bool pkt_format;
+
+ /* Call back to further send this packet to txrx layer */
+ cds_ol_mon_thread_cb callback;
+};
+
+/*
** CDS Scheduler context
** The scheduler context contains the following:
** ** the messages queues
@@ -204,6 +240,46 @@ typedef struct _cds_sched_context {
/* high throughput required */
bool high_throughput_required;
#endif
+ /* MON thread lock */
+ spinlock_t ol_mon_thread_lock;
+
+ /* OL MON thread handle */
+ struct task_struct *ol_mon_thread;
+
+ /* Handle of Event for MON thread to signal startup */
+ struct completion ol_mon_start_event;
+
+ /* Completion object to suspend OL MON thread */
+ struct completion ol_suspend_mon_event;
+
+ /* Completion objext to resume OL MON thread */
+ struct completion ol_resume_mon_event;
+
+ /* Completion object for OL MON thread shutdown */
+ struct completion ol_mon_shutdown;
+
+ /* Waitq for OL MON thread */
+ wait_queue_head_t ol_mon_wait_queue;
+
+ unsigned long ol_mon_event_flag;
+
+ /* MON buffer queue */
+ struct list_head ol_mon_thread_queue;
+
+ /* Spinlock to synchronize between tasklet and thread */
+ spinlock_t ol_mon_queue_lock;
+
+ /* MON queue length */
+ unsigned int ol_mon_queue_len;
+
+ /* Lock to synchronize free buffer queue access */
+ spinlock_t cds_ol_mon_pkt_freeq_lock;
+
+ /* Free message queue for OL MON processing */
+ struct list_head cds_ol_mon_pkt_freeq;
+
+ /* MON thread affinity cpu */
+ unsigned long mon_thread_cpu;
} cds_sched_context, *p_cds_sched_context;
/**
@@ -529,6 +605,79 @@ static inline int cds_sched_handle_throughput_req(
#endif
+/**
+ * cds_drop_monpkt() - API to drop pending mon packets
+ * @pschedcontext: Pointer to the global CDS Sched Context
+ *
+ * This api drops all the pending packets in the queue.
+ *
+ * Return: none
+ */
+void cds_drop_monpkt(p_cds_sched_context pschedcontext);
+
+/**
+ * cds_indicate_monpkt() - API to Indicate rx data packet
+ * @pschedcontext: pointer to CDS Sched Context
+ * @pkt: CDS OL MON pkt pointer containing to mon data message buffer
+ *
+ * Return: none
+ */
+void cds_indicate_monpkt(p_cds_sched_context pschedcontext,
+ struct cds_ol_mon_pkt *pkt);
+
+/**
+ * cds_wakeup_mon_thread() - wakeup mon thread
+ * @Arg: Pointer to the global CDS Sched Context
+ *
+ * This api wake up cds_ol_mon_thread() to process pkt
+ *
+ * Return: none
+ */
+void cds_wakeup_mon_thread(p_cds_sched_context pschedcontext);
+
+/**
+ * cds_close_mon_thread() - close the Tlshim MON thread
+ * @p_cds_context: Pointer to the global CDS Context
+ *
+ * This api closes the Tlshim MON thread:
+ *
+ * Return: qdf status
+ */
+QDF_STATUS cds_close_mon_thread(void *p_cds_context);
+
+/**
+ * cds_alloc_ol_mon_pkt() - API to return next available cds message
+ * @pSchedContext: Pointer to the global CDS Sched Context
+ *
+ * This api returns next available cds message buffer used for mon data
+ * processing
+ *
+ * Return: Pointer to cds message buffer
+ */
+struct cds_ol_mon_pkt *cds_alloc_ol_mon_pkt(p_cds_sched_context pschedcontext);
+
+/**
+ * cds_free_ol_mon_pkt() - api to release cds message to the freeq
+ * This api returns the cds message used for mon data to the free queue
+ * @pSchedContext: Pointer to the global CDS Sched Context
+ * @pkt: CDS message buffer to be returned to free queue.
+ *
+ * Return: none
+ */
+void cds_free_ol_mon_pkt(p_cds_sched_context pschedcontext,
+ struct cds_ol_mon_pkt *pkt);
+
+/**
+ * cds_free_ol_mon_pkt_freeq() - free cds buffer free queue
+ * @pSchedContext - pointer to the global CDS Sched Context
+ *
+ * This API does mem free of the buffers available in free cds buffer
+ * queue which is used for mon Data processing.
+ *
+ * Return: none
+ */
+void cds_free_ol_mon_pkt_freeq(p_cds_sched_context pschedcontext);
+
/*---------------------------------------------------------------------------
\brief cds_sched_open() - initialize the CDS Scheduler
diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c
index 531afce9e0c6..c6de500cc785 100644
--- a/core/cds/src/cds_api.c
+++ b/core/cds/src/cds_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -966,6 +966,14 @@ QDF_STATUS cds_post_disable(void)
return QDF_STATUS_E_INVAL;
}
+ if (cds_get_pktcap_mode_enable()) {
+ qdf_status = cds_close_mon_thread(gp_cds_context);
+ if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+ cds_err("Failed to close MON thread!");
+ return QDF_STATUS_E_INVAL;
+ }
+ }
+
ol_txrx_pdev_pre_detach(txrx_pdev, 1);
return QDF_STATUS_SUCCESS;
@@ -3055,3 +3063,29 @@ QDF_STATUS cds_deregister_mode_change_cb(void)
return QDF_STATUS_SUCCESS;
}
+
+bool cds_get_pktcap_mode_enable(void)
+{
+ hdd_context_t *hdd_ctx;
+
+ hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+ if (!hdd_ctx) {
+ cds_err("HDD context is NULL");
+ return false;
+ }
+
+ return hdd_ctx->config->pktcap_mode_enable;
+}
+
+uint8_t cds_get_pktcapture_mode(void)
+{
+ hdd_context_t *hdd_ctx;
+
+ hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+ if (!hdd_ctx) {
+ cds_err("HDD context is NULL");
+ return 0;
+ }
+
+ return hdd_ctx->pktcapture_mode;
+}
diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c
index ee5ab899f2b0..bbf7be5293c1 100644
--- a/core/cds/src/cds_concurrency.c
+++ b/core/cds/src/cds_concurrency.c
@@ -5936,6 +5936,13 @@ static QDF_STATUS cds_pcl_modification_for_p2p_go(
cds_err("failed to get enabled channel modified pcl for GO");
return status;
}
+ status = cds_modify_sap_pcl_based_on_srd(
+ pcl_channels, pcl_weight, len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get srd modified pcl for SAP");
+ return status;
+ }
+
cds_debug("enabled channel modified pcl len:%d", *len);
for (i = 0; i < *len; i++)
cds_debug("chan:%d weight:%d",
@@ -6140,6 +6147,14 @@ QDF_STATUS cds_get_pcl(enum cds_con_mode mode,
pcl_channels[i], pcl_weight[i]);
}
+ status = cds_mode_specific_modification_on_pcl(pcl_channels, pcl_weight,
+ len, mode);
+
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get modified pcl for mode %d", mode);
+ return status;
+ }
+
return QDF_STATUS_SUCCESS;
}
diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c
index d06b8de713ff..5bb7e5bdd6e3 100644
--- a/core/cds/src/cds_sched.c
+++ b/core/cds/src/cds_sched.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -80,6 +80,9 @@ enum notifier_state {
struct _cds_sched_context *gp_cds_sched_context;
static int cds_mc_thread(void *Arg);
+static int cds_ol_mon_thread(void *arg);
+static QDF_STATUS cds_alloc_ol_mon_pkt_freeq(p_cds_sched_context pSchedContext);
+
#ifdef QCA_CONFIG_SMP
static int cds_ol_rx_thread(void *arg);
static uint32_t affine_cpu;
@@ -519,6 +522,25 @@ QDF_STATUS cds_sched_open(void *p_cds_context,
mutex_init(&pSchedContext->affinity_lock);
pSchedContext->high_throughput_required = false;
#endif
+ if (cds_get_pktcap_mode_enable()) {
+ spin_lock_init(&pSchedContext->ol_mon_thread_lock);
+ init_waitqueue_head(&pSchedContext->ol_mon_wait_queue);
+ init_completion(&pSchedContext->ol_mon_start_event);
+ init_completion(&pSchedContext->ol_suspend_mon_event);
+ init_completion(&pSchedContext->ol_resume_mon_event);
+ init_completion(&pSchedContext->ol_mon_shutdown);
+ pSchedContext->ol_mon_event_flag = 0;
+ spin_lock_init(&pSchedContext->ol_mon_queue_lock);
+ spin_lock_init(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ INIT_LIST_HEAD(&pSchedContext->ol_mon_thread_queue);
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ INIT_LIST_HEAD(&pSchedContext->cds_ol_mon_pkt_freeq);
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ if (cds_alloc_ol_mon_pkt_freeq(pSchedContext) !=
+ QDF_STATUS_SUCCESS)
+ goto mon_freeqalloc_failure;
+ }
+
gp_cds_sched_context = pSchedContext;
/* Create the CDS Main Controller thread */
@@ -550,6 +572,20 @@ QDF_STATUS cds_sched_open(void *p_cds_context,
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
("CDS OL RX thread Created"));
#endif
+ if (cds_get_pktcap_mode_enable()) {
+ pSchedContext->ol_mon_thread = kthread_create(cds_ol_mon_thread,
+ pSchedContext,
+ "cds_ol_mon_thread");
+ if (IS_ERR(pSchedContext->ol_mon_thread)) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
+ "%s: Could not Create CDS OL MON Thread",
+ __func__);
+ goto OL_MON_THREAD_START_FAILURE;
+ }
+ wake_up_process(pSchedContext->ol_mon_thread);
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
+ ("CDS OL MON thread Created"));
+ }
/*
* Now make sure all threads have started before we exit.
* Each thread should normally ACK back when it starts.
@@ -562,12 +598,28 @@ QDF_STATUS cds_sched_open(void *p_cds_context,
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: CDS OL Rx Thread has started", __func__);
#endif
+ if (cds_get_pktcap_mode_enable()) {
+ wait_for_completion_interruptible(
+ &pSchedContext->ol_mon_start_event);
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
+ "%s: CDS OL MON Thread has started", __func__);
+ }
+
/* We're good now: Let's get the ball rolling!!! */
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: CDS Scheduler successfully Opened", __func__);
return QDF_STATUS_SUCCESS;
+OL_MON_THREAD_START_FAILURE:
#ifdef QCA_CONFIG_SMP
+ /* Try and force the Main thread controller to exit */
+ set_bit(RX_SHUTDOWN_EVENT, &pSchedContext->ol_rx_event_flag);
+ set_bit(RX_POST_EVENT, &pSchedContext->ol_rx_event_flag);
+ wake_up_interruptible(&pSchedContext->ol_rx_wait_queue);
+ /* Wait for RX Thread to exit */
+ wait_for_completion(&pSchedContext->ol_rx_shutdown);
+#endif
+
OL_RX_THREAD_START_FAILURE:
/* Try and force the Main thread controller to exit */
set_bit(MC_SHUTDOWN_EVENT, &pSchedContext->mcEventFlag);
@@ -575,10 +627,12 @@ OL_RX_THREAD_START_FAILURE:
wake_up_interruptible(&pSchedContext->mcWaitQueue);
/* Wait for MC to exit */
wait_for_completion_interruptible(&pSchedContext->McShutdown);
-#endif
MC_THREAD_START_FAILURE:
+ if (cds_get_pktcap_mode_enable())
+ cds_free_ol_mon_pkt_freeq(gp_cds_sched_context);
+mon_freeqalloc_failure:
#ifdef QCA_CONFIG_SMP
qdf_cpuhp_unregister(&pSchedContext->cpuhp_event_handle);
cds_free_ol_rx_pkt_freeq(gp_cds_sched_context);
@@ -1268,6 +1322,355 @@ static int cds_ol_rx_thread(void *arg)
}
#endif
+/**
+ * cds_free_ol_mon_pkt_freeq() - free cds buffer free queue
+ * @pSchedContext - pointer to the global CDS Sched Context
+ *
+ * This API does mem free of the buffers available in free cds buffer
+ * queue which is used for mon Data processing.
+ *
+ * Return: none
+ */
+void cds_free_ol_mon_pkt_freeq(p_cds_sched_context pSchedContext)
+{
+ struct cds_ol_mon_pkt *pkt;
+
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ while (!list_empty(&pSchedContext->cds_ol_mon_pkt_freeq)) {
+ pkt = list_entry((&pSchedContext->cds_ol_mon_pkt_freeq)->next,
+ typeof(*pkt), list);
+ list_del(&pkt->list);
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ qdf_mem_free(pkt);
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ }
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+}
+
+/**
+ * cds_alloc_ol_mon_pkt_freeq() - Function to allocate free buffer queue
+ * @pSchedContext - pointer to the global CDS Sched Context
+ *
+ * This API allocates CDS_MAX_OL_MON_PKT number of cds message buffers
+ * which are used for mon data processing.
+ *
+ * Return: status of memory allocation
+ */
+static QDF_STATUS cds_alloc_ol_mon_pkt_freeq(p_cds_sched_context pSchedContext)
+{
+ struct cds_ol_mon_pkt *pkt, *tmp;
+ int i;
+
+ for (i = 0; i < CDS_MAX_OL_MON_PKT; i++) {
+ pkt = qdf_mem_malloc(sizeof(*pkt));
+ if (!pkt) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+ "%s Vos packet allocation for ol mon thread failed",
+ __func__);
+ goto free;
+ }
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ list_add_tail(&pkt->list, &pSchedContext->cds_ol_mon_pkt_freeq);
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ }
+
+ return QDF_STATUS_SUCCESS;
+
+free:
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ list_for_each_entry_safe(pkt, tmp, &pSchedContext->cds_ol_mon_pkt_freeq,
+ list) {
+ list_del(&pkt->list);
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ qdf_mem_free(pkt);
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ }
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ return QDF_STATUS_E_NOMEM;
+}
+
+/**
+ * cds_free_ol_mon_pkt() - api to release cds message to the freeq
+ * This api returns the cds message used for mon data to the free queue
+ * @pSchedContext: Pointer to the global CDS Sched Context
+ * @pkt: CDS message buffer to be returned to free queue.
+ *
+ * Return: none
+ */
+void
+cds_free_ol_mon_pkt(p_cds_sched_context pSchedContext,
+ struct cds_ol_mon_pkt *pkt)
+{
+ memset(pkt, 0, sizeof(*pkt));
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ list_add_tail(&pkt->list, &pSchedContext->cds_ol_mon_pkt_freeq);
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+}
+
+/**
+ * cds_alloc_ol_mon_pkt() - API to return next available cds message
+ * @pSchedContext: Pointer to the global CDS Sched Context
+ *
+ * This api returns next available cds message buffer used for mon data
+ * processing
+ *
+ * Return: Pointer to cds message buffer
+ */
+struct cds_ol_mon_pkt *cds_alloc_ol_mon_pkt(p_cds_sched_context pSchedContext)
+{
+ struct cds_ol_mon_pkt *pkt;
+
+ spin_lock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ if (list_empty(&pSchedContext->cds_ol_mon_pkt_freeq)) {
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ return NULL;
+ }
+ pkt = list_first_entry(&pSchedContext->cds_ol_mon_pkt_freeq,
+ struct cds_ol_mon_pkt, list);
+ list_del(&pkt->list);
+ spin_unlock_bh(&pSchedContext->cds_ol_mon_pkt_freeq_lock);
+ return pkt;
+}
+
+/**
+ * cds_indicate_monpkt() - indicate mon data packet
+ * @Arg: Pointer to the global CDS Sched Context
+ * @pkt: CDS data message buffer
+ *
+ * This api enqueues the mon packet into ol_mon_thread_queue and notifies
+ * cds_ol_mon_thread()
+ *
+ * Return: none
+ */
+void
+cds_indicate_monpkt(p_cds_sched_context pSchedContext,
+ struct cds_ol_mon_pkt *pkt)
+{
+ spin_lock_bh(&pSchedContext->ol_mon_queue_lock);
+ list_add_tail(&pkt->list, &pSchedContext->ol_mon_thread_queue);
+ spin_unlock_bh(&pSchedContext->ol_mon_queue_lock);
+ set_bit(RX_POST_EVENT, &pSchedContext->ol_mon_event_flag);
+ wake_up_interruptible(&pSchedContext->ol_mon_wait_queue);
+}
+
+/**
+ * cds_wakeup_mon_thread() - wakeup mon thread
+ * @Arg: Pointer to the global CDS Sched Context
+ *
+ * This api wake up cds_ol_mon_thread() to process pkt
+ *
+ * Return: none
+ */
+void
+cds_wakeup_mon_thread(p_cds_sched_context pSchedContext)
+{
+ set_bit(RX_POST_EVENT, &pSchedContext->ol_mon_event_flag);
+ wake_up_interruptible(&pSchedContext->ol_mon_wait_queue);
+}
+
+/**
+ * cds_close_mon_thread() - close the Tlshim Rx thread
+ * @p_cds_context: Pointer to the global CDS Context
+ *
+ * This api closes the Tlshim Rx thread:
+ *
+ * Return: qdf status
+ */
+QDF_STATUS cds_close_mon_thread(void *p_cds_context)
+{
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
+ "%s: invoked", __func__);
+
+ if (!gp_cds_sched_context) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+ "%s: gp_cds_sched_context == NULL", __func__);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ if (!gp_cds_sched_context->ol_mon_thread)
+ return QDF_STATUS_SUCCESS;
+
+ /* Shut down Tlshim Rx thread */
+ set_bit(RX_SHUTDOWN_EVENT, &gp_cds_sched_context->ol_mon_event_flag);
+ set_bit(RX_POST_EVENT, &gp_cds_sched_context->ol_mon_event_flag);
+ wake_up_interruptible(&gp_cds_sched_context->ol_mon_wait_queue);
+ wait_for_completion(&gp_cds_sched_context->ol_mon_shutdown);
+ gp_cds_sched_context->ol_mon_thread = NULL;
+ cds_drop_monpkt(gp_cds_sched_context);
+ cds_free_ol_mon_pkt_freeq(gp_cds_sched_context);
+
+ return QDF_STATUS_SUCCESS;
+} /* cds_close_mon_thread */
+
+/**
+ * cds_drop_monpkt() - api to drop pending mon packets for a sta
+ * @pschedcontext: Pointer to the global CDS Sched Context
+ *
+ * This api drops all queued packets for a station.
+ *
+ * Return: none
+ */
+void cds_drop_monpkt(p_cds_sched_context pschedcontext)
+{
+ struct list_head local_list;
+ struct cds_ol_mon_pkt *pkt, *tmp;
+ qdf_nbuf_t buf, next_buf;
+
+ INIT_LIST_HEAD(&local_list);
+ spin_lock_bh(&pschedcontext->ol_mon_queue_lock);
+ if (list_empty(&pschedcontext->ol_mon_thread_queue)) {
+ spin_unlock_bh(&pschedcontext->ol_mon_queue_lock);
+ return;
+ }
+ list_for_each_entry_safe(pkt, tmp,
+ &pschedcontext->ol_mon_thread_queue,
+ list)
+ list_move_tail(&pkt->list, &local_list);
+
+ spin_unlock_bh(&pschedcontext->ol_mon_queue_lock);
+
+ list_for_each_entry_safe(pkt, tmp, &local_list, list) {
+ list_del(&pkt->list);
+ buf = pkt->monpkt;
+ while (buf) {
+ next_buf = qdf_nbuf_queue_next(buf);
+ qdf_nbuf_free(buf);
+ buf = next_buf;
+ }
+ cds_free_ol_mon_pkt(pschedcontext, pkt);
+ }
+}
+
+/**
+ * cds_mon_from_queue() - function to process pending mon packets
+ * @pschedcontext: Pointer to the global CDS Sched Context
+ *
+ * This api traverses the pending buffer list and calling the callback.
+ * This callback would essentially send the packet to HDD.
+ *
+ * Return: none
+ */
+static void cds_mon_from_queue(p_cds_sched_context pschedcontext)
+{
+ struct cds_ol_mon_pkt *pkt;
+ uint8_t vdev_id;
+ uint8_t tid;
+
+ spin_lock_bh(&pschedcontext->ol_mon_queue_lock);
+ while (!list_empty(&pschedcontext->ol_mon_thread_queue)) {
+ pkt = list_first_entry(&pschedcontext->ol_mon_thread_queue,
+ struct cds_ol_mon_pkt, list);
+ list_del(&pkt->list);
+ spin_unlock_bh(&pschedcontext->ol_mon_queue_lock);
+ vdev_id = pkt->vdev_id;
+ tid = pkt->tid;
+ pkt->callback(pkt->context, pkt->monpkt, vdev_id,
+ tid, pkt->status, pkt->pkt_format);
+ cds_free_ol_mon_pkt(pschedcontext, pkt);
+ spin_lock_bh(&pschedcontext->ol_mon_queue_lock);
+ }
+ spin_unlock_bh(&pschedcontext->ol_mon_queue_lock);
+}
+
+/**
+ * cds_ol_mon_thread() - cds main tlshim mon thread
+ * @Arg: pointer to the global CDS Sched Context
+ *
+ * This api is the thread handler for mon Data packet processing.
+ *
+ * Return: thread exit code
+ */
+static int cds_ol_mon_thread(void *arg)
+{
+ p_cds_sched_context pschedcontext = (p_cds_sched_context)arg;
+ unsigned long pref_cpu = 0;
+ bool shutdown = false;
+ int status, i;
+
+ if (!arg) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+ "%s: Bad Args passed", __func__);
+ return 0;
+ }
+
+ set_user_nice(current, -1);
+#ifdef MSM_PLATFORM
+ set_wake_up_idle(true);
+#endif
+
+ /**
+ * Find the available cpu core other than cpu 0 and
+ * bind the thread
+ */
+ for_each_online_cpu(i) {
+ if (i == 0)
+ continue;
+ pref_cpu = i;
+ break;
+ }
+
+ cds_set_cpus_allowed_ptr(current, pref_cpu);
+
+ complete(&pschedcontext->ol_mon_start_event);
+
+ while (!shutdown) {
+ status =
+ wait_event_interruptible(
+ pschedcontext->ol_mon_wait_queue,
+ test_bit(RX_POST_EVENT,
+ &pschedcontext->ol_mon_event_flag) ||
+ test_bit(RX_SUSPEND_EVENT,
+ &pschedcontext->ol_mon_event_flag));
+ if (status == -ERESTARTSYS)
+ break;
+
+ clear_bit(RX_POST_EVENT, &pschedcontext->ol_mon_event_flag);
+ while (true) {
+ if (test_bit(RX_SHUTDOWN_EVENT,
+ &pschedcontext->ol_mon_event_flag)) {
+ clear_bit(RX_SHUTDOWN_EVENT,
+ &pschedcontext->ol_mon_event_flag);
+ if (test_bit(
+ RX_SUSPEND_EVENT,
+ &pschedcontext->ol_mon_event_flag)) {
+ clear_bit(
+ RX_SUSPEND_EVENT,
+ &pschedcontext->ol_mon_event_flag);
+ complete
+ (&pschedcontext->ol_suspend_mon_event);
+ }
+ QDF_TRACE(QDF_MODULE_ID_QDF,
+ QDF_TRACE_LEVEL_INFO,
+ "%s: Shutting down OL MON Thread",
+ __func__);
+ shutdown = true;
+ break;
+ }
+ cds_mon_from_queue(pschedcontext);
+
+ if (test_bit(RX_SUSPEND_EVENT,
+ &pschedcontext->ol_mon_event_flag)) {
+ clear_bit(RX_SUSPEND_EVENT,
+ &pschedcontext->ol_mon_event_flag);
+ spin_lock(&pschedcontext->ol_mon_thread_lock);
+ INIT_COMPLETION
+ (pschedcontext->ol_resume_mon_event);
+ complete(&pschedcontext->ol_suspend_mon_event);
+ spin_unlock(&pschedcontext->ol_mon_thread_lock);
+ wait_for_completion_interruptible
+ (&pschedcontext->ol_resume_mon_event);
+ }
+ break;
+ }
+ }
+
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
+ "%s: Exiting CDS OL mon thread", __func__);
+ complete_and_exit(&pschedcontext->ol_mon_shutdown, 0);
+
+ return 0;
+}
+
void cds_remove_timer_from_sys_msg(uint32_t timer_cookie)
{
p_cds_msg_wrapper msg_wrapper = NULL;
@@ -1353,6 +1756,9 @@ QDF_STATUS cds_sched_close(void *p_cds_context)
cds_close_rx_thread(p_cds_context);
+ if (cds_get_pktcap_mode_enable())
+ cds_close_mon_thread(p_cds_context);
+
gp_cds_sched_context = NULL;
return QDF_STATUS_SUCCESS;
} /* cds_sched_close() */
diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c
index 78b76225854c..f82e7cc157f8 100644
--- a/core/dp/htt/htt_rx.c
+++ b/core/dp/htt/htt_rx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -1211,7 +1211,7 @@ static int
htt_rx_amsdu_pop_ll(htt_pdev_handle pdev,
qdf_nbuf_t rx_ind_msg,
qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
- uint32_t *msdu_count)
+ qdf_nbuf_t *head_mon_msdu, uint32_t *msdu_count)
{
int msdu_len, msdu_chaining = 0;
qdf_nbuf_t msdu;
@@ -1237,6 +1237,7 @@ htt_rx_amsdu_pop_ll(htt_pdev_handle pdev,
+ HTT_RX_PPDU_DESC_SIZE32));
}
msdu = *head_msdu = htt_rx_netbuf_pop(pdev);
+ *head_mon_msdu = NULL;
while (1) {
int last_msdu, msdu_len_invalid, msdu_chained;
int byte_offset;
@@ -1496,6 +1497,7 @@ htt_rx_amsdu_pop_hl(
qdf_nbuf_t rx_ind_msg,
qdf_nbuf_t *head_msdu,
qdf_nbuf_t *tail_msdu,
+ qdf_nbuf_t *head_mon_msdu,
uint32_t *msdu_count)
{
pdev->rx_desc_size_hl =
@@ -1513,6 +1515,7 @@ htt_rx_amsdu_pop_hl(
(qdf_nbuf_data(rx_ind_msg)));
qdf_nbuf_set_next(*tail_msdu, NULL);
+ *head_mon_msdu = NULL;
return 0;
}
@@ -1522,6 +1525,7 @@ htt_rx_frag_pop_hl(
qdf_nbuf_t frag_msg,
qdf_nbuf_t *head_msdu,
qdf_nbuf_t *tail_msdu,
+ qdf_nbuf_t *mon_head_msdu,
uint32_t *msdu_count)
{
qdf_nbuf_pull_head(frag_msg, HTT_RX_FRAG_IND_BYTES);
@@ -1536,6 +1540,7 @@ htt_rx_frag_pop_hl(
*head_msdu = *tail_msdu = frag_msg;
qdf_nbuf_set_next(*tail_msdu, NULL);
+ *mon_head_msdu = NULL;
return 0;
}
@@ -2099,17 +2104,18 @@ static uint8_t htt_mon_rx_get_rtap_flags(struct htt_host_rx_desc_base *rx_desc)
/**
* 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
+ * @desc: Pointer to struct htt_host_rx_desc_base
* @rx_status: Return variable updated with rx_status
*
* Return: None
*/
-static 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)
+void htt_rx_mon_get_rx_status(htt_pdev_handle pdev,
+ void *desc,
+ struct mon_rx_status *rx_status)
{
uint16_t channel_flags = 0;
struct mon_channel *ch_info = &pdev->mon_ch_info;
+ struct htt_host_rx_desc_base *rx_desc = desc;
rx_status->tsft = (u_int64_t)TSF_TIMESTAMP(rx_desc);
rx_status->chan_freq = ch_info->ch_freq;
@@ -2151,6 +2157,7 @@ static 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 *head_mon_msdu,
uint32_t *replenish_cnt)
{
qdf_nbuf_t msdu, next, prev = NULL;
@@ -2186,6 +2193,7 @@ static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES);
paddr = htt_rx_in_ord_paddr_get(msg_word);
msdu = htt_rx_in_order_netbuf_pop(pdev, paddr);
+ *head_mon_msdu = NULL;
if (qdf_unlikely(NULL == msdu)) {
qdf_print("%s: netbuf pop failed!\n", __func__);
@@ -2378,9 +2386,11 @@ static int
htt_rx_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 *head_mon_msdu,
uint32_t *replenish_cnt)
{
qdf_nbuf_t msdu, next, prev = NULL;
+ qdf_nbuf_t mon_prev = NULL;
uint8_t *rx_ind_data;
uint32_t *msg_word;
uint32_t rx_ctx_id;
@@ -2393,6 +2403,7 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
qdf_mem_info_t mem_map_table = {0};
int ret = 1;
bool ipa_smmu = false;
+ qdf_nbuf_t mon_msdu = NULL;
HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0);
@@ -2428,6 +2439,8 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
paddr = htt_rx_in_ord_paddr_get(msg_word);
(*head_msdu) = msdu = htt_rx_in_order_netbuf_pop(pdev, paddr);
+ (*head_mon_msdu) = NULL;
+
if (qdf_unlikely(NULL == msdu)) {
qdf_print("%s: netbuf pop failed!\n", __func__);
*tail_msdu = NULL;
@@ -2492,6 +2505,26 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
msdu_count--;
+ if (cds_get_pktcap_mode_enable() &&
+ (ol_cfg_pktcapture_mode(pdev->ctrl_pdev) &
+ PKT_CAPTURE_MODE_DATA_ONLY) &&
+ pdev->txrx_pdev->mon_cb && !frag_ind) {
+ mon_msdu = qdf_nbuf_copy(msdu);
+ if (mon_msdu) {
+ qdf_nbuf_push_head(mon_msdu,
+ HTT_RX_STD_DESC_RESERVATION);
+ qdf_nbuf_set_next(mon_msdu, NULL);
+
+ if (!(*head_mon_msdu)) {
+ *head_mon_msdu = mon_msdu;
+ mon_prev = mon_msdu;
+ } else {
+ qdf_nbuf_set_next(mon_prev, mon_msdu);
+ mon_prev = mon_msdu;
+ }
+ }
+ }
+
/* calling callback function for packet logging */
if (pdev->rx_pkt_dump_cb) {
if (qdf_unlikely(RX_DESC_MIC_ERR_IS_SET &&
@@ -2972,7 +3005,7 @@ int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc)
int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
qdf_nbuf_t rx_ind_msg,
qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
- uint32_t *msdu_count);
+ qdf_nbuf_t *head_mon_msdu, uint32_t *msdu_count);
/*
* htt_rx_frag_pop -
@@ -2982,7 +3015,7 @@ int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
int (*htt_rx_frag_pop)(htt_pdev_handle pdev,
qdf_nbuf_t rx_ind_msg,
qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
- uint32_t *msdu_count);
+ qdf_nbuf_t *head_mon_msdu, uint32_t *msdu_count);
int
(*htt_rx_offload_msdu_cnt)(
diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c
index 53a5636dc1bf..ff5c6e281b68 100644
--- a/core/dp/htt/htt_t2h.c
+++ b/core/dp/htt/htt_t2h.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -1121,6 +1121,18 @@ void htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus,
break;
}
+ case HTT_T2H_MSG_TYPE_TX_OFFLOAD_DELIVER_IND:
+ {
+ if (qdf_unlikely(
+ !pdev->cfg.is_full_reorder_offload)) {
+ break;
+ }
+
+ ol_tx_offload_deliver_indication_handler(
+ pdev->txrx_pdev, msg_word);
+ break;
+ }
+
case HTT_T2H_MSG_TYPE_RX_PN_IND:
{
u_int16_t peer_id;
diff --git a/core/dp/ol/inc/ol_cfg.h b/core/dp/ol/inc/ol_cfg.h
index a99794dc5ca7..907b0455cdd0 100644
--- a/core/dp/ol/inc/ol_cfg.h
+++ b/core/dp/ol/inc/ol_cfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -87,6 +87,8 @@ struct txrx_pdev_cfg_t {
bool flow_steering_enabled;
struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM];
+
+ uint8_t pktcapture_mode;
};
/**
@@ -603,4 +605,8 @@ uint16_t ol_cfg_get_send_limit(ol_pdev_handle pdev, int ac);
int ol_cfg_get_credit_reserve(ol_pdev_handle pdev, int ac);
int ol_cfg_get_discard_weight(ol_pdev_handle pdev, int ac);
+
+int ol_cfg_pktcapture_mode(ol_pdev_handle pdev);
+
+void ol_cfg_set_pktcapture_mode(ol_pdev_handle pdev, int val);
#endif /* _OL_CFG__H_ */
diff --git a/core/dp/ol/inc/ol_htt_api.h b/core/dp/ol/inc/ol_htt_api.h
index 11edcdb1170c..56f3f92c8fb2 100644
--- a/core/dp/ol/inc/ol_htt_api.h
+++ b/core/dp/ol/inc/ol_htt_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -361,6 +361,10 @@ static inline void htt_ipa_uc_detach(struct htt_pdev_t *pdev)
void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch);
+void htt_rx_mon_get_rx_status(htt_pdev_handle pdev,
+ void *rx_desc,
+ struct mon_rx_status *rx_status);
+
void ol_htt_mon_note_chan(ol_txrx_pdev_handle pdev, int mon_ch);
#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
diff --git a/core/dp/ol/inc/ol_htt_rx_api.h b/core/dp/ol/inc/ol_htt_rx_api.h
index d67d70285c93..e6435f5cc7aa 100644
--- a/core/dp/ol/inc/ol_htt_rx_api.h
+++ b/core/dp/ol/inc/ol_htt_rx_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -647,13 +647,13 @@ extern int
(*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
qdf_nbuf_t rx_ind_msg,
qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
- uint32_t *msdu_count);
+ qdf_nbuf_t *head_mon_msdu, uint32_t *msdu_count);
extern int
(*htt_rx_frag_pop)(htt_pdev_handle pdev,
qdf_nbuf_t rx_ind_msg,
qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
- uint32_t *msdu_count);
+ qdf_nbuf_t *head_mon_msdu, uint32_t *msdu_count);
/**
* @brief Return the maximum number of available msdus currently
diff --git a/core/dp/ol/inc/ol_txrx_htt_api.h b/core/dp/ol/inc/ol_txrx_htt_api.h
index 3a9ee439c8e3..0e477bee7af3 100644
--- a/core/dp/ol/inc/ol_txrx_htt_api.h
+++ b/core/dp/ol/inc/ol_txrx_htt_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -147,6 +147,10 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
int num_msdus,
enum htt_tx_status status, void *msg_word);
+void
+ol_tx_offload_deliver_indication_handler(ol_txrx_pdev_handle,
+ void *msg);
+
void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits);
struct rate_report_t {
diff --git a/core/dp/ol/inc/ol_txrx_osif_api.h b/core/dp/ol/inc/ol_txrx_osif_api.h
index eea3d384d437..d2fe056a63d2 100644
--- a/core/dp/ol/inc/ol_txrx_osif_api.h
+++ b/core/dp/ol/inc/ol_txrx_osif_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -76,6 +76,23 @@ qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle data_vdev,
void ol_rx_data_process(struct ol_txrx_peer_t *peer,
qdf_nbuf_t rx_buf_list);
+/**
+ * ol_txrx_mon_data_process(): process data tx and rx packets
+ * for pkt capture mode. (normal tx/rx + offloaded tx/rx)
+ * @vdev_id: vdev id for which packet is captured
+ * @mon_buf_list: netbuf list
+ * @type: data process type
+ * @tid: tid number
+ * @status: Tx status
+ * @pktformat: Frame format
+ *
+ * Return: none
+ */
+void ol_txrx_mon_data_process(uint8_t vdev_id,
+ qdf_nbuf_t mon_buf_list,
+ enum mon_data_process_type type,
+ uint8_t tid, uint8_t status, bool pktformat);
+
void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer,
bool drop);
/**
diff --git a/core/dp/txrx/ol_cfg.c b/core/dp/txrx/ol_cfg.c
index 15cded77f702..e97f7f2f625c 100644
--- a/core/dp/txrx/ol_cfg.c
+++ b/core/dp/txrx/ol_cfg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -562,3 +562,36 @@ int ol_cfg_get_discard_weight(ol_pdev_handle pdev, int ac)
else
return 0;
}
+
+/**
+ * ol_cfg_pktcapture_mode() - return pktcapture mode
+ * @pdev : handle to the physical device
+ *
+ * Return: 0 - disable
+ * 1 - Mgmt packets
+ * 2 - Data packets
+ * 3 - Both Mgmt and Data packets
+ */
+int ol_cfg_pktcapture_mode(ol_pdev_handle pdev)
+{
+ struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev;
+
+ return cfg->pktcapture_mode;
+}
+
+/**
+ * ol_cfg_set_pktcapture_mode() - set pktcapture mode
+ * @pdev : handle to the physical device
+ * @val : 0 - disable
+ * 1 - Mgmt packets
+ * 2 - Data packets
+ * 3 - Both Mgmt and Data packets
+ *
+ * Return: none
+ */
+void ol_cfg_set_pktcapture_mode(ol_pdev_handle pdev, int val)
+{
+ struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev;
+
+ cfg->pktcapture_mode = val;
+}
diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c
index 92bf922e81e3..17f3696b2ab3 100644
--- a/core/dp/txrx/ol_rx.c
+++ b/core/dp/txrx/ol_rx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -596,6 +596,7 @@ ol_rx_indication_handler(ol_txrx_pdev_handle pdev,
rx_ind_msg,
&head_msdu,
&tail_msdu,
+ NULL,
&msdu_count);
#ifdef HTT_RX_RESTORE
if (htt_pdev->rx_ring.rx_reset) {
@@ -654,7 +655,7 @@ ol_rx_indication_handler(ol_txrx_pdev_handle pdev,
for (i = 0; i < num_mpdus; i++) {
/* pull the MPDU's MSDUs off the buffer queue */
htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &msdu,
- &tail_msdu, &msdu_count);
+ &tail_msdu, NULL, &msdu_count);
#ifdef HTT_RX_RESTORE
if (htt_pdev->rx_ring.rx_reset) {
ol_rx_trigger_restore(htt_pdev, msdu,
@@ -1465,7 +1466,7 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
struct ol_txrx_peer_t *peer = NULL;
htt_pdev_handle htt_pdev = NULL;
int status;
- qdf_nbuf_t head_msdu = NULL, tail_msdu = NULL;
+ qdf_nbuf_t head_msdu = NULL, tail_msdu = NULL, head_mon_msdu = NULL;
uint8_t *rx_ind_data;
uint32_t *msg_word;
uint32_t msdu_count;
@@ -1473,6 +1474,9 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
uint8_t pktlog_bit;
#endif
uint32_t filled = 0;
+ uint8_t vdev_id;
+ bool is_pkt_capture_flow_id = false;
+
if (tid >= OL_TXRX_NUM_EXT_TIDS) {
ol_txrx_err("%s: invalid tid, %u\n", __FUNCTION__, tid);
WARN_ON(1);
@@ -1504,6 +1508,11 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
msg_word = (uint32_t *)rx_ind_data;
/* Get the total number of MSDUs */
msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1));
+ if (cds_get_pktcap_mode_enable())
+ /* Get the flow id to check if it is for offloaded data */
+ is_pkt_capture_flow_id =
+ HTT_RX_IN_ORD_PADDR_IND_PKT_CAPTURE_MODE_IS_MONITOR_SET
+ (*(msg_word + 1));
ol_rx_ind_record_event(msdu_count, OL_RX_INDICATION_POP_START);
@@ -1513,7 +1522,7 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
* corresponding rx MSDU network buffer.
*/
status = htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &head_msdu,
- &tail_msdu, &msdu_count);
+ &tail_msdu, &head_mon_msdu, &msdu_count);
ol_rx_ind_record_event(status, OL_RX_INDICATION_POP_END);
if (qdf_unlikely(0 == status)) {
@@ -1531,6 +1540,12 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
if (!head_msdu) {
ol_txrx_dbg("No packet to send to HDD");
+ while (head_mon_msdu) {
+ qdf_nbuf_t msdu = head_mon_msdu;
+
+ head_mon_msdu = qdf_nbuf_next(head_mon_msdu);
+ htt_rx_desc_frame_free(htt_pdev, msdu);
+ }
return;
}
@@ -1549,6 +1564,9 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
*/
if (peer) {
vdev = peer->vdev;
+ vdev_id = vdev->vdev_id;
+ } else if (is_pkt_capture_flow_id) {
+ vdev_id = HTT_INVALID_VDEV;
} else {
ol_txrx_dbg(
"%s: Couldn't find peer from ID 0x%x\n",
@@ -1564,6 +1582,23 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
return;
}
+ if (head_mon_msdu)
+ ol_txrx_mon_data_process(
+ vdev_id, head_mon_msdu,
+ PROCESS_TYPE_DATA_RX, 0, 0,
+ TXRX_PKT_FORMAT_8023);
+
+ if (is_pkt_capture_flow_id) {
+ /* The pkt is for offloaded data, drop here */
+ while (head_msdu) {
+ qdf_nbuf_t msdu = head_msdu;
+
+ head_msdu = qdf_nbuf_next(head_msdu);
+ htt_rx_desc_frame_free(htt_pdev, msdu);
+ }
+ return;
+ }
+
peer->rx_opt_proc(vdev, peer, tid, head_msdu);
}
#endif
diff --git a/core/dp/txrx/ol_rx_defrag.c b/core/dp/txrx/ol_rx_defrag.c
index a58047242ed4..4373999b4467 100644
--- a/core/dp/txrx/ol_rx_defrag.c
+++ b/core/dp/txrx/ol_rx_defrag.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -59,6 +59,8 @@
#include <ol_rx_defrag.h>
#include <enet.h>
#include <qdf_time.h> /* qdf_system_time */
+#include <htt_internal.h>
+
#define DEFRAG_IEEE80211_ADDR_EQ(a1, a2) \
(!qdf_mem_cmp(a1, a2, IEEE80211_ADDR_LEN))
@@ -371,7 +373,7 @@ ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev,
pktlog_bit =
(htt_rx_amsdu_rx_in_order_get_pktlog(rx_frag_ind_msg) == 0x01);
ret = htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu,
- &tail_msdu, &msdu_count);
+ &tail_msdu, NULL, &msdu_count);
/* Return if msdu pop fails from rx hash table, as recovery
* is triggered and we exit gracefully.
*/
@@ -799,6 +801,41 @@ ol_rx_defrag(ol_txrx_pdev_handle pdev,
if (ol_cfg_frame_type(pdev->ctrl_pdev) == wlan_frm_fmt_802_3)
ol_rx_defrag_nwifi_to_8023(pdev, msdu);
+ if (cds_get_pktcap_mode_enable() &&
+ (ol_cfg_pktcapture_mode(pdev->ctrl_pdev) &
+ PKT_CAPTURE_MODE_DATA_ONLY) &&
+ pdev->mon_cb) {
+ qdf_nbuf_t tmp_msdu, tmp_msdu_next;
+ qdf_nbuf_t mon_prev = NULL;
+ qdf_nbuf_t mon_msdu = NULL;
+ qdf_nbuf_t head_mon_msdu = NULL;
+
+ tmp_msdu = msdu;
+ while (tmp_msdu) {
+ tmp_msdu_next = qdf_nbuf_next(tmp_msdu);
+ mon_msdu = qdf_nbuf_copy(tmp_msdu);
+ if (mon_msdu) {
+ qdf_nbuf_push_head(mon_msdu,
+ HTT_RX_STD_DESC_RESERVATION);
+ qdf_nbuf_set_next(mon_msdu, NULL);
+
+ if (!(head_mon_msdu)) {
+ head_mon_msdu = mon_msdu;
+ mon_prev = mon_msdu;
+ } else {
+ qdf_nbuf_set_next(mon_prev, mon_msdu);
+ mon_prev = mon_msdu;
+ }
+ }
+ tmp_msdu = tmp_msdu_next;
+ }
+ if (head_mon_msdu)
+ ol_txrx_mon_data_process(
+ vdev->vdev_id, head_mon_msdu,
+ PROCESS_TYPE_DATA_RX, 0, 0,
+ TXRX_PKT_FORMAT_8023);
+ }
+
ol_rx_fwd_check(vdev, peer, tid, msdu);
}
diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c
index 71fcda87da90..da4ab21e38c1 100644
--- a/core/dp/txrx/ol_tx_send.c
+++ b/core/dp/txrx/ol_tx_send.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -53,6 +53,7 @@
#include <ol_tx_queue.h>
#include <ol_txrx.h>
#include <pktlog_ac_fmt.h>
+#include <utils_api.h>
#ifdef TX_CREDIT_RECLAIM_SUPPORT
@@ -690,6 +691,69 @@ static void ol_tx_update_arp_stats(struct ol_tx_desc_t *tx_desc,
}
}
+/**
+ * ol_tx_get_txcomplete_payloads(): extract Tx data hdr from Tx completion
+ * for pkt capture mode
+ * @msg_word: Tx completion htt msg
+ * @num_msdus: number of msdus
+ *
+ * Return: none
+ */
+static inline
+struct htt_tx_data_hdr_information *ol_tx_get_txcomplete_payloads(
+ uint32_t *msg_word, int num_msdus)
+{
+ int offset_dwords;
+ u_int32_t has_tx_tsf;
+ u_int32_t has_retry;
+ u_int32_t has_ack_rssi;
+ u_int32_t has_tx_tsf64;
+ u_int32_t has_tx_compl_payload;
+ struct htt_tx_compl_ind_append_retries *retry_list = NULL;
+ struct htt_tx_data_hdr_information *txcomplete_payload_list = NULL;
+
+ has_tx_compl_payload = HTT_TX_COMPL_IND_APPEND4_GET(*msg_word);
+ if (num_msdus <= 0 || !has_tx_compl_payload)
+ return NULL;
+
+ offset_dwords = 1 + ((num_msdus + 1) >> 1);
+
+ has_retry = HTT_TX_COMPL_IND_APPEND_GET(*msg_word);
+ if (has_retry) {
+ int retry_index = 0;
+ int width_for_each_retry =
+ (sizeof(struct htt_tx_compl_ind_append_retries) +
+ 3) >> 2;
+
+ retry_list = (struct htt_tx_compl_ind_append_retries *)
+ (msg_word + offset_dwords);
+ while (retry_list) {
+ if (retry_list[retry_index++].flag == 0)
+ break;
+ }
+ offset_dwords += retry_index * width_for_each_retry;
+ }
+ has_tx_tsf = HTT_TX_COMPL_IND_APPEND1_GET(*msg_word);
+ if (has_tx_tsf) {
+ int width_for_each_tsf =
+ (sizeof(struct htt_tx_compl_ind_append_tx_tstamp)) >> 2;
+ offset_dwords += width_for_each_tsf * num_msdus;
+ }
+
+ has_ack_rssi = HTT_TX_COMPL_IND_APPEND2_GET(*msg_word);
+ if (has_ack_rssi)
+ offset_dwords += ((num_msdus + 1) >> 1);
+
+ has_tx_tsf64 = HTT_TX_COMPL_IND_APPEND3_GET(*msg_word);
+ if (has_tx_tsf64)
+ offset_dwords += (num_msdus << 1);
+
+ txcomplete_payload_list = (struct htt_tx_data_hdr_information *)
+ (msg_word + offset_dwords);
+
+ return txcomplete_payload_list;
+}
+
#ifdef WLAN_FEATURE_TSF_PLUS
static inline struct htt_tx_compl_ind_append_tx_tstamp *ol_tx_get_txtstamps(
u_int32_t *msg_word, int num_msdus)
@@ -749,6 +813,181 @@ static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev,
}
#endif
+#define RESERVE_BYTES 100
+
+/**
+ * ol_tx_process_mon_tx_completion(): process tx packets for pkt capture mode
+ * @pdev: device handler
+ * @tx_desc: tx desc
+ * @payload: tx data header
+ * @tid: tid number
+ * @status: Tx status
+ *
+ * Return: none
+ */
+static inline void
+ol_tx_process_mon_tx_completion(
+ ol_txrx_pdev_handle pdev,
+ struct ol_tx_desc_t *tx_desc,
+ struct htt_tx_data_hdr_information *payload,
+ uint8_t tid, uint8_t status)
+{
+ qdf_nbuf_t netbuf;
+ int nbuf_len;
+ struct qdf_tso_seg_elem_t *tso_seg = NULL;
+
+ qdf_assert(tx_desc);
+
+ ol_tx_flow_pool_lock(tx_desc);
+ /*
+ * In cases when vdev has gone down and tx completion
+ * are received, leads to NULL vdev access.
+ * So, check for NULL before dereferencing it.
+ */
+ if (!tx_desc->vdev) {
+ ol_tx_flow_pool_unlock(tx_desc);
+ return;
+ }
+
+ ol_tx_flow_pool_unlock(tx_desc);
+
+ if (tx_desc->pkt_type == OL_TX_FRM_TSO) {
+ if (!tx_desc->tso_desc)
+ return;
+
+ tso_seg = tx_desc->tso_desc;
+ nbuf_len = tso_seg->seg.total_len;
+ } else {
+ int i, extra_frag_len = 0;
+
+ i = QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(tx_desc->netbuf);
+ if (i > 0)
+ extra_frag_len =
+ QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(tx_desc->netbuf);
+ nbuf_len = qdf_nbuf_len(tx_desc->netbuf) - extra_frag_len;
+ }
+
+ netbuf = qdf_nbuf_alloc(NULL,
+ roundup(nbuf_len + RESERVE_BYTES, 4),
+ RESERVE_BYTES, 4, false);
+ if (!netbuf)
+ return;
+
+ qdf_nbuf_put_tail(netbuf, nbuf_len);
+
+ if (tx_desc->pkt_type == OL_TX_FRM_TSO) {
+ uint8_t frag_cnt, num_frags = 0;
+ int frag_len = 0;
+ uint32_t tcp_seq_num;
+ uint16_t ip_len;
+
+ qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex);
+
+ if (tso_seg->seg.num_frags > 0)
+ num_frags = tso_seg->seg.num_frags - 1;
+
+ /*Num of frags in a tso seg cannot be less than 2 */
+ if (num_frags < 1) {
+ qdf_print("ERROR: num of frags in tso segment is %d\n",
+ (num_frags + 1));
+ qdf_nbuf_free(netbuf);
+ qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
+ return;
+ }
+
+ tcp_seq_num = tso_seg->seg.tso_flags.tcp_seq_num;
+ tcp_seq_num = ani_cpu_to_be32(tcp_seq_num);
+
+ ip_len = tso_seg->seg.tso_flags.ip_len;
+ ip_len = ani_cpu_to_be16(ip_len);
+
+ for (frag_cnt = 0; frag_cnt < num_frags; frag_cnt++) {
+ qdf_mem_copy(qdf_nbuf_data(netbuf) + frag_len,
+ tso_seg->seg.tso_frags[frag_cnt].vaddr,
+ tso_seg->seg.tso_frags[frag_cnt].length);
+ frag_len += tso_seg->seg.tso_frags[frag_cnt].length;
+ }
+
+ qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
+
+ qdf_mem_copy((qdf_nbuf_data(netbuf) + IPV4_PKT_LEN_OFFSET),
+ &ip_len, sizeof(ip_len));
+ qdf_mem_copy((qdf_nbuf_data(netbuf) + IPV4_TCP_SEQ_NUM_OFFSET),
+ &tcp_seq_num, sizeof(tcp_seq_num));
+ } else {
+ qdf_mem_copy(qdf_nbuf_data(netbuf),
+ qdf_nbuf_data(tx_desc->netbuf),
+ nbuf_len);
+ }
+
+ qdf_nbuf_push_head(
+ netbuf,
+ sizeof(struct htt_tx_data_hdr_information));
+ qdf_mem_copy(qdf_nbuf_data(netbuf), payload,
+ sizeof(struct htt_tx_data_hdr_information));
+
+ ol_txrx_mon_data_process(tx_desc->vdev_id,
+ netbuf, PROCESS_TYPE_DATA_TX_COMPL,
+ tid, status, TXRX_PKT_FORMAT_8023);
+}
+
+void
+ol_tx_offload_deliver_indication_handler(ol_txrx_pdev_handle pdev, void *msg)
+{
+ int nbuf_len;
+ qdf_nbuf_t netbuf;
+ uint8_t status;
+ uint8_t tid = 0;
+ bool pkt_format;
+ u_int32_t *msg_word = (u_int32_t *)msg;
+ u_int8_t *buf = (u_int8_t *)msg;
+ struct htt_tx_data_hdr_information *txhdr;
+ struct htt_tx_offload_deliver_ind_hdr_t *offload_deliver_msg;
+ bool is_pkt_during_roam = false;
+ uint8_t vdev_id;
+
+ offload_deliver_msg = (struct htt_tx_offload_deliver_ind_hdr_t *)msg;
+
+ txhdr = (struct htt_tx_data_hdr_information *)
+ (msg_word + 1);
+
+ vdev_id = offload_deliver_msg->vdev_id;
+ nbuf_len = offload_deliver_msg->tx_mpdu_bytes;
+
+ netbuf = qdf_nbuf_alloc(NULL,
+ roundup(nbuf_len + RESERVE_BYTES, 4),
+ RESERVE_BYTES, 4, false);
+
+ if (!netbuf)
+ return;
+
+ qdf_nbuf_put_tail(netbuf, nbuf_len);
+
+ qdf_mem_copy(qdf_nbuf_data(netbuf),
+ buf + sizeof(struct htt_tx_offload_deliver_ind_hdr_t),
+ nbuf_len);
+
+ qdf_nbuf_push_head(
+ netbuf,
+ sizeof(struct htt_tx_data_hdr_information));
+
+ qdf_mem_copy(qdf_nbuf_data(netbuf), txhdr,
+ sizeof(struct htt_tx_data_hdr_information));
+
+ status = offload_deliver_msg->status;
+ pkt_format = offload_deliver_msg->format;
+ tid = offload_deliver_msg->tid_num;
+ /* Is FW sends offload data during roaming */
+ is_pkt_during_roam = (offload_deliver_msg->reserved_2 ? true : false);
+ if (is_pkt_during_roam)
+ vdev_id = HTT_INVALID_VDEV;
+
+ ol_txrx_mon_data_process(
+ vdev_id,
+ netbuf, PROCESS_TYPE_DATA_TX,
+ tid, status, pkt_format);
+}
+
/**
* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of
* ol_tx_completion_handler().
@@ -768,8 +1007,10 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
tp_ol_packetdump_cb packetdump_cb;
uint32_t is_tx_desc_freed = 0;
struct htt_tx_compl_ind_append_tx_tstamp *txtstamp_list = NULL;
+ struct htt_tx_data_hdr_information *txcomplete_payload_list = NULL;
u_int32_t *msg_word = (u_int32_t *)msg;
u_int16_t *desc_ids = (u_int16_t *)(msg_word + 1);
+ uint8_t tid;
union ol_tx_desc_list_elem_t *lcl_freelist = NULL;
union ol_tx_desc_list_elem_t *tx_desc_last = NULL;
@@ -777,10 +1018,18 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
TAILQ_INIT(&tx_descs);
+ tid = HTT_TX_COMPL_IND_TID_GET(*msg_word);
ol_tx_delay_compute(pdev, status, desc_ids, num_msdus);
if (status == htt_tx_status_ok)
txtstamp_list = ol_tx_get_txtstamps(msg_word, num_msdus);
+ if (cds_get_pktcap_mode_enable() &&
+ (ol_cfg_pktcapture_mode(pdev->ctrl_pdev) &
+ PKT_CAPTURE_MODE_DATA_ONLY) &&
+ pdev->mon_cb)
+ txcomplete_payload_list =
+ ol_tx_get_txcomplete_payloads(msg_word, num_msdus);
+
for (i = 0; i < num_msdus; i++) {
tx_desc_id = desc_ids[i];
if (tx_desc_id >= pdev->tx_desc.pool_size) {
@@ -794,10 +1043,15 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
tx_desc->status = status;
netbuf = tx_desc->netbuf;
+ if (txcomplete_payload_list)
+ ol_tx_process_mon_tx_completion(
+ pdev,
+ tx_desc,
+ &txcomplete_payload_list[i], tid, status);
+
if (txtstamp_list)
ol_tx_timestamp(pdev, netbuf,
- (u_int64_t)txtstamp_list->timestamp[i]
- );
+ (u_int64_t)txtstamp_list->timestamp[i]);
QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE);
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index 630d27168381..53c9e12d0284 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -2446,6 +2446,48 @@ ol_txrx_vdev_attach(ol_txrx_pdev_handle pdev,
}
/**
+ * ol_txrx_mon_cb_deregister() - Deregister pkt capture mode callback
+ * @void:
+ *
+ * Return: None
+ */
+void ol_txrx_mon_cb_deregister(void)
+{
+ ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+
+ if (qdf_unlikely(!pdev)) {
+ qdf_print("%s: pdev is NULL!\n", __func__);
+ qdf_assert(0);
+ return;
+ }
+
+ pdev->mon_osif_dev = NULL;
+ pdev->mon_cb = NULL;
+}
+
+/**
+ * ol_txrx_mon_cb_register() - Register pkt capture mode callback
+ * @osif_vdev: the virtual device's OS shim object
+ * @mon_cb: callback to register
+ *
+ * Return: None
+ */
+void ol_txrx_mon_cb_register(void *osif_vdev,
+ ol_txrx_mon_callback_fp mon_cb)
+{
+ ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+
+ if (qdf_unlikely(!pdev)) {
+ qdf_print("%s: pdev is NULL!\n", __func__);
+ qdf_assert(0);
+ return;
+ }
+
+ pdev->mon_osif_dev = osif_vdev;
+ pdev->mon_cb = mon_cb;
+}
+
+/**
*ol_txrx_vdev_register - Link a vdev's data object with the
* matching OS shim vdev object.
*
@@ -3772,8 +3814,11 @@ ol_txrx_clear_peer_internal(struct ol_txrx_peer_t *peer)
{
p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
/* Drop pending Rx frames in CDS */
- if (sched_ctx)
+ if (sched_ctx) {
cds_drop_rxpkt_by_staid(sched_ctx, peer->local_id);
+ if (cds_get_pktcap_mode_enable())
+ cds_drop_monpkt(sched_ctx);
+ }
/* Purge the cached rx frame queue */
ol_txrx_flush_rx_frames(peer, 1);
@@ -5423,6 +5468,783 @@ static inline int ol_txrx_drop_nbuf_list(qdf_nbuf_t buf_list)
}
/**
+ * ol_txrx_mon_mgmt_cb(): callback to process management packets
+ * for pkt capture mode
+ * @ppdev: device handler
+ * @nbuf_list: netbuf list
+ * @vdev_id: vdev id for which packet is captured
+ * @tid: tid number
+ * @status: Tx status
+ * @pktformat: Frame format
+ *
+ * Return: none
+ */
+static void
+ol_txrx_mon_mgmt_cb(void *ppdev, void *nbuf_list, uint8_t vdev_id,
+ uint8_t tid, uint8_t status, bool pkt_format)
+{
+ struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
+ uint8_t drop_count;
+ void *mon_osif_dev;
+ qdf_nbuf_t msdu, next_buf;
+ ol_txrx_mon_callback_fp data_rx = NULL;
+ void *cds_ctx = cds_get_global_context();
+
+ if (qdf_unlikely(!cds_ctx) || qdf_unlikely(!pdev))
+ goto free_buf;
+
+ data_rx = pdev->mon_cb;
+ mon_osif_dev = pdev->mon_osif_dev;
+
+ if (!data_rx || !mon_osif_dev)
+ goto free_buf;
+
+ msdu = nbuf_list;
+ while (msdu) {
+ next_buf = qdf_nbuf_queue_next(msdu);
+ qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */
+ if (QDF_STATUS_SUCCESS != data_rx(mon_osif_dev, msdu)) {
+ ol_txrx_err("Frame Rx to HDD failed");
+ qdf_nbuf_free(msdu);
+ }
+ msdu = next_buf;
+ }
+
+ return;
+free_buf:
+ drop_count = ol_txrx_drop_nbuf_list(nbuf_list);
+ ol_txrx_dbg("%s:Dropped frames %u", __func__, drop_count);
+}
+
+/**
+ * ol_txrx_mon_mgmt_process(): process management packets for pkt capture mode
+ * @txrx_status: mon_rx_status to update radiotap header
+ * @nbuf: netbuf
+ * @status: Tx status
+ * @pktformat: Frame format
+ *
+ * Return: true if pkt is post to thread else false
+ */
+bool ol_txrx_mon_mgmt_process(struct mon_rx_status *txrx_status,
+ qdf_nbuf_t nbuf, uint8_t status)
+{
+ uint32_t headroom;
+ struct cds_ol_mon_pkt *pkt;
+ ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+ p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
+
+ if (unlikely(!sched_ctx))
+ return false;
+
+ if (!pdev) {
+ ol_txrx_err("pdev is NULL");
+ return false;
+ }
+
+ /*
+ * Calculate the headroom and adjust head to prepare radiotap header
+ */
+ headroom = qdf_nbuf_headroom(nbuf);
+ qdf_nbuf_push_head(nbuf, headroom);
+ qdf_nbuf_update_radiotap(txrx_status, nbuf, headroom);
+
+ pkt = cds_alloc_ol_mon_pkt(sched_ctx);
+ if (!pkt)
+ return false;
+
+ pkt->callback = ol_txrx_mon_mgmt_cb;
+ pkt->context = (void *)pdev;
+ pkt->monpkt = (void *)nbuf;
+ pkt->vdev_id = HTT_INVALID_VDEV;
+ pkt->tid = HTT_INVALID_TID;
+ pkt->status = status;
+ pkt->pkt_format = TXRX_PKT_FORMAT_80211;
+ cds_indicate_monpkt(sched_ctx, pkt);
+
+ return true;
+}
+
+/**
+ * ol_txrx_convert8023to80311() - convert 802.3 packet to 803.11
+ * format from rx desc
+ * @bssid: bssid
+ * @msdu: netbuf
+ * @desc: rx desc
+ *
+ * Return: none
+ */
+static QDF_STATUS
+ol_txrx_convert8023to80311(uint8_t *bssid,
+ qdf_nbuf_t msdu, void *desc)
+{
+ struct ethernet_hdr_t *eth_hdr;
+ struct llc_snap_hdr_t *llc_hdr;
+ struct ieee80211_frame *wh;
+ uint8_t hdsize, new_hdsize;
+ struct ieee80211_qoscntl *qos_cntl;
+ uint16_t seq_no;
+ uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) +
+ sizeof(struct llc_snap_hdr_t)];
+ const uint8_t ethernet_II_llc_snap_header_prefix[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ uint16_t ether_type;
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+ struct htt_host_rx_desc_base *rx_desc = desc;
+
+ eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu);
+ hdsize = sizeof(struct ethernet_hdr_t);
+ wh = (struct ieee80211_frame *)localbuf;
+
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
+ *(uint16_t *)wh->i_dur = 0;
+
+ new_hdsize = 0;
+
+ /* DA , BSSID , SA */
+ qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr,
+ IEEE80211_ADDR_LEN);
+ qdf_mem_copy(wh->i_addr2, bssid,
+ IEEE80211_ADDR_LEN);
+ qdf_mem_copy(wh->i_addr3, eth_hdr->src_addr,
+ IEEE80211_ADDR_LEN);
+
+ wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
+
+ if (rx_desc->attention.more_data)
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+
+ if (rx_desc->attention.power_mgmt)
+ wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
+
+ if (rx_desc->attention.fragment)
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
+
+ if (rx_desc->attention.order)
+ wh->i_fc[1] |= IEEE80211_FC1_ORDER;
+
+ if (rx_desc->mpdu_start.retry)
+ wh->i_fc[1] |= IEEE80211_FC1_RETRY;
+
+ seq_no = rx_desc->mpdu_start.seq_num;
+ seq_no = (seq_no << IEEE80211_SEQ_SEQ_SHIFT) & IEEE80211_SEQ_SEQ_MASK;
+ qdf_mem_copy(wh->i_seq, &seq_no, sizeof(seq_no));
+
+ new_hdsize = sizeof(struct ieee80211_frame);
+
+ if (rx_desc->attention.non_qos == 0) {
+ qos_cntl =
+ (struct ieee80211_qoscntl *)(localbuf + new_hdsize);
+ qos_cntl->i_qos[0] =
+ (rx_desc->mpdu_start.tid & IEEE80211_QOS_TID);
+ wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
+
+ qos_cntl->i_qos[1] = 0;
+ new_hdsize += sizeof(struct ieee80211_qoscntl);
+ }
+
+ /*
+ * Prepare llc Header
+ */
+ llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize);
+ ether_type = (eth_hdr->ethertype[0] << 8) |
+ (eth_hdr->ethertype[1]);
+ if (ether_type >= IEEE8023_MAX_LEN) {
+ qdf_mem_copy(llc_hdr,
+ ethernet_II_llc_snap_header_prefix,
+ sizeof
+ (ethernet_II_llc_snap_header_prefix));
+ if (ether_type == ETHERTYPE_AARP ||
+ ether_type == ETHERTYPE_IPX) {
+ llc_hdr->org_code[2] =
+ BTEP_SNAP_ORGCODE_2;
+ /* 0xf8; bridge tunnel header */
+ }
+ llc_hdr->ethertype[0] = eth_hdr->ethertype[0];
+ llc_hdr->ethertype[1] = eth_hdr->ethertype[1];
+ new_hdsize += sizeof(struct llc_snap_hdr_t);
+ }
+
+ /*
+ * Remove 802.3 Header by adjusting the head
+ */
+ qdf_nbuf_pull_head(msdu, hdsize);
+
+ /*
+ * Adjust the head and prepare 802.11 Header
+ */
+ qdf_nbuf_push_head(msdu, new_hdsize);
+ qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize);
+
+ return status;
+}
+
+#define SHORT_PREAMBLE 1
+#define LONG_PREAMBLE 0
+
+/**
+ * ol_txrx_get_tx_rate() - get tx rate for tx packet
+ * format from rx desc
+ * @preamble_type: preamble type
+ * @rate: rate code
+ * @preamble: preamble
+ *
+ * Return: rate
+ */
+static unsigned char ol_txrx_get_tx_rate(uint8_t preamble_type,
+ uint8_t rate,
+ uint8_t *preamble)
+{
+ char ret = 0x0;
+ *preamble = LONG_PREAMBLE;
+
+ if (preamble_type == 0) {
+ switch (rate) {
+ case 0x0:
+ ret = 0x60;
+ break;
+ case 0x1:
+ ret = 0x30;
+ break;
+ case 0x2:
+ ret = 0x18;
+ break;
+ case 0x3:
+ ret = 0x0c;
+ break;
+ case 0x4:
+ ret = 0x6c;
+ break;
+ case 0x5:
+ ret = 0x48;
+ break;
+ case 0x6:
+ ret = 0x24;
+ break;
+ case 0x7:
+ ret = 0x12;
+ break;
+ default:
+ break;
+ }
+ } else if (preamble_type == 1) {
+ switch (rate) {
+ case 0x0:
+ ret = 0x16;
+ *preamble = LONG_PREAMBLE;
+ case 0x1:
+ ret = 0xB;
+ *preamble = LONG_PREAMBLE;
+ break;
+ case 0x2:
+ ret = 0x4;
+ *preamble = LONG_PREAMBLE;
+ break;
+ case 0x3:
+ ret = 0x2;
+ *preamble = LONG_PREAMBLE;
+ break;
+ case 0x4:
+ ret = 0x16;
+ *preamble = SHORT_PREAMBLE;
+ break;
+ case 0x5:
+ ret = 0xB;
+ *preamble = SHORT_PREAMBLE;
+ break;
+ case 0x6:
+ ret = 0x4;
+ *preamble = SHORT_PREAMBLE;
+ break;
+ default:
+ break;
+ }
+ } else {
+ qdf_print("Invalid rate info\n");
+ }
+ return ret;
+}
+
+/**
+ * ol_txrx_get_phy_info(): get phy info for tx packets for pkt
+ * capture mode(normal tx + offloaded tx) to prepare radiotap header
+ * @mon_hdr: tx data header
+ * @tx_status: tx status to be updated with phy info
+ *
+ * Return: none
+ */
+static void ol_txrx_get_phy_info(struct ol_txrx_mon_hdr_elem_t *mon_hdr,
+ struct mon_rx_status *tx_status)
+{
+ uint8_t preamble = 0;
+ uint8_t preamble_type = mon_hdr->preamble;
+ uint8_t mcs = 0, bw = 0;
+ uint16_t vht_flags = 0, ht_flags = 0;
+
+ switch (preamble_type) {
+ case 0x0:
+ case 0x1:
+ /* legacy */
+ tx_status->rate = ol_txrx_get_tx_rate(preamble_type,
+ mon_hdr->rate,
+ &preamble);
+ break;
+ case 0x2:
+ ht_flags = 1;
+ bw = mon_hdr->bw;
+ if (mon_hdr->nss == 2)
+ mcs = 8 + mon_hdr->mcs;
+ else
+ mcs = mon_hdr->mcs;
+ break;
+ case 0x3:
+ vht_flags = 1;
+ bw = mon_hdr->bw;
+ mcs = mon_hdr->mcs;
+
+ /* fallthrough */
+ default:
+ break;
+ }
+
+ tx_status->mcs = mcs;
+ tx_status->bw = bw;
+ tx_status->nr_ant = mon_hdr->nss;
+ tx_status->is_stbc = mon_hdr->stbc;
+ tx_status->sgi = mon_hdr->sgi;
+ tx_status->ldpc = mon_hdr->ldpc;
+ tx_status->beamformed = mon_hdr->beamformed;
+ tx_status->vht_flag_values3[0] = mcs << 0x4 | (mon_hdr->nss + 1);
+ tx_status->ht_flags = ht_flags;
+ tx_status->vht_flags = vht_flags;
+ tx_status->rtap_flags |= ((preamble == 1) ? BIT(1) : 0);
+ if (bw == 0)
+ tx_status->vht_flag_values2 = 0;
+ else if (bw == 1)
+ tx_status->vht_flag_values2 = 1;
+ else if (bw == 2)
+ tx_status->vht_flag_values2 = 4;
+}
+
+/**
+ * ol_txrx_update_tx_status(): update tx status for tx packets for
+ * pkt capture mode(normal tx + offloaded tx) to prepare radiotap header
+ * @pdev: device handler
+ * @tx_status: tx status to be updated
+ * @mon_hdr: tx data header
+ *
+ * Return: none
+ */
+static void
+ol_txrx_update_tx_status(struct ol_txrx_pdev_t *pdev,
+ struct mon_rx_status *tx_status,
+ struct ol_txrx_mon_hdr_elem_t *mon_hdr)
+{
+ struct mon_channel *ch_info = &pdev->htt_pdev->mon_ch_info;
+ uint16_t channel_flags = 0;
+
+ tx_status->tsft = (u_int64_t)(mon_hdr->timestamp);
+ tx_status->chan_freq = ch_info->ch_freq;
+ tx_status->chan_num = ch_info->ch_num;
+
+ ol_txrx_get_phy_info(mon_hdr, tx_status);
+
+ if (mon_hdr->preamble == 0)
+ channel_flags |= IEEE80211_CHAN_OFDM;
+ else if (mon_hdr->preamble == 1)
+ channel_flags |= IEEE80211_CHAN_CCK;
+
+ channel_flags |=
+ (cds_chan_to_band(ch_info->ch_num) == CDS_BAND_2GHZ ?
+ IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
+
+ tx_status->chan_flags = channel_flags;
+ tx_status->ant_signal_db = mon_hdr->rssi_comb;
+}
+
+/**
+ * ol_txrx_mon_tx_data_cb(): callback to process data tx packets
+ * for pkt capture mode. (normal tx + offloaded tx)
+ * @ppdev: device handler
+ * @nbuf_list: netbuf list
+ * @vdev_id: vdev id for which packet is captured
+ * @tid: tid number
+ * @status: Tx status
+ * @pktformat: Frame format
+ *
+ * Return: none
+ */
+static void
+ol_txrx_mon_tx_data_cb(void *ppdev, void *nbuf_list, uint8_t vdev_id,
+ uint8_t tid, uint8_t status, bool pkt_format)
+{
+ struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
+ qdf_nbuf_t msdu, next_buf;
+ struct ol_txrx_peer_t *peer;
+ void *mon_osif_dev;
+ struct ol_txrx_vdev_t *vdev;
+ uint8_t drop_count;
+ uint8_t chan = 0;
+ struct htt_tx_data_hdr_information *cmpl_desc = NULL;
+ struct ol_txrx_mon_hdr_elem_t mon_hdr = {0};
+ struct ethernet_hdr_t *eth_hdr;
+ struct llc_snap_hdr_t *llc_hdr;
+ struct ieee80211_frame *wh;
+ uint8_t hdsize, new_hdsize;
+ struct ieee80211_qoscntl *qos_cntl;
+ uint16_t ether_type;
+ uint32_t headroom;
+ uint16_t seq_no, fc_ctrl;
+ uint8_t bssid[OL_TXRX_MAC_ADDR_LEN];
+ ol_txrx_mon_callback_fp data_rx = NULL;
+ struct mon_rx_status tx_status = {0};
+ uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) +
+ sizeof(struct llc_snap_hdr_t)];
+ const uint8_t ethernet_II_llc_snap_header_prefix[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ if (qdf_unlikely(!pdev))
+ goto free_buf;
+
+ if (vdev_id != HTT_INVALID_VDEV) {
+ vdev = (struct ol_txrx_vdev_t *)
+ ol_txrx_get_vdev_from_vdev_id(vdev_id);
+ if (!vdev)
+ goto free_buf;
+
+ qdf_spin_lock_bh(&pdev->peer_ref_mutex);
+ peer = TAILQ_FIRST(&vdev->peer_list);
+ qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
+ if (!peer)
+ goto free_buf;
+
+ qdf_spin_lock_bh(&peer->peer_info_lock);
+ qdf_mem_copy(bssid, &peer->mac_addr.raw, IEEE80211_ADDR_LEN);
+ qdf_spin_unlock_bh(&peer->peer_info_lock);
+ }
+
+ data_rx = pdev->mon_cb;
+ mon_osif_dev = pdev->mon_osif_dev;
+
+ if (!data_rx || !mon_osif_dev)
+ goto free_buf;
+
+ msdu = nbuf_list;
+ while (msdu) {
+ next_buf = qdf_nbuf_queue_next(msdu);
+ qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */
+
+ cmpl_desc = (struct htt_tx_data_hdr_information *)
+ (qdf_nbuf_data(msdu));
+
+ mon_hdr.timestamp = cmpl_desc->phy_timestamp_l32;
+ mon_hdr.preamble = cmpl_desc->preamble;
+ mon_hdr.mcs = cmpl_desc->mcs;
+ mon_hdr.bw = cmpl_desc->bw;
+ mon_hdr.nss = cmpl_desc->nss;
+ mon_hdr.rssi_comb = cmpl_desc->rssi;
+ mon_hdr.rate = cmpl_desc->rate;
+ mon_hdr.stbc = cmpl_desc->stbc;
+ mon_hdr.sgi = cmpl_desc->sgi;
+ mon_hdr.ldpc = cmpl_desc->ldpc;
+ mon_hdr.beamformed = cmpl_desc->beamformed;
+
+ qdf_nbuf_pull_head(
+ msdu,
+ sizeof(struct htt_tx_data_hdr_information));
+
+ if (pkt_format == TXRX_PKT_FORMAT_8023) {
+ eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu);
+ hdsize = sizeof(struct ethernet_hdr_t);
+ wh = (struct ieee80211_frame *)localbuf;
+
+ *(uint16_t *)wh->i_dur = 0;
+
+ new_hdsize = 0;
+
+ if (vdev_id == HTT_INVALID_VDEV)
+ qdf_mem_copy(bssid, eth_hdr->dest_addr,
+ IEEE80211_ADDR_LEN);
+
+ /* BSSID , SA , DA */
+ qdf_mem_copy(wh->i_addr1, bssid,
+ IEEE80211_ADDR_LEN);
+ qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr,
+ IEEE80211_ADDR_LEN);
+ qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr,
+ IEEE80211_ADDR_LEN);
+
+ seq_no = cmpl_desc->seqno;
+ seq_no = (seq_no << IEEE80211_SEQ_SEQ_SHIFT) &
+ IEEE80211_SEQ_SEQ_MASK;
+ fc_ctrl = cmpl_desc->framectrl;
+ qdf_mem_copy(wh->i_fc, &fc_ctrl, sizeof(fc_ctrl));
+ qdf_mem_copy(wh->i_seq, &seq_no, sizeof(seq_no));
+
+ wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+
+ new_hdsize = sizeof(struct ieee80211_frame);
+
+ if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
+ qos_cntl = (struct ieee80211_qoscntl *)
+ (localbuf + new_hdsize);
+ qos_cntl->i_qos[0] =
+ (tid & IEEE80211_QOS_TID);
+ qos_cntl->i_qos[1] = 0;
+ new_hdsize += sizeof(struct ieee80211_qoscntl);
+ }
+ /*
+ * Prepare llc Header
+ */
+ llc_hdr = (struct llc_snap_hdr_t *)
+ (localbuf + new_hdsize);
+ ether_type = (eth_hdr->ethertype[0] << 8) |
+ (eth_hdr->ethertype[1]);
+ if (ether_type >= IEEE8023_MAX_LEN) {
+ qdf_mem_copy(
+ llc_hdr,
+ ethernet_II_llc_snap_header_prefix,
+ sizeof
+ (ethernet_II_llc_snap_header_prefix));
+ if (ether_type == ETHERTYPE_AARP ||
+ ether_type == ETHERTYPE_IPX) {
+ llc_hdr->org_code[2] =
+ BTEP_SNAP_ORGCODE_2;
+ /* 0xf8; bridge tunnel header */
+ }
+ llc_hdr->ethertype[0] = eth_hdr->ethertype[0];
+ llc_hdr->ethertype[1] = eth_hdr->ethertype[1];
+ new_hdsize += sizeof(struct llc_snap_hdr_t);
+ }
+
+ /*
+ * Remove 802.3 Header by adjusting the head
+ */
+ qdf_nbuf_pull_head(msdu, hdsize);
+
+ /*
+ * Adjust the head and prepare 802.11 Header
+ */
+ qdf_nbuf_push_head(msdu, new_hdsize);
+ qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize);
+ }
+
+ /*
+ * Get the channel info and update the rx status
+ */
+ cds_get_chan_by_session_id(vdev_id, &chan);
+ ol_htt_mon_note_chan(pdev, chan);
+
+ ol_txrx_update_tx_status(pdev, &tx_status, &mon_hdr);
+
+ /*
+ * Calculate the headroom and adjust head
+ * to prepare radiotap header.
+ */
+ headroom = qdf_nbuf_headroom(msdu);
+ qdf_nbuf_push_head(msdu, headroom);
+ qdf_nbuf_update_radiotap(&tx_status, msdu, headroom);
+
+ if (QDF_STATUS_SUCCESS != data_rx(mon_osif_dev, msdu)) {
+ ol_txrx_err("Frame Tx to HDD failed");
+ qdf_nbuf_free(msdu);
+ }
+
+ msdu = next_buf;
+ }
+ return;
+
+free_buf:
+ drop_count = ol_txrx_drop_nbuf_list(nbuf_list);
+}
+
+/**
+ * ol_txrx_mon_rx_data_cb(): callback to process data rx packets
+ * for pkt capture mode. (normal rx + offloaded rx)
+ * @ppdev: device handler
+ * @nbuf_list: netbuf list
+ * @vdev_id: vdev id for which packet is captured
+ * @tid: tid number
+ * @status: Tx status
+ * @pktformat: Frame format
+ *
+ * Return: none
+ */
+static void
+ol_txrx_mon_rx_data_cb(void *ppdev, void *nbuf_list, uint8_t vdev_id,
+ uint8_t tid, uint8_t status, bool pkt_format)
+{
+ struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
+ qdf_nbuf_t buf_list = (qdf_nbuf_t)nbuf_list;
+ qdf_nbuf_t msdu, next_buf;
+ void *mon_osif_dev;
+ struct ol_txrx_vdev_t *vdev;
+ uint8_t drop_count;
+ struct ol_txrx_peer_t *peer;
+ uint8_t chan = 0;
+ struct htt_host_rx_desc_base *rx_desc;
+ struct mon_rx_status rx_status = {0};
+ uint32_t headroom;
+ ol_txrx_mon_callback_fp data_rx = NULL;
+ static uint8_t preamble_type;
+ static uint32_t vht_sig_a_1;
+ static uint32_t vht_sig_a_2;
+ uint8_t bssid[OL_TXRX_MAC_ADDR_LEN];
+
+ if (qdf_unlikely(!pdev))
+ goto free_buf;
+
+ if (vdev_id != HTT_INVALID_VDEV) {
+ vdev = (struct ol_txrx_vdev_t *)
+ ol_txrx_get_vdev_from_vdev_id(vdev_id);
+ if (!vdev)
+ goto free_buf;
+
+ qdf_spin_lock_bh(&pdev->peer_ref_mutex);
+ peer = TAILQ_FIRST(&vdev->peer_list);
+ qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
+ if (!peer)
+ goto free_buf;
+
+ qdf_spin_lock_bh(&peer->peer_info_lock);
+ qdf_mem_copy(bssid, &peer->mac_addr.raw, IEEE80211_ADDR_LEN);
+ qdf_spin_unlock_bh(&peer->peer_info_lock);
+ }
+
+ data_rx = pdev->mon_cb;
+ mon_osif_dev = pdev->mon_osif_dev;
+
+ if (!data_rx || !mon_osif_dev)
+ goto free_buf;
+
+ msdu = buf_list;
+ while (msdu) {
+ struct ethernet_hdr_t *eth_hdr;
+
+ next_buf = qdf_nbuf_queue_next(msdu);
+ qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */
+
+ rx_desc = htt_rx_desc(msdu);
+
+ /*
+ * Only the first mpdu has valid preamble type, so use it
+ * till the last mpdu is reached
+ */
+ if (rx_desc->attention.first_mpdu) {
+ preamble_type = rx_desc->ppdu_start.preamble_type;
+ if (preamble_type == 8 || preamble_type == 9 ||
+ preamble_type == 0x0c || preamble_type == 0x0d) {
+ vht_sig_a_1 = VHT_SIG_A_1(rx_desc);
+ vht_sig_a_2 = VHT_SIG_A_2(rx_desc);
+ }
+ } else {
+ rx_desc->ppdu_start.preamble_type = preamble_type;
+ if (preamble_type == 8 || preamble_type == 9 ||
+ preamble_type == 0x0c || preamble_type == 0x0d) {
+ VHT_SIG_A_1(rx_desc) = vht_sig_a_1;
+ VHT_SIG_A_2(rx_desc) = vht_sig_a_2;
+ }
+ }
+
+ if (rx_desc->attention.last_mpdu) {
+ preamble_type = 0;
+ vht_sig_a_1 = 0;
+ vht_sig_a_2 = 0;
+ }
+
+ qdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION);
+
+ /*
+ * Get the channel info and update the rx status
+ */
+ cds_get_chan_by_session_id(vdev_id, &chan);
+ ol_htt_mon_note_chan(pdev, chan);
+ htt_rx_mon_get_rx_status(pdev->htt_pdev, rx_desc, &rx_status);
+
+ /* clear IEEE80211_RADIOTAP_F_FCS flag*/
+ rx_status.rtap_flags &= ~(BIT(4));
+
+ /*
+ * convert 802.3 header format into 802.11 format
+ */
+ if (vdev_id == HTT_INVALID_VDEV) {
+ eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu);
+ qdf_mem_copy(bssid, eth_hdr->src_addr,
+ IEEE80211_ADDR_LEN);
+ }
+
+ ol_txrx_convert8023to80311(bssid, msdu, rx_desc);
+
+ /*
+ * Calculate the headroom and adjust head
+ * to prepare radiotap header.
+ */
+ headroom = qdf_nbuf_headroom(msdu);
+ qdf_nbuf_push_head(msdu, headroom);
+ qdf_nbuf_update_radiotap(&rx_status, msdu, headroom);
+
+ if (QDF_STATUS_SUCCESS != data_rx(mon_osif_dev, msdu)) {
+ ol_txrx_err("Frame Rx to HDD failed");
+ qdf_nbuf_free(msdu);
+ }
+ msdu = next_buf;
+ }
+
+ return;
+
+free_buf:
+ drop_count = ol_txrx_drop_nbuf_list(buf_list);
+}
+
+void ol_txrx_mon_data_process(uint8_t vdev_id,
+ qdf_nbuf_t mon_buf_list,
+ enum mon_data_process_type type,
+ uint8_t tid, uint8_t status, bool pkt_format)
+{
+ uint8_t drop_count;
+ struct cds_ol_mon_pkt *pkt;
+ ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+ p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
+ cds_ol_mon_thread_cb callback = NULL;
+
+ if (!pdev) {
+ ol_txrx_err("pdev is NULL");
+ goto drop_rx_buf;
+ }
+ if (unlikely(!sched_ctx))
+ goto drop_rx_buf;
+ pkt = cds_alloc_ol_mon_pkt(sched_ctx);
+ if (!pkt)
+ goto drop_rx_buf;
+
+ switch (type) {
+ case PROCESS_TYPE_DATA_RX:
+ callback = ol_txrx_mon_rx_data_cb;
+ break;
+ case PROCESS_TYPE_DATA_TX:
+ callback = ol_txrx_mon_tx_data_cb;
+ break;
+ case PROCESS_TYPE_DATA_TX_COMPL:
+ callback = ol_txrx_mon_tx_data_cb;
+ break;
+ default:
+ return;
+ }
+ pkt->callback = callback;
+ pkt->context = (void *)pdev;
+ pkt->monpkt = (void *)mon_buf_list;
+ pkt->vdev_id = vdev_id;
+ pkt->tid = tid;
+ pkt->status = status;
+ pkt->pkt_format = pkt_format;
+ cds_indicate_monpkt(sched_ctx, pkt);
+ return;
+
+drop_rx_buf:
+ drop_count = ol_txrx_drop_nbuf_list(mon_buf_list);
+}
+
+/**
* ol_rx_data_cb() - data rx callback
* @peer: peer
* @buf_list: buffer list
@@ -5570,6 +6392,7 @@ static QDF_STATUS ol_txrx_enqueue_rx_frames(
}
return QDF_STATUS_SUCCESS;
}
+
/**
* ol_rx_data_process() - process rx frame
* @peer: peer
diff --git a/core/dp/txrx/ol_txrx.h b/core/dp/txrx/ol_txrx.h
index 6c2c0c6d2a6b..8bdd418f587d 100644
--- a/core/dp/txrx/ol_txrx.h
+++ b/core/dp/txrx/ol_txrx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -48,6 +48,9 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer,
ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev,
uint8_t *peer_addr,
uint8_t *peer_id);
+
+bool ol_txrx_mon_mgmt_process(struct mon_rx_status *rx_status,
+ qdf_nbuf_t nbuf, uint8_t status);
/**
* ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems
* @ctrl_pdev: the control pdev handle
diff --git a/core/dp/txrx/ol_txrx_flow_control.c b/core/dp/txrx/ol_txrx_flow_control.c
index d1c39b6f6fcf..39d372b5a134 100644
--- a/core/dp/txrx/ol_txrx_flow_control.c
+++ b/core/dp/txrx/ol_txrx_flow_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -444,12 +444,12 @@ ol_tx_distribute_descs_to_deficient_pools(struct ol_tx_flow_pool_t *src_pool)
if (dst_pool->status == FLOW_POOL_ACTIVE_PAUSED) {
if (dst_pool->avail_desc > dst_pool->start_th) {
pdev->pause_cb(dst_pool->member_flow_id,
- WLAN_WAKE_ALL_NETIF_QUEUE,
- WLAN_DATA_FLOW_CONTROL);
+ WLAN_NETIF_PRIORITY_QUEUE_ON,
+ WLAN_DATA_FLOW_CONTROL_PRIORITY);
pdev->pause_cb(dst_pool->member_flow_id,
- WLAN_NETIF_PRIORITY_QUEUE_ON,
- WLAN_DATA_FLOW_CONTROL_PRIORITY);
+ WLAN_WAKE_ALL_NETIF_QUEUE,
+ WLAN_DATA_FLOW_CONTROL);
dst_pool->status =
FLOW_POOL_ACTIVE_UNPAUSED;
@@ -708,6 +708,9 @@ void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type,
case FLOW_TYPE_VDEV:
ol_tx_flow_pool_vdev_map(pool, flow_id);
pdev->pause_cb(flow_id,
+ WLAN_NETIF_PRIORITY_QUEUE_ON,
+ WLAN_DATA_FLOW_CONTROL_PRIORITY);
+ pdev->pause_cb(flow_id,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_DATA_FLOW_CONTROL);
break;
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index 189aa21c6eb3..fe230839a151 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -558,6 +558,26 @@ struct ol_txrx_fw_stats_desc_elem_t {
struct ol_txrx_fw_stats_desc_t desc;
};
+/**
+ * ol_txrx_mon_hdr_elem_t - tx packets header struture to update radiotap header
+ * for packet capture mode
+ */
+struct ol_txrx_mon_hdr_elem_t {
+ uint32_t timestamp;
+ uint8_t preamble;
+ uint8_t mcs;
+ uint8_t rate;
+ uint8_t rssi_comb;
+ uint8_t nss;
+ uint8_t bw;
+ bool stbc;
+ bool sgi;
+ bool ldpc;
+ bool beamformed;
+ bool dir; /* rx:0 , tx:1 */
+ uint8_t status; /* tx status */
+};
+
/*
* As depicted in the diagram below, the pdev contains an array of
* NUM_EXT_TID ol_tx_active_queues_in_tid_t elements.
@@ -618,6 +638,9 @@ struct ol_txrx_pdev_t {
/* osdev - handle for mem alloc / free, map / unmap */
qdf_device_t osdev;
+ void *mon_osif_dev;
+ ol_txrx_mon_callback_fp mon_cb;
+
htt_pdev_handle htt_pdev;
#ifdef WLAN_FEATURE_FASTPATH
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 0c36f4851814..49bfcedce5a0 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -15423,6 +15423,49 @@ enum hw_filter_mode {
#define CFG_BTM_QUERY_BITMASK_DEFAULT (0x8)
/*
+ * <ini>
+ * pktcap_mode_enable - Control to decide pktcapture mode enable/disable
+ *
+ * @Min: 0
+ * @Max: 1
+ *
+ * @Default: 0 - disable
+ * 1 - enable
+ *
+ * This ini is used to enable/disable pktcapture mode
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_PKTCAP_MODE_ENABLE_NAME "pktcap_mode_enable"
+#define CFG_PKTCAP_MODE_ENABLE_MIN (0)
+#define CFG_PKTCAP_MODE_ENABLE_MAX (1)
+#define CFG_PKTCAP_MODE_ENABLE_DEFAULT (0)
+
+/*
+ * pktcapture_mode - Control to decide pktcapture mode
+ *
+ * @Min: 0
+ * @Max: 3
+ *
+ * @Default: 0 - Capture no packets
+ * 1 - Capture Mgmt packets only
+ * 2 - Capture Data packets only
+ * 3 - Capture Both Data & Mgmt packets
+ *
+ * This ini is used to decide pktcapture mode
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_PKTCAPTURE_MODE_NAME "pktcapture_mode"
+#define CFG_PKTCAPTURE_MODE_MIN (0)
+#define CFG_PKTCAPTURE_MODE_MAX (3)
+#define CFG_PKTCAPTURE_MODE_DEFAULT (0)
+
+/*
* Type declarations
*/
@@ -16379,6 +16422,9 @@ struct hdd_config {
uint32_t btm_sticky_time;
uint32_t btm_query_bitmask;
uint16_t beacon_reporting;
+
+ bool pktcap_mode_enable;
+ uint8_t pktcapture_mode;
};
#define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var))
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index a0d9c12d6ef4..0b3e8790a629 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1980,6 +1980,7 @@ struct hdd_context_s {
bool is_ol_rx_thread_suspended;
#endif
+ bool is_ol_mon_thread_suspended;
bool hdd_wlan_suspended;
bool suspended;
/* flag to start pktlog after SSR/PDR if previously enabled */
@@ -2263,6 +2264,8 @@ struct hdd_context_s {
enum sar_version sar_version;
bool is_ssr_in_progress;
+
+ uint8_t pktcapture_mode;
};
int hdd_validate_channel_and_bandwidth(hdd_adapter_t *adapter,
@@ -2297,6 +2300,84 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *pHddCtx, uint8_t session_type,
const char *name, tSirMacAddr macAddr,
unsigned char name_assign_type,
bool rtnl_held);
+
+#ifdef WLAN_FEATURE_PKT_CAPTURE
+
+/**
+ * wlan_hdd_is_session_type_monitor() - check if session type is MONITOR
+ * @session_type: session type
+ *
+ * Return: True - if session type for adapter is monitor, else False
+ *
+ */
+bool wlan_hdd_is_session_type_monitor(uint8_t session_type);
+
+/**
+ * wlan_hdd_check_mon_concurrency() - check if MONITOR and STA concurrency
+ * is UP when packet capture mode is enabled.
+ * @void
+ *
+ * Return: True - if STA and monitor concurrency is there, else False
+ *
+ */
+bool wlan_hdd_check_mon_concurrency(void);
+
+/**
+ * wlan_hdd_add_monitor_check() - check for monitor intf and add if needed
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: output pointer to hold created monitor adapter
+ * @type: type of the interface
+ * @name: name of the interface
+ * @rtnl_held: True if RTNL lock is held
+ * @name_assign_type: the name of assign type of the netdev
+ *
+ * Return: 0 - on success
+ * err code - on failure
+ */
+int wlan_hdd_add_monitor_check(hdd_context_t *hdd_ctx, hdd_adapter_t **adapter,
+ enum nl80211_iftype type, const char *name,
+ bool rtnl_held, unsigned char name_assign_type);
+
+/**
+ * wlan_hdd_del_monitor() - delete monitor interface
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: adapter to be deleted
+ * @rtnl_held: rtnl lock held
+ *
+ * This function is invoked to delete monitor interface.
+ *
+ * Return: None
+ */
+void wlan_hdd_del_monitor(hdd_context_t *hdd_ctx,
+ hdd_adapter_t *adapter, bool rtnl_held);
+#else
+static inline
+bool wlan_hdd_is_session_type_monitor(uint8_t session_type)
+{
+ return false;
+}
+
+static inline
+bool wlan_hdd_check_mon_concurrency(void)
+{
+ return false;
+}
+
+static inline
+int wlan_hdd_add_monitor_check(hdd_context_t *hdd_ctx, hdd_adapter_t **adapter,
+ enum nl80211_iftype type, const char *name,
+ bool rtnl_held, unsigned char name_assign_type)
+{
+ return 0;
+}
+
+static inline
+void wlan_hdd_del_monitor(hdd_context_t *hdd_ctx,
+ hdd_adapter_t *adapter, bool rtnl_held)
+{
+}
+#endif /* WLAN_FEATURE_PKT_CAPTURE */
+
QDF_STATUS hdd_close_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter,
bool rtnl_held);
QDF_STATUS hdd_close_all_adapters(hdd_context_t *pHddCtx, bool rtnl_held);
diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h
index 361bdbeed4a9..98dcffe89acf 100644
--- a/core/hdd/inc/wlan_hdd_tx_rx.h
+++ b/core/hdd/inc/wlan_hdd_tx_rx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -188,6 +188,36 @@ const char *hdd_action_type_to_string(enum netif_action_type action);
void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
enum netif_action_type action, enum netif_reason_type reason);
int hdd_set_mon_rx_cb(struct net_device *dev);
+
+#ifdef WLAN_FEATURE_PKT_CAPTURE
+/**
+ * hdd_set_mon_mode_cb() - Set pkt capture mode callback
+ * @dev: Pointer to net_device structure
+ *
+ * Return: 0 on success; non-zero for failure
+ */
+int hdd_set_mon_mode_cb(struct net_device *dev);
+
+/**
+ * hdd_reset_mon_mode_cb() - Reset pkt capture mode callback
+ * @void
+ *
+ * Return: None
+ */
+void hdd_reset_mon_mode_cb(void);
+#else
+static inline
+int hdd_set_mon_mode_cb(struct net_device *dev)
+{
+ return -ENOTSUPP;
+}
+
+static inline
+void hdd_reset_mon_mode_cb(void)
+{
+}
+#endif /* WLAN_FEATURE_PKT_CAPTURE */
+
void hdd_send_rps_ind(hdd_adapter_t *adapter);
void hdd_send_rps_disable_ind(hdd_adapter_t *adapter);
void wlan_hdd_classify_pkt(struct sk_buff *skb);
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index dba9f1cfad47..9102bc7bac2b 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/core/hdd/src/wlan_hdd_cfg.c
@@ -5811,6 +5811,20 @@ struct reg_table_entry g_registry_table[] = {
CFG_NTH_BEACON_REPORTING_OFFLOAD_DEFAULT,
CFG_NTH_BEACON_REPORTING_OFFLOAD_MIN,
CFG_NTH_BEACON_REPORTING_OFFLOAD_MAX),
+
+ REG_VARIABLE(CFG_PKTCAP_MODE_ENABLE_NAME, WLAN_PARAM_Integer,
+ struct hdd_config, pktcap_mode_enable,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_PKTCAP_MODE_ENABLE_DEFAULT,
+ CFG_PKTCAP_MODE_ENABLE_MIN,
+ CFG_PKTCAP_MODE_ENABLE_MAX),
+
+ REG_VARIABLE(CFG_PKTCAPTURE_MODE_NAME, WLAN_PARAM_Integer,
+ struct hdd_config, pktcapture_mode,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_PKTCAPTURE_MODE_DEFAULT,
+ CFG_PKTCAPTURE_MODE_MIN,
+ CFG_PKTCAPTURE_MODE_MAX),
};
/**
@@ -7857,6 +7871,10 @@ void hdd_cfg_print(hdd_context_t *pHddCtx)
hdd_debug("Name = [%s] value = [%u]",
CFG_NTH_BEACON_REPORTING_OFFLOAD_NAME,
pHddCtx->config->beacon_reporting);
+ hdd_debug("Name = [%s] value = [%d]",
+ CFG_PKTCAP_MODE_ENABLE_NAME, pHddCtx->config->pktcap_mode_enable);
+ hdd_debug("Name = [%s] value = [%d]",
+ CFG_PKTCAPTURE_MODE_NAME, pHddCtx->config->pktcapture_mode);
}
/**
@@ -8068,6 +8086,22 @@ static void hdd_set_rx_mode_value(hdd_context_t *hdd_ctx)
}
/**
+ * hdd_set_pktcapture_mode_value() - set pktcapture_mode values
+ * @hdd_ctx: hdd context
+ *
+ * Return: none
+ */
+static void hdd_set_pktcapture_mode_value(hdd_context_t *hdd_ctx)
+{
+ if (hdd_ctx->config->pktcapture_mode > CFG_PKTCAPTURE_MODE_MAX) {
+ hdd_warn("pktcapture_mode wrong configuration. Make it default");
+ hdd_ctx->config->pktcapture_mode = CFG_PKTCAPTURE_MODE_DEFAULT;
+ }
+
+ hdd_ctx->pktcapture_mode = hdd_ctx->config->pktcapture_mode;
+}
+
+/**
* hdd_parse_config_ini() - parse the ini configuration file
* @pHddCtx: the pointer to hdd context
*
@@ -8171,6 +8205,7 @@ QDF_STATUS hdd_parse_config_ini(hdd_context_t *pHddCtx)
/* Loop through the registry table and apply all these configs */
qdf_status = hdd_apply_cfg_ini(pHddCtx, cfgIniTable, i);
hdd_set_rx_mode_value(pHddCtx);
+ hdd_set_pktcapture_mode_value(pHddCtx);
if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam())
hdd_override_all_ps(pHddCtx);
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 6cfbc3d2c828..44e6d3f24c1b 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -5436,8 +5436,8 @@ int wlan_hdd_send_roam_auth_event(hdd_adapter_t *adapter, uint8_t *bssid,
ETH_ALEN + req_rsn_len + rsp_rsn_len +
sizeof(uint8_t) + SIR_REPLAY_CTR_LEN +
SIR_KCK_KEY_LEN + roam_info_ptr->kek_len +
- sizeof(uint8_t) + (8 * NLMSG_HDRLEN) +
- fils_params_len,
+ sizeof(uint16_t) + sizeof(uint8_t) +
+ (9 * NLMSG_HDRLEN) + fils_params_len,
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX,
GFP_KERNEL);
@@ -6761,7 +6761,7 @@ static int hdd_map_req_id_to_pattern_id(hdd_context_t *hdd_ctx,
}
}
mutex_unlock(&hdd_ctx->op_ctx.op_lock);
- return -EINVAL;
+ return -ENOBUFS;
}
/**
@@ -6829,7 +6829,8 @@ wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
{
struct sSirAddPeriodicTxPtrn *add_req;
QDF_STATUS status;
- uint32_t request_id, ret, len;
+ uint32_t request_id, len;
+ int32_t ret;
uint8_t pattern_id = 0;
struct qdf_mac_addr dst_addr;
uint16_t eth_type = htons(ETH_P_IP);
@@ -6848,29 +6849,34 @@ wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
/* Parse and fetch request Id */
if (!tb[PARAM_REQUEST_ID]) {
hdd_err("attr request id failed");
+ ret = -EINVAL;
goto fail;
}
request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
if (request_id == MAX_REQUEST_ID) {
hdd_err("request_id cannot be MAX");
+ ret = -EINVAL;
goto fail;
}
hdd_debug("Request Id: %u", request_id);
if (!tb[PARAM_PERIOD]) {
hdd_err("attr period failed");
+ ret = -EINVAL;
goto fail;
}
add_req->usPtrnIntervalMs = nla_get_u32(tb[PARAM_PERIOD]);
hdd_debug("Period: %u ms", add_req->usPtrnIntervalMs);
if (add_req->usPtrnIntervalMs == 0) {
hdd_err("Invalid interval zero, return failure");
+ ret = -EINVAL;
goto fail;
}
if (!tb[PARAM_SRC_MAC_ADDR]) {
hdd_err("attr source mac address failed");
+ ret = -EINVAL;
goto fail;
}
nla_memcpy(add_req->mac_address.bytes, tb[PARAM_SRC_MAC_ADDR],
@@ -6881,11 +6887,13 @@ wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
if (!qdf_is_macaddr_equal(&add_req->mac_address,
&adapter->macAddressCurrent)) {
hdd_err("input src mac address and connected ap bssid are different");
+ ret = -EINVAL;
goto fail;
}
if (!tb[PARAM_DST_MAC_ADDR]) {
hdd_err("attr dst mac address failed");
+ ret = -EINVAL;
goto fail;
}
nla_memcpy(dst_addr.bytes, tb[PARAM_DST_MAC_ADDR], QDF_MAC_ADDR_SIZE);
@@ -6894,6 +6902,7 @@ wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
if (!tb[PARAM_IP_PACKET]) {
hdd_err("attr ip packet failed");
+ ret = -EINVAL;
goto fail;
}
add_req->ucPtrnSize = nla_len(tb[PARAM_IP_PACKET]);
@@ -6904,6 +6913,7 @@ wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
ETH_HLEN)) {
hdd_err("Invalid IP packet len: %d",
add_req->ucPtrnSize);
+ ret = -EINVAL;
goto fail;
}
@@ -6938,16 +6948,15 @@ wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
status = sme_add_periodic_tx_ptrn(hdd_ctx->hHal, add_req);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("sme_add_periodic_tx_ptrn failed (err=%d)", status);
+ ret = qdf_status_to_os_return(status);
goto fail;
}
EXIT();
- qdf_mem_free(add_req);
- return 0;
fail:
qdf_mem_free(add_req);
- return -EINVAL;
+ return ret;
}
/**
@@ -14803,6 +14812,9 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
TRACE_CODE_HDD_CFG80211_CHANGE_IFACE,
pAdapter->sessionId, type));
+ if (wlan_hdd_check_mon_concurrency())
+ return -EINVAL;
+
hdd_debug("Device_mode = %d, IFTYPE = 0x%x",
pAdapter->device_mode, type);
diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c
index 9591ca930787..72e2ebbb7b2e 100644
--- a/core/hdd/src/wlan_hdd_driver_ops.c
+++ b/core/hdd/src/wlan_hdd_driver_ops.c
@@ -1377,11 +1377,11 @@ static void hdd_cleanup_on_fw_down(void)
ENTER();
hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
- qdf_complete_wait_events();
cds_set_target_ready(false);
if (hdd_ctx != NULL)
hdd_cleanup_scan_queue(hdd_ctx, NULL);
wlan_hdd_purge_notifier();
+ qdf_complete_wait_events();
EXIT();
}
@@ -1447,6 +1447,7 @@ static void wlan_hdd_pld_uevent(struct device *dev,
cds_set_target_ready(false);
hdd_pld_ipa_uc_shutdown_pipes();
wlan_hdd_purge_notifier();
+ qdf_complete_wait_events();
break;
case PLD_FW_DOWN:
hdd_cleanup_on_fw_down();
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index c78c66991e96..8f472765401c 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -319,6 +319,7 @@ const char *hdd_device_mode_to_string(uint8_t device_mode)
CASE_RETURN_STRING(QDF_P2P_GO_MODE);
CASE_RETURN_STRING(QDF_FTM_MODE);
CASE_RETURN_STRING(QDF_IBSS_MODE);
+ CASE_RETURN_STRING(QDF_MONITOR_MODE);
CASE_RETURN_STRING(QDF_P2P_DEVICE_MODE);
CASE_RETURN_STRING(QDF_OCB_MODE);
CASE_RETURN_STRING(QDF_NDI_MODE);
@@ -1984,7 +1985,12 @@ static int __hdd_mon_open(struct net_device *dev)
}
hdd_mon_mode_ether_setup(dev);
- ret = hdd_set_mon_rx_cb(dev);
+
+ if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
+ ret = hdd_set_mon_rx_cb(dev);
+ else
+ ret = hdd_set_mon_mode_cb(dev);
+
set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags);
return ret;
}
@@ -2682,16 +2688,21 @@ static int __hdd_stop(struct net_device *dev)
WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
- hdd_debug("Disabling Auto Power save timer");
- sme_ps_disable_auto_ps_timer(
- WLAN_HDD_GET_HAL_CTX(adapter),
- adapter->sessionId);
+ if (!wlan_hdd_is_session_type_monitor(adapter->device_mode)) {
+ hdd_debug("Disabling Auto Power save timer");
+ sme_ps_disable_auto_ps_timer(
+ WLAN_HDD_GET_HAL_CTX(adapter),
+ adapter->sessionId);
+ }
if (adapter->device_mode == QDF_STA_MODE) {
hdd_debug("Sending Lpass stop notifcation");
hdd_lpass_notify_stop(hdd_ctx);
}
+ if (wlan_hdd_is_session_type_monitor(adapter->device_mode))
+ hdd_reset_mon_mode_cb();
+
/*
* NAN data interface is different in some sense. The traffic on NDI is
* bursty in nature and depends on the need to transfer. The service
@@ -3231,6 +3242,7 @@ static void hdd_adapter_init_action_frame_random_mac(hdd_adapter_t *adapter)
* @hdd_ctx: global hdd context
* @macAddr: mac address to assign to the interface
* @name: User-visible name of the interface
+ * @session_type: interface type to be created
*
* hdd adapter pointer would point to the netdev->priv space, this function
* would retrive the pointer, and setup the hdd adapter configuration.
@@ -3240,7 +3252,8 @@ static void hdd_adapter_init_action_frame_random_mac(hdd_adapter_t *adapter)
static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx,
tSirMacAddr macAddr,
unsigned char name_assign_type,
- const char *name)
+ const char *name,
+ uint8_t session_type)
{
struct net_device *pWlanDev = NULL;
hdd_adapter_t *adapter = NULL;
@@ -3253,9 +3266,10 @@ static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS)
name_assign_type,
#endif
- (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() ?
- hdd_mon_mode_ether_setup : ether_setup),
- NUM_TX_QUEUES);
+ ((QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() ||
+ wlan_hdd_is_session_type_monitor(session_type)) ?
+ hdd_mon_mode_ether_setup : ether_setup),
+ NUM_TX_QUEUES);
if (pWlanDev != NULL) {
@@ -3306,7 +3320,10 @@ static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx,
hdd_set_tso_flags(hdd_ctx, pWlanDev);
- hdd_set_station_ops(adapter->dev);
+ if (wlan_hdd_is_session_type_monitor(session_type))
+ pWlanDev->netdev_ops = &wlan_mon_drv_ops;
+ else
+ hdd_set_station_ops(adapter->dev);
hdd_dev_setup_destructor(pWlanDev);
pWlanDev->ieee80211_ptr = &adapter->wdev;
@@ -4478,7 +4495,7 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type,
case QDF_MONITOR_MODE:
adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr,
name_assign_type,
- iface_name);
+ iface_name, session_type);
if (NULL == adapter) {
hdd_err("failed to allocate adapter for session %d",
@@ -4583,7 +4600,7 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type,
case QDF_FTM_MODE:
adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr,
name_assign_type,
- "wlan0");
+ "wlan0", session_type);
if (NULL == adapter) {
hdd_err("Failed to allocate adapter for FTM mode");
return NULL;
@@ -4735,6 +4752,8 @@ QDF_STATUS hdd_close_all_adapters(hdd_context_t *hdd_ctx, bool rtnl_held)
if (pHddAdapterNode && QDF_STATUS_SUCCESS == status) {
wlan_hdd_release_intf_addr(hdd_ctx,
pHddAdapterNode->pAdapter->macAddressCurrent.bytes);
+ cds_clear_concurrency_mode(
+ pHddAdapterNode->pAdapter->device_mode);
hdd_cleanup_adapter(hdd_ctx, pHddAdapterNode->pAdapter,
rtnl_held);
@@ -5955,6 +5974,11 @@ QDF_STATUS hdd_start_all_adapters(hdd_context_t *hdd_ctx)
hdd_delete_sta(adapter);
break;
case QDF_MONITOR_MODE:
+ if (wlan_hdd_is_session_type_monitor(
+ QDF_MONITOR_MODE)) {
+ hdd_set_mon_mode_cb(adapter->dev);
+ break;
+ }
hdd_init_station_mode(adapter);
hdd_set_mon_rx_cb(adapter->dev);
wlan_hdd_set_mon_chan(adapter, adapter->mon_chan,
@@ -6796,6 +6820,10 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx)
hdd_cleanup_scan_queue(hdd_ctx, NULL);
hdd_abort_mac_scan_all_adapters(hdd_ctx);
hdd_abort_sched_scan_all_adapters(hdd_ctx);
+
+ if (wlan_hdd_is_session_type_monitor(QDF_MONITOR_MODE))
+ hdd_reset_mon_mode_cb();
+
hdd_stop_all_adapters(hdd_ctx, true);
hdd_deinit_all_adapters(hdd_ctx, false);
}
@@ -9156,6 +9184,153 @@ static int hdd_open_concurrent_interface(hdd_context_t *hdd_ctx, bool rtnl_held)
return 0;
}
+#ifdef WLAN_FEATURE_PKT_CAPTURE
+
+/**
+ * wlan_hdd_is_session_type_monitor() - check if session type is MONITOR
+ * @session_type: session type
+ *
+ * Return: True - if session type for adapter is monitor, else False
+ *
+ */
+bool wlan_hdd_is_session_type_monitor(uint8_t session_type)
+{
+ if (cds_get_pktcap_mode_enable() &&
+ QDF_MONITOR_MODE == session_type)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * wlan_hdd_check_mon_concurrency() - check if MONITOR and STA concurrency
+ * is UP when packet capture mode is enabled.
+ * @void
+ *
+ * Return: True - if STA and monitor concurrency is there, else False
+ *
+ */
+bool wlan_hdd_check_mon_concurrency(void)
+{
+ if (cds_get_pktcap_mode_enable()) {
+ if (cds_get_concurrency_mode() ==
+ (QDF_STA_MASK | QDF_MONITOR_MASK)) {
+ hdd_err("STA + MON mode is UP");
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * wlan_hdd_del_monitor() - delete monitor interface
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: adapter to be deleted
+ * @rtnl_held: rtnl lock held
+ *
+ * This function is invoked to delete monitor interface.
+ *
+ * Return: None
+ */
+void wlan_hdd_del_monitor(hdd_context_t *hdd_ctx,
+ hdd_adapter_t *adapter, bool rtnl_held)
+{
+ wlan_hdd_release_intf_addr(hdd_ctx,
+ adapter->macAddressCurrent.bytes);
+ hdd_stop_adapter(hdd_ctx, adapter, true);
+ hdd_deinit_adapter(hdd_ctx, adapter, true);
+ hdd_close_adapter(hdd_ctx, adapter, true);
+
+ hdd_open_p2p_interface(hdd_ctx, true);
+}
+
+/**
+ * wlan_hdd_add_monitor_check() - check for monitor intf and add if needed
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: output pointer to hold created monitor adapter
+ * @type: type of the interface
+ * @name: name of the interface
+ * @rtnl_held: True if RTNL lock is held
+ * @name_assign_type: the name of assign type of the netdev
+ *
+ * Return: 0 - on success
+ * err code - on failure
+ */
+int
+wlan_hdd_add_monitor_check(hdd_context_t *hdd_ctx, hdd_adapter_t **adapter,
+ enum nl80211_iftype type, const char *name,
+ bool rtnl_held, unsigned char name_assign_type)
+{
+ hdd_adapter_t *sta_adapter;
+ hdd_adapter_t *mon_adapter;
+ uint32_t mode;
+
+ *adapter = NULL;
+
+ if (!cds_get_pktcap_mode_enable())
+ return 0;
+
+ /*
+ * If add interface request is for monitor mode, then it can run in
+ * parallel with only one station interface.
+ * If there is no existing station interface return error
+ */
+ if (type != NL80211_IFTYPE_MONITOR)
+ return 0;
+
+ if (hdd_ctx->no_of_open_sessions[QDF_MONITOR_MODE]) {
+ hdd_err("monitor mode already exists, only one is possible");
+ return -EBUSY;
+ }
+
+ /* Ensure there is only one station interface */
+ if (hdd_ctx->no_of_open_sessions[QDF_STA_MODE] != 1) {
+ hdd_err("cannot add monitor mode, due to %u sta interfaces",
+ hdd_ctx->no_of_open_sessions[QDF_STA_MODE]);
+ return -EINVAL;
+ }
+
+ sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE);
+ if (!sta_adapter) {
+ hdd_err("No station adapter");
+ return -EINVAL;
+ }
+
+ if (hdd_ctx->no_of_open_sessions[QDF_SAP_MODE]) {
+ hdd_err("cannot add monitor mode, due to SAP concurrency");
+ return -EINVAL;
+ }
+
+ /* delete p2p interface */
+ for (mode = QDF_P2P_CLIENT_MODE; mode <= QDF_P2P_DEVICE_MODE; mode++) {
+ hdd_adapter_t *adapter;
+
+ if (mode == QDF_FTM_MODE ||
+ mode == QDF_MONITOR_MODE ||
+ mode == QDF_IBSS_MODE)
+ continue;
+
+ adapter = hdd_get_adapter(hdd_ctx, mode);
+ if (adapter)
+ hdd_close_adapter(hdd_ctx, adapter, rtnl_held);
+ }
+
+ mon_adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, name,
+ wlan_hdd_get_intf_addr(
+ hdd_ctx,
+ QDF_MONITOR_MODE),
+ name_assign_type, rtnl_held);
+ if (!mon_adapter) {
+ hdd_err("hdd_open_adapter failed");
+ hdd_open_p2p_interface(hdd_ctx, rtnl_held);
+ return -EINVAL;
+ }
+
+ *adapter = mon_adapter;
+ return 0;
+}
+#endif /* WLAN_FEATURE_PKT_CAPTURE */
+
/**
* hdd_open_interfaces - Open all required interfaces
* hdd_ctx: HDD context
diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c
index 3b6ad6df8477..572a7a41043d 100644
--- a/core/hdd/src/wlan_hdd_p2p.c
+++ b/core/hdd/src/wlan_hdd_p2p.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -2959,6 +2959,9 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
return ERR_PTR(-EINVAL);
}
+ if (wlan_hdd_check_mon_concurrency())
+ return ERR_PTR(-EINVAL);
+
pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
if ((pAdapter != NULL) &&
!(wlan_hdd_validate_session_id(pAdapter->sessionId))) {
@@ -2971,6 +2974,15 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
}
}
+ ret = wlan_hdd_add_monitor_check(pHddCtx, &pAdapter, type, name,
+ true, name_assign_type);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+ if (pAdapter) {
+ EXIT();
+ return pAdapter->dev->ieee80211_ptr;
+ }
+
if (session_type == QDF_SAP_MODE) {
struct wireless_dev *sap_dev;
bool allow_add_sap = wlan_hdd_allow_sap_add(pHddCtx, name,
@@ -3179,6 +3191,10 @@ int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (pVirtAdapter->device_mode == QDF_SAP_MODE &&
wlan_sap_is_pre_cac_active(pHddCtx->hHal)) {
hdd_clean_up_pre_cac_interface(pHddCtx);
+ } else if (wlan_hdd_is_session_type_monitor(
+ pVirtAdapter->device_mode)) {
+ wlan_hdd_del_monitor(pHddCtx, pVirtAdapter, TRUE);
+ hdd_reset_mon_mode_cb();
} else {
wlan_hdd_release_intf_addr(pHddCtx,
pVirtAdapter->macAddressCurrent.bytes);
diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c
index 7d42532877c4..1d3e868c93e2 100644
--- a/core/hdd/src/wlan_hdd_power.c
+++ b/core/hdd/src/wlan_hdd_power.c
@@ -1518,6 +1518,11 @@ QDF_STATUS hdd_wlan_shutdown(void)
pHddCtx->is_ol_rx_thread_suspended = false;
}
#endif
+ if (cds_get_pktcap_mode_enable() &&
+ pHddCtx->is_ol_mon_thread_suspended) {
+ complete(&cds_sched_context->ol_resume_mon_event);
+ pHddCtx->is_ol_mon_thread_suspended = false;
+ }
hdd_ipa_uc_ssr_deinit();
@@ -1882,6 +1887,13 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
pHddCtx->is_ol_rx_thread_suspended = false;
}
#endif
+ /* Resume tlshim mon thread */
+ if (cds_get_pktcap_mode_enable() &&
+ pHddCtx->is_ol_mon_thread_suspended) {
+ complete(&cds_sched_context->ol_resume_mon_event);
+ pHddCtx->is_ol_mon_thread_suspended = false;
+ }
+
hdd_resume_wlan();
MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
@@ -2161,10 +2173,28 @@ fetch_adapter:
clear_bit(RX_SUSPEND_EVENT,
&cds_sched_context->ol_rx_event_flag);
hdd_err("Failed to stop tl_shim rx thread");
- goto resume_all;
+ goto resume_mc;
}
pHddCtx->is_ol_rx_thread_suspended = true;
#endif
+ /* Suspend tlshim mon thread */
+ if (cds_get_pktcap_mode_enable()) {
+ set_bit(RX_SUSPEND_EVENT,
+ &cds_sched_context->ol_mon_event_flag);
+ wake_up_interruptible(&cds_sched_context->ol_mon_wait_queue);
+ rc = wait_for_completion_timeout(&cds_sched_context->
+ ol_suspend_mon_event,
+ msecs_to_jiffies
+ (RX_TLSHIM_SUSPEND_TIMEOUT));
+ if (!rc) {
+ clear_bit(RX_SUSPEND_EVENT,
+ &cds_sched_context->ol_mon_event_flag);
+ hdd_err("Failed to stop tl_shim mon thread");
+ goto resume_all;
+ }
+ pHddCtx->is_ol_mon_thread_suspended = true;
+ }
+
MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
NO_SESSION, pHddCtx->isWiphySuspended));
@@ -2175,12 +2205,14 @@ fetch_adapter:
EXIT();
return 0;
-#ifdef QCA_CONFIG_SMP
resume_all:
-
+#ifdef QCA_CONFIG_SMP
+ complete(&cds_sched_context->ol_resume_rx_event);
+ pHddCtx->is_ol_rx_thread_suspended = false;
+#endif
+resume_mc:
complete(&cds_sched_context->ResumeMcEvent);
pHddCtx->isMcThreadSuspended = false;
-#endif
resume_tx:
diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c
index 806b8129f8f2..5b7d009630c1 100644
--- a/core/hdd/src/wlan_hdd_stats.c
+++ b/core/hdd/src/wlan_hdd_stats.c
@@ -3970,11 +3970,6 @@ static int wlan_hdd_get_peer_info(hdd_adapter_t *adapter,
return ret;
}
-int wlan_hdd_get_station_remote(struct wiphy *wiphy,
- struct net_device *dev,
- const u8 *mac,
- struct station_info *sinfo);
-
/**
* wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
* @wiphy: pointer to wiphy
@@ -3986,7 +3981,7 @@ int wlan_hdd_get_station_remote(struct wiphy *wiphy,
*
* Return: 0 on success, otherwise error value
*/
-int wlan_hdd_get_station_remote(struct wiphy *wiphy,
+static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
struct net_device *dev,
const u8 *mac,
struct station_info *sinfo)
@@ -4099,8 +4094,15 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
return -EINVAL;
}
- if (pAdapter->device_mode == QDF_SAP_MODE)
+ if (pAdapter->device_mode == QDF_SAP_MODE) {
+ if (pCfg->sap_get_peer_info) {
+ status = wlan_hdd_get_station_remote(wiphy, dev,
+ mac, sinfo);
+ if (!status)
+ return 0;
+ }
return wlan_hdd_get_sap_stats(pAdapter, sinfo);
+ }
if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
(0 == ssidlen)) {
diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c
index 03e7b7269daf..646488d9fb95 100644
--- a/core/hdd/src/wlan_hdd_tx_rx.c
+++ b/core/hdd/src/wlan_hdd_tx_rx.c
@@ -1180,6 +1180,13 @@ static void __hdd_tx_timeout(struct net_device *dev)
u64 diff_jiffies;
int i = 0;
+ hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+ if (hdd_ctx->hdd_wlan_suspended) {
+ hdd_debug("Device is suspended, ignore WD timeout");
+ return;
+ }
+
TX_TIMEOUT_TRACE(dev, QDF_MODULE_ID_HDD_DATA);
DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_TX_TIMEOUT,
NULL, 0, QDF_TX));
@@ -1200,7 +1207,6 @@ static void __hdd_tx_timeout(struct net_device *dev)
QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
"carrier state: %d", netif_carrier_ok(dev));
- hdd_ctx = WLAN_HDD_GET_CTX(adapter);
wlan_hdd_display_netif_queue_history(hdd_ctx, QDF_STATS_VERB_LVL_HIGH);
ol_tx_dump_flow_pool_info();
@@ -2357,6 +2363,36 @@ void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
adapter->queue_oper_history[index].pause_map = adapter->pause_map;
}
+#ifdef WLAN_FEATURE_PKT_CAPTURE
+/**
+ * hdd_set_mon_mode_cb() - Set pkt capture mode callback
+ * @dev: Pointer to net_device structure
+ *
+ * Return: 0 on success; non-zero for failure
+ */
+int hdd_set_mon_mode_cb(struct net_device *dev)
+{
+ ol_txrx_mon_callback_fp mon_cb;
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+ mon_cb = hdd_mon_rx_packet_cbk;
+ ol_txrx_mon_cb_register(adapter, mon_cb);
+
+ return 0;
+}
+
+/**
+ * hdd_reset_mon_mode_cb() - Reset pkt capture mode callback
+ * @void
+ *
+ * Return: None
+ */
+void hdd_reset_mon_mode_cb(void)
+{
+ ol_txrx_mon_cb_deregister();
+}
+#endif /* WLAN_FEATURE_PKT_CAPTURE */
+
/**
* hdd_set_mon_rx_cb() - Set Monitor mode Rx callback
* @dev: Pointer to net_device structure
diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h
index b39ea7041107..cc2a2e910913 100644
--- a/core/mac/inc/qwlan_version.h
+++ b/core/mac/inc/qwlan_version.h
@@ -33,8 +33,8 @@
#define QWLAN_VERSION_MINOR 1
#define QWLAN_VERSION_PATCH 1
#define QWLAN_VERSION_EXTRA "E"
-#define QWLAN_VERSION_BUILD 72
+#define QWLAN_VERSION_BUILD 73
-#define QWLAN_VERSIONSTR "5.1.1.72E"
+#define QWLAN_VERSIONSTR "5.1.1.73E"
#endif /* QWLAN_VERSION_H */
diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h
index 9fd6a95ede24..74188d03867d 100644
--- a/core/mac/src/pe/include/lim_session.h
+++ b/core/mac/src/pe/include/lim_session.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -440,10 +440,6 @@ typedef struct sPESession /* Added to Support BT-AMP */
/* Fast Transition (FT) */
tftPEContext ftPEContext;
bool isNonRoamReassoc;
-#ifdef WLAN_FEATURE_11W
- qdf_mc_timer_t pmfComebackTimer;
- tComebackTimerInfo pmfComebackTimerInfo;
-#endif /* WLAN_FEATURE_11W */
uint8_t is_key_installed;
/* timer for reseting protection fileds at regular intervals */
qdf_mc_timer_t protection_fields_reset_timer;
diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c
index 1d7c0fb67187..29fab1e11f75 100644
--- a/core/mac/src/pe/lim/lim_api.c
+++ b/core/mac/src/pe/lim/lim_api.c
@@ -723,9 +723,6 @@ static void pe_shutdown_notifier_cb(void *ctx)
if (LIM_IS_AP_ROLE(session))
qdf_mc_timer_stop(&session->
protection_fields_reset_timer);
-#ifdef WLAN_FEATURE_11W
- qdf_mc_timer_stop(&session->pmfComebackTimer);
-#endif
}
}
}
diff --git a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
index 83b5bb2999f2..48a97ceb8d67 100644
--- a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
+++ b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -468,6 +468,53 @@ static void lim_stop_reassoc_retry_timer(tpAniSirGlobal mac_ctx)
lim_deactivate_and_change_timer(mac_ctx, eLIM_REASSOC_FAIL_TIMER);
}
+#ifdef WLAN_FEATURE_11W
+
+#define LIM_MIN_RSSI 0
+
+static void
+lim_handle_assoc_reject_status(tpAniSirGlobal mac_ctx,
+ tpPESession session_entry,
+ tpSirAssocRsp assoc_rsp,
+ tSirMacAddr source_addr)
+{
+ struct sir_rssi_disallow_lst ap_info = {{0}};
+ uint32_t timeout_value =
+ assoc_rsp->TimeoutInterval.timeoutValue;
+
+ if (!(session_entry->limRmfEnabled &&
+ assoc_rsp->statusCode == eSIR_MAC_TRY_AGAIN_LATER &&
+ (assoc_rsp->TimeoutInterval.present &&
+ (assoc_rsp->TimeoutInterval.timeoutType ==
+ SIR_MAC_TI_TYPE_ASSOC_COMEBACK))))
+ return;
+
+ /*
+ * Add to rssi reject list, which takes care of retry
+ * delay too. Fill the RSSI as 0, so the only param
+ * which will allow the bssid to connect is retry delay.
+ */
+ ap_info.retry_delay = timeout_value;
+ qdf_mem_copy(ap_info.bssid.bytes, source_addr,
+ QDF_MAC_ADDR_SIZE);
+ ap_info.expected_rssi = LIM_MIN_RSSI;
+ lim_assoc_rej_add_to_rssi_based_reject_list(mac_ctx,
+ &ap_info);
+
+ pe_debug("ASSOC res with eSIR_MAC_TRY_AGAIN_LATER recvd. Add to time reject list(rssi reject in mac_ctx %d",
+ timeout_value);
+
+}
+#else
+static void
+lim_handle_assoc_reject_status(tpAniSirGlobal mac_ctx,
+ tpPESession session_entry,
+ tpSirAssocRsp assoc_rsp,
+ tSirMacAddr source_addr)
+{
+}
+#endif
+
/**
* lim_process_assoc_rsp_frame() - Processes assoc response
* @mac_ctx: Pointer to Global MAC structure
@@ -700,19 +747,24 @@ lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx,
else
lim_stop_reassoc_retry_timer(mac_ctx);
+ lim_handle_assoc_reject_status(mac_ctx, session_entry, assoc_rsp,
+ hdr->sa);
+
if (eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS ==
assoc_rsp->statusCode &&
- assoc_rsp->rssi_assoc_rej.present)
+ assoc_rsp->rssi_assoc_rej.present) {
+ struct sir_rssi_disallow_lst ap_info = {{0}};
+
+ ap_info.retry_delay = assoc_rsp->rssi_assoc_rej.retry_delay *
+ QDF_MC_TIMER_TO_MS_UNIT;
+ qdf_mem_copy(ap_info.bssid.bytes, hdr->sa, QDF_MAC_ADDR_SIZE);
+ ap_info.expected_rssi = assoc_rsp->rssi_assoc_rej.delta_rssi +
+ WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info);
lim_assoc_rej_add_to_rssi_based_reject_list(mac_ctx,
- &assoc_rsp->rssi_assoc_rej, hdr->sa,
- WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info));
+ &ap_info);
+ }
- if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS
-#ifdef WLAN_FEATURE_11W
- && (!session_entry->limRmfEnabled ||
- assoc_rsp->statusCode != eSIR_MAC_TRY_AGAIN_LATER)
-#endif
- ) {
+ if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS) {
/*
*Re/Association response was received
* either with failure code.
@@ -768,63 +820,6 @@ lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx,
* NOTE: for BTAMP case, it is being handled in
* lim_process_mlm_assoc_req
*/
-#ifdef WLAN_FEATURE_11W
- if (session_entry->limRmfEnabled &&
- assoc_rsp->statusCode == eSIR_MAC_TRY_AGAIN_LATER) {
- if (assoc_rsp->TimeoutInterval.present &&
- (assoc_rsp->TimeoutInterval.timeoutType ==
- SIR_MAC_TI_TYPE_ASSOC_COMEBACK)) {
- uint16_t timeout_value =
- assoc_rsp->TimeoutInterval.timeoutValue;
- if (timeout_value < 10) {
- /*
- * if this value is less than 10 then our timer
- * will fail to start and due to this we will
- * never re-attempt. Better modify the timer
- * value here.
- */
- timeout_value = 10;
- }
- pe_debug("ASSOC res with eSIR_MAC_TRY_AGAIN_LATER recvd.Starting timer to wait timeout: %d",
- timeout_value);
- if (QDF_STATUS_SUCCESS !=
- qdf_mc_timer_start(
- &session_entry->pmfComebackTimer,
- timeout_value)) {
- pe_err("Failed to start comeback timer");
-
- assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED;
- assoc_cnf.protStatusCode =
- eSIR_MAC_UNSPEC_FAILURE_STATUS;
-
- /*
- * Delete Pre-auth context for the
- * associated BSS
- */
- if (lim_search_pre_auth_list(mac_ctx, hdr->sa))
- lim_delete_pre_auth_node(mac_ctx,
- hdr->sa);
-
- goto assocReject;
- }
- } else {
- pe_warn("ASSOC resp with try again event recvd, but try again time interval IE is wrong");
-
- assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED;
- assoc_cnf.protStatusCode =
- eSIR_MAC_UNSPEC_FAILURE_STATUS;
-
- /* Delete Pre-auth context for the associated BSS */
- if (lim_search_pre_auth_list(mac_ctx, hdr->sa))
- lim_delete_pre_auth_node(mac_ctx, hdr->sa);
-
- goto assocReject;
- }
- qdf_mem_free(beacon);
- qdf_mem_free(assoc_rsp);
- return;
- }
-#endif
if (!lim_is_roam_synch_in_progress(session_entry)) {
if (lim_set_link_state
(mac_ctx, eSIR_LINK_POSTASSOC_STATE,
diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
index f5afc60e231e..b5ec1062909c 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
@@ -1389,19 +1389,6 @@ static void lim_process_mlm_assoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf)
/* map the session entry pointer to the AssocFailureTimer */
mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId =
mlm_assoc_req->sessionId;
-#ifdef WLAN_FEATURE_11W
- /*
- * Store current MLM state in case ASSOC response returns with
- * TRY_AGAIN_LATER return code.
- */
- if (session_entry->limRmfEnabled) {
- session_entry->pmfComebackTimerInfo.limPrevMlmState =
- session_entry->limPrevMlmState;
- session_entry->pmfComebackTimerInfo.limMlmState =
- session_entry->limMlmState;
- }
-#endif /* WLAN_FEATURE_11W */
-
session_entry->limPrevMlmState = session_entry->limMlmState;
session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE;
MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE,
diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
index da44e6c14053..5110ecd9432a 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
@@ -429,30 +429,6 @@ static void lim_send_mlm_assoc_req(tpAniSirGlobal mac_ctx,
(uint32_t *) assoc_req);
}
-#ifdef WLAN_FEATURE_11W
-/**
- * lim_pmf_comeback_timer_callback() -PMF callback handler
- * @context: Timer context
- *
- * This function is called to processes the PMF comeback
- * callback
- *
- * Return: None
- */
-void lim_pmf_comeback_timer_callback(void *context)
-{
- tComebackTimerInfo *info = (tComebackTimerInfo *) context;
- tpAniSirGlobal mac_ctx = info->pMac;
- tpPESession psessionEntry = &mac_ctx->lim.gpSession[info->sessionID];
-
- pe_err("comeback later timer expired. sending MLM ASSOC req");
- /* set MLM state such that ASSOC REQ packet will be sent out */
- psessionEntry->limPrevMlmState = info->limPrevMlmState;
- psessionEntry->limMlmState = info->limMlmState;
- lim_send_mlm_assoc_req(mac_ctx, psessionEntry);
-}
-#endif /* WLAN_FEATURE_11W */
-
/**
* lim_process_mlm_auth_cnf()-Process Auth confirmation
* @mac_ctx: Pointer to Global MAC structure
diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c
index 09c079b26d30..7f9e83624d68 100644
--- a/core/mac/src/pe/lim/lim_session.c
+++ b/core/mac/src/pe/lim/lim_session.c
@@ -243,36 +243,6 @@ restart_timer:
}
}
-#ifdef WLAN_FEATURE_11W
-/**
- * pe_init_pmf_comeback_timer: init PMF comeback timer
- * @mac_ctx: pointer to global adapter context
- * @session: pe session
- * @session_id: session ID
- *
- * Return: void
- */
-static void pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx,
-tpPESession session, uint8_t session_id)
-{
- QDF_STATUS status;
-
- session->pmfComebackTimerInfo.pMac = mac_ctx;
- session->pmfComebackTimerInfo.sessionID = session_id;
- status = qdf_mc_timer_init(&session->pmfComebackTimer,
- QDF_TIMER_TYPE_SW, lim_pmf_comeback_timer_callback,
- (void *)&session->pmfComebackTimerInfo);
- if (!QDF_IS_STATUS_SUCCESS(status))
- pe_err("cannot init pmf comeback timer");
-}
-#else
-static inline void
-pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx,
- tpPESession session, uint8_t session_id)
-{
-}
-#endif
-
#ifdef WLAN_FEATURE_FILS_SK
/**
* pe_delete_fils_info: API to delete fils session info
@@ -546,7 +516,6 @@ pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId,
pe_err("cannot create ap_ecsa_timer");
}
pe_init_fils_info(session_ptr);
- pe_init_pmf_comeback_timer(pMac, session_ptr, *sessionId);
session_ptr->deauthmsgcnt = 0;
session_ptr->disassocmsgcnt = 0;
session_ptr->ht_client_cnt = 0;
@@ -841,12 +810,7 @@ void pe_delete_session(tpAniSirGlobal mac_ctx, tpPESession session)
session->addIeParams.probeRespBCNData_buff = NULL;
session->addIeParams.probeRespBCNDataLen = 0;
}
-#ifdef WLAN_FEATURE_11W
- if (QDF_TIMER_STATE_RUNNING ==
- qdf_mc_timer_get_current_state(&session->pmfComebackTimer))
- qdf_mc_timer_stop(&session->pmfComebackTimer);
- qdf_mc_timer_destroy(&session->pmfComebackTimer);
-#endif
+
pe_delete_fils_info(session);
session->valid = false;
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index b981f7b54f27..253c87bbfced 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/core/mac/src/pe/lim/lim_utils.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -7335,8 +7335,7 @@ lim_assoc_rej_rem_entry_with_lowest_delta(qdf_list_t *list)
}
void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx,
- tDot11fTLVrssi_assoc_rej *rssi_assoc_rej,
- tSirMacAddr bssid, int8_t rssi)
+ struct sir_rssi_disallow_lst *ap_info)
{
struct sir_rssi_disallow_lst *entry;
QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -7347,16 +7346,13 @@ void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx,
return;
}
- pe_debug("%pM: assoc resp rssi %d, delta rssi %d retry delay %d sec and list size %d",
- bssid, rssi, rssi_assoc_rej->delta_rssi,
- rssi_assoc_rej->retry_delay,
+ pe_debug("%pM: assoc resp, expected rssi %d retry delay %d sec and list size %d",
+ ap_info->bssid.bytes, ap_info->expected_rssi,
+ ap_info->retry_delay,
qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid));
- qdf_mem_copy(entry->bssid.bytes,
- bssid, QDF_MAC_ADDR_SIZE);
- entry->retry_delay = rssi_assoc_rej->retry_delay *
- QDF_MC_TIMER_TO_MS_UNIT;
- entry->expected_rssi = rssi + rssi_assoc_rej->delta_rssi;
+ *entry = *ap_info;
+
entry->time_during_rejection =
qdf_do_div(qdf_get_monotonic_boottime(),
QDF_MC_TIMER_TO_MS_UNIT);
diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h
index 2a6b5a633850..46894381acd7 100644
--- a/core/mac/src/pe/lim/lim_utils.h
+++ b/core/mac/src/pe/lim/lim_utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -612,7 +612,6 @@ void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param);
void lim_set_protected_bit(tpAniSirGlobal pMac,
tpPESession psessionEntry,
tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr);
-void lim_pmf_comeback_timer_callback(void *context);
#else
static inline void lim_set_protected_bit(tpAniSirGlobal pMac,
tpPESession psessionEntry,
@@ -806,9 +805,7 @@ void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx,
* lim_assoc_rej_add_to_rssi_based_reject_list() - Add BSSID to the rssi based
* rejection list
* @mac_ctx: mac ctx
- * @rssi_assoc_rej: rssi assoc reject attribute
- * @bssid : BSSID of the AP
- * @rssi : RSSI of the assoc resp
+ * @ap_info: bssid info to be added to reject list.
*
* Add BSSID to the rssi based rejection list. Also if number
* of entries is greater than MAX_RSSI_AVOID_BSSID_LIST
@@ -817,8 +814,7 @@ void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx,
* Return: void
*/
void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx,
- tDot11fTLVrssi_assoc_rej *rssi_assoc_rej,
- tSirMacAddr bssid, int8_t rssi);
+ struct sir_rssi_disallow_lst *ap_info);
/**
* lim_check_if_vendor_oui_match() - Check if the given OUI match in IE buffer
diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c
index 94a2fe95f287..0fc6fdf9dfd7 100644
--- a/core/sap/src/sap_api_link_cntl.c
+++ b/core/sap/src/sap_api_link_cntl.c
@@ -314,12 +314,9 @@ wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, void *pcontext,
scan_status);
sap_ctx->channel =
sap_select_default_oper_chan(sap_ctx->acs_cfg);
- sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED;
- sap_ctx->sap_status = eSAP_STATUS_SUCCESS;
- goto close_session;
+ sap_ctx->acs_cfg->pri_ch = sap_ctx->channel;
+ goto end;
}
- QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
- FL("CSR scan_status = eCSR_SCAN_SUCCESS (%d)"), scan_status);
/*
* Now do
* 1. Get scan results
@@ -362,19 +359,14 @@ wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, void *pcontext,
FL("No suitable channel, so select default channel"));
sap_ctx->channel =
sap_select_default_oper_chan(sap_ctx->acs_cfg);
+ sap_ctx->acs_cfg->pri_ch = sap_ctx->channel;
} else {
/* Valid Channel Found from scan results. */
sap_ctx->acs_cfg->pri_ch = oper_channel;
sap_ctx->channel = oper_channel;
}
- sap_config_acs_result(hal_handle, sap_ctx,
- sap_ctx->acs_cfg->ht_sec_ch);
- QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
- FL("Channel selected = %d"), sap_ctx->channel);
- sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED;
- sap_ctx->sap_status = eSAP_STATUS_SUCCESS;
-close_session:
+end:
#ifdef SOFTAP_CHANNEL_RANGE
if (sap_ctx->channelList != NULL) {
/*
@@ -387,6 +379,14 @@ close_session:
sap_ctx->num_of_channel = 0;
}
#endif
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
+ FL("Channel selected = %d"), sap_ctx->channel);
+ sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED;
+ sap_ctx->sap_status = eSAP_STATUS_SUCCESS;
+
+ sap_config_acs_result(hal_handle, sap_ctx,
+ sap_ctx->acs_cfg->ht_sec_ch);
+
sap_hdd_signal_event_handler(sap_ctx);
return status;
}
diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h
index c0ec960d1947..0fdba87e92e9 100644
--- a/core/sme/inc/csr_api.h
+++ b/core/sme/inc/csr_api.h
@@ -1594,7 +1594,7 @@ typedef struct tagCsrRoamInfo {
int rx_rate;
tSirMacCapabilityInfo capability_info;
uint32_t rx_mc_bc_cnt;
- uint8_t roam_reason;
+ uint16_t roam_reason;
} tCsrRoamInfo;
typedef struct tagCsrFreqScanInfo {
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index e287fe51acc3..0757c8f5d6e9 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -3373,7 +3373,8 @@ QDF_STATUS sme_scan_request(tHalHandle hal, uint8_t session_id,
msg.reserved = 0;
msg.bodyval = 0;
if (QDF_STATUS_SUCCESS !=
- cds_mq_post_message(QDF_MODULE_ID_SME, &msg)) {
+ cds_mq_post_message_by_priority(QDF_MODULE_ID_SME,
+ &msg, HIGH_PRIORITY)) {
sme_err("sme_scan_req failed to post msg");
csr_scan_free_request(mac_ctx, scan_msg->scan_param);
qdf_mem_free(scan_msg->scan_param);
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 27d6fe309f43..ec312f0e09cf 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -10769,7 +10769,7 @@ void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf)
pRoamInfo->ampdu = pUpperLayerAssocCnf->ampdu;
pRoamInfo->sgi_enable = pUpperLayerAssocCnf->sgi_enable;
pRoamInfo->tx_stbc = pUpperLayerAssocCnf->tx_stbc;
- pRoamInfo->tx_stbc = pUpperLayerAssocCnf->rx_stbc;
+ pRoamInfo->rx_stbc = pUpperLayerAssocCnf->rx_stbc;
pRoamInfo->ch_width = pUpperLayerAssocCnf->ch_width;
pRoamInfo->mode = pUpperLayerAssocCnf->mode;
pRoamInfo->max_supp_idx = pUpperLayerAssocCnf->max_supp_idx;
diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c
index db2cf6882f61..7aa68046e552 100644
--- a/core/sme/src/csr/csr_api_scan.c
+++ b/core/sme/src/csr/csr_api_scan.c
@@ -1615,24 +1615,17 @@ static bool csr_is_better_bss(tpAniSirGlobal mac_ctx,
return ret;
}
-/* Add the channel to the occupiedChannels array */
-static void csr_scan_add_to_occupied_channels(tpAniSirGlobal pMac,
- struct tag_csrscan_result *pResult,
- uint8_t sessionId,
- tCsrChannel *occupied_ch,
- tDot11fBeaconIEs *pIes,
- bool is_init_list)
+/* Add special channel to the occupiedChannels array */
+static void csr_add_to_occupied_channels(tpAniSirGlobal pMac,
+ uint8_t ch,
+ uint8_t sessionId,
+ tCsrChannel *occupied_ch,
+ bool is_init_list)
{
QDF_STATUS status;
- uint8_t ch;
uint8_t num_occupied_ch = occupied_ch->numChannels;
uint8_t *occupied_ch_lst = occupied_ch->channelList;
- ch = pResult->Result.BssDescriptor.channelId;
- if (!csr_neighbor_roam_connected_profile_match(pMac,
- sessionId, pResult, pIes))
- return;
-
if (is_init_list)
pMac->scan.roam_candidate_count[sessionId]++;
@@ -1653,6 +1646,29 @@ static void csr_scan_add_to_occupied_channels(tpAniSirGlobal pMac,
}
}
+/* Add the channel to the occupiedChannels array */
+static void csr_scan_add_to_occupied_channels(
+ tpAniSirGlobal pMac,
+ struct tag_csrscan_result *pResult,
+ uint8_t sessionId,
+ tCsrChannel *occupied_ch,
+ tDot11fBeaconIEs *pIes,
+ bool is_init_list)
+{
+ uint8_t ch;
+
+ ch = pResult->Result.BssDescriptor.channelId;
+ if (!csr_neighbor_roam_connected_profile_match(pMac, sessionId,
+ pResult, pIes))
+ return;
+ csr_add_to_occupied_channels(
+ pMac,
+ ch,
+ sessionId,
+ occupied_ch,
+ is_init_list);
+}
+
/* Put the BSS into the scan result list */
/* pIes can not be NULL */
static void csr_scan_add_result(tpAniSirGlobal pMac, struct tag_csrscan_result
@@ -8027,6 +8043,7 @@ void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId)
tDot11fBeaconIEs *pIes = NULL;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
+ tCsrRoamConnectedProfile *profile = NULL;
if (0 != pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) {
/*
@@ -8046,10 +8063,20 @@ void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId)
return;
}
+ profile = &pMac->roam.roamSession[sessionId].connectedProfile;
+ if (!profile)
+ return;
+
/* Empty occupied channels here */
pMac->scan.occupiedChannels[sessionId].numChannels = 0;
pMac->scan.roam_candidate_count[sessionId] = 0;
+ csr_add_to_occupied_channels(
+ pMac, profile->operationChannel,
+ sessionId,
+ &pMac->scan.occupiedChannels[sessionId],
+ false);
+
csr_ll_lock(&pMac->scan.scanResultList);
pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
while (pEntry) {
diff --git a/core/utils/logging/src/wlan_logging_sock_svc.c b/core/utils/logging/src/wlan_logging_sock_svc.c
index 4ba9000fe110..d1aa26b0854c 100644
--- a/core/utils/logging/src/wlan_logging_sock_svc.c
+++ b/core/utils/logging/src/wlan_logging_sock_svc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -1149,7 +1149,7 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
- if (!gwlan_logging.pkt_stats_pcur_node || (NULL == pkt_stats_dump)) {
+ if (!gwlan_logging.pkt_stats_pcur_node) {
spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
return;
}
@@ -1182,7 +1182,7 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
pktlog_hdr->size),
data, pktlog_hdr->size);
- if (pkt_stats_dump->type == STOP_MONITOR) {
+ if (pkt_stats_dump && pkt_stats_dump->type == STOP_MONITOR) {
wake_up_thread = true;
wlan_get_pkt_stats_free_node();
}
diff --git a/core/utils/pktlog/pktlog_internal.c b/core/utils/pktlog/pktlog_internal.c
index aafddb42ef4e..72758c4a265c 100644
--- a/core/utils/pktlog/pktlog_internal.c
+++ b/core/utils/pktlog/pktlog_internal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -919,6 +919,7 @@ A_STATUS process_sw_event(void *pdev, void *data)
qdf_mem_copy(sw_event.sw_event,
((char *)fw_data->data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
+ cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, sw_event.sw_event);
return A_OK;
}
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index 03c7a5c91456..252de47335ca 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -1762,6 +1762,7 @@ typedef struct {
#ifdef FEATURE_WLAN_D0WOW
atomic_t in_d0wow;
#endif
+ bool is_pktcapture_enabled;
} t_wma_handle, *tp_wma_handle;
/**
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index 23c60673ed19..bc38ae1ee80a 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -602,6 +602,10 @@ QDF_STATUS wma_vdev_start(tp_wma_handle wma, struct wma_vdev_start_req *req,
void wma_vdev_resp_timer(void *data);
+int wma_set_packet_capture_mode(tp_wma_handle wma_handle,
+ uint8_t vdev_id,
+ uint8_t val);
+
struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma,
uint8_t vdev_id,
uint32_t msg_type, uint8_t type,
@@ -715,6 +719,10 @@ void wma_process_update_userpos(tp_wma_handle wma_handle,
void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle,
tHalHiddenSsidVdevRestart *pReq);
+int
+wma_mgmt_offload_data_event_handler(void *handle, uint8_t *data,
+ uint32_t data_len);
+
/*
* wma_power.c functions declarations
*/
diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c
index 952ac186fb2a..c4818c412a45 100644
--- a/core/wma/src/wma_dev_if.c
+++ b/core/wma/src/wma_dev_if.c
@@ -1455,17 +1455,21 @@ QDF_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev,
/* for each remote ibss peer, clear its keys */
if (wma_is_vdev_in_ibss_mode(wma, vdev_id) &&
qdf_mem_cmp(peer_addr, mac_addr_raw, IEEE80211_ADDR_LEN)) {
- tSetStaKeyParams key_info;
+ tpSetStaKeyParams key_info;
+ key_info = qdf_mem_malloc(sizeof(*key_info));
+ if (!key_info) {
+ return QDF_STATUS_E_NOMEM;
+ }
WMA_LOGD("%s: remote ibss peer %pM key clearing\n", __func__,
peer_addr);
- qdf_mem_set(&key_info, sizeof(key_info), 0);
- key_info.smesessionId = vdev_id;
- qdf_mem_copy(key_info.peer_macaddr.bytes, peer_addr,
+ qdf_mem_set(key_info, sizeof(*key_info), 0);
+ key_info->smesessionId = vdev_id;
+ qdf_mem_copy(key_info->peer_macaddr.bytes, peer_addr,
IEEE80211_ADDR_LEN);
- key_info.sendRsp = false;
+ key_info->sendRsp = false;
- wma_set_stakey(wma, &key_info);
+ wma_set_stakey(wma, key_info);
}
return QDF_STATUS_SUCCESS;
@@ -2211,6 +2215,23 @@ ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle,
if (status != QDF_STATUS_SUCCESS)
WMA_LOGE("failed to set retry threshold(err=%d)",
status);
+
+ if (cds_get_pktcap_mode_enable() &&
+ wma_handle->is_pktcapture_enabled &&
+ (cds_get_pktcapture_mode() != PKT_CAPTURE_MODE_DISABLE)) {
+ uint8_t val = cds_get_pktcapture_mode();
+
+ status = wma_set_packet_capture_mode(
+ wma_handle, vdev_id, val);
+
+ if (status != QDF_STATUS_SUCCESS)
+ WMA_LOGE("failed to set capture mode (err=%d)",
+ status);
+ else if (status == QDF_STATUS_SUCCESS)
+ ol_cfg_set_pktcapture_mode(txrx_pdev->ctrl_pdev,
+ val);
+ }
+
break;
}
@@ -3211,6 +3232,26 @@ void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id,
}
/**
+ * wma_set_packet_capture_mode() - set packet capture mode
+ * @wma: wma handle
+ * @vdev_id: vdev id
+ * @val: mode to set
+ *
+ * Return: 0 on success, errno on failure
+ */
+int wma_set_packet_capture_mode(tp_wma_handle wma_handle,
+ uint8_t vdev_id,
+ uint8_t val)
+{
+ int ret;
+
+ ret = wma_cli_set_command(vdev_id,
+ WMI_VDEV_PARAM_PACKET_CAPTURE_MODE,
+ val, VDEV_CMD);
+ return ret;
+}
+
+/**
* wma_vdev_resp_timer() - wma response timeout function
* @data: target request params
*
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index d9d06e49fb08..693c1b531ea8 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -5263,6 +5263,28 @@ int wma_rx_service_ready_event(void *handle, uint8_t *cmd_param_info,
}
}
+ if (cds_get_pktcap_mode_enable() &&
+ WMI_SERVICE_EXT_IS_ENABLED(
+ wma_handle->wmi_service_bitmap,
+ wma_handle->wmi_service_ext_bitmap,
+ WMI_SERVICE_PACKET_CAPTURE_SUPPORT)) {
+ uint8_t status;
+
+ status = wmi_unified_register_event_handler(
+ wma_handle->wmi_handle,
+ WMI_VDEV_MGMT_OFFLOAD_EVENTID,
+ wma_mgmt_offload_data_event_handler,
+ WMA_RX_SERIALIZER_CTX);
+ if (status) {
+ WMA_LOGE("Failed to register MGMT offload handler");
+ return -EINVAL;
+ }
+ WMI_RSRC_CFG_FLAG_PACKET_CAPTURE_SUPPORT_SET(
+ wma_handle->wlan_resource_config.flag1, 1);
+
+ wma_handle->is_pktcapture_enabled = true;
+ }
+
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_MGMT_TX_WMI)) {
WMA_LOGD("Firmware supports management TX over WMI,use WMI interface instead of HTT for management Tx");
@@ -5298,6 +5320,7 @@ int wma_rx_service_ready_event(void *handle, uint8_t *cmd_param_info,
} else {
WMA_LOGE("FW doesnot support WMI_SERVICE_MGMT_TX_WMI, Use HTT interface for Management Tx");
}
+
#ifdef WLAN_FEATURE_GTK_OFFLOAD
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_GTK_OFFLOAD)) {
diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c
index 919b2543053e..d09813fd949a 100644
--- a/core/wma/src/wma_mgmt.c
+++ b/core/wma/src/wma_mgmt.c
@@ -2181,7 +2181,6 @@ void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info)
key_params.key_len = key_info->key[i].keyLength;
status = wma_setup_install_key_cmd(wma_handle, &key_params,
opmode);
- qdf_mem_zero(&key_params, sizeof(struct wma_set_key_params));
if (status == QDF_STATUS_E_NOMEM) {
WMA_LOGE("%s:Failed to setup install key buf",
__func__);
@@ -2211,9 +2210,12 @@ void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info)
/* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */
key_info->status = QDF_STATUS_SUCCESS;
out:
+ qdf_mem_zero(&key_params, sizeof(struct wma_set_key_params));
if (key_info->sendRsp)
wma_send_msg_high_priority(wma_handle, WMA_SET_STAKEY_RSP,
(void *)key_info, 0);
+ else
+ qdf_mem_free(key_info);
}
/**
@@ -2771,6 +2773,110 @@ static const char *wma_get_status_str(uint32_t status)
}
}
+#define RATE_LIMIT 16
+#define RESERVE_BYTES 100
+
+/**
+ * wma_process_mon_mgmt_tx_data(): process management tx packets
+ * for pkt capture mode
+ * @hdr: wmi_mgmt_hdr
+ * @nbuf: netbuf
+ *
+ * Return: true if pkt is post to thread else false
+ */
+static bool
+wma_process_mon_mgmt_tx_data(wmi_mgmt_hdr *hdr,
+ qdf_nbuf_t nbuf, uint8_t status)
+{
+ struct ol_txrx_pdev_t *pdev_ctx;
+ ol_txrx_mon_callback_fp data_rx = NULL;
+ struct mon_rx_status txrx_status = {0};
+ uint16_t channel_flags = 0;
+
+ pdev_ctx = cds_get_context(QDF_MODULE_ID_TXRX);
+ if (!pdev_ctx) {
+ WMA_LOGE(FL("Failed to get the context"));
+ return false;
+ }
+
+ data_rx = pdev_ctx->mon_cb;
+ if (!data_rx)
+ return false;
+
+ txrx_status.tsft = (u_int64_t)hdr->tsf_l32;
+ txrx_status.chan_num = cds_freq_to_chan(hdr->chan_freq);
+ txrx_status.chan_freq = hdr->chan_freq;
+ /* hdr->rate is in Kbps, convert into Mbps */
+ txrx_status.rate = (hdr->rate_kbps / 1000);
+ txrx_status.ant_signal_db = hdr->rssi;
+ /* RSSI -128 is invalid rssi for TX, add 96 here,
+ * will be normalized during radiotap updation
+ */
+ if (txrx_status.ant_signal_db == -128)
+ txrx_status.ant_signal_db += 96;
+
+ txrx_status.nr_ant = 1;
+ txrx_status.rtap_flags |=
+ ((txrx_status.rate == 6 /* Mbps */) ? BIT(1) : 0);
+ channel_flags |=
+ ((txrx_status.rate == 6 /* Mbps */) ?
+ IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK);
+ channel_flags |=
+ (cds_chan_to_band(txrx_status.chan_num) == CDS_BAND_2GHZ ?
+ IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
+ txrx_status.chan_flags = channel_flags;
+ txrx_status.rate = ((txrx_status.rate == 6 /* Mbps */) ? 0x0c : 0x02);
+
+ return ol_txrx_mon_mgmt_process(&txrx_status, nbuf, status);
+}
+
+static int wma_process_mon_mgmt_tx_completion(tp_wma_handle wma_handle,
+ uint32_t desc_id,
+ uint32_t status,
+ wmi_mgmt_hdr *mgmt_hdr)
+{
+ struct wmi_desc_t *wmi_desc;
+ qdf_nbuf_t wbuf, nbuf;
+ int nbuf_len;
+
+ if (desc_id >= WMI_DESC_POOL_MAX) {
+ WMA_LOGE("%s: Invalid desc id %d", __func__, desc_id);
+ return -EINVAL;
+ }
+
+ WMA_LOGD("%s: status: %s wmi_desc_id: %d", __func__,
+ wma_get_status_str(status), desc_id);
+
+ wmi_desc = (struct wmi_desc_t *)
+ (&wma_handle->wmi_desc_pool.array[desc_id]);
+
+ if (!wmi_desc) {
+ WMA_LOGE("%s: Invalid wmi desc", __func__);
+ return -EINVAL;
+ }
+
+ nbuf = wmi_desc->nbuf;
+ nbuf_len = qdf_nbuf_len(nbuf);
+
+ wbuf = qdf_nbuf_alloc(NULL, roundup(nbuf_len + RESERVE_BYTES, 4),
+ RESERVE_BYTES, 4, false);
+
+ if (!wbuf) {
+ WMA_LOGE("%s: Failed to allocate wbuf for mgmt len(%u)",
+ __func__, nbuf_len);
+ return -ENOMEM;
+ }
+
+ qdf_nbuf_put_tail(wbuf, nbuf_len);
+
+ qdf_mem_copy(qdf_nbuf_data(wbuf), qdf_nbuf_data(nbuf), nbuf_len);
+
+ if (!wma_process_mon_mgmt_tx_data(mgmt_hdr, wbuf, status))
+ qdf_nbuf_free(wbuf);
+
+ return 0;
+}
+
/**
* wma_process_mgmt_tx_completion() - process mgmt completion
* @wma_handle: wma handle
@@ -2838,13 +2944,16 @@ static int wma_process_mgmt_tx_completion(tp_wma_handle wma_handle,
*
* Return: 0 on success; error number otherwise
*/
-
int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params,
uint32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf;
wmi_mgmt_tx_compl_event_fixed_param *cmpl_params;
+ wmi_mgmt_hdr *mgmt_hdr = NULL;
+ ol_txrx_pdev_handle pdev;
+
+ pdev = cds_get_context(QDF_MODULE_ID_TXRX);
param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *)
cmpl_event_params;
@@ -2853,7 +2962,16 @@ int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params,
return -EINVAL;
}
cmpl_params = param_buf->fixed_param;
-
+ if (pdev && cds_get_pktcap_mode_enable() &&
+ (ol_cfg_pktcapture_mode(pdev->ctrl_pdev) &
+ PKT_CAPTURE_MODE_MGMT_ONLY) &&
+ pdev->mon_cb) {
+ mgmt_hdr = (wmi_mgmt_hdr *)(param_buf->mgmt_hdr);
+ wma_process_mon_mgmt_tx_completion(
+ wma_handle,
+ cmpl_params->desc_id,
+ cmpl_params->status, mgmt_hdr);
+ }
wma_process_mgmt_tx_completion(wma_handle,
cmpl_params->desc_id, cmpl_params->status);
@@ -2879,6 +2997,10 @@ int wma_mgmt_tx_bundle_completion_handler(void *handle, uint8_t *buf,
uint32_t *status;
uint32_t i, buf_len;
bool excess_data = false;
+ wmi_mgmt_hdr *mgmt_hdr = NULL;
+ ol_txrx_pdev_handle pdev;
+
+ pdev = cds_get_context(QDF_MODULE_ID_TXRX);
param_buf = (WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID_param_tlvs *)buf;
if (!param_buf || !wma_handle) {
@@ -2914,7 +3036,16 @@ int wma_mgmt_tx_bundle_completion_handler(void *handle, uint8_t *buf,
param_buf->num_status);
return -EINVAL;
}
-
+ if (pdev && cds_get_pktcap_mode_enable() &&
+ (ol_cfg_pktcapture_mode(pdev->ctrl_pdev) &
+ PKT_CAPTURE_MODE_MGMT_ONLY) &&
+ pdev->mon_cb) {
+ mgmt_hdr = (wmi_mgmt_hdr *)(param_buf->mgmt_hdr);
+ for (i = 0; i < num_reports; i++)
+ wma_process_mon_mgmt_tx_completion(
+ wma_handle, desc_ids[i],
+ status[i], &mgmt_hdr[i]);
+ }
for (i = 0; i < num_reports; i++)
wma_process_mgmt_tx_completion(wma_handle,
desc_ids[i], status[i]);
@@ -3506,6 +3637,54 @@ static inline int wma_process_rmf_frame(tp_wma_handle wma_handle,
#endif
/**
+ * wma_process_mon_mgmt_rx_data(): process management rx packets
+ * for pkt capture mode
+ * @hdr: wmi_mgmt_rx_hdr
+ * @nbuf: netbuf
+ *
+ * Return: true if pkt is post to thread else false
+ */
+static bool
+wma_process_mon_mgmt_rx_data(wmi_mgmt_rx_hdr *hdr,
+ qdf_nbuf_t nbuf)
+{
+ struct ol_txrx_pdev_t *pdev_ctx;
+ ol_txrx_mon_callback_fp data_rx = NULL;
+ struct mon_rx_status txrx_status = {0};
+ uint16_t channel_flags = 0;
+
+ pdev_ctx = cds_get_context(QDF_MODULE_ID_TXRX);
+ if (!pdev_ctx) {
+ WMA_LOGE(FL("Failed to get the context"));
+ return false;
+ }
+
+ data_rx = pdev_ctx->mon_cb;
+ if (!data_rx)
+ return false;
+
+ txrx_status.tsft = (u_int64_t)hdr->rx_tsf_l32;
+ txrx_status.chan_num = hdr->channel;
+ txrx_status.chan_freq = cds_chan_to_freq(txrx_status.chan_num);
+ /* hdr->rate is in Kbps, convert into Mbps */
+ txrx_status.rate = (hdr->rate / 1000);
+ txrx_status.ant_signal_db = hdr->snr;
+ txrx_status.nr_ant = 1;
+ txrx_status.rtap_flags |=
+ ((txrx_status.rate == 6 /* Mbps */) ? BIT(1) : 0);
+ channel_flags |=
+ ((txrx_status.rate == 6 /* Mbps */) ?
+ IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK);
+ channel_flags |=
+ (cds_chan_to_band(txrx_status.chan_num) == CDS_BAND_2GHZ ?
+ IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
+ txrx_status.chan_flags = channel_flags;
+ txrx_status.rate = ((txrx_status.rate == 6 /* Mbps */) ? 0x0c : 0x02);
+
+ return ol_txrx_mon_mgmt_process(&txrx_status, nbuf, 0);
+}
+
+/**
* wma_is_pkt_drop_candidate() - check if the mgmt frame should be droppped
* @wma_handle: wma handle
* @peer_addr: peer MAC address
@@ -3602,8 +3781,105 @@ end:
return should_drop;
}
-#define RATE_LIMIT 16
-#define RESERVE_BYTES 100
+/**
+ * wma_mgmt_offload_data_event_handler() - process management offload frame.
+ * @handle: wma handle
+ * @data: mgmt data
+ * @data_len: data length
+ *
+ * Return: 0 for success or error code
+ */
+int
+wma_mgmt_offload_data_event_handler(void *handle, uint8_t *data,
+ uint32_t data_len)
+{
+ tp_wma_handle wma_handle = (tp_wma_handle)handle;
+ WMI_VDEV_MGMT_OFFLOAD_EVENTID_param_tlvs *param_tlvs = NULL;
+ wmi_mgmt_hdr *hdr = NULL;
+ static uint8_t limit_prints_invalid_len = RATE_LIMIT - 1;
+ static uint8_t limit_prints_load_unload = RATE_LIMIT - 1;
+ static uint8_t limit_prints_recovery = RATE_LIMIT - 1;
+ uint8_t status;
+ qdf_nbuf_t wbuf;
+
+ if (!wma_handle) {
+ WMA_LOGE("%s: Failed to get WMA context", __func__);
+ return -EINVAL;
+ }
+
+ param_tlvs = (WMI_VDEV_MGMT_OFFLOAD_EVENTID_param_tlvs *)data;
+ if (!param_tlvs) {
+ WMA_LOGE("Get NULL point message from FW");
+ return -EINVAL;
+ }
+
+ hdr = param_tlvs->fixed_param;
+ if (!hdr) {
+ WMA_LOGE("Offload data event is NULL");
+ return -EINVAL;
+ }
+
+ if (hdr->buf_len > param_tlvs->num_bufp) {
+ WMA_LOGE(
+ "Invalid frame len hdr->buf_len:%u, param_tlvs->num_bufp:%u",
+ hdr->buf_len, param_tlvs->num_bufp);
+ return -EINVAL;
+ }
+ if (hdr->buf_len < sizeof(struct ieee80211_frame) ||
+ hdr->buf_len > data_len) {
+ limit_prints_invalid_len++;
+ if (limit_prints_invalid_len == RATE_LIMIT) {
+ WMA_LOGD(
+ "Invalid mgmt packet, data_len %u, hdr->buf_len %u",
+ data_len, hdr->buf_len);
+ limit_prints_invalid_len = 0;
+ }
+ return -EINVAL;
+ }
+
+ if (cds_is_load_or_unload_in_progress()) {
+ limit_prints_load_unload++;
+ if (limit_prints_load_unload == RATE_LIMIT) {
+ WMA_LOGD(FL("Load/Unload in progress"));
+ limit_prints_load_unload = 0;
+ }
+ return -EINVAL;
+ }
+
+ if (cds_is_driver_recovering()) {
+ limit_prints_recovery++;
+ if (limit_prints_recovery == RATE_LIMIT) {
+ WMA_LOGD(FL("Recovery in progress"));
+ limit_prints_recovery = 0;
+ }
+ return -EINVAL;
+ }
+
+ if (cds_is_driver_in_bad_state()) {
+ WMA_LOGW(FL("Driver in bad state"));
+ return -EINVAL;
+ }
+
+ wbuf = qdf_nbuf_alloc(NULL,
+ roundup(hdr->buf_len + RESERVE_BYTES, 4),
+ RESERVE_BYTES, 4, false);
+ if (!wbuf) {
+ WMA_LOGE("%s: Failed to allocate wbuf for mgmt pkt len(%u)",
+ __func__, hdr->buf_len);
+ return -ENOMEM;
+ }
+
+ qdf_nbuf_put_tail(wbuf, hdr->buf_len);
+ qdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL);
+ qdf_mem_copy(qdf_nbuf_data(wbuf), param_tlvs->bufp, hdr->buf_len);
+
+ status = hdr->tx_status;
+ if (!wma_process_mon_mgmt_tx_data(hdr, wbuf, status))
+ qdf_nbuf_free(wbuf);
+
+ return 0;
+}
+
/**
* wma_mgmt_rx_process() - process management rx frame.
* @handle: wma handle
@@ -3620,7 +3896,8 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data,
wmi_mgmt_rx_hdr *hdr = NULL;
uint8_t vdev_id = WMA_INVALID_VDEV_ID;
cds_pkt_t *rx_pkt;
- qdf_nbuf_t wbuf;
+ ol_txrx_pdev_handle pdev;
+ qdf_nbuf_t wbuf, nbuf;
struct ieee80211_frame *wh;
uint8_t mgt_type, mgt_subtype;
struct wma_txrx_node *iface = NULL;
@@ -3634,6 +3911,7 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data,
WMA_LOGE("%s: Failed to get WMA context", __func__);
return -EINVAL;
}
+ pdev = cds_get_context(QDF_MODULE_ID_TXRX);
param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) data;
if (!param_tlvs) {
@@ -3883,7 +4161,31 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data,
packetdump_cb(rx_pkt->pkt_buf, QDF_STATUS_SUCCESS,
rx_pkt->pkt_meta.sessionId, RX_MGMT_PKT);
+ if (pdev && cds_get_pktcap_mode_enable() &&
+ (ol_cfg_pktcapture_mode(pdev->ctrl_pdev) &
+ PKT_CAPTURE_MODE_MGMT_ONLY)) {
+ if (pdev->mon_cb) {
+ nbuf = qdf_nbuf_alloc(NULL, roundup(
+ hdr->buf_len + RESERVE_BYTES, 4),
+ RESERVE_BYTES, 4, false);
+ if (nbuf) {
+ qdf_nbuf_put_tail(nbuf, hdr->buf_len);
+ qdf_mem_copy(qdf_nbuf_data(nbuf),
+ qdf_nbuf_data(wbuf),
+ hdr->buf_len);
+ if (!wma_process_mon_mgmt_rx_data(hdr, nbuf))
+ qdf_nbuf_free(nbuf);
+ }
+ }
+ if (hdr->status & WMI_RX_OFFLOAD_MON_MODE) {
+ /* It is offloaded mgmt pkt, drop here */
+ cds_pkt_return_packet(rx_pkt);
+ return 0;
+ }
+ }
+
wma_handle->mgmt_rx(wma_handle, rx_pkt);
+
return 0;
}
diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c
index 3bb9e2e049d7..2d03ba804e8f 100644
--- a/core/wma/src/wma_scan_roam.c
+++ b/core/wma/src/wma_scan_roam.c
@@ -3001,6 +3001,30 @@ static void wma_roam_remove_self_reassoc(tp_wma_handle wma, uint32_t vdev_id)
}
/**
+ * wma_get_phy_mode: get current PHY Mode
+ * @chan: channel number
+ * @chan_width: maximum channel width possible
+ * @phy_mode: PHY Mode
+ *
+ * Return: None
+ */
+static
+void wma_get_phy_mode(uint8_t chan, uint32_t chan_width, uint32_t *phy_mode)
+{
+ uint32_t dot11_mode;
+ struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE);
+
+ if (!mac) {
+ WMA_LOGE("MAC context is NULL");
+ *phy_mode = MODE_UNKNOWN;
+ return;
+ }
+
+ wlan_cfg_get_int(mac, WNI_CFG_DOT11_MODE, &dot11_mode);
+ *phy_mode = wma_chan_phy_mode(chan, chan_width, dot11_mode);
+}
+
+/**
* wma_roam_synch_event_handler() - roam synch event handler
* @handle: wma handle
* @event: event data
@@ -3019,6 +3043,7 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event,
tp_wma_handle wma = (tp_wma_handle) handle;
roam_offload_synch_ind *roam_synch_ind_ptr = NULL;
tpSirBssDescription bss_desc_ptr = NULL;
+ uint8_t channel;
uint16_t ie_len = 0;
int status = -EINVAL;
tSirRoamOffloadScanReq *roam_req;
@@ -3216,6 +3241,20 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event,
wma->interfaces[synch_event->vdev_id].chan_width =
roam_synch_ind_ptr->join_rsp->vht_channel_width;
+ /*
+ * update phy_mode in wma to avoid mismatch in phymode between
+ * host and firmware. The phymode stored in
+ * interface[vdev_id].chanmode is sent to firmware as part of
+ * opmode update during either - vht opmode action frame received
+ * or during opmode change detected while processing beacon.
+ * Any mismatch of this value with firmware phymode results in
+ * firmware assert.
+ */
+ channel = cds_freq_to_chan(wma->interfaces[synch_event->vdev_id].mhz);
+ wma_get_phy_mode(channel,
+ wma->interfaces[synch_event->vdev_id].chan_width,
+ &wma->interfaces[synch_event->vdev_id].chanmode);
+
wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context,
roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_COMPLETE);
wma->interfaces[synch_event->vdev_id].roam_synch_delay =
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index 7fc33d40bf42..201734cf9b2f 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -1113,7 +1113,6 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
tSirLLStatsResults *link_stats_results;
wmi_chan_cca_stats *wmi_cca_stats;
wmi_peer_signal_stats *wmi_peer_signal;
- wmi_peer_ac_rx_stats *wmi_peer_rx;
struct sir_wifi_ll_ext_stats *ll_stats;
struct sir_wifi_ll_ext_peer_stats *peer_stats;
struct sir_wifi_chan_cca_stats *cca_stats;
@@ -1157,7 +1156,6 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
}
wmi_cca_stats = param_buf->chan_cca_stats;
wmi_peer_signal = param_buf->peer_signal_stats;
- wmi_peer_rx = param_buf->peer_ac_rx_stats;
if (fixed_param->num_peer_signal_stats >
param_buf->num_peer_signal_stats ||
fixed_param->num_peer_ac_tx_stats >
@@ -1204,10 +1202,15 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
ll_stats->peer_num = peer_num;
result = (uint8_t *)ll_stats->stats;
+ if (!result) {
+ WMA_LOGE("%s: result is null", __func__);
+ qdf_mem_free(link_stats_results);
+ return -EINVAL;
+ }
peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result;
ll_stats->peer_stats = peer_stats;
- for (i = 0; i < peer_num; i++) {
+ for (i = 0; i < peer_num && peer_stats; i++) {
peer_stats[i].peer_id = WIFI_INVALID_PEER_ID;
peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID;
}
@@ -1215,7 +1218,10 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
/* Per peer signal */
result_size -= sizeof(struct sir_wifi_ll_ext_stats);
dst_len = sizeof(struct sir_wifi_peer_signal_stats);
- for (i = 0; i < fixed_param->num_peer_signal_stats; i++) {
+ for (i = 0;
+ i < fixed_param->num_peer_signal_stats &&
+ peer_stats && wmi_peer_signal;
+ i++) {
peer_stats[i].peer_id = wmi_peer_signal->peer_id;
peer_stats[i].vdev_id = wmi_peer_signal->vdev_id;
peer_signal = &peer_stats[i].peer_signal_stats;
@@ -1223,7 +1229,7 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
WMA_LOGD("%d antennas for peer %d",
wmi_peer_signal->num_chains_valid,
wmi_peer_signal->peer_id);
- if (dst_len <= result_size) {
+ if (dst_len <= result_size && peer_signal) {
peer_signal->vdev_id = wmi_peer_signal->vdev_id;
peer_signal->peer_id = wmi_peer_signal->peer_id;
peer_signal->num_chain =
@@ -1264,15 +1270,30 @@ static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats);
cca_stats = (struct sir_wifi_chan_cca_stats *)result;
ll_stats->cca = cca_stats;
- dst_len = sizeof(struct sir_wifi_chan_cca_stats);
- for (i = 0; i < ll_stats->channel_num; i++) {
+ dst_len = sizeof(*cca_stats);
+ for (i = 0;
+ i < ll_stats->channel_num && cca_stats && wmi_cca_stats;
+ i++) {
if (dst_len <= result_size) {
- qdf_mem_copy(&cca_stats[i], &wmi_cca_stats->vdev_id,
- dst_len);
+ cca_stats->vdev_id = wmi_cca_stats->vdev_id;
+ cca_stats->idle_time = wmi_cca_stats->idle_time;
+ cca_stats->tx_time = wmi_cca_stats->tx_time;
+ cca_stats->rx_in_bss_time =
+ wmi_cca_stats->rx_in_bss_time;
+ cca_stats->rx_out_bss_time =
+ wmi_cca_stats->rx_out_bss_time;
+ cca_stats->rx_busy_time = wmi_cca_stats->rx_busy_time;
+ cca_stats->rx_in_bad_cond_time =
+ wmi_cca_stats->rx_in_bad_cond_time;
+ cca_stats->tx_in_bad_cond_time =
+ wmi_cca_stats->tx_in_bad_cond_time;
+ cca_stats->wlan_not_avail_time =
+ wmi_cca_stats->wlan_not_avail_time;
result_size -= dst_len;
} else {
WMA_LOGE(FL("Invalid length of CCA."));
}
+ cca_stats++;
}
result += i * sizeof(struct sir_wifi_chan_cca_stats);
@@ -3289,6 +3310,14 @@ int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info,
buf_len += event->num_peer_stats * sizeof(*peer_stats);
}
+ if (buf_len > param_buf->num_data) {
+ WMA_LOGE("%s: num_data: %d Invalid num_pdev_stats:%d or num_vdev_stats:%d or num_peer_stats:%d",
+ __func__, param_buf->num_data,
+ event->num_pdev_stats,
+ event->num_vdev_stats, event->num_peer_stats);
+ return -EINVAL;
+ }
+
rssi_event =
(wmi_per_chain_rssi_stats *) param_buf->chain_stats;
if (rssi_event) {
@@ -3309,7 +3338,6 @@ int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info,
WMA_LOGE("excess wmi buffer: stats pdev %d vdev %d peer %d",
event->num_pdev_stats, event->num_vdev_stats,
event->num_peer_stats);
- QDF_ASSERT(0);
return -EINVAL;
}