| /** @file moal_shim.c |
| * |
| * @brief This file contains the callback functions registered to MLAN |
| * |
| * |
| * Copyright 2008-2021 NXP |
| * |
| * This software file (the File) is distributed by NXP |
| * under the terms of the GNU General Public License Version 2, June 1991 |
| * (the License). You may use, redistribute and/or modify the 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" |
| #ifdef USB |
| #include "moal_usb.h" |
| #endif |
| #ifdef SDIO |
| #include "moal_sdio.h" |
| #endif |
| #ifdef PCIE |
| #include "moal_pcie.h" |
| #endif |
| #ifdef UAP_SUPPORT |
| #include "moal_uap.h" |
| #endif |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #include "moal_cfg80211.h" |
| #include "moal_cfg80211_util.h" |
| #endif |
| #include <asm/div64.h> |
| |
| #if defined(PCIE) || defined(SDIO) |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70) |
| #ifdef IMX_SUPPORT |
| #include <linux/busfreq-imx.h> |
| #endif |
| #endif |
| |
| #include <linux/etherdevice.h> |
| |
| #endif /*defined(PCIE) || defined(SDIO) */ |
| |
| /******************************************************** |
| Local Variables |
| ********************************************************/ |
| /** moal_lock */ |
| typedef struct _moal_lock { |
| /** Lock */ |
| spinlock_t lock; |
| /** Flags */ |
| unsigned long flags; |
| } moal_lock; |
| |
| /******************************************************** |
| Global Variables |
| ********************************************************/ |
| |
| extern int wifi_status; |
| |
| /******************************************************** |
| Local Functions |
| ********************************************************/ |
| |
| /******************************************************** |
| Global Functions |
| ********************************************************/ |
| /** |
| * @brief Alloc a buffer |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 size, t_u32 flag, t_u8 **ppbuf) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| gfp_t mem_flag = |
| (in_interrupt() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| |
| #ifdef USB |
| if (!IS_USB(handle->card_type)) |
| #endif |
| { |
| 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 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(t_void *pmoal, t_u8 *pbuf) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| |
| 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 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(t_void *pmoal, t_u32 size, t_u8 **ppbuf) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| |
| *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 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(t_void *pmoal, t_u8 *pbuf) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| |
| if (!pbuf) |
| return MLAN_STATUS_FAILURE; |
| vfree(pbuf); |
| atomic_dec(&handle->vmalloc_count); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| #ifdef PCIE |
| /** |
| * @brief Alloc a consistent block of memory |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 size, t_u8 **ppbuf, t_pu64 pbuf_pa) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| pcie_service_card *card = (pcie_service_card *)handle->card; |
| dma_addr_t dma; |
| *pbuf_pa = 0; |
| |
| if (!card) |
| return MLAN_STATUS_FAILURE; |
| |
| *ppbuf = (t_u8 *)pci_alloc_consistent(card->dev, size, |
| (dma_addr_t *) & dma); |
| if (*ppbuf == NULL) { |
| PRINTM(MERROR, |
| "%s: allocate consistent memory (%d bytes) failed!\n", |
| __func__, (int)size); |
| return MLAN_STATUS_FAILURE; |
| } |
| *pbuf_pa = (t_u64)dma; |
| atomic_inc(&handle->malloc_cons_count); |
| |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Free a consistent block of memory |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 size, t_u8 *pbuf, t_u64 buf_pa) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| pcie_service_card *card = handle->card; |
| |
| if (!pbuf || !card) |
| 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 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(t_void *pmoal, t_u8 *pbuf, |
| t_u64 *pbuf_pa, t_u32 size, t_u32 flag) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| pcie_service_card *card = (pcie_service_card *)handle->card; |
| |
| dma_addr_t dma; |
| |
| if (!card) |
| return MLAN_STATUS_FAILURE; |
| |
| /* 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 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(t_void *pmoal, t_u8 *pbuf, |
| t_u64 buf_pa, t_u32 size, t_u32 flag) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| pcie_service_card *card = (pcie_service_card *)handle->card; |
| |
| if (!card) |
| return MLAN_STATUS_FAILURE; |
| |
| pci_unmap_single(card->dev, buf_pa, size, flag); |
| |
| return MLAN_STATUS_SUCCESS; |
| } |
| #endif /* PCIE */ |
| |
| /** |
| * @brief Fill memory with constant byte |
| * |
| * @param pmoal 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(t_void *pmoal, t_void *pmem, t_u8 byte, 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 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(t_void *pmoal, t_void *pdest, const t_void *psrc, t_u32 num) |
| { |
| t_void *p = pdest; |
| |
| if (pdest && psrc && num) |
| p = memcpy(pdest, psrc, num); |
| |
| return p; |
| } |
| |
| /** |
| * @brief Copy memory from one area to another |
| * |
| * @param pmoal 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 |
| * @param dest_size size of dest memory. |
| * |
| * @return Pointer to the dest memory |
| */ |
| t_void * |
| moal_memcpy_ext(t_void *pmoal, t_void *pdest, |
| const t_void *psrc, t_u32 num, t_u32 dest_size) |
| { |
| t_void *p = pdest; |
| if (pdest && psrc && num && dest_size) |
| p = memcpy(pdest, psrc, MIN(num, dest_size)); |
| |
| return p; |
| } |
| |
| /** |
| * @brief Move memory from one area to another |
| * |
| * @param pmoal 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(t_void *pmoal, t_void *pdest, const t_void *psrc, 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 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(t_void *pmoal, const t_void *pmem1, const t_void *pmem2, t_u32 num) |
| { |
| t_s32 result; |
| |
| result = memcmp(pmem1, pmem2, num); |
| |
| return result; |
| } |
| |
| /** |
| * @brief Delay function |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param delay delay in micro-second |
| * |
| * @return N/A |
| */ |
| t_void |
| moal_udelay(t_void *pmoal, t_u32 delay) |
| { |
| if (delay >= 1000) |
| msleep(delay / 1000); |
| if (delay % 1000) |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) |
| usleep_range(delay % 1000 - 1, delay % 1000); |
| #else |
| udelay(delay % 1000); |
| #endif |
| } |
| |
| /** |
| * @brief usleep_range function |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param min_delay minimal delay in micro-second |
| * @param max_delay delay in micro-second |
| * |
| * @return N/A |
| */ |
| t_void |
| moal_usleep_range(t_void *pmoal, t_u32 min_delay, t_u32 max_delay) |
| { |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) |
| usleep_range(min_delay, max_delay); |
| #endif |
| } |
| |
| /** |
| * @brief Retrieves the current system time |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 *psec, t_u32 *pusec) |
| { |
| wifi_timeval t; |
| |
| woal_get_monotonic_time(&t); |
| *psec = t.time_sec; |
| *pusec = t.time_usec; |
| |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Retrieves the current boot time |
| * |
| * @param pmoal 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(t_void *pmoal, 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 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(t_void *pmoal, t_void **pptimer, |
| IN t_void (*callback) (t_void *pcontext), t_void *pcontext) |
| { |
| moal_drv_timer *timer = NULL; |
| gfp_t 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 Pointer to the MOAL context |
| * @param ptimer Pointer to the timer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_free_timer(t_void *pmoal, 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 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(t_void *pmoal, t_void *ptimer, t_u8 periodic, 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 Pointer to the MOAL context |
| * @param ptimer Pointer to the timer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| moal_stop_timer(t_void *pmoal, 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 Pointer to the MOAL context |
| * @param pplock Pointer to the lock |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| moal_init_lock(t_void *pmoal, t_void **pplock) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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 Pointer to the MOAL context |
| * @param plock Lock |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_free_lock(t_void *pmoal, t_void *plock) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| moal_lock *mlock = plock; |
| |
| kfree(mlock); |
| if (mlock) |
| atomic_dec(&handle->lock_count); |
| |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Request a spin lock |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param plock Pointer to the lock |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| moal_spin_lock(t_void *pmoal, t_void *plock) |
| __acquires(&plock->lock) |
| { |
| moal_lock *mlock = plock; |
| unsigned long flags = 0; |
| spin_lock_irqsave(&mlock->lock, flags); |
| mlock->flags = flags; |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Request a spin_unlock |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param plock Pointer to the lock |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| moal_spin_unlock(t_void *pmoal, t_void *plock) |
| __releases(&plock->lock) |
| { |
| moal_lock *mlock = (moal_lock *)plock; |
| spin_unlock_irqrestore(&mlock->lock, mlock->flags); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function collects AMSDU TP statistics. |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param amsdu_process_delay amsdu process time |
| * @param amsdu_copy_delay amsdu copy time |
| * |
| * @return N/A |
| */ |
| void |
| moal_amsdu_tp_accounting(t_void *pmoal, t_s32 amsdu_process_delay, |
| t_s32 amsdu_copy_delay) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| handle->tp_acnt.rx_amsdu_delay[handle->tp_acnt.rx_amsdu_index] = |
| amsdu_process_delay; |
| handle->tp_acnt.rx_amsdu_copy_delay[handle->tp_acnt.rx_amsdu_index] = |
| amsdu_copy_delay; |
| handle->tp_acnt.rx_amsdu_index++; |
| if (handle->tp_acnt.rx_amsdu_index >= TXRX_MAX_SAMPLE) |
| handle->tp_acnt.rx_amsdu_index = 0; |
| } |
| |
| /** |
| * @brief This function collects TP statistics. |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param buf pointer to the buffer of a packet |
| * @param drop_point Drop pointer user set |
| * |
| * @return N/A |
| */ |
| void |
| moal_tp_accounting(t_void *pmoal, void *buf, t_u32 drop_point) |
| { |
| struct sk_buff *skb = NULL; |
| moal_handle *handle = (moal_handle *)pmoal; |
| pmlan_buffer pmbuf = (pmlan_buffer)buf; |
| t_s32 delay; |
| wifi_timeval t; |
| |
| if (drop_point < MAX_TP_ACCOUNT_DROP_POINT_NUM) { |
| if (drop_point == 4) { |
| handle->tp_acnt.tx_bytes[drop_point] += pmbuf->data_len; |
| } else { |
| skb = (struct sk_buff *)buf; |
| handle->tp_acnt.tx_bytes[drop_point] += skb->len; |
| } |
| handle->tp_acnt.tx_packets[drop_point]++; |
| } else if (drop_point <= RX_DROP_P5) { |
| t_u16 rx_len = 0; |
| if (drop_point == RX_DROP_P1 || drop_point == RX_DROP_P2) |
| rx_len = pmbuf->data_len - *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset) + 2); //remove rx_pkt_offset |
| else if (drop_point == RX_DROP_P3) //aggr pkt |
| rx_len = pmbuf->data_len; |
| else if (drop_point == RX_DROP_P4) { //before to kernel |
| skb = (struct sk_buff *)buf; |
| rx_len = skb->len; |
| } |
| handle->tp_acnt.rx_bytes[drop_point - |
| MAX_TP_ACCOUNT_DROP_POINT_NUM] += |
| rx_len; |
| handle->tp_acnt.rx_packets[drop_point - |
| MAX_TP_ACCOUNT_DROP_POINT_NUM]++; |
| } else if (drop_point == RX_TIME_PKT) { |
| woal_get_monotonic_time(&t); |
| /* deque - pcie receive */ |
| delay = (t_s32)(pmbuf->extra_ts_sec - |
| pmbuf->in_ts_sec) * 1000000; |
| delay += (t_s32)(pmbuf->extra_ts_usec - pmbuf->in_ts_usec); |
| handle->tp_acnt.rx_delay1_driver[handle->tp_acnt.rx_index] = |
| delay; |
| /* before netif_rx - deque */ |
| delay = (t_s32)(pmbuf->out_ts_sec - |
| pmbuf->extra_ts_sec) * 1000000; |
| delay += (t_s32)(pmbuf->out_ts_usec - pmbuf->extra_ts_usec); |
| handle->tp_acnt.rx_delay2_driver[handle->tp_acnt.rx_index] = |
| delay; |
| /* netif_rx to netif_rx return */ |
| delay = (t_s32)(t.time_sec - pmbuf->out_ts_sec) * 1000000; |
| delay += (t_s32)(t.time_usec - pmbuf->out_ts_usec); |
| handle->tp_acnt.rx_delay_kernel[handle->tp_acnt.rx_index] = |
| delay; |
| handle->tp_acnt.rx_index++; |
| if (handle->tp_acnt.rx_index >= TXRX_MAX_SAMPLE) |
| handle->tp_acnt.rx_index = 0; |
| } else if (drop_point == TX_TIME_PKT) { |
| delay = (t_s32)(pmbuf->out_ts_sec - pmbuf->in_ts_sec) * 1000000; |
| delay += (t_s32)(pmbuf->out_ts_usec - pmbuf->in_ts_usec); |
| handle->tp_acnt.tx_delay_driver[handle->tp_acnt.tx_index] = |
| delay; |
| handle->tp_acnt.tx_index++; |
| if (handle->tp_acnt.tx_index >= TXRX_MAX_SAMPLE) |
| handle->tp_acnt.tx_index = 0; |
| } |
| } |
| |
| void |
| moal_tp_accounting_rx_param(t_void *pmoal, unsigned int type, |
| unsigned int rsvd1) |
| { |
| moal_handle *phandle = (moal_handle *)pmoal; |
| switch (type) { |
| case 0: //Rx interrupt |
| phandle->tp_acnt.rx_intr_cnt++; |
| break; |
| case 1: //rx_pkts_queued |
| phandle->tp_acnt.rx_pending = rsvd1; |
| break; |
| case 2: //paused |
| phandle->tp_acnt.rx_paused_cnt++; |
| break; |
| case 3: //tx interrupt count |
| phandle->tp_acnt.tx_intr_cnt++; |
| break; |
| case 4: //rx amsdu count |
| phandle->tp_acnt.rx_amsdu_cnt++; |
| phandle->tp_acnt.rx_amsdu_pkt_cnt += rsvd1; |
| break; |
| case 5: //tx amsdu count |
| phandle->tp_acnt.tx_amsdu_cnt++; |
| phandle->tp_acnt.tx_amsdu_pkt_cnt += rsvd1; |
| break; |
| case 6: //rxbd rdptr full count |
| phandle->tp_acnt.rx_rdptr_full_cnt++; |
| break; |
| case 7: //tx hard xmit skb realloc count |
| phandle->tp_acnt.tx_xmit_skb_realloc_cnt++; |
| break; |
| case 8: //tx stop queue count |
| phandle->tp_acnt.tx_stop_queue_cnt++; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /** |
| * @brief This function reads one block of firmware data from MOAL |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 offset, t_u32 len, t_u8 *pbuf) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| |
| if (!pbuf || !len || !handle->firmware) |
| return MLAN_STATUS_FAILURE; |
| |
| if (offset + len > handle->firmware->size) |
| return MLAN_STATUS_FAILURE; |
| |
| moal_memcpy_ext(handle, pbuf, handle->firmware->data + offset, len, |
| len); |
| |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function get vdll data from moal |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @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_vdll_data(t_void *pmoal, t_u32 len, t_u8 *pbuf) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| mlan_status status = MLAN_STATUS_FAILURE; |
| t_u32 offset = 0; |
| t_u8 req_fw = MFALSE; |
| |
| if (!handle->firmware) { |
| req_fw = MTRUE; |
| woal_vdll_req_fw(handle); |
| } |
| |
| if (handle->firmware) { |
| if (len < handle->firmware->size) { |
| offset = handle->firmware->size - len; |
| moal_memcpy_ext(handle, pbuf, |
| handle->firmware->data + offset, len, |
| len); |
| status = MLAN_STATUS_SUCCESS; |
| } else { |
| PRINTM(MERROR, "Invalid VDLL length = %d, fw_len=%d\n", |
| len, (int)handle->firmware->size); |
| } |
| if (req_fw) { |
| release_firmware(handle->firmware); |
| handle->firmware = NULL; |
| } |
| } |
| return status; |
| } |
| |
| /** |
| * @brief This function is called when MLAN completes the initialization |
| * firmware. |
| * |
| * @param pmoal 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(t_void *pmoal, |
| mlan_status status, |
| mlan_hw_info * phw, pmlan_bss_tbl ptbl) |
| { |
| #if defined(PCIE9098) |
| moal_handle *handle = (moal_handle *)pmoal; |
| #endif |
| |
| ENTER(); |
| if (status == MLAN_STATUS_SUCCESS) { |
| PRINTM(MCMND, "Get Hw Spec done, fw_cap=0x%x\n", phw->fw_cap); |
| #ifdef PCIE9098 |
| /** Special/Temporary handling to manage the driver version string |
| * to identify Seahawk/AW690 (skyhawk based) based on fw_cap_ext |
| * value set by Fw */ |
| if (phw->fw_cap_ext & MBIT(31) && |
| IS_PCIE9098(handle->card_type)) { |
| moal_memcpy_ext(handle, driver_version, CARD_PCIEAW690, |
| strlen(CARD_PCIEAW690), |
| strlen(driver_version)); |
| moal_memcpy_ext(handle, |
| driver_version + strlen(INTF_CARDTYPE) + |
| strlen(KERN_VERSION), V17, strlen(V17), |
| strlen(driver_version) - |
| strlen(INTF_CARDTYPE) - |
| strlen(KERN_VERSION)); |
| moal_memcpy_ext(handle, handle->driver_version, |
| driver_version, strlen(driver_version), |
| MLAN_MAX_VER_STR_LEN - 1); |
| } |
| #endif |
| } |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function is called when MLAN completes the initialization |
| * firmware. |
| * |
| * @param pmoal 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(t_void *pmoal, mlan_status status) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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 Pointer to the MOAL context |
| * @param status The status code for mlan_shutdown request |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_shutdown_fw_complete(t_void *pmoal, mlan_status status) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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 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(t_void *pmoal, |
| pmlan_ioctl_req pioctl_req, mlan_status status) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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 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(t_void *pmoal, t_u32 size, pmlan_buffer *pmbuf) |
| { |
| *pmbuf = woal_alloc_mlan_buffer((moal_handle *)pmoal, size); |
| if (NULL == *pmbuf) |
| return MLAN_STATUS_FAILURE; |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function frees mlan_buffer. |
| * |
| * @param pmoal 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(t_void *pmoal, pmlan_buffer pmbuf) |
| { |
| if (!pmbuf) |
| return MLAN_STATUS_FAILURE; |
| woal_free_mlan_buffer((moal_handle *)pmoal, pmbuf); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function is called when MLAN complete send data packet. |
| * |
| * @param pmoal 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(t_void *pmoal, pmlan_buffer pmbuf, mlan_status status) |
| { |
| moal_private *priv = NULL; |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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, 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; |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| woal_packet_fate_monitor(priv, |
| PACKET_TYPE_TX, |
| TX_PKT_FATE_SENT, |
| FRAME_TYPE_ETHERNET_II, |
| 0, 0, |
| skb->data, |
| skb->data_len); |
| #endif |
| } else { |
| priv->stats.tx_errors++; |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| woal_packet_fate_monitor(priv, |
| PACKET_TYPE_TX, |
| TX_PKT_FATE_DRV_DROP_OTHER, |
| FRAME_TYPE_ETHERNET_II, |
| 0, 0, |
| skb->data, |
| skb->data_len); |
| #endif |
| } |
| #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: |
| if ((atomic_read(&handle->tx_pending) == 0) && |
| !is_zero_timeval(handle->tx_time_start)) { |
| woal_get_monotonic_time(&handle->tx_time_end); |
| handle->tx_time += |
| (t_u64)(timeval_to_usec(handle->tx_time_end) - |
| timeval_to_usec(handle->tx_time_start)); |
| PRINTM(MINFO, |
| "%s : start_timeval=%d:%d end_timeval=%d:%d inter=%llu tx_time=%llu\n", |
| __func__, handle->tx_time_start.time_sec, |
| handle->tx_time_start.time_usec, |
| handle->tx_time_end.time_sec, |
| handle->tx_time_end.time_usec, |
| (t_u64)(timeval_to_usec(handle->tx_time_end) - |
| timeval_to_usec(handle->tx_time_start)), |
| handle->tx_time); |
| handle->tx_time_start.time_sec = 0; |
| handle->tx_time_start.time_usec = 0; |
| } |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| #ifdef USB |
| /** |
| * @brief This function is called when MLAN complete receiving |
| * data/event/command |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param pmbuf Pointer to the mlan buffer structure |
| * @param port Port number for receive |
| * @param status The status code for mlan_receive request |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_recv_complete(t_void *pmoal, pmlan_buffer pmbuf, |
| t_u32 port, mlan_status status) |
| { |
| moal_private *priv = NULL; |
| moal_handle *handle = (moal_handle *)pmoal; |
| struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card; |
| ENTER(); |
| |
| if ((pmbuf && (pmbuf->flags & MLAN_BUF_FLAG_RX_DEAGGR)) || !pmbuf) |
| atomic_dec(&handle->rx_pending); |
| |
| if (pmbuf) { |
| priv = woal_bss_index_to_priv(handle, pmbuf->bss_index); |
| if (priv && (pmbuf->buf_type == MLAN_BUF_TYPE_DATA) && |
| (status == MLAN_STATUS_FAILURE)) { |
| priv->stats.rx_dropped++; |
| } |
| /* Reuse the buffer in case of command/event */ |
| if (port == cardp->rx_cmd_ep) |
| woal_submit_rx_urb(handle, port); |
| else { |
| woal_free_mlan_buffer(handle, pmbuf); |
| if ((atomic_read(&handle->rx_pending) < |
| USB_LOW_RX_PENDING) && |
| atomic_read(&cardp->rx_data_urb_pending) < |
| MVUSB_RX_DATA_URB) |
| woal_usb_submit_rx_data_urbs(handle); |
| } |
| } else if (port == cardp->rx_data_ep) { |
| if ((atomic_read(&handle->rx_pending) < USB_LOW_RX_PENDING) && |
| atomic_read(&cardp->rx_data_urb_pending) < |
| MVUSB_RX_DATA_URB) |
| woal_usb_submit_rx_data_urbs(handle); |
| } |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function write a command/data packet to card. |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param pmbuf Pointer to the mlan buffer structure |
| * @param port Port number for sent |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or |
| * MLAN_STATUS_PENDING or MLAN_STATUS_RESOURCE |
| */ |
| mlan_status |
| moal_write_data_async(t_void *pmoal, pmlan_buffer pmbuf, t_u32 port) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| ENTER(); |
| if (handle->is_suspended == MTRUE) { |
| PRINTM(MERROR, |
| "write_data_async is not allowed while suspended\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| ret = woal_write_data_async((moal_handle *)pmoal, pmbuf, (t_u8)port); |
| LEAVE(); |
| return ret; |
| } |
| #endif /* USB */ |
| |
| /** |
| * @brief This function write a command/data packet to card. |
| * This function blocks the call until it finishes |
| * |
| * @param pmoal 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(t_void *pmoal, pmlan_buffer pmbuf, |
| t_u32 port, t_u32 timeout) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| return handle->ops.write_data_sync(handle, pmbuf, port, timeout); |
| } |
| |
| /** |
| * @brief This function read data packet/event/command from card. |
| * This function blocks the call until it finish |
| * |
| * @param pmoal 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(t_void *pmoal, |
| pmlan_buffer pmbuf, t_u32 port, t_u32 timeout) |
| { |
| moal_handle *handle = (moal_handle *)pmoal; |
| return handle->ops.read_data_sync(handle, pmbuf, port, timeout); |
| } |
| |
| #if defined(SDIO) || defined(PCIE) |
| /** |
| * @brief This function writes data into card register. |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 reg, t_u32 data) |
| { |
| int ret = MLAN_STATUS_FAILURE; |
| moal_handle *handle = (moal_handle *)pmoal; |
| if (handle->ops.write_reg) |
| ret = handle->ops.write_reg(handle, reg, data); |
| return ret; |
| } |
| |
| /** |
| * @brief This function reads data from card register. |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 reg, t_u32 *data) |
| { |
| int ret = MLAN_STATUS_FAILURE; |
| moal_handle *handle = (moal_handle *)pmoal; |
| if (handle->ops.read_reg) |
| ret = handle->ops.read_reg(handle, reg, data); |
| return ret; |
| } |
| |
| #endif /* SDIO || PCIE */ |
| |
| /** |
| * @brief This function uploads amsdu packet to the network stack |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param pmbuf Pointer to the mlan buffer structure |
| * |
| * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| moal_recv_amsdu_packet(t_void *pmoal, pmlan_buffer pmbuf) |
| { |
| mlan_status status = MLAN_STATUS_FAILURE; |
| struct sk_buff *skb = NULL; |
| struct sk_buff *frame = NULL; |
| int remaining; |
| const struct ethhdr *eth; |
| u8 dst[ETH_ALEN], src[ETH_ALEN]; |
| moal_handle *handle = (moal_handle *)pmoal; |
| moal_private *priv = NULL; |
| struct net_device *netdev = NULL; |
| u8 *payload; |
| mlan_buffer mbuf; |
| t_u8 drop = 0; |
| t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = |
| { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
| |
| wifi_timeval t1, t2; |
| t_s32 delay; |
| t_u32 in_ts_sec = 0; |
| t_u32 in_ts_usec = 0; |
| |
| ENTER(); |
| memset(&mbuf, 0, sizeof(mlan_buffer)); |
| mbuf.bss_index = pmbuf->bss_index; |
| |
| priv = woal_bss_index_to_priv(pmoal, pmbuf->bss_index); |
| if (priv == NULL) { |
| PRINTM(MERROR, "%s: priv is null\n", __func__); |
| goto done; |
| } |
| netdev = priv->netdev; |
| skb = (struct sk_buff *)pmbuf->pdesc; |
| if (!skb) |
| goto done; |
| |
| skb_reserve(skb, pmbuf->data_offset); |
| if (skb_tailroom(skb) < (int)pmbuf->data_len) { |
| PRINTM(MERROR, "skb overflow: tail room=%d, data_len=%d\n", |
| skb_tailroom(skb), pmbuf->data_len); |
| goto done; |
| } |
| skb_put(skb, pmbuf->data_len); |
| |
| //rx_trace 8 |
| if (handle->tp_acnt.on) { |
| moal_tp_accounting(pmoal, skb, RX_DROP_P4); |
| woal_get_monotonic_time(&t1); |
| in_ts_sec = t1.time_sec; |
| in_ts_usec = t1.time_usec; |
| if (pmbuf && pmbuf->in_ts_sec) { |
| pmbuf->out_ts_sec = t1.time_sec; |
| pmbuf->out_ts_usec = t1.time_usec; |
| } |
| } |
| if (handle->tp_acnt.drop_point == RX_DROP_P4) { |
| status = MLAN_STATUS_PENDING; |
| dev_kfree_skb(skb); |
| goto done; |
| } |
| |
| while (skb != frame) { |
| __be16 len; |
| u8 padding; |
| unsigned int subframe_len; |
| eth = (struct ethhdr *)skb->data; |
| len = ntohs(eth->h_proto); |
| subframe_len = sizeof(struct ethhdr) + len; |
| remaining = skb->len; |
| |
| if (subframe_len > remaining) { |
| PRINTM(MERROR, |
| "Error in len: remaining = %d, subframe_len = %d\n", |
| remaining, subframe_len); |
| break; |
| } |
| memcpy(dst, eth->h_dest, ETH_ALEN); |
| memcpy(src, eth->h_source, ETH_ALEN); |
| |
| padding = (4 - subframe_len) & 0x3; |
| |
| skb_pull(skb, sizeof(struct ethhdr)); |
| |
| if (remaining <= (subframe_len + padding)) { |
| frame = skb; |
| status = MLAN_STATUS_PENDING; |
| } else { |
| frame = skb_clone(skb, GFP_ATOMIC); |
| skb_trim(frame, len); |
| eth = (struct ethhdr *)skb_pull(skb, len + padding); |
| if (!eth) { |
| PRINTM(MERROR, "Invalid amsdu packet\n"); |
| break; |
| } |
| } |
| skb_reset_network_header(frame); |
| frame->dev = netdev; |
| frame->priority = skb->priority; |
| payload = frame->data; |
| if (ether_addr_equal(payload, rfc1042_eth_hdr)) { |
| /* Remove RFC1042 */ |
| skb_pull(frame, 6); |
| memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); |
| memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); |
| } else { |
| memcpy(skb_push(frame, sizeof(__be16)), &len, |
| sizeof(__be16)); |
| memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); |
| memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); |
| } |
| mbuf.pbuf = frame->data; |
| mbuf.data_len = frame->len; |
| mlan_process_deaggr_pkt(handle->pmlan_adapter, &mbuf, &drop); |
| if (drop) { |
| dev_kfree_skb(frame); |
| continue; |
| } |
| frame->protocol = eth_type_trans(frame, netdev); |
| frame->ip_summed = CHECKSUM_NONE; |
| if (in_interrupt()) |
| netif_rx(frame); |
| else { |
| if (atomic_read(&handle->rx_pending) > |
| MAX_RX_PENDING_THRHLD) |
| netif_rx(frame); |
| else { |
| if (handle->params.net_rx == MTRUE) { |
| local_bh_disable(); |
| netif_receive_skb(frame); |
| local_bh_enable(); |
| } else { |
| netif_rx_ni(frame); |
| } |
| } |
| } |
| } |
| if (handle->tp_acnt.on) { |
| if (pmbuf && pmbuf->in_ts_sec) |
| moal_tp_accounting(handle, pmbuf, RX_TIME_PKT); |
| |
| woal_get_monotonic_time(&t2); |
| delay = (t_s32)(t2.time_sec - in_ts_sec) * 1000000; |
| delay += (t_s32)(t2.time_usec - in_ts_usec); |
| moal_amsdu_tp_accounting(pmoal, delay, 0); |
| } |
| done: |
| if (status == MLAN_STATUS_PENDING) |
| atomic_dec(&handle->mbufalloc_count); |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @brief This function uploads the packet to the network stack |
| * |
| * @param pmoal 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(t_void *pmoal, pmlan_buffer pmbuf) |
| { |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| moal_private *priv = NULL; |
| struct sk_buff *skb = NULL; |
| moal_handle *handle = (moal_handle *)pmoal; |
| #if defined(USB) || defined(PCIE) |
| t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE; |
| #endif |
| dot11_rxcontrol rxcontrol; |
| t_u8 rx_info_flag = MFALSE; |
| int j; |
| struct ethhdr *ethh = NULL; |
| struct net_device *netdev = NULL; |
| |
| ENTER(); |
| if (pmbuf) { |
| #ifdef USB |
| #ifdef STA_SUPPORT |
| if (IS_USB(handle->card_type)) { |
| struct usb_card_rec *cardp = |
| (struct usb_card_rec *)handle->card; |
| if (cardp->rx_deaggr_ctrl.enable) { |
| max_rx_data_size = |
| cardp->rx_deaggr_ctrl.aggr_max; |
| if (cardp->rx_deaggr_ctrl.aggr_mode == |
| MLAN_USB_AGGR_MODE_NUM) { |
| max_rx_data_size *= |
| MAX(MLAN_USB_MAX_PKT_SIZE, |
| cardp->rx_deaggr_ctrl. |
| aggr_align); |
| max_rx_data_size = |
| MAX(max_rx_data_size, |
| MLAN_RX_DATA_BUF_SIZE); |
| } |
| } |
| } |
| #endif |
| #endif |
| |
| priv = woal_bss_index_to_priv(pmoal, pmbuf->bss_index); |
| skb = (struct sk_buff *)pmbuf->pdesc; |
| if (priv) { |
| if (skb) { |
| skb_reserve(skb, pmbuf->data_offset); |
| if (skb_tailroom(skb) < (int)pmbuf->data_len) { |
| PRINTM(MERROR, |
| "skb overflow: tail room=%d, data_len=%d\n", |
| skb_tailroom(skb), |
| pmbuf->data_len); |
| status = MLAN_STATUS_FAILURE; |
| priv->stats.rx_dropped++; |
| goto done; |
| } |
| skb_put(skb, pmbuf->data_len); |
| 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!!!\n", __func__); |
| 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++; |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| woal_packet_fate_monitor(priv, |
| PACKET_TYPE_RX, |
| RX_PKT_FATE_DRV_DROP_NOBUFS, |
| FRAME_TYPE_ETHERNET_II, |
| 0, 0, |
| (t_u8 |
| *)(pmbuf-> |
| pbuf + |
| pmbuf-> |
| data_offset), |
| pmbuf-> |
| data_len); |
| #endif |
| goto done; |
| } |
| skb_reserve(skb, MLAN_NET_IP_ALIGN); |
| moal_memcpy_ext(handle, skb->data, |
| (t_u8 *)(pmbuf->pbuf + |
| pmbuf->data_offset), |
| pmbuf->data_len, |
| pmbuf->data_len); |
| skb_put(skb, pmbuf->data_len); |
| } |
| ethh = (struct ethhdr *)(skb->data); |
| if (ntohs(ethh->h_proto) == ETH_P_PAE) |
| PRINTM(MEVENT, |
| "wlan: %s Rx EAPOL pkt from " MACSTR |
| "\n", |
| priv->netdev->name, |
| MAC2STR(ethh->h_source)); |
| if (!netdev) |
| netdev = priv->netdev; |
| skb->dev = netdev; |
| skb->protocol = eth_type_trans(skb, netdev); |
| skb->ip_summed = CHECKSUM_NONE; |
| |
| #if defined(USB) || defined(PCIE) |
| /* This is only required only in case of 11n and |
| USB as we alloc if(skb_tailroom(skb) < |
| pmbuf->data_len){ PRINTM(MERROR,"skb overflow: |
| tail room=%d, data_len\n", skb_tailroom(skb), |
| pmbuf->data_len); status = MLAN_STATUS_FAILURE; |
| priv->stats.rx_dropped++; |
| goto done; |
| } |
| * 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 (!IS_SD(priv->phandle->card_type)) { |
| if (skb->truesize > max_rx_data_size) |
| skb->truesize += |
| (skb->len - max_rx_data_size); |
| } |
| #endif |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (!woal_filter_packet(priv, skb->data, skb->len, 0)) { |
| PRINTM(MEVENT, |
| "drop filtered packet %s\n", |
| priv->netdev->name); |
| status = MLAN_STATUS_FAILURE; |
| priv->stats.rx_dropped++; |
| woal_packet_fate_monitor(priv, PACKET_TYPE_RX, |
| RX_PKT_FATE_DRV_DROP_FILTER, |
| FRAME_TYPE_ETHERNET_II, |
| 0, 0, skb->data, |
| skb->len); |
| dev_kfree_skb(skb); |
| goto done; |
| } |
| #endif |
| priv->stats.rx_bytes += skb->len; |
| priv->stats.rx_packets++; |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| woal_packet_fate_monitor(priv, PACKET_TYPE_RX, |
| RX_PKT_FATE_SUCCESS, |
| FRAME_TYPE_ETHERNET_II, |
| 0, 0, skb->data, skb->len); |
| #endif |
| #ifdef ANDROID_KERNEL |
| if (handle->params.wakelock_timeout) { |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) |
| __pm_wakeup_event(&handle->ws, |
| handle->params. |
| wakelock_timeout); |
| #else |
| wake_lock_timeout(&handle->wake_lock, |
| msecs_to_jiffies(handle-> |
| params. |
| wakelock_timeout)); |
| #endif |
| } |
| #endif |
| if (priv->rx_protocols.protocol_num) { |
| for (j = 0; |
| j < priv->rx_protocols.protocol_num; j++) { |
| if (htons((__force t_u16)skb->protocol) |
| == priv->rx_protocols.protocols[j]) |
| rx_info_flag = MTRUE; |
| } |
| } |
| if (rx_info_flag && |
| (skb_tailroom(skb) > (int)sizeof(rxcontrol))) { |
| memset(&rxcontrol, 0, sizeof(dot11_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)); |
| moal_memcpy_ext(handle, skb->data, &rxcontrol, |
| sizeof(dot11_rxcontrol), |
| sizeof(dot11_rxcontrol)); |
| } |
| //rx_trace 8 |
| if (priv->phandle->tp_acnt.on) { |
| wifi_timeval t; |
| moal_tp_accounting(handle, skb, RX_DROP_P4); |
| if (pmbuf && pmbuf->in_ts_sec) { |
| woal_get_monotonic_time(&t); |
| pmbuf->out_ts_sec = t.time_sec; |
| pmbuf->out_ts_usec = t.time_usec; |
| } |
| } |
| if (priv->phandle->tp_acnt.drop_point == RX_DROP_P4) { |
| status = MLAN_STATUS_PENDING; |
| dev_kfree_skb(skb); |
| } else if (in_interrupt()) |
| netif_rx(skb); |
| else { |
| if (atomic_read(&handle->rx_pending) > |
| MAX_RX_PENDING_THRHLD) |
| netif_rx(skb); |
| else { |
| if (handle->params.net_rx == MTRUE) { |
| local_bh_disable(); |
| netif_receive_skb(skb); |
| local_bh_enable(); |
| } else { |
| netif_rx_ni(skb); |
| } |
| } |
| } |
| if (priv->phandle->tp_acnt.on) { |
| if (pmbuf && pmbuf->in_ts_sec) |
| moal_tp_accounting(handle, pmbuf, |
| RX_TIME_PKT); |
| } |
| } |
| } |
| done: |
| LEAVE(); |
| return status; |
| } |
| |
| #if defined(PCIE) || defined(SDIO) |
| void |
| woal_request_busfreq_pmqos_add(t_void *handle) |
| { |
| moal_handle *pmhandle = (moal_handle *)handle; |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70) |
| #ifdef IMX_SUPPORT |
| if (IS_PCIE(pmhandle->card_type)) { |
| request_bus_freq(BUS_FREQ_HIGH); |
| } |
| #endif |
| #endif |
| if (moal_extflg_isset(pmhandle, EXT_PMQOS)) { |
| #if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 6, 0) |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) |
| #ifdef IMX_SUPPORT |
| pm_qos_add_request(&pmhandle->woal_pm_qos_req, |
| PM_QOS_CPU_DMA_LATENCY, 0); |
| #endif |
| #endif |
| #elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) |
| #ifdef IMX_SUPPORT |
| cpu_latency_qos_add_request(&pmhandle->woal_pm_qos_req, 0); |
| #endif |
| #endif |
| } |
| return; |
| } |
| |
| void |
| woal_release_busfreq_pmqos_remove(t_void *handle) |
| { |
| |
| moal_handle *pmhandle = (moal_handle *)handle; |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70) |
| #ifdef IMX_SUPPORT |
| if (IS_PCIE(pmhandle->card_type)) { |
| release_bus_freq(BUS_FREQ_HIGH); |
| } |
| #endif |
| #endif |
| |
| if (moal_extflg_isset(pmhandle, EXT_PMQOS)) { |
| #if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 6, 0) |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) |
| #ifdef IMX_SUPPORT |
| pm_qos_remove_request(&pmhandle->woal_pm_qos_req); |
| #endif |
| #endif |
| #elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) |
| #ifdef IMX_SUPPORT |
| cpu_latency_qos_remove_request(&pmhandle->woal_pm_qos_req); |
| #endif |
| #endif |
| } |
| return; |
| } |
| #endif /*defined(PCIE) || defined(SDIO) */ |
| |
| /** |
| * @brief This function checks media_connected state for |
| * BSS types UAP/STA/P2P_GO/GC |
| * |
| * @param pmoal Pointer to the MOAL context |
| * |
| */ |
| int |
| woal_check_media_connected(t_void *pmoal) |
| { |
| int i; |
| moal_handle *pmhandle = (moal_handle *)pmoal; |
| moal_private *pmpriv = NULL; |
| for (i = 0; i < pmhandle->priv_num && (pmpriv = pmhandle->priv[i]); i++) { |
| if (!pmpriv) |
| continue; |
| if (pmpriv->media_connected == MTRUE) { |
| return MTRUE; |
| } |
| } |
| return MFALSE; |
| } |
| |
| /** |
| * @brief This function checks connect and disconnect |
| * events for BSS types UAP/STA/P2P_GO/GC |
| * |
| * @param pmoal Pointer to the MOAL context |
| * |
| */ |
| static void |
| moal_connection_status_check_pmqos(t_void *pmoal) |
| { |
| moal_handle *pmhandle = (moal_handle *)pmoal; |
| if ((woal_check_media_connected(pmoal) == MTRUE)) { |
| |
| if (pmhandle->request_pm == MFALSE) { |
| pmhandle->request_pm = MTRUE; |
| #if defined(PCIE) || defined(SDIO) |
| woal_request_busfreq_pmqos_add(pmhandle); |
| #endif |
| } |
| } else { |
| if (pmhandle->request_pm == MTRUE) { |
| pmhandle->request_pm = MFALSE; |
| #if defined(PCIE) || defined(SDIO) |
| woal_release_busfreq_pmqos_remove(pmhandle); |
| #endif |
| } |
| } |
| |
| } |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) |
| /** |
| * @brief Handle RX MGMT PKT event |
| * |
| * @param priv A pointer moal_private structure |
| * @param pkt A pointer to pkt |
| * @param len length of pkt |
| * |
| * @return N/A |
| */ |
| static void |
| woal_rx_mgmt_pkt_event(moal_private *priv, t_u8 *pkt, t_u16 len) |
| { |
| struct woal_event *evt; |
| unsigned long flags; |
| moal_handle *handle = priv->phandle; |
| |
| evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC); |
| if (evt) { |
| evt->priv = priv; |
| evt->type = WOAL_EVENT_RX_MGMT_PKT; |
| evt->evt.event_len = len; |
| moal_memcpy_ext(priv->phandle, evt->evt.event_buf, pkt, |
| evt->evt.event_len, sizeof(evt->evt.event_buf)); |
| INIT_LIST_HEAD(&evt->link); |
| spin_lock_irqsave(&handle->evt_lock, flags); |
| list_add_tail(&evt->link, &handle->evt_queue); |
| spin_unlock_irqrestore(&handle->evt_lock, flags); |
| queue_work(handle->evt_workqueue, &handle->evt_work); |
| } |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief This function handles event receive |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param pmevent Pointer to the mlan event structure |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_recv_event(t_void *pmoal, 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 |
| #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; |
| moal_handle *handle = (moal_handle *)pmoal; |
| moal_handle *ref_handle = NULL; |
| |
| #ifdef STA_CFG80211 |
| t_u8 hw_test; |
| #endif |
| int cfg80211_wext; |
| |
| #ifdef STA_CFG80211 |
| t_u8 channel_status; |
| moal_private *remain_priv = NULL; |
| #endif |
| #if defined(UAP_CFG80211) || defined(STA_CFG80211) |
| chan_band_info *pchan_info = NULL; |
| #endif |
| t_u8 radar_detected; |
| |
| t_u8 auto_fw_dump = MFALSE; |
| ENTER(); |
| if (pmevent->event_id == MLAN_EVENT_ID_FW_DUMP_INFO) { |
| if (!handle->is_fw_dump_timer_set) { |
| PRINTM(MMSG, "FW trigger fw dump\n"); |
| handle->is_fw_dump_timer_set = MTRUE; |
| woal_mod_timer(&handle->fw_dump_timer, MOAL_TIMER_5S); |
| } |
| woal_store_firmware_dump(pmoal, pmevent); |
| handle->driver_status = MTRUE; |
| ref_handle = (moal_handle *)handle->pref_mac; |
| if (ref_handle) |
| ref_handle->driver_status = MTRUE; |
| goto done; |
| } |
| 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 defined(PCIE) |
| if (pmevent->event_id == MLAN_EVENT_ID_SSU_DUMP_FILE) { |
| goto done; |
| } |
| #endif /* SSU_SUPPORT */ |
| if (pmevent->event_id == MLAN_EVENT_ID_STORE_HOST_CMD_RESP) { |
| goto done; |
| } |
| priv = woal_bss_index_to_priv(pmoal, 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; |
| } |
| |
| cfg80211_wext = priv->phandle->params.cfg80211_wext; |
| #ifdef STA_CFG80211 |
| hw_test = moal_extflg_isset(pmoal, EXT_HW_TEST); |
| #endif |
| 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); |
| moal_memcpy_ext(priv->phandle, wrqu.ap_addr.sa_data, |
| pmevent->event_buf, ETH_ALEN, |
| sizeof(wrqu.ap_addr.sa_data)); |
| 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)) { |
| moal_memcpy_ext(priv->phandle, priv->cfg_bssid, |
| pmevent->event_buf, ETH_ALEN, 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); |
| moal_memcpy_ext(priv->phandle, pmevent->event_buf, |
| CUS_EVT_AP_CONNECTED, custom_len, 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); |
| moal_connection_status_check_pmqos(pmoal); |
| break; |
| |
| case MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER: |
| case MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER: |
| case MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER: |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (IS_STA_CFG80211(cfg80211_wext)) |
| woal_ring_event_logger(priv, VERBOSE_RING_ID, pmevent); |
| #endif |
| #endif |
| 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) { |
| cancel_delayed_work( |
| &priv->phandle->scan_timeout_work); |
| 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 (!is_zero_timeval(priv->phandle->scan_time_start)) { |
| woal_get_monotonic_time(&priv->phandle->scan_time_end); |
| priv->phandle->scan_time += |
| (t_u64)(timeval_to_usec |
| (priv->phandle->scan_time_end) - |
| timeval_to_usec(priv->phandle-> |
| scan_time_start)); |
| PRINTM(MINFO, |
| "%s : start_timeval=%d:%d end_timeval=%d:%d inter=%llu scan_time=%llu\n", |
| __func__, |
| priv->phandle->scan_time_start.time_sec, |
| priv->phandle->scan_time_start.time_usec, |
| priv->phandle->scan_time_end.time_sec, |
| priv->phandle->scan_time_end.time_usec, |
| (t_u64)(timeval_to_usec |
| (priv->phandle->scan_time_end) - |
| timeval_to_usec(priv->phandle-> |
| scan_time_start)), |
| priv->phandle->scan_time); |
| priv->phandle->scan_time_start.time_sec = 0; |
| priv->phandle->scan_time_start.time_usec = 0; |
| } |
| |
| 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); |
| moal_memcpy_ext(priv->phandle, pmevent->event_buf, |
| (t_u8 *)CUS_EVT_OBSS_SCAN_PARAM, |
| strlen(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 = (t_u8 __user *)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); |
| moal_memcpy_ext(priv->phandle, pmevent->event_buf, |
| (t_u8 *)CUS_EVT_BW_CHANGED, |
| strlen(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 = (t_u8 __user *)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; |
| priv->auth_alg = 0xFFFF; |
| #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 */ |
| moal_connection_status_check_pmqos(pmoal); |
| 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); |
| cfg80211_put_bss(priv->wdev->wiphy, bss); |
| } |
| if (!hw_test && priv->roaming_enabled) |
| woal_config_bgscan_and_rssi(priv, MFALSE); |
| else { |
| cfg80211_cqm_rssi_notify(priv->netdev, |
| NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) |
| 0, |
| #endif |
| GFP_KERNEL); |
| } |
| 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); |
| moal_memcpy_ext(priv->phandle, pmevent->event_buf, |
| (t_u8 *)FW_DEBUG_INFO, strlen(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 (moal_extflg_isset(priv->phandle, EXT_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 (moal_extflg_isset(priv->phandle, EXT_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_status = MTRUE; |
| ref_handle = (moal_handle *)priv->phandle->pref_mac; |
| if (ref_handle) |
| ref_handle->driver_status = MTRUE; |
| if (drvdbg & MFW_D) |
| auto_fw_dump = MTRUE; |
| |
| woal_moal_debug_info(priv, NULL, MFALSE); |
| if (!auto_fw_dump && !handle->fw_dump) |
| woal_process_hang(priv->phandle); |
| wifi_status = 2; |
| break; |
| case MLAN_EVENT_ID_DRV_WIFI_STATUS: |
| wifi_status = *(t_u16 *)(pmevent->event_buf + sizeof(t_u32)); |
| 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; |
| if (MLAN_STATUS_SUCCESS == |
| woal_get_scan_table(priv, MOAL_NO_WAIT, |
| &scan_resp)) |
| PRINTM(MIOCTL, |
| "Triggered 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); |
| } else { |
| #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35) |
| if (priv->mrvl_rssi_low) { |
| cfg80211_cqm_rssi_notify(priv->netdev, |
| NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) |
| 0, |
| #endif |
| GFP_KERNEL); |
| } |
| #endif |
| } |
| } |
| #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) |
| woal_bgscan_stop_event(priv); |
| } |
| #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); |
| PRINTM(MMSG, |
| "wlan: Report sched_scan result\n"); |
| woal_report_sched_scan_result(priv); |
| priv->last_event = 0; |
| PRINTM(MEVENT, |
| "Reporting Sched_Scan results\n"); |
| } |
| } |
| #endif |
| #endif |
| break; |
| #endif /* STA_SUPPORT */ |
| |
| case MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY: |
| radar_detected = pmevent->event_buf[0]; |
| |
| #ifdef UAP_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) |
| if (!IS_STA_OR_UAP_CFG80211(cfg80211_wext)) |
| break; |
| |
| if (priv->phandle->is_cac_timer_set) { |
| 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; |
| } |
| #endif /* CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */ |
| #endif /* UAP_CFG80211 */ |
| break; |
| case MLAN_EVENT_ID_FW_RADAR_DETECTED: |
| |
| #ifdef UAP_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) |
| if (!IS_STA_OR_UAP_CFG80211(cfg80211_wext)) |
| break; |
| 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 { |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)) |
| woal_cfg80211_dfs_vendor_event(priv, |
| event_dfs_radar_detected, |
| &priv->chan); |
| else { |
| #endif |
| if (priv->uap_host_based && priv->bss_started) |
| cfg80211_radar_event(priv->wdev->wiphy, |
| &priv->chan, |
| GFP_KERNEL); |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| } |
| #endif |
| } |
| #endif /* CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0 */ |
| #endif /* UAP_CFG80211 */ |
| break; |
| 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; |
| |
| 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)) { |
| moal_memcpy_ext(priv->phandle, &priv->chan, |
| &priv->csa_chan, |
| sizeof(struct |
| cfg80211_chan_def), |
| 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, 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, 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, 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, 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 |
| memset(&pm_info, 0, sizeof(mlan_ds_ps_info)); |
| 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, 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, 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: |
| 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); |
| moal_memcpy_ext(priv->phandle, priv->current_addr, |
| pmevent->event_buf + 6, ETH_ALEN, ETH_ALEN); |
| moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr, |
| priv->current_addr, ETH_ALEN, 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, 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 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 |
| 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)) { |
| 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_channel_switch_event(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); |
| moal_connection_status_check_pmqos(pmoal); |
| break; |
| case MLAN_EVENT_ID_UAP_FW_BSS_IDLE: |
| priv->media_connected = MFALSE; |
| woal_broadcast_event(priv, pmevent->event_buf, |
| pmevent->event_len); |
| moal_connection_status_check_pmqos(pmoal); |
| break; |
| case MLAN_EVENT_ID_UAP_FW_MIC_COUNTERMEASURES:{ |
| t_u16 status = 0; |
| status = *(t_u16 *)(pmevent->event_buf + 4); |
| if (status) { |
| priv->media_connected = MFALSE; |
| woal_stop_queue(priv->netdev); |
| if (netif_carrier_ok(priv->netdev)) |
| netif_carrier_off(priv->netdev); |
| } else { |
| 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; |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) |
| 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); |
| if (priv->host_mlme && |
| (priv->auth_flag & HOST_MLME_AUTH_PENDING)) { |
| priv->auth_flag = 0; |
| priv->host_mlme = MFALSE; |
| priv->auth_alg = 0xFFFF; |
| } |
| 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 |
| #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 = NULL; |
| t_u8 addr[ETH_ALEN]; |
| sinfo = kzalloc(sizeof(struct station_info), |
| GFP_ATOMIC); |
| if (sinfo) { |
| sinfo->filled = 0; |
| sinfo->generation = 0; |
| /* copy the station mac address */ |
| memset(addr, 0xFF, ETH_ALEN); |
| moal_memcpy_ext(priv->phandle, addr, |
| pmevent->event_buf, ETH_ALEN, |
| 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); |
| kfree(sinfo); |
| } |
| } |
| #endif /* UAP_CFG80211 */ |
| memmove((pmevent->event_buf + strlen(CUS_EVT_STA_CONNECTED) + |
| 1), pmevent->event_buf, pmevent->event_len); |
| moal_memcpy_ext(priv->phandle, pmevent->event_buf, |
| (t_u8 *)CUS_EVT_STA_CONNECTED, |
| strlen(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 = (t_u8 __user *)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) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| /**Forward Deauth, Auth and disassoc frame to Host*/ |
| if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) { |
| t_u16 reason_code = |
| woal_le16_to_cpu(*(t_u16 *)pmevent-> |
| event_buf); |
| PRINTM(MCMND, "deauth reason code =0x%x\n", |
| reason_code); |
| /** BIT 14 indicate deauth is initiated by FW */ |
| if (reason_code & MBIT(14)) |
| woal_host_mlme_disconnect(priv, 0, |
| pmevent-> |
| event_buf + |
| 2); |
| } else |
| #endif |
| 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); |
| moal_memcpy_ext(priv->phandle, pmevent->event_buf, |
| (t_u8 *)CUS_EVT_STA_DISCONNECTED, |
| strlen(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 = (t_u8 __user *)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: |
| #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 && |
| (GET_BSS_ROLE(priv) != MLAN_BSS_ROLE_UAP) && |
| (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 (ieee80211_is_auth(((struct |
| ieee80211_mgmt |
| *) |
| pkt) |
| ->frame_control)) { |
| PRINTM(MEVENT, |
| "HostMlme %s: Received auth frame type = 0x%x\n", |
| priv->netdev->name, |
| priv->auth_alg); |
| |
| if (priv-> |
| auth_flag & |
| HOST_MLME_AUTH_PENDING) { |
| if (priv->auth_alg != |
| WLAN_AUTH_SAE) { |
| priv->auth_flag |
| &= |
| ~HOST_MLME_AUTH_PENDING; |
| priv->auth_flag |
| |= |
| HOST_MLME_AUTH_DONE; |
| priv->phandle-> |
| host_mlme_priv |
| = priv; |
| queue_work |
| (priv-> |
| phandle-> |
| evt_workqueue, |
| &priv-> |
| phandle-> |
| host_mlme_work); |
| } |
| } else { |
| PRINTM(MERROR, |
| "HostMlme %s: Drop auth frame, auth_flag=0x%x auth_alg=0x%x\n", |
| priv->netdev-> |
| name, |
| priv->auth_flag, |
| priv->auth_alg); |
| break; |
| } |
| } else { |
| PRINTM(MEVENT, |
| "HostMlme %s: Receive deauth/disassociate\n", |
| priv->netdev->name); |
| if (!priv->wdev->current_bss) { |
| PRINTM(MEVENT, |
| "HostMlme: Drop deauth/disassociate, current_bss = null\n"); |
| break; |
| } |
| priv->cfg_disconnect = MTRUE; |
| woal_mgmt_frame_register(priv, |
| IEEE80211_STYPE_DEAUTH, |
| MFALSE); |
| woal_mgmt_frame_register(priv, |
| IEEE80211_STYPE_DISASSOC, |
| MFALSE); |
| woal_send_disconnect_to_system |
| (priv, |
| DEF_DEAUTH_REASON_CODE); |
| priv->host_mlme = MFALSE; |
| priv->auth_flag = 0; |
| priv->auth_alg = 0xFFFF; |
| } |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) |
| woal_rx_mgmt_pkt_event(priv, 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 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| woal_packet_fate_monitor(priv, PACKET_TYPE_RX, |
| RX_PKT_FATE_SUCCESS, |
| FRAME_TYPE_80211_MGMT, |
| 0, 0, |
| ((t_u8 *)pmevent-> |
| event_buf) + |
| sizeof(pmevent-> |
| event_id), |
| pmevent->event_len - |
| sizeof(pmevent-> |
| event_id) - |
| MLAN_MAC_ADDR_LENGTH); |
| #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; |
| moal_memcpy_ext(priv->phandle, |
| &bss->param.ssid_bssid, |
| &priv->phandle-> |
| delay_ssid_bssid, |
| sizeof(mlan_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 && |
| moal_extflg_isset(priv->phandle, EXT_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:{ |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| unsigned long flag; |
| tx_status_event *tx_status = |
| (tx_status_event *)(pmevent->event_buf + 4); |
| struct tx_status_info *tx_info = NULL; |
| 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 defined(STA_CFG80211) || defined(UAP_CFG80211) |
| 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; |
| } |
| } |
| #endif |
| PRINTM(MEVENT, "Wlan: Tx status=%d\n", ack); |
| #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 |
| } |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| woal_packet_fate_monitor(priv, PACKET_TYPE_TX, |
| ack ? TX_PKT_FATE_ACKED |
| : TX_PKT_FATE_SENT, |
| FRAME_TYPE_80211_MGMT, |
| 0, 0, skb->data, |
| skb->len); |
| #endif |
| #endif |
| dev_kfree_skb_any(skb); |
| kfree(tx_info); |
| } else { |
| |
| spin_unlock_irqrestore(&priv->tx_stat_lock, |
| flag); |
| } |
| #endif |
| } |
| break; |
| case MLAN_EVENT_ID_DRV_FT_RESPONSE: |
| #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); |
| moal_memcpy_ext(priv->phandle, priv->target_ap_bssid, |
| pmevent->event_buf, ETH_ALEN, 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; |
| default: |
| break; |
| } |
| done: |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief This function prints the debug message in mlan |
| * |
| * @param pmoal Pointer to the MOAL context |
| * @param level debug level |
| * @param pformat point to string format buf |
| * |
| * @return N/A |
| */ |
| __attribute__ ((format(printf, 3, 4))) |
| t_void moal_print(t_void *pmoal, t_u32 level, 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 Pointer to the MOAL context |
| * @param bss_index BSS index |
| * @param level debug level |
| * |
| * @return N/A |
| */ |
| t_void |
| moal_print_netintf(t_void *pmoal, t_u32 bss_index, t_u32 level) |
| { |
| #ifdef DEBUG_LEVEL1 |
| moal_handle *phandle = (moal_handle *)pmoal; |
| |
| 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 A pointer to moal_private structure |
| * @param cond Condition to check |
| * |
| * @return N/A |
| */ |
| t_void |
| moal_assert(t_void *pmoal, t_u32 cond) |
| { |
| if (!cond) { |
| panic("Assert failed: Panic!"); |
| } |
| } |
| |
| /** |
| * @brief This function save the histogram data |
| * |
| * @param pmoal 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(t_void *pmoal, t_u32 bss_index, |
| t_u16 rx_rate, t_s8 snr, t_s8 nflr, t_u8 antenna) |
| { |
| moal_private *priv = NULL; |
| priv = woal_bss_index_to_priv(pmoal, bss_index); |
| if (priv && antenna >= priv->phandle->card_info->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 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(t_void *pmoal, t_u32 bss_index, |
| t_u8 *peer_addr, t_s8 snr, t_s8 nflr) |
| { |
| moal_private *priv = NULL; |
| struct tdls_peer *peer = NULL; |
| unsigned long flags; |
| priv = woal_bss_index_to_priv(pmoal, 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 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(t_u64 num, 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 t_void |
| * @param bss_index index of priv |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_wait_hostcmd_complete(t_void *pmoal, t_u32 bss_index) |
| { |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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 t_void |
| * @param bss_index index of priv |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| moal_notify_hostcmd_complete(t_void *pmoal, t_u32 bss_index) |
| { |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| moal_handle *handle = (moal_handle *)pmoal; |
| 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 |