mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2025-01-15 16:25:35 +00:00
bd8827d169
The sdk release is from NXP offial web: https://www.nxp.com/products/wireless/wi-fi-plus-bluetooth/ 88w8997-wi-fi-dual-band-with-bluetooth-5-for-a-v-streaming-and-digital-tv:88W8997?tab=Design_Tools_Tab The release file is: PCIE-WLAN-UART-BT-8997-U16-X86-W16.68.10.p16-16.26.10.p16-C4X16640_V4-MGPL The sdk version is: W16.68.10.p16 Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
3476 lines
96 KiB
C
Executable file
3476 lines
96 KiB
C
Executable file
/** @file moal_shim.c
|
|
*
|
|
* @brief This file contains the callback functions registered to MLAN
|
|
*
|
|
* Copyright (C) 2008-2019, Marvell International Ltd.
|
|
*
|
|
* This software file (the "File") is distributed by Marvell International
|
|
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
* (the "License"). You may use, redistribute and/or modify this File in
|
|
* accordance with the terms and conditions of the License, a copy of which
|
|
* is available by writing to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
|
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
*
|
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
* this warranty disclaimer.
|
|
*
|
|
*/
|
|
|
|
/********************************************************
|
|
Change log:
|
|
10/21/2008: initial version
|
|
********************************************************/
|
|
|
|
#include "moal_main.h"
|
|
#include "moal_pcie.h"
|
|
#ifdef UAP_SUPPORT
|
|
#include "moal_uap.h"
|
|
#endif
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
#include "moal_cfg80211.h"
|
|
#include "moal_cfgvendor.h"
|
|
#endif
|
|
extern int drv_mode;
|
|
#include <asm/div64.h>
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
/** moal_lock */
|
|
typedef struct _moal_lock {
|
|
/** Lock */
|
|
spinlock_t lock;
|
|
/** Flags */
|
|
unsigned long flags;
|
|
} moal_lock;
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
extern int cfg80211_wext;
|
|
|
|
extern int hw_test;
|
|
|
|
#ifdef ANDROID_KERNEL
|
|
extern int wakelock_timeout;
|
|
#endif
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
extern int dfs_offload;
|
|
#endif
|
|
#endif
|
|
|
|
/** napi support*/
|
|
extern int napi;
|
|
|
|
typedef MLAN_PACK_START struct {
|
|
t_u32 t4;
|
|
t_u8 t4_error;
|
|
t_u32 t1;
|
|
t_u8 t1_error;
|
|
t_u64 egress_time;
|
|
} MLAN_PACK_END confirm_timestamps;
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
/**
|
|
* @brief Alloc a buffer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param size The size of the buffer to be allocated
|
|
* @param flag The type of the buffer to be allocated
|
|
* @param ppbuf Pointer to a buffer location to store buffer pointer allocated
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_malloc(IN t_void *pmoal_handle,
|
|
IN t_u32 size, IN t_u32 flag, OUT t_u8 **ppbuf)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
t_u32 mem_flag = (in_interrupt() || irqs_disabled())?
|
|
GFP_ATOMIC : GFP_KERNEL;
|
|
|
|
if (flag & MLAN_MEM_DMA)
|
|
mem_flag |= GFP_DMA;
|
|
|
|
*ppbuf = kzalloc(size, mem_flag);
|
|
if (*ppbuf == NULL) {
|
|
PRINTM(MERROR, "%s: allocate memory (%d bytes) failed!\n",
|
|
__func__, (int)size);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
atomic_inc(&handle->malloc_count);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Free a buffer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pbuf Pointer to the buffer to be freed
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_mfree(IN t_void *pmoal_handle, IN t_u8 *pbuf)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
|
|
if (!pbuf)
|
|
return MLAN_STATUS_FAILURE;
|
|
kfree(pbuf);
|
|
atomic_dec(&handle->malloc_count);
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Alloc a vitual-address-continuous buffer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param size The size of the buffer to be allocated
|
|
* @param ppbuf Pointer to a buffer location to store buffer pointer allocated
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_vmalloc(IN t_void *pmoal_handle, IN t_u32 size, OUT t_u8 **ppbuf)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
|
|
*ppbuf = vmalloc(size);
|
|
if (*ppbuf == NULL) {
|
|
PRINTM(MERROR, "%s: vmalloc (%d bytes) failed!", __func__,
|
|
(int)size);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
atomic_inc(&handle->vmalloc_count);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Free a buffer allocated by vmalloc
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pbuf Pointer to the buffer to be freed
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_vfree(IN t_void *pmoal_handle, IN t_u8 *pbuf)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
|
|
if (!pbuf)
|
|
return MLAN_STATUS_FAILURE;
|
|
vfree(pbuf);
|
|
atomic_dec(&handle->vmalloc_count);
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Alloc a consistent block of memory
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param size The size of the buffer to be allocated
|
|
* @param ppbuf Pointer to a buffer location to store memory allocated
|
|
* @param pbuf_pa Pointer to a buffer location to store physical address of above memory
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_malloc_consistent(IN t_void *pmoal_handle,
|
|
IN t_u32 size, OUT t_u8 **ppbuf, OUT t_u64 *pbuf_pa)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
*pbuf_pa = 0;
|
|
*ppbuf = (t_u8 *)pci_alloc_consistent(card->dev, size,
|
|
(dma_addr_t *) pbuf_pa);
|
|
if (*ppbuf == NULL) {
|
|
PRINTM(MERROR,
|
|
"%s: allocate consistent memory (%d bytes) failed!\n",
|
|
__func__, (int)size);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
atomic_inc(&handle->malloc_cons_count);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Free a consistent block of memory
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param size Size of them memory to be freed
|
|
* @param pbuf Pointer to the memory to be freed
|
|
* @param buf_pa Physical address of the memory to be freed
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_mfree_consistent(IN t_void *pmoal_handle,
|
|
IN t_u32 size, IN t_u8 *pbuf, IN t_u64 buf_pa)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
pcie_service_card *card = handle->card;
|
|
|
|
if (!pbuf)
|
|
return MLAN_STATUS_FAILURE;
|
|
|
|
pci_free_consistent(card->dev, size, pbuf, buf_pa);
|
|
atomic_dec(&handle->malloc_cons_count);
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Map a block of memory to device
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pbuf Pointer to the buffer to be mapped
|
|
* @param pbuf_pa Pointer to store the physical address of buffer
|
|
* @param size Size of the buffer to be mapped
|
|
* @param flag Flags for mapping IO
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_map_memory(IN t_void *pmoal_handle,
|
|
IN t_u8 *pbuf, OUT t_u64 *pbuf_pa, IN t_u32 size, IN t_u32 flag)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
|
|
dma_addr_t dma;
|
|
|
|
/* Init memory to device */
|
|
dma = pci_map_single(card->dev, pbuf, size, flag);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
|
|
if (pci_dma_mapping_error(card->dev, dma)) {
|
|
#else
|
|
if (pci_dma_mapping_error(dma)) {
|
|
#endif
|
|
PRINTM(MERROR, "Tx ring: failed to pci_map_single\n");
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
*pbuf_pa = dma;
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Unmap a block of memory from device
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pbuf Pointer to the buffer to unmap
|
|
* @param buf_pa Physical address of buffer to unmap
|
|
* @param size Size of the buffer to unmap
|
|
* @param flag Flags for mapping IO
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_unmap_memory(IN t_void *pmoal_handle,
|
|
IN t_u8 *pbuf, IN t_u64 buf_pa, IN t_u32 size, IN t_u32 flag)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
|
|
pci_unmap_single(card->dev, buf_pa, size, flag);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Fill memory with constant byte
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmem Pointer to the memory area
|
|
* @param byte A constant byte
|
|
* @param num Number of bytes to fill
|
|
*
|
|
* @return Pointer to the memory area
|
|
*/
|
|
t_void *
|
|
moal_memset(IN t_void *pmoal_handle,
|
|
IN t_void *pmem, IN t_u8 byte, IN t_u32 num)
|
|
{
|
|
t_void *p = pmem;
|
|
|
|
if (pmem && num)
|
|
p = memset(pmem, byte, num);
|
|
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* @brief Copy memory from one area to another
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pdest Pointer to the dest memory
|
|
* @param psrc Pointer to the src memory
|
|
* @param num Number of bytes to move
|
|
*
|
|
* @return Pointer to the dest memory
|
|
*/
|
|
t_void *
|
|
moal_memcpy(IN t_void *pmoal_handle,
|
|
IN t_void *pdest, IN const t_void *psrc, IN t_u32 num)
|
|
{
|
|
t_void *p = pdest;
|
|
|
|
if (pdest && psrc && num)
|
|
p = memcpy(pdest, psrc, num);
|
|
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* @brief Move memory from one area to another
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pdest Pointer to the dest memory
|
|
* @param psrc Pointer to the src memory
|
|
* @param num Number of bytes to move
|
|
*
|
|
* @return Pointer to the dest memory
|
|
*/
|
|
t_void *
|
|
moal_memmove(IN t_void *pmoal_handle,
|
|
IN t_void *pdest, IN const t_void *psrc, IN t_u32 num)
|
|
{
|
|
t_void *p = pdest;
|
|
|
|
if (pdest && psrc && num)
|
|
p = memmove(pdest, psrc, num);
|
|
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* @brief Compare two memory areas
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmem1 Pointer to the first memory
|
|
* @param pmem2 Pointer to the second memory
|
|
* @param num Number of bytes to compare
|
|
*
|
|
* @return Compare result returns by memcmp
|
|
*/
|
|
t_s32
|
|
moal_memcmp(IN t_void *pmoal_handle,
|
|
IN const t_void *pmem1, IN const t_void *pmem2, IN t_u32 num)
|
|
{
|
|
t_s32 result;
|
|
|
|
result = memcmp(pmem1, pmem2, num);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Delay function
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param delay delay in micro-second
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void
|
|
moal_udelay(IN t_void *pmoal_handle, IN t_u32 delay)
|
|
{
|
|
if (delay >= 1000)
|
|
mdelay(delay / 1000);
|
|
if (delay % 1000)
|
|
udelay(delay % 1000);
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieves the current system time
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param psec Pointer to buf for the seconds of system time
|
|
* @param pusec Pointer to buf the micro seconds of system time
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_get_system_time(IN t_void *pmoal_handle, OUT t_u32 *psec, OUT t_u32 *pusec)
|
|
{
|
|
struct timeval t;
|
|
|
|
woal_get_monotonic_time(&t);
|
|
*psec = (t_u32)t.tv_sec;
|
|
*pusec = (t_u32)t.tv_usec;
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief usleep function
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param usmin Minimum value for sleep in usecs
|
|
* @param usmax Maximum value for sleep in usecs
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_usleep(IN t_void *pmoal_handle, IN t_u64 min, IN t_u64 max)
|
|
{
|
|
usleep_range(min, max);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieves the current boot time
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pnsec Pointer to buf for the Nanoseconds of boot time
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_get_boot_ktime(IN t_void *pmoal_handle, OUT t_u64 *pnsec)
|
|
{
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
|
|
ktime_t time;
|
|
|
|
time = ktime_get_with_offset(TK_OFFS_BOOT);
|
|
*pnsec = *(t_u64 *)&(time);
|
|
#endif
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes the timer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pptimer Pointer to the timer
|
|
* @param callback Pointer to callback function
|
|
* @param pcontext Pointer to context
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_init_timer(IN t_void *pmoal_handle,
|
|
OUT t_void **pptimer,
|
|
IN t_void (*callback) (t_void *pcontext), IN t_void *pcontext)
|
|
{
|
|
moal_drv_timer *timer = NULL;
|
|
t_u32 mem_flag = (in_interrupt() || irqs_disabled())?
|
|
GFP_ATOMIC : GFP_KERNEL;
|
|
|
|
timer = kmalloc(sizeof(moal_drv_timer), mem_flag);
|
|
if (timer == NULL)
|
|
return MLAN_STATUS_FAILURE;
|
|
woal_initialize_timer(timer, callback, pcontext);
|
|
*pptimer = (t_void *)timer;
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Free the timer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param ptimer Pointer to the timer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_free_timer(IN t_void *pmoal_handle, IN t_void *ptimer)
|
|
{
|
|
moal_drv_timer *timer = (moal_drv_timer *)ptimer;
|
|
|
|
if (timer) {
|
|
if ((timer->timer_is_canceled == MFALSE) && timer->time_period) {
|
|
PRINTM(MWARN,
|
|
"mlan try to free timer without stop timer!\n");
|
|
woal_cancel_timer(timer);
|
|
}
|
|
kfree(timer);
|
|
}
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Start the timer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param ptimer Pointer to the timer
|
|
* @param periodic Periodic timer
|
|
* @param msec Timer value in milliseconds
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_start_timer(IN t_void *pmoal_handle,
|
|
IN t_void *ptimer, IN t_u8 periodic, IN t_u32 msec)
|
|
{
|
|
if (!ptimer)
|
|
return MLAN_STATUS_FAILURE;
|
|
|
|
((moal_drv_timer *)ptimer)->timer_is_periodic = periodic;
|
|
woal_mod_timer((moal_drv_timer *)ptimer, msec);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Stop the timer
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param ptimer Pointer to the timer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_stop_timer(IN t_void *pmoal_handle, IN t_void *ptimer)
|
|
{
|
|
if (!ptimer)
|
|
return MLAN_STATUS_FAILURE;
|
|
woal_cancel_timer((moal_drv_timer *)ptimer);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes the lock
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pplock Pointer to the lock
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_init_lock(IN t_void *pmoal_handle, OUT t_void **pplock)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
moal_lock *mlock = NULL;
|
|
|
|
mlock = kmalloc(sizeof(moal_lock), GFP_ATOMIC);
|
|
if (!mlock)
|
|
return MLAN_STATUS_FAILURE;
|
|
spin_lock_init(&mlock->lock);
|
|
*pplock = (t_void *)mlock;
|
|
|
|
atomic_inc(&handle->lock_count);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Free the lock
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param plock Lock
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_free_lock(IN t_void *pmoal_handle, IN t_void *plock)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
moal_lock *mlock = plock;
|
|
|
|
kfree(mlock);
|
|
if (mlock)
|
|
atomic_dec(&handle->lock_count);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Request a spin lock
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param plock Pointer to the lock
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_spin_lock(IN t_void *pmoal_handle, IN t_void *plock)
|
|
{
|
|
moal_lock *mlock = plock;
|
|
unsigned long flags = 0;
|
|
|
|
if (mlock) {
|
|
spin_lock_irqsave(&mlock->lock, flags);
|
|
mlock->flags = flags;
|
|
return MLAN_STATUS_SUCCESS;
|
|
} else {
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Request a spin_unlock
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param plock Pointer to the lock
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_spin_unlock(IN t_void *pmoal_handle, IN t_void *plock)
|
|
{
|
|
moal_lock *mlock = (moal_lock *)plock;
|
|
|
|
if (mlock) {
|
|
spin_unlock_irqrestore(&mlock->lock, mlock->flags);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
} else {
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief This function reads one block of firmware data from MOAL
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param offset Offset from where the data will be copied
|
|
* @param len Length to be copied
|
|
* @param pbuf Buffer where the data will be copied
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_get_fw_data(IN t_void *pmoal_handle,
|
|
IN t_u32 offset, IN t_u32 len, OUT t_u8 *pbuf)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
|
|
if (!pbuf || !len)
|
|
return MLAN_STATUS_FAILURE;
|
|
|
|
if (offset + len > handle->firmware->size)
|
|
return MLAN_STATUS_FAILURE;
|
|
|
|
memcpy(pbuf, handle->firmware->data + offset, len);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when MLAN completes the initialization firmware.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param status The status code for mlan_init_fw request
|
|
* @param phw pointer to mlan_hw_info
|
|
* @param ptbl pointer to mplan_bss_tbl
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_get_hw_spec_complete(IN t_void *pmoal_handle, IN mlan_status status,
|
|
IN mlan_hw_info * phw, IN pmlan_bss_tbl ptbl)
|
|
{
|
|
ENTER();
|
|
if (status == MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MCMND, "Get Hw Spec done, fw_cap=0x%x\n", phw->fw_cap);
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when MLAN completes the initialization firmware.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param status The status code for mlan_init_fw request
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_init_fw_complete(IN t_void *pmoal_handle, IN mlan_status status)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
ENTER();
|
|
if (status == MLAN_STATUS_SUCCESS)
|
|
handle->hardware_status = HardwareStatusReady;
|
|
handle->init_wait_q_woken = MTRUE;
|
|
wake_up(&handle->init_wait_q);
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when MLAN shutdown firmware is completed.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param status The status code for mlan_shutdown request
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_shutdown_fw_complete(IN t_void *pmoal_handle, IN mlan_status status)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
ENTER();
|
|
handle->hardware_status = HardwareStatusNotReady;
|
|
handle->init_wait_q_woken = MTRUE;
|
|
wake_up_interruptible(&handle->init_wait_q);
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when an MLAN IOCTL is completed.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pioctl_req pointer to structure mlan_ioctl_req
|
|
* @param status The status code for mlan_ioctl request
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_ioctl_complete(IN t_void *pmoal_handle,
|
|
IN pmlan_ioctl_req pioctl_req, IN mlan_status status)
|
|
{
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
moal_private *priv = NULL;
|
|
wait_queue *wait;
|
|
unsigned long flags = 0;
|
|
ENTER();
|
|
|
|
if (!atomic_read(&handle->ioctl_pending))
|
|
PRINTM(MERROR, "ERR: Unexpected IOCTL completed: %p\n",
|
|
pioctl_req);
|
|
else
|
|
atomic_dec(&handle->ioctl_pending);
|
|
priv = woal_bss_index_to_priv(handle, pioctl_req->bss_index);
|
|
if (!priv) {
|
|
PRINTM(MERROR,
|
|
"IOCTL %p complete with NULL priv, bss_index=%d\n",
|
|
pioctl_req, pioctl_req->bss_index);
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (status != MLAN_STATUS_SUCCESS && status != MLAN_STATUS_COMPLETE)
|
|
PRINTM(MERROR,
|
|
"IOCTL failed: %p id=0x%x, sub_id=0x%x action=%d, status_code=0x%x\n",
|
|
pioctl_req, pioctl_req->req_id,
|
|
(*(t_u32 *)pioctl_req->pbuf), (int)pioctl_req->action,
|
|
pioctl_req->status_code);
|
|
else
|
|
PRINTM(MIOCTL,
|
|
"IOCTL completed: %p id=0x%x sub_id=0x%x, action=%d, status=%d, status_code=0x%x\n",
|
|
pioctl_req, pioctl_req->req_id,
|
|
(*(t_u32 *)pioctl_req->pbuf), (int)pioctl_req->action,
|
|
status, pioctl_req->status_code);
|
|
|
|
spin_lock_irqsave(&handle->driver_lock, flags);
|
|
wait = (wait_queue *)pioctl_req->reserved_1;
|
|
if (wait) {
|
|
wait->condition = MTRUE;
|
|
wait->status = status;
|
|
if (wait->wait_timeout) {
|
|
wake_up(&wait->wait);
|
|
} else {
|
|
if ((status != MLAN_STATUS_SUCCESS) &&
|
|
(pioctl_req->status_code ==
|
|
MLAN_ERROR_CMD_TIMEOUT)) {
|
|
PRINTM(MERROR, "IOCTL: command timeout\n");
|
|
} else {
|
|
wake_up_interruptible(&wait->wait);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&handle->driver_lock, flags);
|
|
} else {
|
|
spin_unlock_irqrestore(&handle->driver_lock, flags);
|
|
if ((status == MLAN_STATUS_SUCCESS) &&
|
|
(pioctl_req->action == MLAN_ACT_GET))
|
|
woal_process_ioctl_resp(priv, pioctl_req);
|
|
kfree(pioctl_req);
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function allocates mlan_buffer.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param size allocation size requested
|
|
* @param pmbuf pointer to pointer to the allocated buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_alloc_mlan_buffer(IN t_void *pmoal_handle,
|
|
IN t_u32 size, OUT pmlan_buffer *pmbuf)
|
|
{
|
|
*pmbuf = woal_alloc_mlan_buffer((moal_handle *)pmoal_handle, size);
|
|
if (NULL == *pmbuf)
|
|
return MLAN_STATUS_FAILURE;
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees mlan_buffer.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmbuf pointer to buffer to be freed
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_free_mlan_buffer(IN t_void *pmoal_handle, IN pmlan_buffer pmbuf)
|
|
{
|
|
if (!pmbuf)
|
|
return MLAN_STATUS_FAILURE;
|
|
woal_free_mlan_buffer((moal_handle *)pmoal_handle, pmbuf);
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when MLAN complete send data packet.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmbuf Pointer to the mlan buffer structure
|
|
* @param status The status code for mlan_send_packet request
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_send_packet_complete(IN t_void *pmoal_handle,
|
|
IN pmlan_buffer pmbuf, IN mlan_status status)
|
|
{
|
|
moal_private *priv = NULL;
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
struct sk_buff *skb = NULL;
|
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
|
|
t_u32 index = 0;
|
|
#endif
|
|
|
|
ENTER();
|
|
if (pmbuf && pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
|
|
woal_free_mlan_buffer(handle, pmbuf);
|
|
atomic_dec(&handle->tx_pending);
|
|
goto done;
|
|
}
|
|
if (pmbuf) {
|
|
priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
|
|
skb = (struct sk_buff *)pmbuf->pdesc;
|
|
if (priv) {
|
|
woal_set_trans_start(priv->netdev);
|
|
if (skb) {
|
|
if (status == MLAN_STATUS_SUCCESS) {
|
|
priv->stats.tx_packets++;
|
|
priv->stats.tx_bytes += skb->len;
|
|
} else {
|
|
priv->stats.tx_errors++;
|
|
}
|
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
|
|
index = skb_get_queue_mapping(skb);
|
|
atomic_dec(&handle->tx_pending);
|
|
if (atomic_dec_return
|
|
(&priv->wmm_tx_pending[index]) ==
|
|
LOW_TX_PENDING) {
|
|
struct netdev_queue *txq =
|
|
netdev_get_tx_queue(priv->
|
|
netdev,
|
|
index);
|
|
if (netif_tx_queue_stopped(txq)) {
|
|
netif_tx_wake_queue(txq);
|
|
PRINTM(MINFO,
|
|
"Wakeup Kernel Queue:%d\n",
|
|
index);
|
|
}
|
|
}
|
|
#else /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
|
|
if (atomic_dec_return(&handle->tx_pending) <
|
|
LOW_TX_PENDING) {
|
|
int i;
|
|
for (i = 0; i < handle->priv_num; i++) {
|
|
#ifdef STA_SUPPORT
|
|
if ((GET_BSS_ROLE
|
|
(handle->priv[i]) ==
|
|
MLAN_BSS_ROLE_STA) &&
|
|
(handle->priv[i]->
|
|
media_connected ||
|
|
priv->
|
|
is_adhoc_link_sensed)) {
|
|
woal_wake_queue(handle->
|
|
priv
|
|
[i]->
|
|
netdev);
|
|
}
|
|
#endif
|
|
#ifdef UAP_SUPPORT
|
|
if ((GET_BSS_ROLE
|
|
(handle->priv[i]) ==
|
|
MLAN_BSS_ROLE_UAP) &&
|
|
(handle->priv[i]->
|
|
media_connected)) {
|
|
woal_wake_queue(handle->
|
|
priv
|
|
[i]->
|
|
netdev);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
|
|
}
|
|
}
|
|
if (skb)
|
|
dev_kfree_skb_any(skb);
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function write a command/data packet to card.
|
|
* This function blocks the call until it finishes
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmbuf Pointer to the mlan buffer structure
|
|
* @param port Port number for sent
|
|
* @param timeout Timeout value in milliseconds (if 0 the wait is forever)
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_write_data_sync(IN t_void *pmoal_handle,
|
|
IN pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
|
|
{
|
|
return woal_write_data_sync((moal_handle *)pmoal_handle, pmbuf, port,
|
|
timeout);
|
|
}
|
|
|
|
/**
|
|
* @brief This function read data packet/event/command from card.
|
|
* This function blocks the call until it finish
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmbuf Pointer to the mlan buffer structure
|
|
* @param port Port number for read
|
|
* @param timeout Timeout value in milliseconds (if 0 the wait is forever)
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_read_data_sync(IN t_void *pmoal_handle,
|
|
IN OUT pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
|
|
{
|
|
return woal_read_data_sync((moal_handle *)pmoal_handle, pmbuf, port,
|
|
timeout);
|
|
}
|
|
|
|
/**
|
|
* @brief This function writes data into card register.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param reg register offset
|
|
* @param data value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_write_reg(IN t_void *pmoal_handle, IN t_u32 reg, IN t_u32 data)
|
|
{
|
|
return woal_write_reg((moal_handle *)pmoal_handle, reg, data);
|
|
}
|
|
|
|
/**
|
|
* @brief This function reads data from card register.
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param reg register offset
|
|
* @param data value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_read_reg(IN t_void *pmoal_handle, IN t_u32 reg, OUT t_u32 *data)
|
|
{
|
|
return woal_read_reg((moal_handle *)pmoal_handle, reg, data);
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
/**
|
|
* @brief This function uploads the packet to the network stack monitor interface
|
|
*
|
|
* @param handle Pointer to the MOAL context
|
|
* @param pmbuf Pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING/MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_recv_packet_to_mon_if(IN moal_handle *handle, IN pmlan_buffer pmbuf)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
struct sk_buff *skb = NULL;
|
|
struct radiotap_header *rth = NULL;
|
|
radiotap_info rt_info = { 0 };
|
|
t_u8 format = 0;
|
|
t_u8 bw = 0;
|
|
t_u8 gi = 0;
|
|
t_u8 ldpc = 0;
|
|
t_u8 chan_num;
|
|
t_u8 band = 0;
|
|
struct ieee80211_hdr *dot11_hdr = NULL;
|
|
t_u8 *payload = NULL;
|
|
t_u32 vht_sig1 = 0;
|
|
t_u32 vht_sig2 = 0;
|
|
ENTER();
|
|
if (!pmbuf->pdesc) {
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
skb = (struct sk_buff *)pmbuf->pdesc;
|
|
|
|
if ((handle->mon_if) && netif_running(handle->mon_if->mon_ndev)) {
|
|
if (handle->mon_if->radiotap_enabled) {
|
|
if (skb_headroom(skb) < sizeof(*rth)) {
|
|
PRINTM(MERROR,
|
|
"%s No space to add Radio TAP header\n",
|
|
__func__);
|
|
status = MLAN_STATUS_FAILURE;
|
|
handle->mon_if->stats.rx_dropped++;
|
|
goto done;
|
|
}
|
|
dot11_hdr =
|
|
(struct ieee80211_hdr *)(pmbuf->pbuf +
|
|
pmbuf->data_offset);
|
|
memcpy(&rt_info,
|
|
pmbuf->pbuf + pmbuf->data_offset -
|
|
sizeof(rt_info), sizeof(rt_info));
|
|
ldpc = (rt_info.rate_info.rate_info & 0x20) >> 5;
|
|
format = (rt_info.rate_info.rate_info & 0x18) >> 3;
|
|
bw = (rt_info.rate_info.rate_info & 0x06) >> 1;
|
|
gi = rt_info.rate_info.rate_info & 0x01;
|
|
skb_push(skb, sizeof(*rth));
|
|
rth = (struct radiotap_header *)skb->data;
|
|
memset(skb->data, 0, sizeof(*rth));
|
|
rth->hdr.it_version = PKTHDR_RADIOTAP_VERSION;
|
|
rth->hdr.it_pad = 0;
|
|
rth->hdr.it_len = cpu_to_le16(sizeof(*rth));
|
|
rth->hdr.it_present =
|
|
cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
|
|
(1 << IEEE80211_RADIOTAP_FLAGS) |
|
|
(1 << IEEE80211_RADIOTAP_CHANNEL) |
|
|
(1 <<
|
|
IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
|
|
(1 <<
|
|
IEEE80211_RADIOTAP_DBM_ANTNOISE) |
|
|
(1 << IEEE80211_RADIOTAP_ANTENNA));
|
|
/** Timstamp */
|
|
rth->body.timestamp = cpu_to_le64(jiffies);
|
|
/** Flags */
|
|
rth->body.flags = (rt_info.extra_info.flags &
|
|
~(RADIOTAP_FLAGS_USE_SGI_HT |
|
|
RADIOTAP_FLAGS_WITH_FRAGMENT |
|
|
RADIOTAP_FLAGS_WEP_ENCRYPTION |
|
|
RADIOTAP_FLAGS_FAILED_FCS_CHECK));
|
|
/** reverse fail fcs, 1 means pass FCS in FW, but means fail FCS in radiotap */
|
|
rth->body.flags |=
|
|
(~rt_info.extra_info.
|
|
flags) & RADIOTAP_FLAGS_FAILED_FCS_CHECK;
|
|
if ((format == MLAN_RATE_FORMAT_HT) && (gi == 1))
|
|
rth->body.flags |= RADIOTAP_FLAGS_USE_SGI_HT;
|
|
if (ieee80211_is_mgmt(dot11_hdr->frame_control) ||
|
|
ieee80211_is_data(dot11_hdr->frame_control)) {
|
|
if ((ieee80211_has_morefrags
|
|
(dot11_hdr->frame_control)) ||
|
|
(!ieee80211_is_first_frag
|
|
(dot11_hdr->seq_ctrl))) {
|
|
rth->body.flags |=
|
|
RADIOTAP_FLAGS_WITH_FRAGMENT;
|
|
}
|
|
}
|
|
if (ieee80211_is_data(dot11_hdr->frame_control) &&
|
|
ieee80211_has_protected(dot11_hdr->frame_control)) {
|
|
payload =
|
|
(t_u8 *)dot11_hdr +
|
|
ieee80211_hdrlen(dot11_hdr->
|
|
frame_control);
|
|
if (!(*(payload + 3) & 0x20))
|
|
/** ExtIV bit shall be 0 for WEP frame */
|
|
rth->body.flags |=
|
|
RADIOTAP_FLAGS_WEP_ENCRYPTION;
|
|
}
|
|
/** Rate, t_u8 only apply for LG mode */
|
|
if (format == MLAN_RATE_FORMAT_LG) {
|
|
rth->hdr.it_present |=
|
|
cpu_to_le32(1 <<
|
|
IEEE80211_RADIOTAP_RATE);
|
|
rth->body.rate = rt_info.rate_info.bitrate;
|
|
}
|
|
/** Channel */
|
|
rth->body.channel.flags = 0;
|
|
if (rt_info.chan_num)
|
|
chan_num = rt_info.chan_num;
|
|
else
|
|
chan_num =
|
|
handle->mon_if->band_chan_cfg.channel;
|
|
band = (chan_num <=
|
|
14) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
|
rth->body.channel.frequency =
|
|
cpu_to_le16(ieee80211_channel_to_frequency
|
|
(chan_num, band));
|
|
rth->body.channel.flags |=
|
|
cpu_to_le16((band ==
|
|
IEEE80211_BAND_2GHZ) ?
|
|
CHANNEL_FLAGS_2GHZ :
|
|
CHANNEL_FLAGS_5GHZ);
|
|
if (rth->body.channel.
|
|
flags & cpu_to_le16(CHANNEL_FLAGS_2GHZ))
|
|
rth->body.channel.flags |=
|
|
cpu_to_le16
|
|
(CHANNEL_FLAGS_DYNAMIC_CCK_OFDM);
|
|
else
|
|
rth->body.channel.flags |=
|
|
cpu_to_le16(CHANNEL_FLAGS_OFDM);
|
|
if (handle->mon_if->chandef.chan &&
|
|
(handle->mon_if->chandef.chan->
|
|
flags & (IEEE80211_CHAN_PASSIVE_SCAN |
|
|
IEEE80211_CHAN_RADAR)))
|
|
rth->body.channel.flags |=
|
|
cpu_to_le16
|
|
(CHANNEL_FLAGS_ONLY_PASSIVSCAN_ALLOW);
|
|
/** Antenna */
|
|
rth->body.antenna_signal = -(rt_info.nf - rt_info.snr);
|
|
rth->body.antenna_noise = -rt_info.nf;
|
|
rth->body.antenna = rt_info.antenna;
|
|
/** MCS */
|
|
if (format == MLAN_RATE_FORMAT_HT) {
|
|
rth->hdr.it_present |=
|
|
cpu_to_le32(1 <<
|
|
IEEE80211_RADIOTAP_MCS);
|
|
rth->body.u.mcs.known =
|
|
rt_info.extra_info.mcs_known;
|
|
rth->body.u.mcs.flags =
|
|
rt_info.extra_info.mcs_flags;
|
|
/** MCS mcs */
|
|
rth->body.u.mcs.known |=
|
|
MCS_KNOWN_MCS_INDEX_KNOWN;
|
|
rth->body.u.mcs.mcs =
|
|
rt_info.rate_info.mcs_index;
|
|
/** MCS bw */
|
|
rth->body.u.mcs.known |= MCS_KNOWN_BANDWIDTH;
|
|
rth->body.u.mcs.flags &= ~(0x03);
|
|
/** Clear, 20MHz as default */
|
|
if (bw == 1)
|
|
rth->body.u.mcs.flags |= RX_BW_40;
|
|
/** MCS gi */
|
|
rth->body.u.mcs.known |=
|
|
MCS_KNOWN_GUARD_INTERVAL;
|
|
rth->body.u.mcs.flags &= ~(1 << 2);
|
|
if (gi)
|
|
rth->body.u.mcs.flags |= gi << 2;
|
|
/** MCS FEC */
|
|
rth->body.u.mcs.known |= MCS_KNOWN_FEC_TYPE;
|
|
rth->body.u.mcs.flags &= ~(1 << 4);
|
|
if (ldpc)
|
|
rth->body.u.mcs.flags |= ldpc << 4;
|
|
}
|
|
/** VHT */
|
|
if (format == MLAN_RATE_FORMAT_VHT) {
|
|
vht_sig1 = rt_info.extra_info.vht_sig1;
|
|
vht_sig2 = rt_info.extra_info.vht_sig2;
|
|
/** Present Flag */
|
|
rth->hdr.it_present |=
|
|
cpu_to_le32(1 <<
|
|
IEEE80211_RADIOTAP_VHT);
|
|
/** STBC */
|
|
rth->body.u.vht.known |=
|
|
cpu_to_le16(VHT_KNOWN_STBC);
|
|
if (vht_sig1 & MBIT(3))
|
|
rth->body.u.vht.flags |= VHT_FLAG_STBC;
|
|
/** TXOP_PS_NA */
|
|
/** TODO: Not support now */
|
|
/** GI */
|
|
rth->body.u.vht.known |=
|
|
cpu_to_le16(VHT_KNOWN_GI);
|
|
if (vht_sig2 & MBIT(0))
|
|
rth->body.u.vht.flags |= VHT_FLAG_SGI;
|
|
/** SGI NSYM DIS */
|
|
rth->body.u.vht.known |=
|
|
cpu_to_le16(VHT_KNOWN_SGI_NSYM_DIS);
|
|
if (vht_sig2 & MBIT(1))
|
|
rth->body.u.vht.flags |=
|
|
VHT_FLAG_SGI_NSYM_M10_9;
|
|
/** LDPC_EXTRA_OFDM_SYM */
|
|
/** TODO: Not support now */
|
|
/** BEAMFORMED */
|
|
rth->body.u.vht.known |=
|
|
cpu_to_le16(VHT_KNOWN_BEAMFORMED);
|
|
if (vht_sig2 & MBIT(8))
|
|
rth->body.u.vht.flags |=
|
|
VHT_FLAG_BEAMFORMED;
|
|
/** BANDWIDTH */
|
|
rth->body.u.vht.known |=
|
|
cpu_to_le16(VHT_KNOWN_BANDWIDTH);
|
|
if (bw == 1)
|
|
rth->body.u.vht.bandwidth = RX_BW_40;
|
|
else if (bw == 2)
|
|
rth->body.u.vht.bandwidth = RX_BW_80;
|
|
/** GROUP_ID */
|
|
rth->body.u.vht.known |=
|
|
cpu_to_le16(VHT_KNOWN_GROUP_ID);
|
|
rth->body.u.vht.group_id =
|
|
(vht_sig1 & (0x3F0)) >> 4;
|
|
/** PARTIAL_AID */
|
|
/** TODO: Not support now */
|
|
/** mcs_nss */
|
|
rth->body.u.vht.mcs_nss[0] =
|
|
(vht_sig2 & (0xF0)) >> 4;
|
|
rth->body.u.vht.mcs_nss[0] |=
|
|
(vht_sig1 & (0x1C00)) >> (10 - 4);
|
|
/** coding */
|
|
if (vht_sig2 & MBIT(2))
|
|
rth->body.u.vht.coding |=
|
|
VHT_CODING_LDPC_USER0;
|
|
}
|
|
}
|
|
skb_set_mac_header(skb, 0);
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
skb->pkt_type = PACKET_OTHERHOST;
|
|
skb->protocol = htons(ETH_P_802_2);
|
|
memset(skb->cb, 0, sizeof(skb->cb));
|
|
skb->dev = handle->mon_if->mon_ndev;
|
|
|
|
handle->mon_if->stats.rx_bytes += skb->len;
|
|
handle->mon_if->stats.rx_packets++;
|
|
|
|
if (in_interrupt())
|
|
netif_rx(skb);
|
|
else
|
|
netif_rx_ni(skb);
|
|
|
|
status = MLAN_STATUS_PENDING;
|
|
}
|
|
|
|
done:
|
|
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function uploads the packet to the network stack
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmbuf Pointer to the mlan buffer structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status
|
|
moal_recv_packet(IN t_void *pmoal_handle, IN pmlan_buffer pmbuf)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
moal_private *priv = NULL;
|
|
struct sk_buff *skb = NULL;
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
t_u32 max_rx_data_size = MLAN_USB_RX_DATA_BUF_SIZE;
|
|
dot11_rxcontrol rxcontrol;
|
|
t_u8 rx_info_flag = MFALSE;
|
|
int j;
|
|
ENTER();
|
|
if (pmbuf) {
|
|
|
|
priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
|
|
skb = (struct sk_buff *)pmbuf->pdesc;
|
|
if (priv) {
|
|
if (skb) {
|
|
skb_reserve(skb, pmbuf->data_offset);
|
|
skb_put(skb, pmbuf->data_len);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
if (pmbuf->flags & MLAN_BUF_FLAG_NET_MONITOR) {
|
|
status = moal_recv_packet_to_mon_if
|
|
(pmoal_handle, pmbuf);
|
|
if (status == MLAN_STATUS_PENDING)
|
|
atomic_dec(&handle->
|
|
mbufalloc_count);
|
|
goto done;
|
|
}
|
|
#endif
|
|
pmbuf->pdesc = NULL;
|
|
pmbuf->pbuf = NULL;
|
|
pmbuf->data_offset = pmbuf->data_len = 0;
|
|
/* pkt been submit to kernel, no need to free by mlan */
|
|
status = MLAN_STATUS_PENDING;
|
|
atomic_dec(&handle->mbufalloc_count);
|
|
} else {
|
|
PRINTM(MERROR,
|
|
"%s without skb attach!!! pkt_len=%d flags=0x%x\n",
|
|
__func__, pmbuf->data_len, pmbuf->flags);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
/** drop the packet without skb in monitor mode */
|
|
if (pmbuf->flags & MLAN_BUF_FLAG_NET_MONITOR) {
|
|
PRINTM(MINFO,
|
|
"%s Drop packet without skb\n",
|
|
__func__);
|
|
status = MLAN_STATUS_FAILURE;
|
|
priv->stats.rx_dropped++;
|
|
goto done;
|
|
}
|
|
#endif
|
|
skb = dev_alloc_skb(pmbuf->data_len +
|
|
MLAN_NET_IP_ALIGN);
|
|
if (!skb) {
|
|
PRINTM(MERROR, "%s fail to alloc skb\n",
|
|
__func__);
|
|
status = MLAN_STATUS_FAILURE;
|
|
priv->stats.rx_dropped++;
|
|
goto done;
|
|
}
|
|
skb_reserve(skb, MLAN_NET_IP_ALIGN);
|
|
memcpy(skb->data,
|
|
(t_u8 *)(pmbuf->pbuf +
|
|
pmbuf->data_offset),
|
|
pmbuf->data_len);
|
|
skb_put(skb, pmbuf->data_len);
|
|
|
|
}
|
|
skb->dev = priv->netdev;
|
|
skb->protocol = eth_type_trans(skb, priv->netdev);
|
|
skb->ip_summed = CHECKSUM_NONE;
|
|
|
|
/* This is only required only in case of 11n and USB as we alloc
|
|
* a buffer of 4K only if its 11N (to be able to receive 4K AMSDU
|
|
* packets). In case of SD we allocate buffers based on the size
|
|
* of packet and hence this is not needed.
|
|
*/
|
|
/* Modifying the truesize here as our allocation for each skb is 4K
|
|
* but we only receive 2K packets and this cause the kernel to start
|
|
* dropping packets in case where application has allocated buffer
|
|
* based on 2K size i.e. if there a 64K packet received (in IP
|
|
* fragments and application allocates 64K to receive this packet
|
|
* but this packet would almost double up because we allocate each
|
|
* 1.5K fragment in 4K and pass it up. As soon as the 64K limit
|
|
* hits kernel will start to drop rest of the fragments. Currently
|
|
* we fail the Filesndl-ht.scr script for UDP, hence this fix
|
|
*/
|
|
|
|
if (skb->truesize > max_rx_data_size)
|
|
skb->truesize += (skb->len - max_rx_data_size);
|
|
priv->stats.rx_bytes += skb->len;
|
|
priv->stats.rx_packets++;
|
|
#ifdef ANDROID_KERNEL
|
|
if (wakelock_timeout) {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
|
|
__pm_wakeup_event(&handle->ws,
|
|
wakelock_timeout);
|
|
#else
|
|
wake_lock_timeout(&handle->wake_lock,
|
|
msecs_to_jiffies
|
|
(wakelock_timeout));
|
|
#endif
|
|
}
|
|
#endif
|
|
if (priv->rx_protocols.protocol_num) {
|
|
for (j = 0; j < priv->rx_protocols.protocol_num;
|
|
j++) {
|
|
if (htons(skb->protocol) ==
|
|
priv->rx_protocols.protocols[j])
|
|
rx_info_flag = MTRUE;
|
|
}
|
|
}
|
|
if (rx_info_flag &&
|
|
(skb_tailroom(skb) > sizeof(rxcontrol))) {
|
|
rxcontrol.datarate = pmbuf->u.rx_info.data_rate;
|
|
rxcontrol.channel = pmbuf->u.rx_info.channel;
|
|
rxcontrol.antenna = pmbuf->u.rx_info.antenna;
|
|
rxcontrol.rssi = pmbuf->u.rx_info.rssi;
|
|
skb_put(skb, sizeof(dot11_rxcontrol));
|
|
memmove(skb->data + sizeof(dot11_rxcontrol),
|
|
skb->data,
|
|
skb->len - sizeof(dot11_rxcontrol));
|
|
memcpy(skb->data, &rxcontrol,
|
|
sizeof(dot11_rxcontrol));
|
|
}
|
|
if (in_interrupt())
|
|
netif_rx(skb);
|
|
else {
|
|
if (atomic_read(&handle->rx_pending) >
|
|
MAX_RX_PENDING_THRHLD)
|
|
netif_rx(skb);
|
|
else
|
|
netif_rx_ni(skb);
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles event receive
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param pmevent Pointer to the mlan event structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_recv_event(IN t_void *pmoal_handle, IN pmlan_event pmevent)
|
|
{
|
|
#ifdef STA_SUPPORT
|
|
int custom_len = 0;
|
|
#ifdef STA_CFG80211
|
|
unsigned long flags;
|
|
#endif
|
|
#endif
|
|
moal_private *priv = NULL;
|
|
#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
|
|
moal_private *pmpriv = NULL;
|
|
#endif
|
|
char *pevent = NULL;
|
|
#if defined(STA_WEXT) || defined(UAP_WEXT)
|
|
#if defined(STA_SUPPORT) || defined(UAP_WEXT)
|
|
#if defined(UAP_SUPPORT) || defined(STA_WEXT)
|
|
union iwreq_data wrqu;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
mlan_ds_ps_info pm_info;
|
|
t_u8 category = 0;
|
|
t_u8 action_code = 0;
|
|
char *buf;
|
|
t_u8 peer_addr[ETH_ALEN] = { 0 };
|
|
moal_wnm_tm_msmt *tm_ind;
|
|
moal_wlan_802_11_header *header;
|
|
moal_timestamps *tsstamp;
|
|
t_u8 payload_len, i;
|
|
moal_ptp_context *ptp_context;
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
t_u8 enable = 1;
|
|
#endif
|
|
#endif
|
|
t_u8 *req_ie = NULL;
|
|
t_u16 ie_len = 0;
|
|
apinfo *pinfo = NULL, *req_tlv = NULL;
|
|
MrvlIEtypesHeader_t *tlv = NULL;
|
|
t_u16 tlv_type = 0, tlv_len = 0, tlv_buf_left = 0;
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
struct cfg80211_roam_info roam_info;
|
|
#endif
|
|
|
|
#if defined(UAP_CFG80211) || defined(STA_CFG80211)
|
|
chan_band_info *pchan_info = NULL;
|
|
#endif
|
|
t_u8 channel_status;
|
|
moal_private *remain_priv = NULL;
|
|
|
|
ENTER();
|
|
|
|
if ((pmevent->event_id != MLAN_EVENT_ID_DRV_DEFER_RX_WORK) &&
|
|
(pmevent->event_id != MLAN_EVENT_ID_DRV_DEFER_HANDLING) &&
|
|
(pmevent->event_id != MLAN_EVENT_ID_DRV_MGMT_FRAME))
|
|
PRINTM(MEVENT, "event id:0x%x\n", pmevent->event_id);
|
|
if (pmevent->event_id == MLAN_EVENT_ID_FW_DUMP_INFO) {
|
|
woal_store_firmware_dump(pmoal_handle, pmevent);
|
|
goto done;
|
|
}
|
|
if (pmevent->event_id == MLAN_EVENT_ID_STORE_HOST_CMD_RESP) {
|
|
woal_save_host_cmdresp((moal_handle *)pmoal_handle,
|
|
(mlan_cmdresp_event *) pmevent);
|
|
goto done;
|
|
}
|
|
priv = woal_bss_index_to_priv(pmoal_handle, pmevent->bss_index);
|
|
if (priv == NULL) {
|
|
PRINTM(MERROR, "%s: priv is null\n", __func__);
|
|
goto done;
|
|
}
|
|
if (priv->netdev == NULL) {
|
|
PRINTM(MERROR, "%s: netdev is null\n", __func__);
|
|
goto done;
|
|
}
|
|
pevent = kzalloc(512, GFP_ATOMIC);
|
|
if (!pevent) {
|
|
PRINTM(MERROR, "Failed to alloc memory for pevent\n");
|
|
goto done;
|
|
}
|
|
switch (pmevent->event_id) {
|
|
#ifdef STA_SUPPORT
|
|
case MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED:
|
|
priv->is_adhoc_link_sensed = MTRUE;
|
|
if (!netif_carrier_ok(priv->netdev))
|
|
netif_carrier_on(priv->netdev);
|
|
woal_wake_queue(priv->netdev);
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_ADHOC_LINK_SENSED);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_ADHOC_LINK_SENSED,
|
|
strlen(CUS_EVT_ADHOC_LINK_SENSED));
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_FW_ADHOC_LINK_LOST:
|
|
woal_stop_queue(priv->netdev);
|
|
if (netif_carrier_ok(priv->netdev))
|
|
netif_carrier_off(priv->netdev);
|
|
priv->is_adhoc_link_sensed = MFALSE;
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_ADHOC_LINK_LOST);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_ADHOC_LINK_LOST,
|
|
strlen(CUS_EVT_ADHOC_LINK_LOST));
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_DRV_CONNECTED:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext) &&
|
|
pmevent->event_len == ETH_ALEN) {
|
|
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
|
|
memcpy(wrqu.ap_addr.sa_data, pmevent->event_buf,
|
|
ETH_ALEN);
|
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
|
wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu,
|
|
NULL);
|
|
}
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
memcpy(priv->cfg_bssid, pmevent->event_buf, ETH_ALEN);
|
|
woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
|
|
PASSIVE_SCAN_CHAN_TIME,
|
|
MIN_SPECIFIC_SCAN_CHAN_TIME);
|
|
}
|
|
#endif
|
|
custom_len = strlen(CUS_EVT_AP_CONNECTED);
|
|
memmove(pmevent->event_buf + custom_len, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
memcpy(pmevent->event_buf, CUS_EVT_AP_CONNECTED, custom_len);
|
|
pmevent->event_len += custom_len;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
woal_update_dscp_mapping(priv);
|
|
priv->media_connected = MTRUE;
|
|
if (!netif_carrier_ok(priv->netdev))
|
|
netif_carrier_on(priv->netdev);
|
|
woal_wake_queue(priv->netdev);
|
|
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_DRV_SCAN_REPORT:
|
|
PRINTM(MINFO, "Scan report\n");
|
|
|
|
if (priv->report_scan_result) {
|
|
priv->report_scan_result = MFALSE;
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
if (priv->phandle->scan_request) {
|
|
PRINTM(MINFO,
|
|
"Reporting scan results\n");
|
|
woal_inform_bss_from_scan_result(priv,
|
|
NULL,
|
|
MOAL_NO_WAIT);
|
|
if (!priv->phandle->first_scan_done) {
|
|
priv->phandle->first_scan_done =
|
|
MTRUE;
|
|
woal_set_scan_time(priv,
|
|
ACTIVE_SCAN_CHAN_TIME,
|
|
PASSIVE_SCAN_CHAN_TIME,
|
|
SPECIFIC_SCAN_CHAN_TIME);
|
|
}
|
|
spin_lock_irqsave(&priv->phandle->
|
|
scan_req_lock, flags);
|
|
if (priv->phandle->scan_request) {
|
|
woal_cfg80211_scan_done(priv->
|
|
phandle->
|
|
scan_request,
|
|
MFALSE);
|
|
priv->phandle->scan_request =
|
|
NULL;
|
|
}
|
|
spin_unlock_irqrestore(&priv->phandle->
|
|
scan_req_lock,
|
|
flags);
|
|
}
|
|
}
|
|
#endif /* STA_CFG80211 */
|
|
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
memset(&wrqu, 0, sizeof(union iwreq_data));
|
|
wireless_send_event(priv->netdev, SIOCGIWSCAN,
|
|
&wrqu, NULL);
|
|
}
|
|
#endif
|
|
woal_broadcast_event(priv, (t_u8 *)&pmevent->event_id,
|
|
sizeof(mlan_event_id));
|
|
|
|
}
|
|
|
|
if (priv->phandle->scan_pending_on_block == MTRUE) {
|
|
priv->phandle->scan_pending_on_block = MFALSE;
|
|
priv->phandle->scan_priv = NULL;
|
|
MOAL_REL_SEMAPHORE(&priv->phandle->async_sem);
|
|
}
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM:
|
|
memmove((pmevent->event_buf + strlen(CUS_EVT_OBSS_SCAN_PARAM) +
|
|
1), pmevent->event_buf, pmevent->event_len);
|
|
memcpy(pmevent->event_buf, (t_u8 *)CUS_EVT_OBSS_SCAN_PARAM,
|
|
strlen(CUS_EVT_OBSS_SCAN_PARAM));
|
|
pmevent->event_buf[strlen(CUS_EVT_OBSS_SCAN_PARAM)] = 0;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_OBSS_SCAN_PARAM));
|
|
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
memset(&wrqu, 0, sizeof(union iwreq_data));
|
|
wrqu.data.pointer = pmevent->event_buf;
|
|
wrqu.data.length =
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1;
|
|
wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
|
|
pmevent->event_buf);
|
|
}
|
|
#endif
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BW_CHANGED:
|
|
memmove((pmevent->event_buf + strlen(CUS_EVT_BW_CHANGED) + 1),
|
|
pmevent->event_buf, pmevent->event_len);
|
|
memcpy(pmevent->event_buf, (t_u8 *)CUS_EVT_BW_CHANGED,
|
|
strlen(CUS_EVT_BW_CHANGED));
|
|
pmevent->event_buf[strlen(CUS_EVT_BW_CHANGED)] = 0;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_BW_CHANGED));
|
|
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
memset(&wrqu, 0, sizeof(union iwreq_data));
|
|
wrqu.data.pointer = pmevent->event_buf;
|
|
wrqu.data.length =
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_BW_CHANGED) + 1;
|
|
wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
|
|
pmevent->event_buf);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_FW_DISCONNECTED:
|
|
|
|
woal_send_disconnect_to_system(priv,
|
|
(t_u16)*pmevent->event_buf);
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
priv->auth_flag = 0;
|
|
priv->host_mlme = MFALSE;
|
|
#endif
|
|
#endif
|
|
#ifdef STA_WEXT
|
|
/* Reset wireless stats signal info */
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
priv->w_stats.qual.level = 0;
|
|
priv->w_stats.qual.noise = 0;
|
|
}
|
|
#endif
|
|
#ifdef REASSOCIATION
|
|
if (priv->reassoc_on == MTRUE) {
|
|
PRINTM(MINFO, "Reassoc: trigger the timer\n");
|
|
priv->reassoc_required = MTRUE;
|
|
priv->phandle->is_reassoc_timer_set = MTRUE;
|
|
woal_mod_timer(&priv->phandle->reassoc_timer,
|
|
REASSOC_TIMER_DEFAULT);
|
|
} else {
|
|
priv->rate_index = AUTO_RATE;
|
|
}
|
|
#endif /* REASSOCIATION */
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_FW_MIC_ERR_UNI:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
#if WIRELESS_EXT >= 18
|
|
woal_send_mic_error_event(priv,
|
|
MLAN_EVENT_ID_FW_MIC_ERR_UNI);
|
|
#else
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_MLME_MIC_ERR_UNI);
|
|
#endif
|
|
}
|
|
#endif /* STA_WEXT */
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
cfg80211_michael_mic_failure(priv->netdev,
|
|
priv->cfg_bssid,
|
|
NL80211_KEYTYPE_PAIRWISE,
|
|
-1, NULL, GFP_KERNEL);
|
|
}
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_MLME_MIC_ERR_UNI,
|
|
strlen(CUS_EVT_MLME_MIC_ERR_UNI));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_MIC_ERR_MUL:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
#if WIRELESS_EXT >= 18
|
|
woal_send_mic_error_event(priv,
|
|
MLAN_EVENT_ID_FW_MIC_ERR_MUL);
|
|
#else
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_MLME_MIC_ERR_MUL);
|
|
#endif
|
|
}
|
|
#endif /* STA_WEXT */
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
cfg80211_michael_mic_failure(priv->netdev,
|
|
priv->cfg_bssid,
|
|
NL80211_KEYTYPE_GROUP, -1,
|
|
NULL, GFP_KERNEL);
|
|
}
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_MLME_MIC_ERR_MUL,
|
|
strlen(CUS_EVT_MLME_MIC_ERR_MUL));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BCN_RSSI_LOW:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_BEACON_RSSI_LOW);
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
|
|
cfg80211_cqm_rssi_notify(priv->netdev,
|
|
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
|
*(t_s16 *)pmevent->event_buf,
|
|
#endif
|
|
GFP_KERNEL);
|
|
priv->last_event |= EVENT_BCN_RSSI_LOW;
|
|
#endif
|
|
if (!hw_test && priv->roaming_enabled)
|
|
woal_config_bgscan_and_rssi(priv, MTRUE);
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
woal_cfg80211_rssi_monitor_event(priv,
|
|
*(t_s16 *)pmevent->
|
|
event_buf);
|
|
#endif
|
|
}
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_BEACON_RSSI_LOW,
|
|
strlen(CUS_EVT_BEACON_RSSI_LOW));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_BEACON_RSSI_HIGH);
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
if (!priv->mrvl_rssi_low) {
|
|
#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
|
|
cfg80211_cqm_rssi_notify(priv->netdev,
|
|
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
|
*(t_s16 *)pmevent->
|
|
event_buf,
|
|
#endif
|
|
GFP_KERNEL);
|
|
#endif
|
|
woal_set_rssi_threshold(priv,
|
|
MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
|
|
MOAL_NO_WAIT);
|
|
}
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
woal_cfg80211_rssi_monitor_event(priv,
|
|
*(t_s16 *)pmevent->
|
|
event_buf);
|
|
#endif
|
|
}
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_BEACON_RSSI_HIGH,
|
|
strlen(CUS_EVT_BEACON_RSSI_HIGH));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BCN_SNR_LOW:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_BEACON_SNR_LOW);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_BEACON_SNR_LOW,
|
|
strlen(CUS_EVT_BEACON_SNR_LOW));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BCN_SNR_HIGH:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_BEACON_SNR_HIGH);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_BEACON_SNR_HIGH,
|
|
strlen(CUS_EVT_BEACON_SNR_HIGH));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_MAX_FAIL:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_MAX_FAIL,
|
|
strlen(CUS_EVT_MAX_FAIL));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_DATA_RSSI_LOW:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_DATA_RSSI_LOW,
|
|
strlen(CUS_EVT_DATA_RSSI_LOW));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_DATA_SNR_LOW:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_DATA_SNR_LOW,
|
|
strlen(CUS_EVT_DATA_SNR_LOW));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_DATA_RSSI_HIGH:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_DATA_RSSI_HIGH);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_DATA_RSSI_HIGH,
|
|
strlen(CUS_EVT_DATA_RSSI_HIGH));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_DATA_SNR_HIGH:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_DATA_SNR_HIGH,
|
|
strlen(CUS_EVT_DATA_SNR_HIGH));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_LINK_QUALITY:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_LINK_QUALITY);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_LINK_QUALITY,
|
|
strlen(CUS_EVT_LINK_QUALITY));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_PORT_RELEASE:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_PORT_RELEASE);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_PORT_RELEASE,
|
|
strlen(CUS_EVT_PORT_RELEASE));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_PRE_BCN_LOST:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_PRE_BEACON_LOST);
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
struct cfg80211_bss *bss = NULL;
|
|
bss = cfg80211_get_bss(priv->wdev->wiphy, NULL,
|
|
priv->cfg_bssid, NULL, 0,
|
|
WLAN_CAPABILITY_ESS,
|
|
WLAN_CAPABILITY_ESS);
|
|
if (bss)
|
|
cfg80211_unlink_bss(priv->wdev->wiphy, bss);
|
|
if (!hw_test && priv->roaming_enabled)
|
|
woal_config_bgscan_and_rssi(priv, MFALSE);
|
|
priv->last_event |= EVENT_PRE_BCN_LOST;
|
|
}
|
|
#endif
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_PRE_BEACON_LOST,
|
|
strlen(CUS_EVT_PRE_BEACON_LOST));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_DEBUG_INFO:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, pmevent->event_buf);
|
|
#endif
|
|
memmove((pmevent->event_buf + strlen(FW_DEBUG_INFO) + 1),
|
|
pmevent->event_buf, pmevent->event_len);
|
|
memcpy(pmevent->event_buf, (t_u8 *)FW_DEBUG_INFO,
|
|
strlen(FW_DEBUG_INFO));
|
|
pmevent->event_buf[strlen(FW_DEBUG_INFO)] = 0;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len +
|
|
strlen(FW_DEBUG_INFO) + 1);
|
|
break;
|
|
case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
WMM_CONFIG_CHANGE_INDICATION);
|
|
#endif
|
|
woal_broadcast_event(priv, WMM_CONFIG_CHANGE_INDICATION,
|
|
strlen(WMM_CONFIG_CHANGE_INDICATION));
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_DRV_REPORT_STRING:
|
|
PRINTM(MINFO, "Report string %s\n", pmevent->event_buf);
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, pmevent->event_buf);
|
|
#endif
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
strlen(pmevent->event_buf));
|
|
break;
|
|
case MLAN_EVENT_ID_FW_WEP_ICV_ERR:
|
|
DBG_HEXDUMP(MCMD_D, "WEP ICV error", pmevent->event_buf,
|
|
pmevent->event_len);
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv, CUS_EVT_WEP_ICV_ERR);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_WEP_ICV_ERR,
|
|
strlen(CUS_EVT_WEP_ICV_ERR));
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_DRV_DEFER_HANDLING:
|
|
queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_FLUSH_RX_WORK:
|
|
if (napi) {
|
|
napi_synchronize(&priv->phandle->napi_rx);
|
|
break;
|
|
}
|
|
flush_workqueue(priv->phandle->rx_workqueue);
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK:
|
|
flush_workqueue(priv->phandle->workqueue);
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_DEFER_RX_WORK:
|
|
if (napi) {
|
|
napi_schedule(&priv->phandle->napi_rx);
|
|
break;
|
|
}
|
|
queue_work(priv->phandle->rx_workqueue,
|
|
&priv->phandle->rx_work);
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_DBG_DUMP:
|
|
priv->phandle->driver_state = MTRUE;
|
|
woal_moal_debug_info(priv, NULL, MFALSE);
|
|
woal_broadcast_event(priv, CUS_EVT_DRIVER_HANG,
|
|
strlen(CUS_EVT_DRIVER_HANG));
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
|
|
woal_cfg80211_vendor_event(priv, event_hang,
|
|
CUS_EVT_DRIVER_HANG,
|
|
strlen(CUS_EVT_DRIVER_HANG));
|
|
#endif
|
|
#endif
|
|
woal_process_hang(priv->phandle);
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BG_SCAN:
|
|
if (priv->media_connected == MTRUE)
|
|
priv->bg_scan_start = MFALSE;
|
|
priv->bg_scan_reported = MTRUE;
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext)) {
|
|
memset(&wrqu, 0, sizeof(union iwreq_data));
|
|
wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu,
|
|
NULL);
|
|
}
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
priv->last_event |= EVENT_BG_SCAN_REPORT;
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
|
|
if (priv->sched_scanning &&
|
|
!priv->phandle->cfg80211_suspend) {
|
|
mlan_scan_resp scan_resp;
|
|
woal_get_scan_table(priv, MOAL_NO_WAIT,
|
|
&scan_resp);
|
|
PRINTM(MIOCTL,
|
|
"Trigger mlan get bgscan result\n");
|
|
}
|
|
#endif
|
|
if (!hw_test && priv->roaming_enabled
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
|
|
&& !priv->phandle->cfg80211_suspend
|
|
#endif
|
|
) {
|
|
priv->roaming_required = MTRUE;
|
|
#ifdef ANDROID_KERNEL
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
|
|
__pm_wakeup_event(&priv->phandle->ws,
|
|
ROAMING_WAKE_LOCK_TIMEOUT);
|
|
#else
|
|
wake_lock_timeout(&priv->phandle->wake_lock,
|
|
msecs_to_jiffies
|
|
(ROAMING_WAKE_LOCK_TIMEOUT));
|
|
#endif
|
|
#endif
|
|
wake_up_interruptible(&priv->phandle->
|
|
reassoc_thread.wait_q);
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
case MLAN_EVENT_ID_FW_BG_SCAN_STOPPED:
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
if (priv->sched_scanning) {
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 14, 6)
|
|
priv->phandle->rx_bgscan_stop = MTRUE;
|
|
priv->phandle->bg_scan_priv = priv;
|
|
queue_work(priv->phandle->rx_workqueue,
|
|
&priv->phandle->rx_work);
|
|
#else
|
|
if (rtnl_is_locked())
|
|
cfg80211_sched_scan_stopped_rtnl(priv->
|
|
wdev->
|
|
wiphy
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
, 0
|
|
#endif
|
|
);
|
|
else
|
|
cfg80211_sched_scan_stopped(priv->wdev->
|
|
wiphy
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
, 0
|
|
#endif
|
|
);
|
|
priv->sched_scanning = MFALSE;
|
|
#endif
|
|
PRINTM(MEVENT, "Sched_Scan stopped\n");
|
|
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_BGSCAN_RESULT:
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
if (priv->sched_scanning &&
|
|
!priv->phandle->cfg80211_suspend) {
|
|
woal_inform_bss_from_scan_result(priv, NULL,
|
|
MOAL_NO_WAIT);
|
|
cfg80211_sched_scan_results(priv->wdev->wiphy
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
,
|
|
priv->bg_scan_reqid
|
|
#endif
|
|
);
|
|
priv->last_event = 0;
|
|
PRINTM(MEVENT,
|
|
"Reporting Sched_Scan results\n");
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 14, 6)
|
|
priv->phandle->rx_bgscan_stop = MTRUE;
|
|
priv->phandle->bg_scan_priv = priv;
|
|
queue_work(priv->phandle->rx_workqueue,
|
|
&priv->phandle->rx_work);
|
|
#else
|
|
if (rtnl_is_locked())
|
|
cfg80211_sched_scan_stopped_rtnl(priv->
|
|
wdev->
|
|
wiphy
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
, 0
|
|
#endif
|
|
);
|
|
else
|
|
cfg80211_sched_scan_stopped(priv->wdev->
|
|
wiphy
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
, 0
|
|
#endif
|
|
);
|
|
priv->sched_scanning = MFALSE;
|
|
#endif
|
|
PRINTM(MEVENT, "Sched_Scan stopped\n");
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
#ifdef UAP_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
|
case MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY:
|
|
if (priv->phandle->is_cac_timer_set) {
|
|
t_u8 radar_detected = pmevent->event_buf[0];
|
|
PRINTM(MEVENT, "%s radar found when CAC \n",
|
|
radar_detected ? "" : "No");
|
|
moal_stop_timer(priv->phandle,
|
|
&priv->phandle->cac_timer);
|
|
priv->phandle->is_cac_timer_set = MFALSE;
|
|
if (radar_detected) {
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
cfg80211_cac_event(priv->netdev,
|
|
&priv->phandle->dfs_channel,
|
|
NL80211_RADAR_CAC_ABORTED,
|
|
GFP_KERNEL);
|
|
#else
|
|
cfg80211_cac_event(priv->netdev,
|
|
NL80211_RADAR_CAC_ABORTED,
|
|
GFP_KERNEL);
|
|
#endif
|
|
cfg80211_radar_event(priv->wdev->wiphy,
|
|
&priv->phandle->
|
|
dfs_channel, GFP_KERNEL);
|
|
} else {
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
cfg80211_cac_event(priv->netdev,
|
|
&priv->phandle->dfs_channel,
|
|
NL80211_RADAR_CAC_FINISHED,
|
|
GFP_KERNEL);
|
|
#else
|
|
cfg80211_cac_event(priv->netdev,
|
|
NL80211_RADAR_CAC_FINISHED,
|
|
GFP_KERNEL);
|
|
#endif
|
|
}
|
|
memset(&priv->phandle->dfs_channel, 0,
|
|
sizeof(struct cfg80211_chan_def));
|
|
priv->phandle->cac_bss_index = 0xff;
|
|
}
|
|
break;
|
|
case MLAN_EVENT_ID_FW_RADAR_DETECTED:
|
|
if (priv->phandle->is_cac_timer_set) {
|
|
if (priv->bss_index == priv->phandle->cac_bss_index) {
|
|
PRINTM(MEVENT, "radar detected during CAC \n");
|
|
woal_cancel_timer(&priv->phandle->cac_timer);
|
|
priv->phandle->is_cac_timer_set = MFALSE;
|
|
/* downstream: cancel the unfinished CAC in Firmware */
|
|
woal_11h_cancel_chan_report_ioctl(priv,
|
|
MOAL_NO_WAIT);
|
|
/* upstream: inform cfg80211 */
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
cfg80211_cac_event(priv->netdev,
|
|
&priv->phandle->dfs_channel,
|
|
NL80211_RADAR_CAC_ABORTED,
|
|
GFP_KERNEL);
|
|
#else
|
|
cfg80211_cac_event(priv->netdev,
|
|
NL80211_RADAR_CAC_ABORTED,
|
|
GFP_KERNEL);
|
|
#endif
|
|
cfg80211_radar_event(priv->wdev->wiphy,
|
|
&priv->phandle->
|
|
dfs_channel, GFP_KERNEL);
|
|
|
|
memset(&priv->phandle->dfs_channel, 0,
|
|
sizeof(priv->phandle->dfs_channel));
|
|
priv->phandle->cac_bss_index = 0xff;
|
|
} else {
|
|
PRINTM(MERROR,
|
|
" Radar event for incorrect inferface \n");
|
|
}
|
|
} else {
|
|
PRINTM(MEVENT, "radar detected during BSS active \n");
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
if (dfs_offload)
|
|
woal_cfg80211_dfs_vendor_event(priv,
|
|
event_dfs_radar_detected,
|
|
&priv->chan);
|
|
else
|
|
#endif
|
|
cfg80211_radar_event(priv->wdev->wiphy,
|
|
&priv->chan, GFP_KERNEL);
|
|
}
|
|
break;
|
|
#endif
|
|
#endif
|
|
case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN:
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext))
|
|
woal_send_iwevcustom_event(priv,
|
|
CUS_EVT_CHANNEL_SWITCH_ANN);
|
|
#endif
|
|
woal_broadcast_event(priv, CUS_EVT_CHANNEL_SWITCH_ANN,
|
|
strlen(CUS_EVT_CHANNEL_SWITCH_ANN));
|
|
break;
|
|
#endif /* STA_SUPPORT */
|
|
case MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE:
|
|
#if defined(UAP_CFG80211) || defined(STA_CFG80211)
|
|
pchan_info = (chan_band_info *) pmevent->event_buf;
|
|
if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
|
|
PRINTM(MMSG,
|
|
"CSA/ECSA: Switch to new channel %d complete!\n",
|
|
pchan_info->channel);
|
|
priv->channel = pchan_info->channel;
|
|
#ifdef UAP_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,12,0)
|
|
if (priv->csa_chan.chan &&
|
|
(pchan_info->channel ==
|
|
priv->csa_chan.chan->hw_value)) {
|
|
memcpy(&priv->chan, &priv->csa_chan,
|
|
sizeof(struct cfg80211_chan_def));
|
|
}
|
|
#endif
|
|
#endif
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
if (MFALSE
|
|
#ifdef UAP_CFG80211
|
|
|| priv->uap_host_based
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
|| priv->sme_current.ssid_len
|
|
#endif
|
|
) {
|
|
PRINTM(MEVENT,
|
|
"CHAN_SWITCH: 11n=%d, chan=%d, center_chan=%d, band=%d, width=%d, 2Offset=%d\n",
|
|
pchan_info->is_11n_enabled,
|
|
pchan_info->channel,
|
|
pchan_info->center_chan,
|
|
pchan_info->bandcfg.chanBand,
|
|
pchan_info->bandcfg.chanWidth,
|
|
pchan_info->bandcfg.chan2Offset);
|
|
woal_cfg80211_notify_channel(priv, pchan_info);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
#ifdef UAP_SUPPORT
|
|
if (priv->bss_role == MLAN_BSS_ROLE_UAP) {
|
|
if (priv->uap_tx_blocked) {
|
|
if (!netif_carrier_ok(priv->netdev))
|
|
netif_carrier_on(priv->netdev);
|
|
woal_start_queue(priv->netdev);
|
|
priv->uap_tx_blocked = MFALSE;
|
|
}
|
|
priv->phandle->chsw_wait_q_woken = MTRUE;
|
|
wake_up_interruptible(&priv->phandle->chsw_wait_q);
|
|
}
|
|
#endif
|
|
break;
|
|
case MLAN_EVENT_ID_FW_STOP_TX:
|
|
woal_stop_queue(priv->netdev);
|
|
if (netif_carrier_ok(priv->netdev))
|
|
netif_carrier_off(priv->netdev);
|
|
break;
|
|
case MLAN_EVENT_ID_FW_START_TX:
|
|
if (!netif_carrier_ok(priv->netdev))
|
|
netif_carrier_on(priv->netdev);
|
|
woal_wake_queue(priv->netdev);
|
|
break;
|
|
case MLAN_EVENT_ID_FW_HS_WAKEUP:
|
|
/* simulate HSCFG_CANCEL command */
|
|
woal_cancel_hs(priv, MOAL_NO_WAIT);
|
|
#ifdef STA_SUPPORT
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_STA);
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext) && pmpriv)
|
|
woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_WAKEUP);
|
|
#endif /* STA_WEXT */
|
|
if (pmpriv)
|
|
woal_broadcast_event(pmpriv, CUS_EVT_HS_WAKEUP,
|
|
strlen(CUS_EVT_HS_WAKEUP));
|
|
#endif /*STA_SUPPORT */
|
|
#ifdef UAP_SUPPORT
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_UAP);
|
|
if (pmpriv) {
|
|
pmevent->event_id = UAP_EVENT_ID_HS_WAKEUP;
|
|
woal_broadcast_event(pmpriv, (t_u8 *)&pmevent->event_id,
|
|
sizeof(t_u32));
|
|
}
|
|
#endif /* UAP_SUPPORT */
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_HS_ACTIVATED:
|
|
#ifdef STA_SUPPORT
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_STA);
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext) && pmpriv)
|
|
woal_send_iwevcustom_event(pmpriv,
|
|
CUS_EVT_HS_ACTIVATED);
|
|
#endif /* STA_WEXT */
|
|
if (pmpriv)
|
|
woal_broadcast_event(pmpriv, CUS_EVT_HS_ACTIVATED,
|
|
strlen(CUS_EVT_HS_ACTIVATED));
|
|
#endif /* STA_SUPPORT */
|
|
#if defined(UAP_SUPPORT)
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_UAP);
|
|
if (pmpriv) {
|
|
pmevent->event_id = UAP_EVENT_ID_DRV_HS_ACTIVATED;
|
|
woal_broadcast_event(pmpriv, (t_u8 *)&pmevent->event_id,
|
|
sizeof(t_u32));
|
|
}
|
|
#endif
|
|
if (priv->phandle->suspend_fail == MFALSE) {
|
|
woal_get_pm_info(priv, &pm_info);
|
|
if (pm_info.is_suspend_allowed == MTRUE) {
|
|
priv->phandle->hs_activated = MTRUE;
|
|
#ifdef MMC_PM_FUNC_SUSPENDED
|
|
woal_wlan_is_suspended(priv->phandle);
|
|
#endif
|
|
}
|
|
priv->phandle->hs_activate_wait_q_woken = MTRUE;
|
|
wake_up(&priv->phandle->hs_activate_wait_q);
|
|
}
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_HS_DEACTIVATED:
|
|
#ifdef STA_SUPPORT
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_STA);
|
|
#ifdef STA_WEXT
|
|
if (IS_STA_WEXT(cfg80211_wext) && pmpriv)
|
|
woal_send_iwevcustom_event(pmpriv,
|
|
CUS_EVT_HS_DEACTIVATED);
|
|
#endif /* STA_WEXT */
|
|
if (pmpriv)
|
|
woal_broadcast_event(pmpriv, CUS_EVT_HS_DEACTIVATED,
|
|
strlen(CUS_EVT_HS_DEACTIVATED));
|
|
#endif /* STA_SUPPORT */
|
|
#if defined(UAP_SUPPORT)
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_UAP);
|
|
if (pmpriv) {
|
|
pmevent->event_id = UAP_EVENT_ID_DRV_HS_DEACTIVATED;
|
|
woal_broadcast_event(pmpriv, (t_u8 *)&pmevent->event_id,
|
|
sizeof(t_u32));
|
|
}
|
|
#endif
|
|
priv->phandle->hs_activated = MFALSE;
|
|
break;
|
|
#ifdef UAP_SUPPORT
|
|
case MLAN_EVENT_ID_UAP_FW_BSS_START:
|
|
if (priv->hist_data)
|
|
woal_hist_data_reset(priv);
|
|
priv->bss_started = MTRUE;
|
|
priv->skip_cac = MFALSE;
|
|
if (!netif_carrier_ok(priv->netdev))
|
|
netif_carrier_on(priv->netdev);
|
|
woal_start_queue(priv->netdev);
|
|
memcpy(priv->current_addr, pmevent->event_buf + 6, ETH_ALEN);
|
|
memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
#ifdef STA_SUPPORT
|
|
#ifdef STA_CFG80211
|
|
pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
|
|
MLAN_BSS_ROLE_STA);
|
|
if (IS_STA_CFG80211(cfg80211_wext) && pmpriv)
|
|
woal_set_scan_time(pmpriv, ACTIVE_SCAN_CHAN_TIME,
|
|
PASSIVE_SCAN_CHAN_TIME,
|
|
MIN_SPECIFIC_SCAN_CHAN_TIME);
|
|
#endif
|
|
#endif
|
|
#ifdef UAP_CFG80211
|
|
#if defined(DFS_TESTING_SUPPORT)
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
|
if (priv->chan_under_nop) {
|
|
PRINTM(MMSG,
|
|
"Channel Under Nop: notify cfg80211 new channel=%d\n",
|
|
priv->channel);
|
|
cfg80211_ch_switch_notify(priv->netdev, &priv->chan);
|
|
priv->chan_under_nop = MFALSE;
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
break;
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
|
|
case MLAN_EVENT_ID_DRV_UAP_CHAN_INFO:
|
|
#ifdef UAP_CFG80211
|
|
if (IS_UAP_CFG80211(cfg80211_wext)) {
|
|
chan_band_info *pchan_info =
|
|
(chan_band_info *) pmevent->event_buf;
|
|
PRINTM(MEVENT,
|
|
"UAP: 11n=%d, chan=%d, center_chan=%d, band=%d, width=%d, 2Offset=%d\n",
|
|
pchan_info->is_11n_enabled, pchan_info->channel,
|
|
pchan_info->center_chan,
|
|
pchan_info->bandcfg.chanBand,
|
|
pchan_info->bandcfg.chanWidth,
|
|
pchan_info->bandcfg.chan2Offset);
|
|
if (priv->uap_host_based &&
|
|
(priv->channel != pchan_info->channel))
|
|
woal_cfg80211_notify_channel(priv, pchan_info);
|
|
}
|
|
#endif
|
|
break;
|
|
#endif
|
|
case MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE:
|
|
priv->media_connected = MTRUE;
|
|
if (!netif_carrier_ok(priv->netdev))
|
|
netif_carrier_on(priv->netdev);
|
|
woal_wake_queue(priv->netdev);
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
break;
|
|
case MLAN_EVENT_ID_UAP_FW_BSS_IDLE:
|
|
priv->media_connected = MFALSE;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
break;
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
case MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED:
|
|
if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
|
|
PRINTM(MEVENT,
|
|
"FW_REMAIN_ON_CHANNEL_EXPIRED cookie = %#llx\n",
|
|
priv->phandle->cookie);
|
|
priv->phandle->remain_on_channel = MFALSE;
|
|
if (priv->phandle->cookie &&
|
|
!priv->phandle->is_remain_timer_set) {
|
|
cfg80211_remain_on_channel_expired(
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
|
|
priv->
|
|
netdev,
|
|
#else
|
|
priv->
|
|
wdev,
|
|
#endif
|
|
priv->
|
|
phandle->
|
|
cookie,
|
|
&priv->
|
|
phandle->
|
|
chan,
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
|
|
priv->
|
|
phandle->
|
|
channel_type,
|
|
#endif
|
|
GFP_ATOMIC);
|
|
priv->phandle->cookie = 0;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
case MLAN_EVENT_ID_UAP_FW_STA_CONNECT:
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
|
|
struct station_info sinfo = { 0 };
|
|
t_u8 addr[ETH_ALEN];
|
|
|
|
sinfo.filled = 0;
|
|
sinfo.generation = 0;
|
|
/* copy the station mac address */
|
|
memset(addr, 0xFF, ETH_ALEN);
|
|
memcpy(addr, pmevent->event_buf, ETH_ALEN);
|
|
/** these field add in kernel 3.2, but some
|
|
* kernel do have the pacth to support it,
|
|
* like T3T and pxa978T 3.0.31 JB, these
|
|
* patch are needed to support
|
|
* wpa_supplicant 2.x */
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 31)
|
|
if (pmevent->event_len > ETH_ALEN) {
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
|
|
/* set station info filled flag */
|
|
sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
|
|
#endif
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
|
|
sinfo.pertid = NULL;
|
|
#endif
|
|
/* get the assoc request ies and length */
|
|
sinfo.assoc_req_ies =
|
|
(const t_u8 *)(pmevent->event_buf +
|
|
ETH_ALEN);
|
|
sinfo.assoc_req_ies_len =
|
|
pmevent->event_len - ETH_ALEN;
|
|
|
|
}
|
|
#endif /* KERNEL_VERSION */
|
|
if (priv->netdev && priv->wdev)
|
|
cfg80211_new_sta(priv->netdev,
|
|
(t_u8 *)addr, &sinfo,
|
|
GFP_KERNEL);
|
|
}
|
|
#endif /* UAP_CFG80211 */
|
|
memmove((pmevent->event_buf + strlen(CUS_EVT_STA_CONNECTED) +
|
|
1), pmevent->event_buf, pmevent->event_len);
|
|
memcpy(pmevent->event_buf, (t_u8 *)CUS_EVT_STA_CONNECTED,
|
|
strlen(CUS_EVT_STA_CONNECTED));
|
|
pmevent->event_buf[strlen(CUS_EVT_STA_CONNECTED)] = 0;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_STA_CONNECTED));
|
|
#ifdef UAP_WEXT
|
|
if (IS_UAP_WEXT(cfg80211_wext)) {
|
|
memset(&wrqu, 0, sizeof(union iwreq_data));
|
|
wrqu.data.pointer = pmevent->event_buf;
|
|
if ((pmevent->event_len +
|
|
strlen(CUS_EVT_STA_CONNECTED) + 1) > IW_CUSTOM_MAX)
|
|
wrqu.data.length =
|
|
ETH_ALEN +
|
|
strlen(CUS_EVT_STA_CONNECTED) + 1;
|
|
else
|
|
wrqu.data.length =
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_STA_CONNECTED) + 1;
|
|
wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
|
|
pmevent->event_buf);
|
|
}
|
|
#endif /* UAP_WEXT */
|
|
break;
|
|
case MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT:
|
|
#ifdef UAP_CFG80211
|
|
if (IS_UAP_CFG80211(cfg80211_wext)) {
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
|
|
/* skip 2 bytes extra header will get the mac address */
|
|
if (priv->netdev && priv->wdev)
|
|
cfg80211_del_sta(priv->netdev,
|
|
pmevent->event_buf + 2,
|
|
GFP_KERNEL);
|
|
#endif /* KERNEL_VERSION */
|
|
}
|
|
#endif /* UAP_CFG80211 */
|
|
memmove((pmevent->event_buf + strlen(CUS_EVT_STA_DISCONNECTED) +
|
|
1), pmevent->event_buf, pmevent->event_len);
|
|
memcpy(pmevent->event_buf, (t_u8 *)CUS_EVT_STA_DISCONNECTED,
|
|
strlen(CUS_EVT_STA_DISCONNECTED));
|
|
pmevent->event_buf[strlen(CUS_EVT_STA_DISCONNECTED)] = 0;
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_STA_DISCONNECTED));
|
|
|
|
#ifdef UAP_WEXT
|
|
if (IS_UAP_WEXT(cfg80211_wext)) {
|
|
memset(&wrqu, 0, sizeof(union iwreq_data));
|
|
wrqu.data.pointer = pmevent->event_buf;
|
|
wrqu.data.length =
|
|
pmevent->event_len +
|
|
strlen(CUS_EVT_STA_DISCONNECTED) + 1;
|
|
wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
|
|
pmevent->event_buf);
|
|
}
|
|
#endif /* UAP_WEXT */
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_MGMT_FRAME:
|
|
buf = (t_u8 *)(pmevent->event_buf + sizeof(pmevent->event_id));
|
|
payload_len =
|
|
pmevent->event_len - sizeof(pmevent->event_id) -
|
|
sizeof(moal_timestamps);
|
|
category = *(buf + sizeof(moal_wlan_802_11_header));
|
|
action_code = *(buf + sizeof(moal_wlan_802_11_header) + 1);
|
|
header = (moal_wlan_802_11_header *) (buf);
|
|
tm_ind = (moal_wnm_tm_msmt *) (buf +
|
|
sizeof(moal_wlan_802_11_header) +
|
|
2);
|
|
tsstamp = (moal_timestamps *) ((t_u8 *)buf + payload_len);
|
|
memcpy(peer_addr, (t_u8 *)&header->addr2, ETH_ALEN);
|
|
if ((category == IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM) &&
|
|
(action_code == 0x1)) {
|
|
sprintf(pevent,
|
|
"%s " FULL_MACSTR
|
|
" %u %u %u %u %u %u %u %u %u %u %lu %llu",
|
|
CUS_EVT_TM_FRAME_INDICATION,
|
|
FULL_MAC2STR(peer_addr), tm_ind->dialog_token,
|
|
tsstamp->t2, tsstamp->t2_err, tsstamp->t3,
|
|
tsstamp->t3_err, tm_ind->follow_up_dialog_token,
|
|
tm_ind->t1, tm_ind->t1_err, tm_ind->t4,
|
|
tm_ind->t4_err,
|
|
(unsigned long)tsstamp->t2 * 10L,
|
|
tsstamp->ingress_time);
|
|
|
|
if (payload_len >
|
|
(sizeof(moal_wnm_tm_msmt) +
|
|
sizeof(moal_wlan_802_11_header) + 2)) {
|
|
ptp_context =
|
|
(moal_ptp_context *) (buf +
|
|
sizeof
|
|
(moal_wlan_802_11_header)
|
|
+ 2 +
|
|
sizeof
|
|
(moal_wnm_tm_msmt));
|
|
sprintf(pevent + strlen(pevent), " %02x %02x",
|
|
ptp_context->vendor_specific,
|
|
ptp_context->length);
|
|
for (i = 0; i < ptp_context->length; i++)
|
|
sprintf(pevent + strlen(pevent),
|
|
" %02x", ptp_context->data[i]);
|
|
}
|
|
woal_broadcast_event(priv, pevent, strlen(pevent));
|
|
}
|
|
#ifdef UAP_WEXT
|
|
if (IS_UAP_WEXT(cfg80211_wext)) {
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
}
|
|
#endif /* UAP_WEXT */
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
|
if (priv->netdev
|
|
&& priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes
|
|
&& priv->mgmt_subtype_mask) {
|
|
/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
|
|
#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
|
|
t_u8 *pkt;
|
|
int freq =
|
|
priv->phandle->
|
|
remain_on_channel ? priv->phandle->chan.
|
|
center_freq :
|
|
woal_get_active_intf_freq(priv);
|
|
if (!freq) {
|
|
if (!priv->phandle->chan.center_freq) {
|
|
PRINTM(MINFO,
|
|
"Skip to report mgmt packet to cfg80211\n");
|
|
break;
|
|
}
|
|
freq = priv->phandle->chan.center_freq;
|
|
}
|
|
|
|
pkt = ((t_u8 *)pmevent->event_buf
|
|
+ sizeof(pmevent->event_id));
|
|
|
|
/* move addr4 */
|
|
memmove(pkt + PACKET_ADDR4_POS,
|
|
pkt + PACKET_ADDR4_POS + ETH_ALEN,
|
|
pmevent->event_len -
|
|
sizeof(pmevent->event_id)
|
|
- PACKET_ADDR4_POS - ETH_ALEN);
|
|
#ifdef WIFI_DIRECT_SUPPORT
|
|
if (ieee80211_is_action
|
|
(((struct ieee80211_mgmt *)pkt)->
|
|
frame_control))
|
|
woal_cfg80211_display_p2p_actframe(pkt,
|
|
pmevent->
|
|
event_len
|
|
-
|
|
sizeof
|
|
(pmevent->
|
|
event_id)
|
|
-
|
|
MLAN_MAC_ADDR_LENGTH,
|
|
ieee80211_get_channel
|
|
(priv->
|
|
wdev->
|
|
wiphy,
|
|
freq),
|
|
MFALSE);
|
|
#endif
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
/**Forward Deauth, Auth and disassoc frame to Host*/
|
|
if (priv->host_mlme &&
|
|
(ieee80211_is_deauth
|
|
(((struct ieee80211_mgmt *)pkt)->
|
|
frame_control)
|
|
||
|
|
ieee80211_is_auth(((struct ieee80211_mgmt
|
|
*)pkt)->frame_control)
|
|
||
|
|
ieee80211_is_disassoc(((struct
|
|
ieee80211_mgmt *)
|
|
pkt)->
|
|
frame_control))) {
|
|
|
|
if ((priv->
|
|
auth_flag & HOST_MLME_AUTH_PENDING)
|
|
&&
|
|
ieee80211_is_auth(((struct
|
|
ieee80211_mgmt
|
|
*)pkt)->
|
|
frame_control)) {
|
|
priv->auth_flag &=
|
|
~HOST_MLME_AUTH_PENDING;
|
|
priv->auth_flag |=
|
|
HOST_MLME_AUTH_DONE;
|
|
priv->host_mlme_wait_condition =
|
|
MTRUE;
|
|
wake_up(&priv->
|
|
host_mlme_wait_q);
|
|
} else {
|
|
PRINTM(MEVENT,
|
|
"HostMlme: Receive deauth/disassociate\n");
|
|
woal_cfg80211_mgmt_frame_register
|
|
(priv->wdev->wiphy,
|
|
priv->wdev,
|
|
IEEE80211_STYPE_DEAUTH,
|
|
MFALSE);
|
|
woal_cfg80211_mgmt_frame_register
|
|
(priv->wdev->wiphy,
|
|
priv->wdev,
|
|
IEEE80211_STYPE_DISASSOC,
|
|
MFALSE);
|
|
priv->host_mlme = MFALSE;
|
|
priv->auth_flag = 0;
|
|
}
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
|
|
cfg80211_rx_mlme_mgmt(priv->netdev,
|
|
pkt,
|
|
pmevent->
|
|
event_len -
|
|
sizeof(pmevent->
|
|
event_id)
|
|
-
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
#else
|
|
if (ieee80211_is_deauth
|
|
(((struct ieee80211_mgmt *)pkt)->
|
|
frame_control))
|
|
cfg80211_send_deauth(priv->
|
|
netdev,
|
|
pkt,
|
|
pmevent->
|
|
event_len -
|
|
sizeof
|
|
(pmevent->
|
|
event_id)
|
|
-
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
else if (ieee80211_is_auth
|
|
(((struct ieee80211_mgmt *)
|
|
pkt)->frame_control))
|
|
cfg80211_send_rx_auth(priv->
|
|
netdev,
|
|
pkt,
|
|
pmevent->
|
|
event_len
|
|
-
|
|
sizeof
|
|
(pmevent->
|
|
event_id)
|
|
-
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
else if (ieee80211_is_disassoc
|
|
(((struct ieee80211_mgmt *)
|
|
pkt)->frame_control))
|
|
cfg80211_send_disassoc(priv->
|
|
netdev,
|
|
pkt,
|
|
pmevent->
|
|
event_len
|
|
-
|
|
sizeof
|
|
(pmevent->
|
|
event_id)
|
|
-
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
|
|
#endif
|
|
|
|
} else
|
|
#endif
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
|
cfg80211_rx_mgmt(
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
|
|
priv->wdev,
|
|
#else
|
|
priv->netdev,
|
|
#endif
|
|
freq, 0,
|
|
((const t_u8 *)
|
|
pmevent->
|
|
event_buf) +
|
|
sizeof(pmevent->
|
|
event_id),
|
|
pmevent->
|
|
event_len -
|
|
sizeof(pmevent->
|
|
event_id)
|
|
-
|
|
MLAN_MAC_ADDR_LENGTH
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
|
, 0
|
|
#endif
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
|
, GFP_ATOMIC
|
|
#endif
|
|
);
|
|
#else
|
|
cfg80211_rx_mgmt(priv->netdev, freq,
|
|
((const t_u8 *)
|
|
pmevent->event_buf) +
|
|
sizeof(pmevent->
|
|
event_id),
|
|
pmevent->event_len -
|
|
sizeof(pmevent->
|
|
event_id) -
|
|
MLAN_MAC_ADDR_LENGTH,
|
|
GFP_ATOMIC);
|
|
#endif
|
|
}
|
|
#endif /* KERNEL_VERSION */
|
|
}
|
|
#endif /* STA_CFG80211 || UAP_CFG80211 */
|
|
break;
|
|
#endif /* UAP_SUPPORT */
|
|
case MLAN_EVENT_ID_DRV_PASSTHRU:
|
|
woal_broadcast_event(priv, pmevent->event_buf,
|
|
pmevent->event_len);
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_ASSOC_FAILURE_REPORT:
|
|
PRINTM(MINFO, "Assoc result\n");
|
|
|
|
if (priv->media_connected) {
|
|
PRINTM(MINFO, "Assoc_Rpt: Media Connected\n");
|
|
if (!netif_carrier_ok(priv->netdev)) {
|
|
PRINTM(MINFO, "Assoc_Rpt: Carrier On\n");
|
|
netif_carrier_on(priv->netdev);
|
|
}
|
|
PRINTM(MINFO, "Assoc_Rpt: Queue Start\n");
|
|
woal_wake_queue(priv->netdev);
|
|
}
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_MEAS_REPORT:
|
|
/* We have received measurement report, wakeup measurement wait queue */
|
|
PRINTM(MINFO, "Measurement Report\n");
|
|
/* Going out of CAC checking period */
|
|
if (priv->phandle->cac_period == MTRUE) {
|
|
priv->phandle->cac_period = MFALSE;
|
|
if (priv->phandle->meas_wait_q_woken == MFALSE) {
|
|
priv->phandle->meas_wait_q_woken = MTRUE;
|
|
wake_up_interruptible(&priv->phandle->
|
|
meas_wait_q);
|
|
}
|
|
|
|
/* Execute delayed BSS START command */
|
|
if (priv->phandle->delay_bss_start == MTRUE) {
|
|
mlan_ioctl_req *req = NULL;
|
|
mlan_ds_bss *bss = NULL;
|
|
|
|
/* Clear flag */
|
|
priv->phandle->delay_bss_start = MFALSE;
|
|
|
|
PRINTM(MMSG,
|
|
"Now CAC measure period end. Execute delayed BSS Start command.\n");
|
|
|
|
req = woal_alloc_mlan_ioctl_req(sizeof
|
|
(mlan_ds_bss));
|
|
if (!req) {
|
|
PRINTM(MERROR,
|
|
"Failed to allocate ioctl request buffer\n");
|
|
goto done;
|
|
}
|
|
bss = (mlan_ds_bss *)req->pbuf;
|
|
req->req_id = MLAN_IOCTL_BSS;
|
|
req->action = MLAN_ACT_SET;
|
|
bss->sub_command = MLAN_OID_BSS_START;
|
|
memcpy(&bss->param.ssid_bssid,
|
|
&priv->phandle->delay_ssid_bssid,
|
|
sizeof(mlan_ssid_bssid));
|
|
|
|
if (woal_request_ioctl(priv, req, MOAL_NO_WAIT)
|
|
!= MLAN_STATUS_PENDING) {
|
|
PRINTM(MERROR,
|
|
"Delayed BSS Start operation failed!\n");
|
|
kfree(req);
|
|
}
|
|
|
|
PRINTM(MMSG, "BSS START Complete!\n");
|
|
}
|
|
#ifdef UAP_SUPPORT
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
if (priv->uap_host_based && dfs_offload)
|
|
woal_cfg80211_dfs_vendor_event(priv,
|
|
event_dfs_cac_finished,
|
|
&priv->chan);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
break;
|
|
case MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ:
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
tdls_tear_down_event *tdls_event =
|
|
(tdls_tear_down_event *)pmevent->event_buf;
|
|
cfg80211_tdls_oper_request(priv->netdev,
|
|
tdls_event->peer_mac_addr,
|
|
NL80211_TDLS_TEARDOWN,
|
|
tdls_event->reason_code,
|
|
GFP_KERNEL);
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
case MLAN_EVENT_ID_FW_TX_STATUS:
|
|
{
|
|
unsigned long flag;
|
|
tx_status_event *tx_status =
|
|
(tx_status_event *)(pmevent->event_buf + 4);
|
|
struct tx_status_info *tx_info = NULL;
|
|
t_u8 catagory = 0, action = 0, dialog_token = 0;
|
|
t_u8 peer_addr[6] = { 0 };
|
|
confirm_timestamps tsbuff = { 0 };
|
|
|
|
PRINTM(MINFO,
|
|
"Receive Tx status: tx_token=%d, pkt_type=0x%x, status=%d tx_seq_num=%d\n",
|
|
tx_status->tx_token_id, tx_status->packet_type,
|
|
tx_status->status, priv->tx_seq_num);
|
|
spin_lock_irqsave(&priv->tx_stat_lock, flag);
|
|
tx_info =
|
|
woal_get_tx_info(priv, tx_status->tx_token_id);
|
|
if (tx_info) {
|
|
bool ack;
|
|
struct sk_buff *skb =
|
|
(struct sk_buff *)tx_info->tx_skb;
|
|
list_del(&tx_info->link);
|
|
spin_unlock_irqrestore(&priv->tx_stat_lock,
|
|
flag);
|
|
if (!tx_status->status)
|
|
ack = true;
|
|
else
|
|
ack = false;
|
|
if (priv->phandle->remain_on_channel &&
|
|
tx_info->cancel_remain_on_channel) {
|
|
remain_priv =
|
|
priv->phandle->priv[priv->
|
|
phandle->
|
|
remain_bss_index];
|
|
if (remain_priv) {
|
|
woal_cfg80211_remain_on_channel_cfg
|
|
(remain_priv,
|
|
MOAL_NO_WAIT, MTRUE,
|
|
&channel_status, NULL,
|
|
0, 0);
|
|
priv->phandle->
|
|
remain_on_channel =
|
|
MFALSE;
|
|
}
|
|
}
|
|
{
|
|
catagory =
|
|
((struct ieee80211_mgmt *)skb->
|
|
data)->u.action.category;
|
|
action = *(&
|
|
((struct ieee80211_mgmt *)
|
|
skb->data)->u.action.
|
|
category + 1);
|
|
dialog_token = *(&((struct ieee80211_mgmt *)skb->data)->u.action.category + 2); //dt is 2 bytes after category
|
|
memcpy(peer_addr,
|
|
(t_u8
|
|
*)((struct ieee80211_mgmt *)
|
|
skb->data)->da, 6);
|
|
PRINTM(MEVENT,
|
|
"Wlan: Tx status=%d, cat = %d, act = %d, dt = %d\n",
|
|
ack, catagory, action,
|
|
dialog_token);
|
|
/* this is a tx done for timining measurement action frame
|
|
* so we need to send the tx timestamp of txed frame back to supplicant
|
|
* for this send the timestamps along with the tx_status event buffer */
|
|
if (catagory ==
|
|
IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM
|
|
&& action == 0x1) {
|
|
/* create a timestamp buffer to send to host supplicant */
|
|
|
|
PRINTM(MEVENT,
|
|
"Wlan: Tx t1=%lld, t4 = %lld, t1_error = %lld, t4_error=%lld\n",
|
|
tx_status->t1_tstamp,
|
|
tx_status->t4_tstamp,
|
|
tx_status->t1_error,
|
|
tx_status->t4_error);
|
|
|
|
/* for timestamps only use lower 32-bits as spec defines 11v timestamps as 32-bits */
|
|
tsbuff.t4 =
|
|
(u32)
|
|
woal_le32_to_cpu
|
|
(tx_status->t4_tstamp);
|
|
tsbuff.t1 =
|
|
(u32)
|
|
woal_le32_to_cpu
|
|
(tx_status->t1_tstamp);
|
|
tsbuff.t4_error =
|
|
(u8)tx_status->t4_error;
|
|
tsbuff.t1_error =
|
|
(u8)tx_status->t4_error;
|
|
tsbuff.egress_time =
|
|
(u64)
|
|
woal_le64_to_cpu
|
|
(tx_status->
|
|
egress_time);
|
|
|
|
if (skb_tailroom(skb) <
|
|
sizeof(confirm_timestamps))
|
|
{
|
|
struct sk_buff *new_skb
|
|
= NULL;
|
|
PRINTM(MWARN,
|
|
"Tx Status: Insufficient skb tailroom %d\n",
|
|
skb_tailroom
|
|
(skb));
|
|
/* Insufficient skb tailroom - allocate a new skb */
|
|
new_skb =
|
|
skb_copy_expand
|
|
(skb, 0,
|
|
sizeof
|
|
(confirm_timestamps),
|
|
GFP_ATOMIC);
|
|
if (unlikely(!new_skb)) {
|
|
PRINTM(MERROR,
|
|
"Tx Status: Cannot allocate skb\n");
|
|
dev_kfree_skb_any
|
|
(skb);
|
|
goto done;
|
|
}
|
|
skb = new_skb;
|
|
PRINTM(MINFO,
|
|
"new skb tailroom %d\n",
|
|
skb_tailroom
|
|
(skb));
|
|
}
|
|
if (tx_info->tx_cookie) {
|
|
memcpy(skb_put
|
|
(skb,
|
|
sizeof
|
|
(confirm_timestamps)),
|
|
&tsbuff,
|
|
sizeof
|
|
(confirm_timestamps));
|
|
} else {
|
|
sprintf(pevent,
|
|
"%s "
|
|
FULL_MACSTR
|
|
" %u %u %u %u %u %u %llu",
|
|
CUS_EVT_TIMING_MSMT_CONFIRM,
|
|
FULL_MAC2STR
|
|
(peer_addr),
|
|
dialog_token,
|
|
tsbuff.t1,
|
|
tsbuff.t1_error,
|
|
tsbuff.t4,
|
|
tsbuff.t4_error,
|
|
tsbuff.t1 * 10,
|
|
tsbuff.
|
|
egress_time);
|
|
woal_broadcast_event
|
|
(priv, pevent,
|
|
strlen
|
|
(pevent));
|
|
}
|
|
}
|
|
}
|
|
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
|
|
if (tx_info->tx_cookie) {
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
|
|
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
|
|
cfg80211_mgmt_tx_status(priv->netdev,
|
|
tx_info->
|
|
tx_cookie,
|
|
skb->data,
|
|
skb->len, ack,
|
|
GFP_ATOMIC);
|
|
#else
|
|
cfg80211_mgmt_tx_status(priv->wdev,
|
|
tx_info->
|
|
tx_cookie,
|
|
skb->data,
|
|
skb->len, ack,
|
|
GFP_ATOMIC);
|
|
#endif
|
|
#endif
|
|
}
|
|
#endif
|
|
dev_kfree_skb_any(skb);
|
|
kfree(tx_info);
|
|
} else
|
|
spin_unlock_irqrestore(&priv->tx_stat_lock,
|
|
flag);
|
|
}
|
|
break;
|
|
|
|
case MLAN_EVENT_ID_DRV_FT_RESPONSE:
|
|
if (priv->phandle->fw_roam_enable)
|
|
break;
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,10,0)
|
|
#ifdef STA_CFG80211
|
|
if (IS_STA_CFG80211(cfg80211_wext)) {
|
|
struct cfg80211_ft_event_params ft_event;
|
|
if (priv->ft_pre_connect)
|
|
break;
|
|
memset(&ft_event, 0,
|
|
sizeof(struct cfg80211_ft_event_params));
|
|
PRINTM(MMSG,
|
|
"wlan : FT response target AP " MACSTR "\n",
|
|
MAC2STR((t_u8 *)pmevent->event_buf));
|
|
DBG_HEXDUMP(MDAT_D, "FT-event ", pmevent->event_buf,
|
|
pmevent->event_len);
|
|
memcpy(priv->target_ap_bssid, pmevent->event_buf,
|
|
ETH_ALEN);
|
|
ft_event.target_ap = priv->target_ap_bssid;
|
|
ft_event.ies = pmevent->event_buf + ETH_ALEN;
|
|
ft_event.ies_len = pmevent->event_len - ETH_ALEN;
|
|
/*TSPEC info is needed by RIC, However the TS operation is configured by mlanutl */
|
|
/*So do not add RIC temporally */
|
|
/*when add RIC, 1. query TS status, 2. copy tspec from addts command */
|
|
ft_event.ric_ies = NULL;
|
|
ft_event.ric_ies_len = 0;
|
|
|
|
cfg80211_ft_event(priv->netdev, &ft_event);
|
|
priv->ft_pre_connect = MTRUE;
|
|
|
|
if (priv->ft_roaming_triggered_by_driver ||
|
|
!(priv->ft_cap & MBIT(0))) {
|
|
priv->ft_wait_condition = MTRUE;
|
|
wake_up(&priv->ft_wait_q);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
case MLAN_EVENT_ID_FW_ROAM_OFFLOAD_RESULT:
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
woal_cfg80211_vendor_event(priv, event_set_key_mgmt_offload,
|
|
&enable, sizeof(enable));
|
|
#endif
|
|
#endif
|
|
memcpy(priv->cfg_bssid, pmevent->event_buf, ETH_ALEN);
|
|
tlv = (MrvlIEtypesHeader_t *)((t_u8 *)pmevent->event_buf +
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
tlv_buf_left = pmevent->event_len - MLAN_MAC_ADDR_LENGTH;
|
|
while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
|
|
tlv_type = woal_le16_to_cpu(tlv->type);
|
|
tlv_len = woal_le16_to_cpu(tlv->len);
|
|
|
|
if (tlv_buf_left <
|
|
(tlv_len + sizeof(MrvlIEtypesHeader_t))) {
|
|
PRINTM(MERROR,
|
|
"Error processing firmware roam success TLVs, bytes left < TLV length\n");
|
|
break;
|
|
}
|
|
|
|
switch (tlv_type) {
|
|
case TLV_TYPE_APINFO:
|
|
pinfo = (apinfo *) tlv;
|
|
break;
|
|
case TLV_TYPE_ASSOC_REQ_IE:
|
|
req_tlv = (apinfo *) tlv;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
|
|
tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
|
|
sizeof
|
|
(MrvlIEtypesHeader_t));
|
|
}
|
|
if (!pinfo) {
|
|
PRINTM(MERROR,
|
|
"ERROR:AP info in roaming event buffer is NULL\n");
|
|
goto done;
|
|
}
|
|
if (req_tlv) {
|
|
req_ie = req_tlv->rsp_ie;
|
|
ie_len = req_tlv->header.len;
|
|
}
|
|
|
|
woal_inform_bss_from_scan_result(priv, NULL, MOAL_NO_WAIT);
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
|
memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
|
|
roam_info.bssid = priv->cfg_bssid;
|
|
roam_info.req_ie = req_ie;
|
|
roam_info.req_ie_len = ie_len;
|
|
roam_info.resp_ie = pinfo->rsp_ie;
|
|
roam_info.resp_ie_len = pinfo->header.len;
|
|
cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
|
|
#else
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
|
|
cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid, req_ie,
|
|
ie_len, pinfo->rsp_ie, pinfo->header.len,
|
|
GFP_KERNEL);
|
|
#else
|
|
cfg80211_roamed(priv->netdev, priv->cfg_bssid, req_ie, ie_len,
|
|
pinfo->rsp_ie, pinfo->header.len, GFP_KERNEL);
|
|
#endif
|
|
#endif
|
|
#ifdef STA_CFG80211
|
|
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
woal_roam_ap_info(priv, pmevent->event_buf, pmevent->event_len);
|
|
#endif
|
|
#endif
|
|
PRINTM(MMSG, "FW Roamed to bssid " MACSTR " successfully\n",
|
|
MAC2STR(priv->cfg_bssid));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
done:
|
|
kfree(pevent);
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function prints the debug message in mlan
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param level debug level
|
|
* @param pformat point to string format buf
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void
|
|
moal_print(IN t_void *pmoal_handle, IN t_u32 level, IN char *pformat, IN ...)
|
|
{
|
|
#ifdef DEBUG_LEVEL1
|
|
va_list args;
|
|
|
|
if (level & MHEX_DUMP) {
|
|
t_u8 *buf = NULL;
|
|
int len = 0;
|
|
|
|
va_start(args, pformat);
|
|
buf = (t_u8 *)va_arg(args, t_u8 *);
|
|
len = (int)va_arg(args, int);
|
|
va_end(args);
|
|
|
|
#ifdef DEBUG_LEVEL2
|
|
if (level & MINFO)
|
|
HEXDUMP((char *)pformat, buf, len);
|
|
else
|
|
#endif /* DEBUG_LEVEL2 */
|
|
{
|
|
if (level & MERROR)
|
|
DBG_HEXDUMP(MERROR, (char *)pformat, buf, len);
|
|
if (level & MCMD_D)
|
|
DBG_HEXDUMP(MCMD_D, (char *)pformat, buf, len);
|
|
if (level & MDAT_D)
|
|
DBG_HEXDUMP(MDAT_D, (char *)pformat, buf, len);
|
|
if (level & MIF_D)
|
|
DBG_HEXDUMP(MIF_D, (char *)pformat, buf, len);
|
|
if (level & MFW_D)
|
|
DBG_HEXDUMP(MFW_D, (char *)pformat, buf, len);
|
|
if (level & MEVT_D)
|
|
DBG_HEXDUMP(MEVT_D, (char *)pformat, buf, len);
|
|
}
|
|
} else {
|
|
if (drvdbg & level) {
|
|
va_start(args, pformat);
|
|
vprintk(pformat, args);
|
|
va_end(args);
|
|
}
|
|
}
|
|
#endif /* DEBUG_LEVEL1 */
|
|
}
|
|
|
|
/**
|
|
* @brief This function prints the network interface name
|
|
*
|
|
* @param pmoal_handle Pointer to the MOAL context
|
|
* @param bss_index BSS index
|
|
* @param level debug level
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void
|
|
moal_print_netintf(IN t_void *pmoal_handle, IN t_u32 bss_index, IN t_u32 level)
|
|
{
|
|
#ifdef DEBUG_LEVEL1
|
|
moal_handle *phandle = (moal_handle *)pmoal_handle;
|
|
|
|
if (phandle) {
|
|
if ((bss_index < MLAN_MAX_BSS_NUM) && phandle->priv[bss_index]
|
|
&& phandle->priv[bss_index]->netdev) {
|
|
if (drvdbg & level)
|
|
printk("%s: ",
|
|
phandle->priv[bss_index]->netdev->name);
|
|
}
|
|
}
|
|
#endif /* DEBUG_LEVEL1 */
|
|
}
|
|
|
|
/**
|
|
* @brief This function asserts the existence of the passed argument
|
|
*
|
|
* @param pmoal_handle A pointer to moal_private structure
|
|
* @param cond Condition to check
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void
|
|
moal_assert(IN t_void *pmoal_handle, IN t_u32 cond)
|
|
{
|
|
if (!cond) {
|
|
panic("Assert failed: Panic!");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief This function save the histogram data
|
|
*
|
|
* @param pmoal_handle A pointer to moal_private structure
|
|
* @param bss_index BSS index
|
|
* @param rx_rate rx rate index
|
|
* @param snr snr
|
|
* @param nflr noise floor
|
|
* @param antenna antenna
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void
|
|
moal_hist_data_add(IN t_void *pmoal_handle, IN t_u32 bss_index, IN t_u8 rx_rate,
|
|
IN t_s8 snr, IN t_s8 nflr, IN t_u8 antenna)
|
|
{
|
|
moal_private *priv = NULL;
|
|
priv = woal_bss_index_to_priv(pmoal_handle, bss_index);
|
|
if (priv && antenna >= priv->phandle->histogram_table_num)
|
|
antenna = 0;
|
|
if (priv && priv->hist_data[antenna])
|
|
woal_hist_data_add(priv, rx_rate, snr, nflr, antenna);
|
|
}
|
|
|
|
/**
|
|
* @brief This function update the peer signal
|
|
*
|
|
* @param pmoal_handle A pointer to moal_private structure
|
|
* @param bss_index BSS index
|
|
* @param peer_addr peer address
|
|
* @param snr snr
|
|
* @param nflr noise floor
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void
|
|
moal_updata_peer_signal(IN t_void *pmoal_handle, IN t_u32 bss_index,
|
|
IN t_u8 *peer_addr, IN t_s8 snr, IN t_s8 nflr)
|
|
{
|
|
moal_private *priv = NULL;
|
|
struct tdls_peer *peer = NULL;
|
|
unsigned long flags;
|
|
priv = woal_bss_index_to_priv(pmoal_handle, bss_index);
|
|
if (priv && priv->enable_auto_tdls) {
|
|
spin_lock_irqsave(&priv->tdls_lock, flags);
|
|
list_for_each_entry(peer, &priv->tdls_list, link) {
|
|
if (!memcmp(peer->peer_addr, peer_addr, ETH_ALEN)) {
|
|
peer->rssi = nflr - snr;
|
|
peer->rssi_jiffies = jiffies;
|
|
break;
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&priv->tdls_lock, flags);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief This function records host time in nano seconds
|
|
*
|
|
* @return 64 bit value of host time in nano seconds
|
|
*/
|
|
s64
|
|
get_host_time_ns(void)
|
|
{
|
|
struct timespec ts;
|
|
getnstimeofday(&ts);
|
|
return timespec_to_ns(&ts);
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieves the current system time
|
|
*
|
|
* @param time Pointer for the seconds of system time
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_get_host_time_ns(OUT t_u64 *time)
|
|
{
|
|
struct timespec ts;
|
|
t_u64 hclk_val;
|
|
|
|
getnstimeofday(&ts);
|
|
hclk_val = (ts.tv_sec * 1000000000L) + ts.tv_nsec;
|
|
*time = hclk_val;
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Performs division of 64-bit num with base
|
|
* @brief do_div does two things
|
|
* @brief 1. modifies the 64-bit num in place with
|
|
* @brief the quotient, i.e., num becomes quotient
|
|
* @brief 2. do_div() returns the 32-bit reminder
|
|
*
|
|
* @param num dividend
|
|
* @param base divisor
|
|
* @return returns 64-bit quotient
|
|
*/
|
|
t_u64
|
|
moal_do_div(IN t_u64 num, IN t_u32 base)
|
|
{
|
|
t_u64 val = num;
|
|
do_div(val, base);
|
|
return val;
|
|
}
|
|
|
|
#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
|
|
/**
|
|
* @brief Performs wait event
|
|
*
|
|
* @param pmoal_handle t_void
|
|
* @param bss_index index of priv
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_wait_hostcmd_complete(IN t_void *pmoal_handle, IN t_u32 bss_index)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
moal_private *priv = woal_bss_index_to_priv(handle, bss_index);
|
|
long time_left = 0;
|
|
|
|
ENTER();
|
|
|
|
if (!priv) {
|
|
PRINTM(MERROR, "moal_wait_event: priv is null!\n");
|
|
goto done;
|
|
}
|
|
|
|
priv->hostcmd_wait_condition = MFALSE;
|
|
time_left =
|
|
wait_event_timeout(priv->hostcmd_wait_q,
|
|
priv->hostcmd_wait_condition,
|
|
MOAL_IOCTL_TIMEOUT);
|
|
|
|
if (!time_left) {
|
|
PRINTM(MERROR, "moal_wait_event: wait timeout ");
|
|
status = MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief wake up esa wait_q
|
|
*
|
|
* @param pmoal_handle t_void
|
|
* @param bss_index index of priv
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status
|
|
moal_notify_hostcmd_complete(IN t_void *pmoal_handle, IN t_u32 bss_index)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
moal_handle *handle = (moal_handle *)pmoal_handle;
|
|
moal_private *priv = woal_bss_index_to_priv(handle, bss_index);
|
|
|
|
ENTER();
|
|
|
|
priv->hostcmd_wait_condition = MTRUE;
|
|
wake_up(&priv->hostcmd_wait_q);
|
|
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
#endif
|