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
This commit is contained in:
Vulupala Shashank Reddy 2020-02-12 09:30:18 +05:30 committed by nshrivas
parent b05094fe3a
commit aa481cc459
7 changed files with 783 additions and 1 deletions

1
Kbuild
View File

@ -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

View File

@ -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_ */

View File

@ -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;
};
/**

View File

@ -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;
}

View File

@ -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 <linux/kthread.h>
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);
}

View File

@ -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_ */

View File

@ -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);
}