From aa481cc459ee07a55091eb92ae2053a23e7b15ba Mon Sep 17 00:00:00 2001 From: Vulupala Shashank Reddy Date: Wed, 12 Feb 2020 09:30:18 +0530 Subject: [PATCH] qcacld-3.0: Create mon thread for packet capture Create mon thread to process the packets for packet capture. Change-Id: I0c83b17273f140970b4feea49cd42da4c540046b CRs-Fixed: 2618657 --- Kbuild | 1 + .../core/inc/wlan_pkt_capture_mon_thread.h | 208 ++++++++ .../core/inc/wlan_pkt_capture_priv.h | 3 + .../core/src/wlan_pkt_capture_main.c | 69 +++ .../core/src/wlan_pkt_capture_mon_thread.c | 460 ++++++++++++++++++ .../inc/wlan_pkt_capture_ucfg_api.h | 32 +- .../src/wlan_pkt_capture_ucfg_api.c | 11 + 7 files changed, 783 insertions(+), 1 deletion(-) create mode 100644 components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h create mode 100644 components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c diff --git a/Kbuild b/Kbuild index a0fcd88f66b9..c5ac2a1714a9 100644 --- a/Kbuild +++ b/Kbuild @@ -1048,6 +1048,7 @@ PKT_CAPTURE_INC := -I$(WLAN_ROOT)/$(PKT_CAPTURE_DIR)/core/inc \ ifeq ($(CONFIG_WLAN_FEATURE_PKT_CAPTURE), y) PKT_CAPTURE_OBJS := $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_main.o \ + $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_mon_thread.o \ $(PKT_CAPTURE_DIR)/dispatcher/src/wlan_pkt_capture_ucfg_api.o endif diff --git a/components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h b/components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h new file mode 100644 index 000000000000..5c28d56dfe0d --- /dev/null +++ b/components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2020 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 + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare APIs which shall be used for monitor thread access. + */ + +#ifndef _WLAN_PKT_CAPTURE_MON_THREAD_H_ +#define _WLAN_PKT_CAPTURE_MON_THREAD_H_ + +#include "wlan_pkt_capture_main.h" + +#define PKT_CAPTURE_RX_POST_EVENT 0x01 +#define PKT_CAPTURE_RX_SUSPEND_EVENT 0x02 +#define PKT_CAPTURE_RX_SHUTDOWN_EVENT 0x04 + +/* + * Maximum number of packets to be allocated for + * Packet Capture Monitor thread. + */ +#define MAX_MON_PKT_SIZE 4000 + +/* timeout in msec to wait for mon thread to suspend */ +#define PKT_CAPTURE_SUSPEND_TIMEOUT 200 + +typedef void (*pkt_capture_mon_thread_cb)(void *context, void *monpkt, + uint8_t vdev_id, uint8_t tid, + uint8_t status, bool pkt_format); + +/* + * struct pkt_capture_mon_pkt - mon packet wrapper for mon data from TXRX + * @list: List for storing mon packets + * @context: Callback context + * @monpkt: Mon skb + * @vdev_id: Vdev id to which this packet is destined + * @tid: Tid of mon packet + * @status: Tx packet status + * @pkt_format: Mon packet format, 0 = 802.3 format , 1 = 802.11 format + * @callback: Mon callback + */ +struct pkt_capture_mon_pkt { + struct list_head list; + void *context; + void *monpkt; + uint8_t vdev_id; + uint8_t tid; + uint8_t status; + bool pkt_format; + pkt_capture_mon_thread_cb callback; +}; + +/** + * struct pkt_capture_mon_context - packet capture mon thread context + * @mon_thread_lock: MON thread lock + * @mon_thread: MON thread handle + * @mon_start_event: Handle of Event for MON thread to signal startup + * @suspend_mon_event: Completion to suspend packet capture MON thread + * @resume_mon_event: Completion to resume packet capture MON thread + * @mon_shutdown: Completion for packet capture MON thread shutdown + * @mon_wait_queue: Waitq for packet capture MON thread + * @mon_event_flag: Mon event flag + * @mon_thread_queue: MON buffer queue + * @mon_queue_lock: Spinlock to synchronize between tasklet and thread + * @mon_pkt_freeq_lock: Lock to synchronize free buffer queue access + * @mon_pkt_freeq: Free message queue for packet capture MON processing + * @is_mon_thread_suspended: flag to check mon thread suspended or not + */ +struct pkt_capture_mon_context { + /* MON thread lock */ + spinlock_t mon_thread_lock; + struct task_struct *mon_thread; + struct completion mon_start_event; + struct completion suspend_mon_event; + struct completion resume_mon_event; + struct completion mon_shutdown; + wait_queue_head_t mon_wait_queue; + unsigned long mon_event_flag; + struct list_head mon_thread_queue; + + /* Spinlock to synchronize between tasklet and thread */ + spinlock_t mon_queue_lock; + + /* Lock to synchronize free buffer queue access */ + spinlock_t mon_pkt_freeq_lock; + + struct list_head mon_pkt_freeq; + bool is_mon_thread_suspended; +}; + +/** + * pkt_capture_suspend_mon_thread() - suspend packet capture mon thread + * vdev: pointer to vdev object manager + * + * Return: 0 on success, -EINVAL on failure + */ +int pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_resume_mon_thread() - resume packet capture mon thread + * vdev: pointer to vdev object manager + * + * Resume packet capture MON thread by completing RX thread resume event. + * + * Return: None + */ +void pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_drop_monpkt() - API to drop pending mon packets + * mon_ctx: pointer to packet capture mon context + * + * This api drops all the pending packets in the queue. + * + * Return: None + */ +void pkt_capture_drop_monpkt(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_indicate_monpkt() - API to Indicate rx data packet + * @vdev: pointer to vdev object manager + * @pkt: MON pkt pointer containing to mon data message buffer + * + * Return: None + */ +void pkt_capture_indicate_monpkt(struct wlan_objmgr_vdev *vdev, + struct pkt_capture_mon_pkt *pkt); + +/** + * pkt_capture_wakeup_mon_thread() - wakeup packet capture mon thread + * @vdev: pointer to vdev object + * + * This api wake up pkt_capture_mon_thread() to process pkt. + * + * Return: None + */ +void pkt_capture_wakeup_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_close_mon_thread() - close packet capture MON thread + * @mon_ctx: pointer to packet capture mon context + * + * This api closes packet capture MON thread. + * + * Return: None + */ +void pkt_capture_close_mon_thread(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_open_mon_thread() - open packet capture MON thread + * @mon_ctx: pointer to packet capture mon context + * + * This api opens the packet capture MON thread. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_open_mon_thread(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_alloc_mon_thread() - alloc resources for + * packet capture MON thread + * @mon_ctx: pointer to packet capture mon context + * + * This api alloc resources for packet capture MON thread. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_alloc_mon_thread(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_alloc_mon_pkt() - API to return next available mon packet + * @vdev: pointer to vdev object manager + * + * This api returns next available mon packet buffer used for mon data + * processing. + * + * Return: Pointer to pkt_capture_mon_pkt + */ +struct pkt_capture_mon_pkt * +pkt_capture_alloc_mon_pkt(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_free_mon_pkt_freeq() - free mon packet free queue + * @mon_ctx: pointer to packet capture mon context + * + * This API does mem free of the buffers available in free mon packet + * queue which is used for mon Data processing. + * + * Return: None + */ +void pkt_capture_free_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx); +#endif /* _WLAN_PKT_CAPTURE_MON_THREAD_H_ */ diff --git a/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h b/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h index a83b4f555763..4ab781232f91 100644 --- a/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h +++ b/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h @@ -29,6 +29,7 @@ #include "wlan_pkt_capture_objmgr.h" #include "wlan_pkt_capture_public_structs.h" +#include "wlan_pkt_capture_mon_thread.h" /** * struct pkt_capture_cfg - packet capture cfg to store ini values @@ -41,9 +42,11 @@ struct pkt_capture_cfg { /** * struct pkt_capture_vdev_priv - Private object to be stored in vdev * @vdev: pointer to vdev object + * @pkt_capture_mon_ctx: pointer to packet capture mon context */ struct pkt_capture_vdev_priv { struct wlan_objmgr_vdev *vdev; + struct pkt_capture_mon_context *mon_ctx; }; /** diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_main.c b/components/pkt_capture/core/src/wlan_pkt_capture_main.c index d64934664f20..b57a7d7995f2 100644 --- a/components/pkt_capture/core/src/wlan_pkt_capture_main.c +++ b/components/pkt_capture/core/src/wlan_pkt_capture_main.c @@ -23,6 +23,7 @@ #include "wlan_pkt_capture_main.h" #include "cfg_ucfg_api.h" +#include "wlan_pkt_capture_mon_thread.h" enum pkt_capture_mode pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) { @@ -42,6 +43,44 @@ enum pkt_capture_mode pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) return psoc_priv->cfg_param.pkt_capture_mode; } +/** + * pkt_capture_mon_context_create() - Create packet capture mon context + * @vdev_priv: pointer to packet capture vdev priv obj + * + * This function allocates memory for packet capture mon context + * + * Return: QDF_STATUS + */ +static QDF_STATUS +pkt_capture_mon_context_create(struct pkt_capture_vdev_priv *vdev_priv) +{ + struct pkt_capture_mon_context *mon_context; + + mon_context = qdf_mem_malloc(sizeof(*mon_context)); + if (!mon_context) { + pkt_capture_err("MON context create failed"); + return QDF_STATUS_E_NOMEM; + } + + vdev_priv->mon_ctx = mon_context; + + return QDF_STATUS_SUCCESS; +} + +/** + * pkt_capture_mon_context_destroy() - Destroy packet capture mon context + * @vdev_priv: pointer to packet capture vdev priv obj + * + * Free packet capture mon context + * + * Return: None + */ +static void +pkt_capture_mon_context_destroy(struct pkt_capture_vdev_priv *vdev_priv) +{ + qdf_mem_free(vdev_priv->mon_ctx); +} + /** * pkt_capture_cfg_init() - Initialize packet capture cfg ini params * @psoc_priv: psoc private object @@ -62,6 +101,7 @@ pkt_capture_cfg_init(struct pkt_psoc_priv *psoc_priv) QDF_STATUS pkt_capture_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) { + struct pkt_capture_mon_context *mon_ctx; struct pkt_capture_vdev_priv *vdev_priv; QDF_STATUS status; @@ -79,8 +119,35 @@ pkt_capture_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) } vdev_priv->vdev = vdev; + + status = pkt_capture_mon_context_create(vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to create mon context"); + goto detach_vdev_priv; + } + mon_ctx = vdev_priv->mon_ctx; + + status = pkt_capture_alloc_mon_thread(mon_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to alloc mon thread"); + goto destroy_mon_context; + } + + status = pkt_capture_open_mon_thread(mon_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to open mon thread"); + goto open_mon_thread_fail; + } return status; +open_mon_thread_fail: + pkt_capture_free_mon_pkt_freeq(mon_ctx); +destroy_mon_context: + pkt_capture_mon_context_destroy(vdev_priv); +detach_vdev_priv: + wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_PKT_CAPTURE, + vdev_priv); free_vdev_priv: qdf_mem_free(vdev_priv); return status; @@ -105,6 +172,8 @@ pkt_capture_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) if (QDF_IS_STATUS_ERROR(status)) pkt_capture_err("Failed to detach vdev component obj"); + pkt_capture_close_mon_thread(vdev_priv->mon_ctx); + pkt_capture_mon_context_destroy(vdev_priv); qdf_mem_free(vdev_priv); return status; } diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c b/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c new file mode 100644 index 000000000000..7a3e80f40d32 --- /dev/null +++ b/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2020 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 + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Define internal APIs related to the packet capture component + */ + +#include "wlan_pkt_capture_priv.h" +#include + +void pkt_capture_free_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt; + + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + while (!list_empty(&mon_ctx->mon_pkt_freeq)) { + pkt = list_entry((&mon_ctx->mon_pkt_freeq)->next, + typeof(*pkt), list); + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + } + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); +} + +/** + * pkt_capture_alloc_mon_pkt_freeq() - Function to allocate free buffer queue + * @mon_ctx: pointer to packet capture mon context + * + * This API allocates MAX_MON_PKT_SIZE number of mon packets + * which are used for mon data processing. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +pkt_capture_alloc_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt, *tmp; + int i; + + for (i = 0; i < MAX_MON_PKT_SIZE; i++) { + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + pkt_capture_err("mon packet freeq allocation fail"); + goto free; + } + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + list_add_tail(&pkt->list, + &mon_ctx->mon_pkt_freeq); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + } + + return QDF_STATUS_SUCCESS; +free: + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, + &mon_ctx->mon_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + } + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + + return QDF_STATUS_E_NOMEM; +} + +/** + * pkt_capture_free_mon_pkt() - api to release mon packet to the freeq + * @mon_ctx: Pointer to packet capture mon context + * @pkt: MON packet buffer to be returned to free queue. + * + * This api returns the mon packet used for mon data to the free queue + * + * Return: None + */ +static void +pkt_capture_free_mon_pkt(struct pkt_capture_mon_context *mon_ctx, + struct pkt_capture_mon_pkt *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + list_add_tail(&pkt->list, &mon_ctx->mon_pkt_freeq); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); +} + +struct pkt_capture_mon_pkt * +pkt_capture_alloc_mon_pkt(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + struct pkt_capture_mon_pkt *pkt; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return NULL; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return NULL; + } + + mon_ctx = vdev_priv->mon_ctx; + if (!mon_ctx) { + pkt_capture_err("packet capture mon context is NULL"); + return NULL; + } + + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + if (list_empty(&mon_ctx->mon_pkt_freeq)) { + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + return NULL; + } + + pkt = list_first_entry(&mon_ctx->mon_pkt_freeq, + struct pkt_capture_mon_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + + return pkt; +} + +void pkt_capture_indicate_monpkt(struct wlan_objmgr_vdev *vdev, + struct pkt_capture_mon_pkt *pkt) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + mon_ctx = vdev_priv->mon_ctx; + + spin_lock_bh(&mon_ctx->mon_queue_lock); + list_add_tail(&pkt->list, &mon_ctx->mon_thread_queue); + spin_unlock_bh(&mon_ctx->mon_queue_lock); + set_bit(PKT_CAPTURE_RX_POST_EVENT, &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); +} + +void pkt_capture_wakeup_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + mon_ctx = vdev_priv->mon_ctx; + + set_bit(PKT_CAPTURE_RX_POST_EVENT, &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); +} + +/** + * pkt_capture_process_from_queue() - function to process pending mon packets + * @mon_ctx: Pointer to packet capture mon 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 +pkt_capture_process_from_queue(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt; + uint8_t vdev_id; + uint8_t tid; + + spin_lock_bh(&mon_ctx->mon_queue_lock); + while (!list_empty(&mon_ctx->mon_thread_queue)) { + pkt = list_first_entry(&mon_ctx->mon_thread_queue, + struct pkt_capture_mon_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->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); + pkt_capture_free_mon_pkt(mon_ctx, pkt); + spin_lock_bh(&mon_ctx->mon_queue_lock); + } + spin_unlock_bh(&mon_ctx->mon_queue_lock); +} + +/** + * pkt_capture_mon_thread() - packet capture mon thread + * @arg: Pointer to vdev object manager + * + * This api is the thread handler for mon Data packet processing. + * + * Return: thread exit code + */ +static int pkt_capture_mon_thread(void *arg) +{ + struct pkt_capture_mon_context *mon_ctx; + unsigned long pref_cpu = 0; + bool shutdown = false; + int status, i; + + if (!arg) { + pkt_capture_err("Bad Args passed to mon thread"); + return 0; + } + mon_ctx = (struct pkt_capture_mon_context *)arg; + 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; + } + + set_cpus_allowed_ptr(current, cpumask_of(pref_cpu)); + + complete(&mon_ctx->mon_start_event); + + while (!shutdown) { + status = + wait_event_interruptible(mon_ctx->mon_wait_queue, + test_bit(PKT_CAPTURE_RX_POST_EVENT, + &mon_ctx->mon_event_flag) || + test_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag)); + if (status == -ERESTARTSYS) + break; + + clear_bit(PKT_CAPTURE_RX_POST_EVENT, + &mon_ctx->mon_event_flag); + while (true) { + if (test_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT, + &mon_ctx->mon_event_flag)) { + clear_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT, + &mon_ctx->mon_event_flag); + if (test_bit( + PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag)) { + clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + complete(&mon_ctx->suspend_mon_event); + } + pkt_capture_info("Shutting down pktcap thread"); + shutdown = true; + break; + } + pkt_capture_process_from_queue(mon_ctx); + + if (test_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag)) { + clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + spin_lock(&mon_ctx->mon_thread_lock); + INIT_COMPLETION(mon_ctx->resume_mon_event); + complete(&mon_ctx->suspend_mon_event); + spin_unlock(&mon_ctx->mon_thread_lock); + wait_for_completion_interruptible + (&mon_ctx->resume_mon_event); + } + break; + } + } + pkt_capture_debug("Exiting packet capture mon thread"); + complete_and_exit(&mon_ctx->mon_shutdown, 0); + + return 0; +} + +void pkt_capture_close_mon_thread(struct pkt_capture_mon_context *mon_ctx) +{ + if (!mon_ctx->mon_thread) + return; + + /* Shut down Tlshim Rx thread */ + set_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT, + &mon_ctx->mon_event_flag); + set_bit(PKT_CAPTURE_RX_POST_EVENT, + &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); + wait_for_completion(&mon_ctx->mon_shutdown); + mon_ctx->mon_thread = NULL; + pkt_capture_drop_monpkt(mon_ctx); + pkt_capture_free_mon_pkt_freeq(mon_ctx); +} + +QDF_STATUS +pkt_capture_open_mon_thread(struct pkt_capture_mon_context *mon_ctx) +{ + mon_ctx->mon_thread = kthread_create(pkt_capture_mon_thread, + mon_ctx, + "pkt_capture_mon_thread"); + + if (IS_ERR(mon_ctx->mon_thread)) { + pkt_capture_fatal("Could not Create packet capture mon thread"); + return QDF_STATUS_E_FAILURE; + } + wake_up_process(mon_ctx->mon_thread); + pkt_capture_debug("packet capture MON thread Created"); + + wait_for_completion_interruptible(&mon_ctx->mon_start_event); + pkt_capture_debug("packet capture MON Thread has started"); + + return QDF_STATUS_SUCCESS; +} + +void pkt_capture_drop_monpkt(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt, *tmp; + struct list_head local_list; + qdf_nbuf_t buf, next_buf; + + INIT_LIST_HEAD(&local_list); + spin_lock_bh(&mon_ctx->mon_queue_lock); + if (list_empty(&mon_ctx->mon_thread_queue)) { + spin_unlock_bh(&mon_ctx->mon_queue_lock); + return; + } + list_for_each_entry_safe(pkt, tmp, + &mon_ctx->mon_thread_queue, + list) + list_move_tail(&pkt->list, &local_list); + + spin_unlock_bh(&mon_ctx->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; + } + pkt_capture_free_mon_pkt(mon_ctx, pkt); + } +} + +int pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + int rc; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return -EINVAL; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return -EINVAL; + } + mon_ctx = vdev_priv->mon_ctx; + if (!mon_ctx) { + pkt_capture_err("packet capture mon context is NULL"); + return -EINVAL; + } + + set_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); + rc = wait_for_completion_timeout( + &mon_ctx->suspend_mon_event, + msecs_to_jiffies(PKT_CAPTURE_SUSPEND_TIMEOUT)); + if (!rc) { + clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + pkt_capture_err("Failed to suspend packet capture mon thread"); + return -EINVAL; + } + mon_ctx->is_mon_thread_suspended = true; + + return 0; +} + +void pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + mon_ctx = vdev_priv->mon_ctx; + if (!mon_ctx) { + pkt_capture_err("packet capture mon context is NULL"); + return; + } + + if (mon_ctx->is_mon_thread_suspended) + complete(&mon_ctx->resume_mon_event); +} + +QDF_STATUS +pkt_capture_alloc_mon_thread(struct pkt_capture_mon_context *mon_ctx) +{ + spin_lock_init(&mon_ctx->mon_thread_lock); + init_waitqueue_head(&mon_ctx->mon_wait_queue); + init_completion(&mon_ctx->mon_start_event); + init_completion(&mon_ctx->suspend_mon_event); + init_completion(&mon_ctx->resume_mon_event); + init_completion(&mon_ctx->mon_shutdown); + mon_ctx->mon_event_flag = 0; + spin_lock_init(&mon_ctx->mon_queue_lock); + spin_lock_init(&mon_ctx->mon_pkt_freeq_lock); + INIT_LIST_HEAD(&mon_ctx->mon_thread_queue); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + INIT_LIST_HEAD(&mon_ctx->mon_pkt_freeq); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + + return pkt_capture_alloc_mon_pkt_freeq(mon_ctx); +} diff --git a/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h b/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h index bc12c61e66fa..fd2a10b140f0 100644 --- a/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h +++ b/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h @@ -54,7 +54,26 @@ void ucfg_pkt_capture_deinit(void); * * Return: enum pkt_capture_mode */ -enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc); +enum pkt_capture_mode +ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pkt_capture_suspend_mon_thread() - suspend packet capture mon thread + * vdev: pointer to vdev object manager + * + * Return: 0 on success, -EINVAL on failure + */ +int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pkt_capture_resume_mon_thread() - resume packet capture mon thread + * vdev: pointer to vdev object manager + * + * Resume packet capture MON thread by completing RX thread resume event + * + * Return: None + */ +void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev); #else static inline QDF_STATUS ucfg_pkt_capture_init(void) @@ -72,5 +91,16 @@ enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) { return PACKET_CAPTURE_MODE_DISABLE; } + +static inline +void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} #endif /* WLAN_FEATURE_PKT_CAPTURE */ #endif /* _WLAN_PKT_CAPTURE_UCFG_API_H_ */ diff --git a/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c b/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c index e16e09dbde0a..2fa53f98800e 100644 --- a/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c +++ b/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c @@ -23,6 +23,7 @@ #include "wlan_pkt_capture_objmgr.h" #include "wlan_pkt_capture_main.h" #include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_pkt_capture_mon_thread.h" enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) { @@ -114,3 +115,13 @@ void ucfg_pkt_capture_deinit(void) if (QDF_IS_STATUS_ERROR(status)) pkt_capture_err("Failed to unregister psoc create handler"); } + +int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + return pkt_capture_suspend_mon_thread(vdev); +} + +void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + pkt_capture_resume_mon_thread(vdev); +}