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:
parent
b05094fe3a
commit
aa481cc459
1
Kbuild
1
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
|
||||
|
||||
|
208
components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h
Normal file
208
components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h
Normal 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_ */
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
460
components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c
Normal file
460
components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c
Normal 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);
|
||||
}
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user