diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2019-06-01 23:03:34 -0700 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2019-06-01 23:03:34 -0700 |
| commit | 3c316fb43ebffd16b407f8a2cf9f52e2800d2b18 (patch) | |
| tree | a1a0c60d92ebc70b878bb3cf5dcae4c60a44218f | |
| parent | e634d1741b5ee45ecde55af2df3d803aa70382a1 (diff) | |
| parent | ab9f60b51d5e33daaaf95bff8fa07ce604a18223 (diff) | |
Merge ab9f60b51d5e33daaaf95bff8fa07ce604a18223 on remote branch
Change-Id: I1f2ce847514a862506ba913d901cf4247ec2d03c
55 files changed, 3062 insertions, 299 deletions
@@ -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; } |
