| /** |
| * @file mlan_misc.c |
| * |
| * @brief This file include Miscellaneous functions for MLAN module |
| * |
| * |
| * Copyright 2009-2024 NXP |
| * |
| * NXP CONFIDENTIAL |
| * The source code contained or described herein and all documents related to |
| * the source code (Materials) are owned by NXP, its |
| * suppliers and/or its licensors. Title to the Materials remains with NXP, |
| * its suppliers and/or its licensors. The Materials contain |
| * trade secrets and proprietary and confidential information of NXP, its |
| * suppliers and/or its licensors. The Materials are protected by worldwide |
| * copyright and trade secret laws and treaty provisions. No part of the |
| * Materials may be used, copied, reproduced, modified, published, uploaded, |
| * posted, transmitted, distributed, or disclosed in any way without NXP's |
| * prior express written permission. |
| * |
| * No license under any patent, copyright, trade secret or other intellectual |
| * property right is granted to or conferred upon you by disclosure or delivery |
| * of the Materials, either expressly, by implication, inducement, estoppel or |
| * otherwise. Any license under such intellectual property rights must be |
| * express and approved by NXP in writing. |
| * |
| * Alternatively, this software may be distributed under the terms of GPL v2. |
| * SPDX-License-Identifier: GPL-2.0 |
| * |
| * |
| */ |
| |
| /************************************************************* |
| Change Log: |
| 05/11/2009: initial version |
| ************************************************************/ |
| #include "mlan.h" |
| #ifdef STA_SUPPORT |
| #include "mlan_join.h" |
| #endif /* STA_SUPPORT */ |
| #include "mlan_util.h" |
| #include "mlan_fw.h" |
| #include "mlan_main.h" |
| #include "mlan_wmm.h" |
| #include "mlan_11n.h" |
| #include "mlan_11ac.h" |
| #include "mlan_11ax.h" |
| #ifdef UAP_SUPPORT |
| #include "mlan_uap.h" |
| #endif |
| /******************************************************** |
| Local Variables |
| ********************************************************/ |
| |
| /******************************************************** |
| Global Variables |
| ********************************************************/ |
| #if defined(USB8978) || defined(SD8978) |
| /** custom Fw data */ |
| /** Fw remap config */ |
| t_u8 fw_data_fw_remap_config[FW_DATA_FW_REMAP_CONFIG_LEN] = { |
| 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, |
| 0x00, 0x6A, 0x26, 0x96, 0xB2, 0x44, 0x65, 0x01, 0x04, 0x01, 0x00, |
| 0x00, 0x80, 0x00, 0x00, 0x0C, 0xA0, 0xCC, 0x1B, 0x6A, 0x41, 0x04, |
| 0x00, 0x0C, 0xA0, 0x02, 0x00, 0x00, 0x00, 0x4A, 0xE7, 0xE5, 0xA3}; |
| #endif |
| |
| #if defined(USB8978) |
| /** USB endpoint config */ |
| t_u8 fw_data_usb_bulk_ep[FW_DATA_USB_BULK_EP_LEN] = { |
| 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, |
| 0x93, 0xCC, 0x0E, 0xB8, 0xFC, 0x83, 0x02, 0xC0, 0x01, 0x00, 0x00, 0x00, |
| 0xF8, 0x83, 0x02, 0xC0, 0xCC, 0x1B, 0x6A, 0x41, 0xAC, 0x56, 0xD9, 0xEB}; |
| #endif |
| |
| #if defined(USB8978) || defined(SD8978) |
| /** DPD curremt optimizations */ |
| t_u8 fw_data_dpd_current_opt[FW_DATA_DPD_CURRENT_OPT_LEN] = { |
| 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, |
| 0x93, 0xCC, 0x0E, 0xB8, 0xF8, 0xAF, 0x00, 0xB0, 0xCC, 0x1B, 0x6A, 0x41, |
| 0xFC, 0xAF, 0x00, 0xB0, 0x01, 0x00, 0x00, 0x00, 0xF5, 0x1D, 0xBA, 0x80}; |
| #endif |
| |
| /******************************************************** |
| Local Functions |
| ********************************************************/ |
| #if defined(PCIE) || defined(SDIO) |
| /** |
| * @brief Check pending irq |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * |
| * @return MTRUE/MFALSE; |
| */ |
| static t_u8 wlan_pending_interrupt(pmlan_adapter pmadapter) |
| { |
| if (!IS_USB(pmadapter->card_type) && pmadapter->ireg) |
| return MTRUE; |
| return MFALSE; |
| } |
| #endif |
| |
| /** Custom IE auto index and mask */ |
| #define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff |
| /** Custom IE mask for delete operation */ |
| #define MLAN_CUSTOM_IE_DELETE_MASK 0 |
| /** Custom IE mask for create new index */ |
| #define MLAN_CUSTOM_IE_NEW_MASK 0x8000 |
| /** Custom IE header size */ |
| #define MLAN_CUSTOM_IE_HDR_SIZE (sizeof(custom_ie) - MAX_IE_SIZE) |
| |
| /** |
| * @brief Check if current custom IE index is used on other interfaces. |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param idx index to check for in use |
| * |
| * @return MLAN_STATUS_SUCCESS --unused, otherwise used. |
| */ |
| static mlan_status wlan_is_custom_ie_index_unused(pmlan_private pmpriv, |
| t_u16 idx) |
| { |
| t_u8 i = 0; |
| pmlan_adapter pmadapter = pmpriv->adapter; |
| pmlan_private priv; |
| ENTER(); |
| |
| for (i = 0; i < pmadapter->priv_num; i++) { |
| priv = pmadapter->priv[i]; |
| /* Check for other interfaces only */ |
| if (priv && priv->bss_index != pmpriv->bss_index) { |
| if (priv->mgmt_ie[idx].mgmt_subtype_mask && |
| priv->mgmt_ie[idx].ie_length) { |
| /* used entry found */ |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| } |
| } |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Get the custom IE index |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * @param mask mask value for which the index to be returned |
| * @param ie_data a pointer to custom_ie structure |
| * @param idx will hold the computed index |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| static mlan_status wlan_custom_ioctl_get_autoidx(pmlan_private pmpriv, |
| pmlan_ioctl_req pioctl_req, |
| t_u16 mask, custom_ie *ie_data, |
| t_u16 *idx) |
| { |
| t_u16 index = 0, insert = MFALSE; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| /* Determine the index where the IE needs to be inserted */ |
| while (!insert) { |
| while (index < MIN(pmpriv->adapter->max_mgmt_ie_index, |
| MAX_MGMT_IE_INDEX)) { |
| if (pmpriv->mgmt_ie[index].mgmt_subtype_mask == |
| MLAN_CUSTOM_IE_AUTO_IDX_MASK) { |
| index++; |
| continue; |
| } |
| if (pmpriv->mgmt_ie[index].mgmt_subtype_mask == mask) { |
| /* Duplicate IE should be avoided */ |
| if (pmpriv->mgmt_ie[index].ie_length) { |
| if (!memcmp(pmpriv->adapter, |
| pmpriv->mgmt_ie[index] |
| .ie_buffer, |
| ie_data->ie_buffer, |
| pmpriv->mgmt_ie[index] |
| .ie_length)) { |
| PRINTM(MINFO, |
| "IE with the same mask exists at index %d mask=0x%x\n", |
| index, mask); |
| *idx = MLAN_CUSTOM_IE_AUTO_IDX_MASK; |
| goto done; |
| } |
| } |
| /* Check if enough space is available */ |
| if (pmpriv->mgmt_ie[index].ie_length + |
| ie_data->ie_length > |
| MAX_IE_SIZE) { |
| index++; |
| continue; |
| } |
| insert = MTRUE; |
| break; |
| } |
| index++; |
| } |
| if (!insert) { |
| for (index = 0; |
| index < MIN(pmpriv->adapter->max_mgmt_ie_index, |
| MAX_MGMT_IE_INDEX); |
| index++) { |
| if (pmpriv->mgmt_ie[index].ie_length == 0) { |
| /* |
| * Check if this index is in use |
| * by other interface If yes, |
| * move ahead to next index |
| */ |
| if (MLAN_STATUS_SUCCESS == |
| wlan_is_custom_ie_index_unused( |
| pmpriv, index)) { |
| insert = MTRUE; |
| break; |
| } else { |
| PRINTM(MINFO, |
| "Skipping IE index %d in use.\n", |
| index); |
| } |
| } |
| } |
| } |
| if (index == pmpriv->adapter->max_mgmt_ie_index && !insert) { |
| PRINTM(MERROR, "Failed to Set the IE buffer\n"); |
| if (pioctl_req) |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| } |
| |
| *idx = index; |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Delete custom IE |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * @param ie_data a pointer to custom_ie structure |
| * @param idx index supplied |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| |
| static mlan_status wlan_custom_ioctl_auto_delete(pmlan_private pmpriv, |
| pmlan_ioctl_req pioctl_req, |
| custom_ie *ie_data, t_u16 idx) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_adapter pmadapter = pmpriv->adapter; |
| t_u16 index = 0, insert = MFALSE, del_len; |
| t_u8 del_ie[MAX_IE_SIZE], ie[MAX_IE_SIZE] = {0}; |
| t_s32 cnt, tmp_len = 0; |
| t_u8 *tmp_ie; |
| |
| ENTER(); |
| memset(pmpriv->adapter, del_ie, 0, MAX_IE_SIZE); |
| memcpy_ext(pmpriv->adapter, del_ie, ie_data->ie_buffer, |
| ie_data->ie_length, MAX_IE_SIZE); |
| del_len = MIN(MAX_IE_SIZE - 1, ie_data->ie_length); |
| |
| if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx) |
| ie_data->ie_index = 0; |
| |
| for (index = 0; |
| index < MIN(pmadapter->max_mgmt_ie_index, MAX_MGMT_IE_INDEX); |
| index++) { |
| if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx && |
| idx < MAX_MGMT_IE_INDEX) |
| index = idx; |
| tmp_ie = pmpriv->mgmt_ie[index].ie_buffer; |
| tmp_len = pmpriv->mgmt_ie[index].ie_length; |
| cnt = 0; |
| while (tmp_len) { |
| if (!memcmp(pmpriv->adapter, tmp_ie, del_ie, del_len)) { |
| memcpy_ext(pmpriv->adapter, ie, |
| pmpriv->mgmt_ie[index].ie_buffer, |
| cnt, MAX_IE_SIZE); |
| if (pmpriv->mgmt_ie[index].ie_length > |
| (cnt + del_len)) |
| memcpy_ext( |
| pmpriv->adapter, &ie[cnt], |
| &pmpriv->mgmt_ie[index].ie_buffer |
| [MIN((MAX_IE_SIZE - 1), |
| (cnt + del_len))], |
| (pmpriv->mgmt_ie[index] |
| .ie_length - |
| (cnt + del_len)), |
| MAX_IE_SIZE - cnt); |
| memset(pmpriv->adapter, |
| &pmpriv->mgmt_ie[index].ie_buffer, 0, |
| sizeof(pmpriv->mgmt_ie[index].ie_buffer)); |
| memcpy_ext(pmpriv->adapter, |
| &pmpriv->mgmt_ie[index].ie_buffer, |
| ie, |
| pmpriv->mgmt_ie[index].ie_length - |
| del_len, |
| MAX_IE_SIZE); |
| pmpriv->mgmt_ie[index].ie_length -= del_len; |
| if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx) |
| /* set a bit to indicate caller about |
| * update */ |
| ie_data->ie_index |= |
| (((t_u16)1) << index); |
| insert = MTRUE; |
| tmp_ie = pmpriv->mgmt_ie[index].ie_buffer; |
| tmp_len = pmpriv->mgmt_ie[index].ie_length; |
| cnt = 0; |
| continue; |
| } |
| tmp_ie++; |
| tmp_len--; |
| cnt++; |
| } |
| if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx) |
| break; |
| } |
| if (index == pmadapter->max_mgmt_ie_index && !insert) { |
| PRINTM(MERROR, "Failed to Clear IE buffer\n"); |
| if (pioctl_req) |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| ret = MLAN_STATUS_FAILURE; |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /******************************************************** |
| Global Functions |
| ********************************************************/ |
| /** |
| * @brief Get custom Fw data |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to custom Fw data buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise |
| * MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_get_custom_fw_data(pmlan_adapter pmadapter, t_u8 *pdata) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u32 fw_data_param = pmadapter->init_para.fw_data_cfg; |
| t_u32 fw_data_param_num = 0, index = 0, i = 0; |
| fw_data_t *pfw_data_list = MNULL; |
| |
| ENTER(); |
| MASSERT(pmadapter); |
| if (MNULL == pdata) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| fw_data_param_num = MIN(MAX_FW_DATA_BLOCK, bitcount(fw_data_param)); |
| pfw_data_list = (fw_data_t *)pdata; |
| for (i = 0; i < fw_data_param_num; i++) { |
| /** initilize the Fw data buffers with correct index */ |
| while (fw_data_param) { |
| index = fw_data_param & (-fw_data_param); |
| switch (index) { |
| #if defined(USB8978) || defined(SD8978) |
| case MBIT(0): |
| pfw_data_list[i].fw_data_buffer = |
| fw_data_fw_remap_config; |
| pfw_data_list[i].fw_data_buffer_len = |
| sizeof(fw_data_fw_remap_config); |
| break; |
| #endif |
| #if defined(USB8978) |
| case MBIT(1): |
| pfw_data_list[i].fw_data_buffer = |
| fw_data_usb_bulk_ep; |
| pfw_data_list[i].fw_data_buffer_len = |
| sizeof(fw_data_usb_bulk_ep); |
| break; |
| #endif |
| #if defined(USB8978) || defined(SD8978) |
| case MBIT(2): |
| pfw_data_list[i].fw_data_buffer = |
| fw_data_dpd_current_opt; |
| pfw_data_list[i].fw_data_buffer_len = |
| sizeof(fw_data_dpd_current_opt); |
| break; |
| #endif |
| default: |
| break; |
| } |
| fw_data_param ^= index; |
| break; |
| } |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief send host cmd |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_host_cmd(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)pioctl_req, |
| (t_void *)&misc->param.hostcmd); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief send host cmd |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tx_frame(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_FRAME, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| &misc->param.tx_frame); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Send function init/shutdown command to firmware |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_init_shutdown(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_INIT) |
| cmd = HostCmd_CMD_FUNC_INIT; |
| else if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_SHUTDOWN) |
| cmd = HostCmd_CMD_FUNC_SHUTDOWN; |
| else { |
| PRINTM(MERROR, "Unsupported parameter\n"); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, cmd, HostCmd_ACT_GEN_SET, 0, |
| (t_void *)pioctl_req, MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get debug information |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success |
| */ |
| mlan_status wlan_get_info_debug_info(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_get_info *info; |
| mlan_debug_info *debug_info = MNULL; |
| t_u32 i; |
| t_u8 *ptid; |
| |
| ENTER(); |
| |
| info = (mlan_ds_get_info *)pioctl_req->pbuf; |
| debug_info = (mlan_debug_info *)info->param.debug_info; |
| |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| ptid = ac_to_tid[WMM_AC_BK]; |
| debug_info->wmm_ac_bk = pmpriv->wmm.packets_out[ptid[0]] + |
| pmpriv->wmm.packets_out[ptid[1]]; |
| ptid = ac_to_tid[WMM_AC_BE]; |
| debug_info->wmm_ac_be = pmpriv->wmm.packets_out[ptid[0]] + |
| pmpriv->wmm.packets_out[ptid[1]]; |
| ptid = ac_to_tid[WMM_AC_VI]; |
| debug_info->wmm_ac_vi = pmpriv->wmm.packets_out[ptid[0]] + |
| pmpriv->wmm.packets_out[ptid[1]]; |
| ptid = ac_to_tid[WMM_AC_VO]; |
| debug_info->wmm_ac_vo = pmpriv->wmm.packets_out[ptid[0]] + |
| pmpriv->wmm.packets_out[ptid[1]]; |
| debug_info->max_tx_buf_size = (t_u32)pmadapter->max_tx_buf_size; |
| debug_info->tx_buf_size = (t_u32)pmadapter->tx_buf_size; |
| debug_info->curr_tx_buf_size = |
| (t_u32)pmadapter->curr_tx_buf_size; |
| debug_info->rx_tbl_num = |
| wlan_get_rxreorder_tbl(pmpriv, debug_info->rx_tbl); |
| debug_info->tx_tbl_num = |
| wlan_get_txbastream_tbl(pmpriv, debug_info->tx_tbl); |
| debug_info->ralist_num = |
| wlan_get_ralist_info(pmpriv, debug_info->ralist); |
| debug_info->tdls_peer_num = |
| wlan_get_tdls_list(pmpriv, debug_info->tdls_peer_list); |
| debug_info->ps_mode = pmadapter->ps_mode; |
| debug_info->ps_state = pmadapter->ps_state; |
| #ifdef STA_SUPPORT |
| debug_info->is_deep_sleep = pmadapter->is_deep_sleep; |
| #endif /* STA_SUPPORT */ |
| debug_info->pm_wakeup_card_req = pmadapter->pm_wakeup_card_req; |
| debug_info->pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try; |
| debug_info->pm_wakeup_in_secs = pmadapter->pm_wakeup_in_secs; |
| debug_info->pm_wakeup_timeout = pmadapter->pm_wakeup_timeout; |
| debug_info->is_hs_configured = pmadapter->is_hs_configured; |
| debug_info->hs_activated = pmadapter->hs_activated; |
| debug_info->pps_uapsd_mode = pmadapter->pps_uapsd_mode; |
| debug_info->sleep_pd = pmadapter->sleep_period.period; |
| debug_info->qos_cfg = pmpriv->wmm_qosinfo; |
| debug_info->tx_lock_flag = pmadapter->tx_lock_flag; |
| debug_info->port_open = pmpriv->port_open; |
| debug_info->tx_pause = pmpriv->tx_pause; |
| debug_info->bypass_pkt_count = |
| util_scalar_read(pmadapter->pmoal_handle, |
| &pmadapter->bypass_pkt_count, |
| pmadapter->callbacks.moal_spin_lock, |
| pmadapter->callbacks.moal_spin_unlock); |
| debug_info->scan_processing = pmadapter->scan_processing; |
| debug_info->scan_state = pmadapter->scan_state; |
| debug_info->mlan_processing = pmadapter->mlan_processing; |
| debug_info->main_lock_flag = pmadapter->main_lock_flag; |
| debug_info->main_process_cnt = pmadapter->main_process_cnt; |
| debug_info->delay_task_flag = pmadapter->delay_task_flag; |
| #ifdef PCIE |
| debug_info->pcie_event_processing = |
| pmadapter->pcie_event_processing; |
| debug_info->pcie_tx_processing = pmadapter->pcie_tx_processing; |
| debug_info->pcie_rx_processing = pmadapter->pcie_rx_processing; |
| #endif |
| debug_info->num_cmd_host_to_card_failure = |
| pmadapter->dbg.num_cmd_host_to_card_failure; |
| debug_info->num_cmd_sleep_cfm_host_to_card_failure = |
| pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; |
| debug_info->num_tx_host_to_card_failure = |
| pmadapter->dbg.num_tx_host_to_card_failure; |
| debug_info->num_alloc_buffer_failure = |
| pmadapter->dbg.num_alloc_buffer_failure; |
| debug_info->num_pkt_dropped = pmadapter->dbg.num_pkt_dropped; |
| |
| debug_info->num_event_deauth = pmadapter->dbg.num_event_deauth; |
| debug_info->num_event_disassoc = |
| pmadapter->dbg.num_event_disassoc; |
| debug_info->num_event_link_lost = |
| pmadapter->dbg.num_event_link_lost; |
| debug_info->num_cmd_deauth = pmadapter->dbg.num_cmd_deauth; |
| debug_info->num_cmd_assoc_success = |
| pmadapter->dbg.num_cmd_assoc_success; |
| debug_info->num_cmd_assoc_failure = |
| pmadapter->dbg.num_cmd_assoc_failure; |
| debug_info->num_cmd_timeout = pmadapter->num_cmd_timeout; |
| debug_info->timeout_cmd_id = pmadapter->dbg.timeout_cmd_id; |
| debug_info->timeout_cmd_act = pmadapter->dbg.timeout_cmd_act; |
| memcpy_ext(pmadapter, debug_info->last_cmd_id, |
| pmadapter->dbg.last_cmd_id, |
| sizeof(pmadapter->dbg.last_cmd_id), |
| sizeof(debug_info->last_cmd_id)); |
| memcpy_ext(pmadapter, debug_info->last_cmd_act, |
| pmadapter->dbg.last_cmd_act, |
| sizeof(pmadapter->dbg.last_cmd_act), |
| sizeof(debug_info->last_cmd_act)); |
| debug_info->last_cmd_index = pmadapter->dbg.last_cmd_index; |
| memcpy_ext(pmadapter, debug_info->last_cmd_resp_id, |
| pmadapter->dbg.last_cmd_resp_id, |
| sizeof(pmadapter->dbg.last_cmd_resp_id), |
| sizeof(debug_info->last_cmd_resp_id)); |
| debug_info->last_cmd_resp_index = |
| pmadapter->dbg.last_cmd_resp_index; |
| memcpy_ext(pmadapter, debug_info->last_event, |
| pmadapter->dbg.last_event, |
| sizeof(pmadapter->dbg.last_event), |
| sizeof(debug_info->last_event)); |
| debug_info->last_event_index = pmadapter->dbg.last_event_index; |
| debug_info->num_no_cmd_node = pmadapter->dbg.num_no_cmd_node; |
| debug_info->pending_cmd = |
| (pmadapter->curr_cmd) ? |
| pmadapter->dbg.last_cmd_id |
| [pmadapter->dbg.last_cmd_index] : |
| 0; |
| debug_info->dnld_cmd_in_secs = pmadapter->dnld_cmd_in_secs; |
| #ifdef SDIO |
| if (IS_SD(pmadapter->card_type)) { |
| debug_info->num_cmdevt_card_to_host_failure = |
| pmadapter->dbg.num_cmdevt_card_to_host_failure; |
| debug_info->num_rx_card_to_host_failure = |
| pmadapter->dbg.num_rx_card_to_host_failure; |
| debug_info->num_int_read_failure = |
| pmadapter->dbg.num_int_read_failure; |
| debug_info->last_int_status = |
| pmadapter->dbg.last_int_status; |
| debug_info->mp_rd_bitmap = |
| pmadapter->pcard_sd->mp_rd_bitmap; |
| debug_info->mp_wr_bitmap = |
| pmadapter->pcard_sd->mp_wr_bitmap; |
| debug_info->curr_rd_port = |
| pmadapter->pcard_sd->curr_rd_port; |
| debug_info->curr_wr_port = |
| pmadapter->pcard_sd->curr_wr_port; |
| debug_info->mp_invalid_update = |
| pmadapter->pcard_sd->mp_invalid_update; |
| debug_info->num_of_irq = |
| pmadapter->pcard_sd->num_of_irq; |
| memcpy_ext(pmadapter, debug_info->mp_update, |
| pmadapter->pcard_sd->mp_update, |
| sizeof(pmadapter->pcard_sd->mp_update), |
| sizeof(debug_info->mp_update)); |
| memcpy_ext(pmadapter, debug_info->mpa_tx_count, |
| pmadapter->pcard_sd->mpa_tx_count, |
| sizeof(pmadapter->pcard_sd->mpa_tx_count), |
| sizeof(debug_info->mpa_tx_count)); |
| debug_info->mpa_sent_last_pkt = |
| pmadapter->pcard_sd->mpa_sent_last_pkt; |
| debug_info->mpa_sent_no_ports = |
| pmadapter->pcard_sd->mpa_sent_no_ports; |
| debug_info->last_recv_wr_bitmap = |
| pmadapter->pcard_sd->last_recv_wr_bitmap; |
| debug_info->last_recv_rd_bitmap = |
| pmadapter->pcard_sd->last_recv_rd_bitmap; |
| debug_info->mp_data_port_mask = |
| pmadapter->pcard_sd->mp_data_port_mask; |
| debug_info->last_mp_index = |
| pmadapter->pcard_sd->last_mp_index; |
| memcpy_ext( |
| pmadapter, debug_info->last_mp_wr_bitmap, |
| pmadapter->pcard_sd->last_mp_wr_bitmap, |
| sizeof(pmadapter->pcard_sd->last_mp_wr_bitmap), |
| sizeof(debug_info->last_mp_wr_bitmap)); |
| memcpy_ext( |
| pmadapter, debug_info->last_mp_wr_ports, |
| pmadapter->pcard_sd->last_mp_wr_ports, |
| sizeof(pmadapter->pcard_sd->last_mp_wr_ports), |
| sizeof(debug_info->last_mp_wr_ports)); |
| memcpy_ext(pmadapter, debug_info->last_mp_wr_len, |
| pmadapter->pcard_sd->last_mp_wr_len, |
| sizeof(pmadapter->pcard_sd->last_mp_wr_len), |
| sizeof(debug_info->last_mp_wr_len)); |
| memcpy_ext(pmadapter, debug_info->last_mp_wr_info, |
| pmadapter->pcard_sd->last_mp_wr_info, |
| sizeof(pmadapter->pcard_sd->last_mp_wr_info), |
| sizeof(debug_info->last_mp_wr_info)); |
| memcpy_ext( |
| pmadapter, debug_info->last_curr_wr_port, |
| pmadapter->pcard_sd->last_curr_wr_port, |
| sizeof(pmadapter->pcard_sd->last_curr_wr_port), |
| sizeof(debug_info->last_curr_wr_port)); |
| debug_info->mpa_buf = pmadapter->pcard_sd->mpa_buf; |
| debug_info->mpa_buf_size = |
| pmadapter->pcard_sd->mpa_buf_size; |
| debug_info->sdio_rx_aggr = |
| pmadapter->pcard_sd->sdio_rx_aggr_enable; |
| memcpy_ext(pmadapter, debug_info->mpa_rx_count, |
| pmadapter->pcard_sd->mpa_rx_count, |
| sizeof(pmadapter->pcard_sd->mpa_rx_count), |
| sizeof(debug_info->mpa_rx_count)); |
| debug_info->mp_aggr_pkt_limit = |
| pmadapter->pcard_sd->mp_aggr_pkt_limit; |
| } |
| #endif |
| #ifdef PCIE |
| if (IS_PCIE(pmadapter->card_type)) { |
| debug_info->txbd_rdptr = |
| pmadapter->pcard_pcie->txbd_rdptr; |
| debug_info->txbd_wrptr = |
| pmadapter->pcard_pcie->txbd_wrptr; |
| debug_info->rxbd_rdptr = |
| pmadapter->pcard_pcie->rxbd_rdptr; |
| debug_info->rxbd_wrptr = |
| pmadapter->pcard_pcie->rxbd_wrptr; |
| debug_info->eventbd_rdptr = |
| pmadapter->pcard_pcie->evtbd_rdptr; |
| debug_info->eventbd_wrptr = |
| pmadapter->pcard_pcie->evtbd_wrptr; |
| debug_info->txbd_ring_vbase = |
| pmadapter->pcard_pcie->txbd_ring_vbase; |
| debug_info->txbd_ring_size = |
| pmadapter->pcard_pcie->txbd_ring_size; |
| debug_info->rxbd_ring_vbase = |
| pmadapter->pcard_pcie->rxbd_ring_vbase; |
| debug_info->rxbd_ring_size = |
| pmadapter->pcard_pcie->rxbd_ring_size; |
| debug_info->evtbd_ring_vbase = |
| pmadapter->pcard_pcie->evtbd_ring_vbase; |
| debug_info->evtbd_ring_size = |
| pmadapter->pcard_pcie->evtbd_ring_size; |
| debug_info->txrx_bd_size = |
| pmadapter->pcard_pcie->txrx_bd_size; |
| } |
| #endif |
| debug_info->data_sent = pmadapter->data_sent; |
| debug_info->data_sent_cnt = pmadapter->data_sent_cnt; |
| debug_info->cmd_sent = pmadapter->cmd_sent; |
| debug_info->cmd_resp_received = pmadapter->cmd_resp_received; |
| debug_info->tx_pkts_queued = |
| util_scalar_read(pmadapter->pmoal_handle, |
| &pmpriv->wmm.tx_pkts_queued, MNULL, |
| MNULL); |
| #ifdef UAP_SUPPORT |
| debug_info->num_bridge_pkts = |
| util_scalar_read(pmadapter->pmoal_handle, |
| &pmadapter->pending_bridge_pkts, |
| pmadapter->callbacks.moal_spin_lock, |
| pmadapter->callbacks.moal_spin_unlock); |
| debug_info->num_drop_pkts = pmpriv->num_drop_pkts; |
| #endif |
| debug_info->fw_hang_report = pmadapter->fw_hang_report; |
| debug_info->mlan_processing = pmadapter->mlan_processing; |
| debug_info->mlan_rx_processing = pmadapter->mlan_rx_processing; |
| debug_info->rx_pkts_queued = pmadapter->rx_pkts_queued; |
| debug_info->mlan_adapter = pmadapter; |
| debug_info->mlan_adapter_size = sizeof(mlan_adapter); |
| debug_info->mlan_priv_num = pmadapter->priv_num; |
| for (i = 0; i < pmadapter->priv_num; i++) { |
| debug_info->mlan_priv[i] = pmadapter->priv[i]; |
| debug_info->mlan_priv_size[i] = sizeof(mlan_private); |
| } |
| } |
| |
| pioctl_req->data_read_written = |
| sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get the MAC control configuration. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING -- success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_mac_control(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| misc->param.mac_ctrl = pmpriv->curr_pkt_filter; |
| } else { |
| pmpriv->curr_pkt_filter = misc->param.mac_ctrl; |
| cmd_action = HostCmd_ACT_GEN_SET; |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc->param.mac_ctrl); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This timer function handles wakeup card timeout. |
| * |
| * @param function_context A pointer to function_context |
| * @return N/A |
| */ |
| t_void wlan_wakeup_card_timeout_func(void *function_context) |
| { |
| pmlan_adapter pmadapter = (pmlan_adapter)function_context; |
| mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); |
| |
| ENTER(); |
| |
| PRINTM(MERROR, "%s: ps_state=%d\n", __FUNCTION__, pmadapter->ps_state); |
| if (pmadapter->ps_state != PS_STATE_AWAKE) { |
| PRINTM_NETINTF(MERROR, pmpriv); |
| PRINTM(MERROR, "Wakeup card timeout(%d)!\n", |
| pmadapter->pm_wakeup_timeout); |
| pmadapter->pm_wakeup_timeout++; |
| pmadapter->pm_wakeup_flag = MTRUE; |
| wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), |
| MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL); |
| } |
| pmadapter->wakeup_fw_timer_is_set = MFALSE; |
| |
| LEAVE(); |
| } |
| |
| /** |
| * @brief Set/Get HS configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_pm_cfg *pm = MNULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| t_u32 prev_cond = 0; |
| |
| ENTER(); |
| |
| pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf; |
| |
| switch (pioctl_req->action) { |
| case MLAN_ACT_SET: |
| #ifdef STA_SUPPORT |
| if (pmadapter->pps_uapsd_mode) { |
| PRINTM(MINFO, |
| "Host Sleep IOCTL is blocked in UAPSD/PPS mode\n"); |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID; |
| status = MLAN_STATUS_FAILURE; |
| break; |
| } |
| #endif /* STA_SUPPORT */ |
| if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) { |
| if (pm->param.hs_cfg.conditions == |
| HOST_SLEEP_CFG_CANCEL) { |
| if (pmadapter->is_hs_configured == MFALSE) { |
| /* Already cancelled */ |
| break; |
| } |
| /* Save previous condition */ |
| prev_cond = pmadapter->hs_cfg.conditions; |
| pmadapter->hs_cfg.conditions = |
| pm->param.hs_cfg.conditions; |
| } else if (pmadapter->hs_cfg.conditions == |
| HOST_SLEEP_CFG_CANCEL) { |
| /* Return failure if no parameters for HS enable |
| */ |
| pioctl_req->status_code = |
| MLAN_ERROR_INVALID_PARAMETER; |
| status = MLAN_STATUS_FAILURE; |
| break; |
| } |
| status = wlan_prepare_cmd( |
| pmpriv, HostCmd_CMD_802_11_HS_CFG_ENH, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| (t_void *)(&pmadapter->hs_cfg)); |
| if (status == MLAN_STATUS_SUCCESS) |
| status = MLAN_STATUS_PENDING; |
| if (pm->param.hs_cfg.conditions == |
| HOST_SLEEP_CFG_CANCEL) { |
| /* Restore previous condition */ |
| pmadapter->hs_cfg.conditions = prev_cond; |
| } |
| } else { |
| pmadapter->hs_cfg.conditions = |
| pm->param.hs_cfg.conditions; |
| pmadapter->hs_cfg.gpio = (t_u8)pm->param.hs_cfg.gpio; |
| pmadapter->hs_cfg.gap = (t_u8)pm->param.hs_cfg.gap; |
| pmadapter->param_type_ind = |
| (t_u8)pm->param.hs_cfg.param_type_ind; |
| pmadapter->ind_gpio = (t_u8)pm->param.hs_cfg.ind_gpio; |
| pmadapter->level = (t_u8)pm->param.hs_cfg.level; |
| pmadapter->param_type_ext = |
| (t_u8)pm->param.hs_cfg.param_type_ext; |
| pmadapter->event_force_ignore = |
| pm->param.hs_cfg.event_force_ignore; |
| pmadapter->event_use_ext_gap = |
| pm->param.hs_cfg.event_use_ext_gap; |
| pmadapter->ext_gap = pm->param.hs_cfg.ext_gap; |
| pmadapter->gpio_wave = pm->param.hs_cfg.gpio_wave; |
| pmadapter->hs_wake_interval = |
| pm->param.hs_cfg.hs_wake_interval; |
| pmadapter->min_wake_holdoff = |
| pm->param.hs_cfg.min_wake_holdoff; |
| } |
| break; |
| case MLAN_ACT_GET: |
| pm->param.hs_cfg.conditions = pmadapter->hs_cfg.conditions; |
| pm->param.hs_cfg.gpio = pmadapter->hs_cfg.gpio; |
| pm->param.hs_cfg.gap = pmadapter->hs_cfg.gap; |
| pm->param.hs_cfg.param_type_ind = pmadapter->param_type_ind; |
| pm->param.hs_cfg.ind_gpio = pmadapter->ind_gpio; |
| pm->param.hs_cfg.level = pmadapter->level; |
| pm->param.hs_cfg.param_type_ext = pmadapter->param_type_ext; |
| pm->param.hs_cfg.event_force_ignore = |
| pmadapter->event_force_ignore; |
| pm->param.hs_cfg.event_use_ext_gap = |
| pmadapter->event_use_ext_gap; |
| pm->param.hs_cfg.ext_gap = pmadapter->ext_gap; |
| pm->param.hs_cfg.gpio_wave = pmadapter->gpio_wave; |
| pm->param.hs_cfg.hs_wake_interval = pmadapter->hs_wake_interval; |
| pm->param.hs_cfg.min_wake_holdoff = pmadapter->min_wake_holdoff; |
| break; |
| default: |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID; |
| status = MLAN_STATUS_FAILURE; |
| break; |
| } |
| |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @brief Get/Set the firmware wakeup method |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_fw_wakeup_method(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action; |
| mlan_ds_pm_cfg *pmcfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_FW_WAKE_METHOD, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &pmcfg->param.fw_wakeup_params); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set Robustcoex gpiocfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_misc_robustcoex(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action; |
| mlan_ds_misc_cfg *robust_coex_cfg = |
| (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_ROBUSTCOEX, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &robust_coex_cfg->param.robustcoexparams); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/get DMCS config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_dmcs_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action; |
| mlan_ds_misc_cfg *dmcs_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DMCS_CONFIG, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &dmcs_cfg->param.dmcs_policy); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(PCIE) |
| /** |
| * @brief Enable SSU support |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_misc_ssu(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = HostCmd_ACT_GEN_GET; |
| mlan_ds_misc_cfg *ssu_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_DEFAULT) |
| cmd_action = HostCmd_ACT_GEN_SET_DEFAULT; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SSU, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &ssu_cfg->param.ssu_params); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set the hal/phy cfg params. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_misc_hal_phy_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *hal_phy_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| t_u16 cmd_act; |
| |
| ENTER(); |
| |
| cmd_act = HostCmd_ACT_GEN_SET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_HAL_PHY_CFG, cmd_act, 0, |
| (t_void *)pioctl_req, |
| &hal_phy_cfg->param.hal_phy_cfg_params); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Enable/disable CSI support |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_misc_csi(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *csi_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| t_u16 cmd_act; |
| |
| ENTER(); |
| |
| if (csi_cfg->param.csi_params.csi_enable == 1) { |
| if (pmadapter->csi_enabled) { |
| PRINTM(MERROR, |
| "Enable CSI: CSI was already enabled.\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| cmd_act = CSI_CMD_ENABLE; |
| } else { |
| if (!pmadapter->csi_enabled) { |
| PRINTM(MERROR, |
| "Disable CSI: CSI was already disabled.\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| cmd_act = CSI_CMD_DISABLE; |
| } |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CSI, cmd_act, 0, |
| (t_void *)pioctl_req, |
| &csi_cfg->param.csi_params); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function allocates a mlan_buffer. |
| * |
| * @param pmadapter Pointer to mlan_adapter |
| * @param data_len Data length |
| * @param head_room head_room reserved in mlan_buffer |
| * @param malloc_flag flag to user moal_malloc |
| * @return mlan_buffer pointer or MNULL |
| */ |
| pmlan_buffer wlan_alloc_mlan_buffer(mlan_adapter *pmadapter, t_u32 data_len, |
| t_u32 head_room, t_u32 malloc_flag) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_buffer pmbuf = MNULL; |
| t_u32 buf_size = 0; |
| t_u8 *tmp_buf = MNULL; |
| pmlan_callbacks pcb = &pmadapter->callbacks; |
| t_u32 mem_flags = MLAN_MEM_DEF | MLAN_MEM_DMA; |
| |
| ENTER(); |
| |
| #ifdef SDIO |
| /* make sure that the data length is at least SDIO block size */ |
| if (IS_SD(pmadapter->card_type)) |
| data_len = (data_len + MLAN_SDIO_BLOCK_SIZE - 1) / |
| MLAN_SDIO_BLOCK_SIZE * MLAN_SDIO_BLOCK_SIZE; |
| #endif |
| |
| /* head_room is not implemented for malloc mlan buffer */ |
| if (malloc_flag & MOAL_MALLOC_BUFFER) { |
| buf_size = |
| (t_u32)(sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT); |
| if (malloc_flag & MOAL_MEM_FLAG_ATOMIC) |
| mem_flags |= MLAN_MEM_FLAG_ATOMIC; |
| if (malloc_flag & MOAL_MEM_FLAG_DIRTY) |
| mem_flags |= MLAN_MEM_FLAG_DIRTY; |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, |
| mem_flags, (t_u8 **)&pmbuf); |
| if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) { |
| pmbuf = MNULL; |
| goto exit; |
| } |
| |
| if (malloc_flag & MOAL_MEM_FLAG_DIRTY) |
| memset(pmadapter, pmbuf, 0x00, |
| sizeof(*pmbuf) + head_room); |
| |
| pmbuf->pdesc = MNULL; |
| /* Align address */ |
| pmbuf->pbuf = (t_u8 *)ALIGN_ADDR( |
| (t_u8 *)pmbuf + sizeof(mlan_buffer), DMA_ALIGNMENT); |
| pmbuf->data_offset = 0; |
| pmbuf->data_len = data_len; |
| pmbuf->flags |= MLAN_BUF_FLAG_MALLOC_BUF; |
| } else if (malloc_flag & MOAL_ALLOC_MLAN_BUFFER) { |
| /* use moal_alloc_mlan_buffer, head_room supported */ |
| ret = pcb->moal_alloc_mlan_buffer( |
| pmadapter->pmoal_handle, |
| data_len + DMA_ALIGNMENT + head_room, &pmbuf); |
| if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) { |
| PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n"); |
| goto exit; |
| } |
| pmbuf->data_offset = head_room; |
| tmp_buf = (t_u8 *)ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset, |
| DMA_ALIGNMENT); |
| pmbuf->data_offset += |
| (t_u32)(tmp_buf - (pmbuf->pbuf + pmbuf->data_offset)); |
| pmbuf->data_len = data_len; |
| pmbuf->flags = 0; |
| } |
| |
| exit: |
| LEAVE(); |
| return pmbuf; |
| } |
| |
| /** |
| * @brief This function frees a mlan_buffer. |
| * |
| * @param pmadapter Pointer to mlan_adapter |
| * @param pmbuf Pointer to mlan_buffer |
| * |
| * @return N/A |
| */ |
| t_void wlan_free_mlan_buffer(mlan_adapter *pmadapter, pmlan_buffer pmbuf) |
| { |
| pmlan_callbacks pcb = &pmadapter->callbacks; |
| ENTER(); |
| |
| if (pcb && pmbuf) { |
| if (pmbuf->flags & MLAN_BUF_FLAG_BRIDGE_BUF) |
| util_scalar_decrement( |
| pmadapter->pmoal_handle, |
| &pmadapter->pending_bridge_pkts, |
| pmadapter->callbacks.moal_spin_lock, |
| pmadapter->callbacks.moal_spin_unlock); |
| if (pmbuf->flags & MLAN_BUF_FLAG_MALLOC_BUF) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmbuf); |
| else |
| pcb->moal_free_mlan_buffer(pmadapter->pmoal_handle, |
| pmbuf); |
| } |
| |
| LEAVE(); |
| return; |
| } |
| |
| /** |
| * @brief Delay function implementation |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param delay Delay value |
| * @param u Units of delay (sec, msec or usec) |
| * |
| * @return N/A |
| */ |
| t_void wlan_delay_func(mlan_adapter *pmadapter, t_u32 delay, t_delay_unit u) |
| { |
| t_u32 now_tv_sec, now_tv_usec; |
| t_u32 upto_tv_sec, upto_tv_usec; |
| pmlan_callbacks pcb = &pmadapter->callbacks; |
| |
| ENTER(); |
| |
| if (pcb->moal_udelay) { |
| if (u == SEC) |
| delay *= 1000000; |
| else if (u == MSEC) |
| delay *= 1000; |
| pcb->moal_udelay(pmadapter->pmoal_handle, delay); |
| } else { |
| pcb->moal_get_system_time(pmadapter->pmoal_handle, &upto_tv_sec, |
| &upto_tv_usec); |
| |
| switch (u) { |
| case SEC: |
| upto_tv_sec += delay; |
| break; |
| case MSEC: |
| delay *= 1000; |
| upto_tv_sec += (delay / 1000000); |
| upto_tv_usec += (delay % 1000000); |
| break; |
| case USEC: |
| upto_tv_sec += (delay / 1000000); |
| upto_tv_usec += (delay % 1000000); |
| break; |
| } |
| |
| do { |
| pcb->moal_get_system_time(pmadapter->pmoal_handle, |
| &now_tv_sec, &now_tv_usec); |
| if (now_tv_sec > upto_tv_sec) { |
| LEAVE(); |
| return; |
| } |
| |
| if ((now_tv_sec == upto_tv_sec) && |
| (now_tv_usec >= upto_tv_usec)) { |
| LEAVE(); |
| return; |
| } |
| } while (MTRUE); |
| } |
| |
| LEAVE(); |
| return; |
| } |
| |
| /** |
| * @brief BSS remove |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_bss_ioctl_bss_remove(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| ENTER(); |
| wlan_cancel_bss_pending_cmd(pmadapter, pioctl_req->bss_index); |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) |
| /** |
| * @brief Set/Get BSS role |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_bss_ioctl_bss_role(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_bss *bss = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| HostCmd_DS_VERSION_EXT dummy; |
| #ifdef USB |
| pmlan_callbacks pcb = &pmadapter->callbacks; |
| pmlan_buffer pmbuf; |
| #endif |
| #if defined(WIFI_DIRECT_SUPPORT) |
| t_u8 bss_mode; |
| #endif |
| t_u8 i; |
| t_u16 global_band = 0; |
| int j; |
| |
| ENTER(); |
| |
| bss = (mlan_ds_bss *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| bss->param.bss_role = GET_BSS_ROLE(pmpriv); |
| } else { |
| if (GET_BSS_ROLE(pmpriv) == bss->param.bss_role) { |
| PRINTM(MIOCTL, "BSS ie already in the desired role!\n"); |
| goto done; |
| } |
| mlan_block_rx_process(pmadapter, MTRUE); |
| /** Switch BSS role */ |
| wlan_free_priv(pmpriv); |
| |
| #ifdef USB |
| if (IS_USB(pmadapter->card_type)) { |
| while ((pmbuf = (pmlan_buffer)util_dequeue_list( |
| pmadapter->pmoal_handle, |
| &pmadapter->rx_data_queue, |
| pcb->moal_spin_lock, |
| pcb->moal_spin_unlock))) { |
| pcb->moal_recv_complete(pmadapter->pmoal_handle, |
| pmbuf, |
| pmadapter->rx_data_ep, |
| MLAN_STATUS_FAILURE); |
| } |
| } |
| #endif |
| pmpriv->bss_role = bss->param.bss_role; |
| if (pmpriv->bss_type == MLAN_BSS_TYPE_UAP) |
| pmpriv->bss_type = MLAN_BSS_TYPE_STA; |
| else if (pmpriv->bss_type == MLAN_BSS_TYPE_STA) |
| pmpriv->bss_type = MLAN_BSS_TYPE_UAP; |
| /* Initialize private structures */ |
| wlan_init_priv(pmpriv); |
| /* restore mac address */ |
| memcpy_ext(pmpriv->adapter, pmpriv->curr_addr, |
| pmpriv->adapter->permanent_addr, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| mlan_block_rx_process(pmadapter, MFALSE); |
| /* Initialize function table */ |
| for (j = 0; mlan_ops[j]; j++) { |
| if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmpriv)) { |
| memcpy_ext(pmadapter, &pmpriv->ops, mlan_ops[j], |
| sizeof(mlan_operations), |
| sizeof(mlan_operations)); |
| } |
| } |
| |
| for (i = 0; i < pmadapter->priv_num; i++) { |
| if (pmadapter->priv[i] && |
| GET_BSS_ROLE(pmadapter->priv[i]) == |
| MLAN_BSS_ROLE_STA) |
| global_band |= pmadapter->priv[i]->config_bands; |
| } |
| |
| if (global_band != pmadapter->config_bands) { |
| if (wlan_set_regiontable(pmpriv, |
| (t_u8)pmadapter->region_code, |
| global_band)) { |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| if (wlan_11d_set_universaltable(pmpriv, global_band)) { |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| pmadapter->config_bands = global_band; |
| } |
| |
| /* Issue commands to initialize firmware */ |
| #if defined(WIFI_DIRECT_SUPPORT) |
| if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) |
| bss_mode = BSS_MODE_WIFIDIRECT_CLIENT; |
| else |
| bss_mode = BSS_MODE_WIFIDIRECT_GO; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE, |
| HostCmd_ACT_GEN_SET, 0, MNULL, |
| &bss_mode); |
| if (ret) |
| goto done; |
| #endif |
| ret = pmpriv->ops.init_cmd(pmpriv, MFALSE); |
| if (ret == MLAN_STATUS_FAILURE) |
| goto done; |
| |
| /* Issue dummy Get command to complete the ioctl */ |
| memset(pmadapter, &dummy, 0, sizeof(HostCmd_DS_VERSION_EXT)); |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, |
| HostCmd_ACT_GEN_GET, 0, |
| (t_void *)pioctl_req, (t_void *)&dummy); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set the custom IE |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * @param send_ioctl Flag to indicate if ioctl should be sent with cmd |
| * (MTRUE if from moal/user, MFALSE if internal) |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_custom_ie_list(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req, |
| t_bool send_ioctl) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| custom_ie *ie_data = MNULL; |
| t_u16 cmd_action = 0, index, mask, i, len, app_data_len; |
| t_s32 ioctl_len; |
| t_u8 *tmp_ie; |
| |
| ENTER(); |
| |
| if ((misc->param.cust_ie.len == 0) || |
| (misc->param.cust_ie.len == sizeof(t_u16))) { |
| pioctl_req->action = MLAN_ACT_GET; |
| /* Get the IE */ |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ie_data = (custom_ie *)(((t_u8 *)&misc->param.cust_ie) + |
| sizeof(MrvlIEtypesHeader_t)); |
| index = ie_data->ie_index; |
| if (index >= pmadapter->max_mgmt_ie_index) { |
| PRINTM(MERROR, "Invalid custom IE index %d\n", index); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| } else { |
| /* ioctl_len : ioctl length from application, start with |
| * misc->param.cust_ie.len and reach upto 0 */ |
| ioctl_len = misc->param.cust_ie.len; |
| |
| /* app_data_len : length from application, start with 0 |
| * and reach upto ioctl_len */ |
| app_data_len = sizeof(MrvlIEtypesHeader_t); |
| misc->param.cust_ie.len = 0; |
| |
| while (ioctl_len > 0) { |
| ie_data = (custom_ie *)(((t_u8 *)&misc->param.cust_ie) + |
| app_data_len); |
| ioctl_len -= |
| (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE); |
| app_data_len += |
| (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE); |
| |
| index = ie_data->ie_index; |
| mask = ie_data->mgmt_subtype_mask; |
| |
| /* Need to be Autohandled */ |
| if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) { |
| /* Automatic Deletion */ |
| if (mask == MLAN_CUSTOM_IE_DELETE_MASK) { |
| ret = wlan_custom_ioctl_auto_delete( |
| pmpriv, pioctl_req, ie_data, |
| index); |
| /* if IE to delete is not found, return |
| * error */ |
| if (ret == MLAN_STATUS_FAILURE) |
| goto done; |
| index = ie_data->ie_index; |
| memset(pmadapter, ie_data, 0, |
| sizeof(custom_ie) * |
| MAX_MGMT_IE_INDEX_TO_FW); |
| len = 0; |
| for (i = 0; |
| i < pmadapter->max_mgmt_ie_index; |
| i++) { |
| /* Check if index is updated |
| * before sending to FW */ |
| if (index & ((t_u16)1) << i) { |
| memcpy_ext( |
| pmadapter, |
| (t_u8 *)ie_data + |
| len, |
| &i, |
| sizeof(ie_data->ie_index), |
| sizeof(ie_data->ie_index)); |
| len += sizeof( |
| ie_data->ie_index); |
| memcpy_ext( |
| pmadapter, |
| (t_u8 *)ie_data + |
| len, |
| &pmpriv->mgmt_ie[i] |
| .mgmt_subtype_mask, |
| sizeof(ie_data->mgmt_subtype_mask), |
| sizeof(ie_data->mgmt_subtype_mask)); |
| len += sizeof( |
| ie_data->mgmt_subtype_mask); |
| memcpy_ext( |
| pmadapter, |
| (t_u8 *)ie_data + |
| len, |
| &pmpriv->mgmt_ie[i] |
| .ie_length, |
| sizeof(ie_data->ie_length), |
| sizeof(ie_data->ie_length)); |
| len += sizeof( |
| ie_data->ie_length); |
| if (pmpriv->mgmt_ie[i] |
| .ie_length) { |
| memcpy_ext( |
| pmadapter, |
| (t_u8 *)ie_data + |
| len, |
| &pmpriv->mgmt_ie[i] |
| .ie_buffer, |
| pmpriv->mgmt_ie[i] |
| .ie_length, |
| pmpriv->mgmt_ie[i] |
| .ie_length); |
| len += pmpriv->mgmt_ie[i] |
| .ie_length; |
| } |
| } |
| } |
| misc->param.cust_ie.len += len; |
| pioctl_req->action = MLAN_ACT_SET; |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } else { /* Automatic Addition */ |
| if (MLAN_STATUS_FAILURE == |
| wlan_custom_ioctl_get_autoidx( |
| pmpriv, pioctl_req, mask, |
| ie_data, &index)) { |
| PRINTM(MERROR, |
| "Failed to Set the IE buffer\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| mask &= ~MLAN_CUSTOM_IE_NEW_MASK; |
| if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == |
| index || |
| index >= MAX_MGMT_IE_INDEX) { |
| ret = MLAN_STATUS_SUCCESS; |
| goto done; |
| } |
| tmp_ie = (t_u8 *)&pmpriv->mgmt_ie[index] |
| .ie_buffer; |
| memcpy_ext( |
| pmadapter, |
| tmp_ie + pmpriv->mgmt_ie[index] |
| .ie_length, |
| &ie_data->ie_buffer, |
| ie_data->ie_length, |
| ie_data->ie_length); |
| pmpriv->mgmt_ie[index].ie_length += |
| ie_data->ie_length; |
| pmpriv->mgmt_ie[index].ie_index = index; |
| pmpriv->mgmt_ie[index] |
| .mgmt_subtype_mask = mask; |
| |
| pioctl_req->action = MLAN_ACT_SET; |
| cmd_action = HostCmd_ACT_GEN_SET; |
| ie_data->ie_index = index; |
| ie_data->ie_length = |
| pmpriv->mgmt_ie[index].ie_length; |
| memcpy_ext( |
| pmadapter, &ie_data->ie_buffer, |
| &pmpriv->mgmt_ie[index] |
| .ie_buffer, |
| pmpriv->mgmt_ie[index].ie_length, |
| MAX_IE_SIZE); |
| misc->param.cust_ie.len += |
| pmpriv->mgmt_ie[index] |
| .ie_length + |
| MLAN_CUSTOM_IE_HDR_SIZE; |
| } |
| } else { |
| if (index >= pmadapter->max_mgmt_ie_index || |
| index >= MAX_MGMT_IE_INDEX) { |
| PRINTM(MERROR, |
| "Invalid custom IE index %d\n", |
| index); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| /* Set/Clear the IE and save it */ |
| if (ie_data->mgmt_subtype_mask == |
| MLAN_CUSTOM_IE_DELETE_MASK && |
| ie_data->ie_length) { |
| PRINTM(MINFO, "Clear the IE buffer\n"); |
| ret = wlan_custom_ioctl_auto_delete( |
| pmpriv, pioctl_req, ie_data, |
| index); |
| /* if IE to delete is not found, return |
| * error */ |
| if (ret == MLAN_STATUS_FAILURE) |
| goto done; |
| memset(pmadapter, ie_data, 0, |
| sizeof(custom_ie) * |
| MAX_MGMT_IE_INDEX_TO_FW); |
| memcpy_ext( |
| pmadapter, (t_u8 *)ie_data, |
| &pmpriv->mgmt_ie[index], |
| pmpriv->mgmt_ie[index].ie_length + |
| MLAN_CUSTOM_IE_HDR_SIZE, |
| pmpriv->mgmt_ie[index].ie_length + |
| MLAN_CUSTOM_IE_HDR_SIZE); |
| } else { |
| /* |
| * Check if this index is being used on |
| * any other interfaces. If yes, then |
| * the request needs to be rejected. |
| */ |
| ret = wlan_is_custom_ie_index_unused( |
| pmpriv, index); |
| if (ret == MLAN_STATUS_FAILURE) { |
| PRINTM(MERROR, |
| "IE index is used by other interface.\n"); |
| PRINTM(MERROR, |
| "Set or delete on index %d is not allowed.\n", |
| index); |
| pioctl_req->status_code = |
| MLAN_ERROR_IOCTL_FAIL; |
| goto done; |
| } |
| PRINTM(MINFO, "Set the IE buffer\n"); |
| if (ie_data->mgmt_subtype_mask == |
| MLAN_CUSTOM_IE_DELETE_MASK) |
| ie_data->ie_length = 0; |
| else { |
| if ((pmpriv->mgmt_ie[index] |
| .mgmt_subtype_mask == |
| ie_data->mgmt_subtype_mask) && |
| (pmpriv->mgmt_ie[index] |
| .ie_length == |
| ie_data->ie_length) && |
| !memcmp(pmpriv->adapter, |
| pmpriv->mgmt_ie[index] |
| .ie_buffer, |
| ie_data->ie_buffer, |
| ie_data->ie_length)) { |
| PRINTM(MIOCTL, |
| "same custom ie already configured!\n"); |
| if (ioctl_len <= 0 && |
| misc->param.cust_ie |
| .len == |
| 0) { |
| goto done; |
| } else { |
| /* remove |
| * matching IE |
| * from app |
| * buffer */ |
| app_data_len -= |
| ie_data->ie_length + |
| MLAN_CUSTOM_IE_HDR_SIZE; |
| memmove(pmadapter, |
| (t_u8 *)ie_data, |
| ie_data->ie_buffer + |
| ie_data->ie_length, |
| ioctl_len); |
| continue; |
| } |
| } |
| } |
| memset(pmadapter, |
| &pmpriv->mgmt_ie[index], 0, |
| sizeof(custom_ie)); |
| memcpy_ext(pmadapter, |
| &pmpriv->mgmt_ie[index], |
| ie_data, sizeof(custom_ie), |
| sizeof(custom_ie)); |
| } |
| |
| misc->param.cust_ie.len += |
| pmpriv->mgmt_ie[index].ie_length + |
| MLAN_CUSTOM_IE_HDR_SIZE; |
| pioctl_req->action = MLAN_ACT_SET; |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } |
| } |
| } |
| |
| /* Send command to firmware */ |
| if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) { |
| ret = wlan_prepare_cmd( |
| pmpriv, HostCmd_CMD_MGMT_IE_LIST, cmd_action, 0, |
| (send_ioctl) ? (t_void *)pioctl_req : MNULL, |
| &misc->param.cust_ie); |
| } |
| #ifdef UAP_SUPPORT |
| else if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) { |
| ret = wlan_prepare_cmd( |
| pmpriv, HostCmd_CMD_APCMD_SYS_CONFIGURE, cmd_action, 0, |
| (send_ioctl) ? (t_void *)pioctl_req : MNULL, |
| (send_ioctl) ? MNULL : &misc->param.cust_ie); |
| } |
| #endif |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read/write adapter register |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_reg_mem_ioctl_reg_rw(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_reg_mem *reg_mem = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0, cmd_no; |
| |
| ENTER(); |
| |
| reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else |
| cmd_action = HostCmd_ACT_GEN_SET; |
| |
| switch (reg_mem->param.reg_rw.type) { |
| case MLAN_REG_MAC: |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| case MLAN_REG_MAC2: |
| #endif |
| cmd_no = HostCmd_CMD_MAC_REG_ACCESS; |
| break; |
| case MLAN_REG_BBP: |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| case MLAN_REG_BBP2: |
| #endif |
| cmd_no = HostCmd_CMD_BBP_REG_ACCESS; |
| break; |
| case MLAN_REG_RF: |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| case MLAN_REG_RF2: |
| #endif |
| cmd_no = HostCmd_CMD_RF_REG_ACCESS; |
| break; |
| case MLAN_REG_CAU: |
| cmd_no = HostCmd_CMD_CAU_REG_ACCESS; |
| break; |
| case MLAN_REG_PSU: |
| cmd_no = HostCmd_CMD_TARGET_ACCESS; |
| break; |
| case MLAN_REG_BCA: |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| case MLAN_REG_BCA2: |
| #endif |
| cmd_no = HostCmd_CMD_BCA_REG_ACCESS; |
| break; |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) || defined(SD9177) || \ |
| defined(SDIW610) || defined(USBIW610) |
| case MLAN_REG_CIU: |
| cmd_no = HostCmd_CMD_REG_ACCESS; |
| break; |
| #endif |
| default: |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID; |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, cmd_no, cmd_action, 0, |
| (t_void *)pioctl_req, |
| (t_void *)®_mem->param.reg_rw); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read the EEPROM contents of the card |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_reg_mem_ioctl_read_eeprom(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_reg_mem *reg_mem = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_EEPROM_ACCESS, |
| cmd_action, 0, (t_void *)pioctl_req, |
| (t_void *)®_mem->param.rd_eeprom); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read/write memory of device |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_reg_mem_ioctl_mem_rw(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_reg_mem *reg_mem = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else |
| cmd_action = HostCmd_ACT_GEN_SET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0, |
| (t_void *)pioctl_req, |
| (t_void *)®_mem->param.mem_rw); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function will check if station list is empty |
| * |
| * @param priv A pointer to mlan_private |
| * |
| * @return MFALSE/MTRUE |
| */ |
| t_u8 wlan_is_station_list_empty(mlan_private *priv) |
| { |
| ENTER(); |
| if (!(util_peek_list(priv->adapter->pmoal_handle, &priv->sta_list, |
| priv->adapter->callbacks.moal_spin_lock, |
| priv->adapter->callbacks.moal_spin_unlock))) { |
| LEAVE(); |
| return MTRUE; |
| } |
| LEAVE(); |
| return MFALSE; |
| } |
| |
| /** |
| * @brief This function will return the pointer to station entry in station |
| * list table which matches the give mac address |
| * |
| * @param priv A pointer to mlan_private |
| * @param mac mac address to find in station list table |
| * |
| * @return A pointer to structure sta_node |
| */ |
| sta_node *wlan_get_station_entry(mlan_private *priv, t_u8 *mac) |
| { |
| sta_node *sta_ptr; |
| |
| ENTER(); |
| |
| if (!mac) { |
| LEAVE(); |
| return MNULL; |
| } |
| sta_ptr = (sta_node *)util_peek_list(priv->adapter->pmoal_handle, |
| &priv->sta_list, MNULL, MNULL); |
| |
| while (sta_ptr && (sta_ptr != (sta_node *)&priv->sta_list)) { |
| if (!memcmp(priv->adapter, sta_ptr->mac_addr, mac, |
| MLAN_MAC_ADDR_LENGTH)) { |
| LEAVE(); |
| return sta_ptr; |
| } |
| sta_ptr = sta_ptr->pnext; |
| } |
| LEAVE(); |
| return MNULL; |
| } |
| |
| /** |
| * @brief This function will add a pointer to station entry in station list |
| * table with the give mac address, if it does not exist already |
| * |
| * @param priv A pointer to mlan_private |
| * @param mac mac address to find in station list table |
| * |
| * @return A pointer to structure sta_node |
| */ |
| sta_node *wlan_add_station_entry(mlan_private *priv, t_u8 *mac) |
| { |
| sta_node *sta_ptr = MNULL; |
| |
| ENTER(); |
| |
| sta_ptr = wlan_get_station_entry(priv, mac); |
| if (sta_ptr) |
| goto done; |
| if (priv->adapter->callbacks.moal_malloc(priv->adapter->pmoal_handle, |
| sizeof(sta_node), MLAN_MEM_DEF, |
| (t_u8 **)&sta_ptr)) { |
| PRINTM(MERROR, "Failed to allocate memory for station node\n"); |
| LEAVE(); |
| return MNULL; |
| } |
| memcpy_ext(priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH, |
| MLAN_MAC_ADDR_LENGTH); |
| util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->sta_list, |
| (pmlan_linked_list)sta_ptr, |
| priv->adapter->callbacks.moal_spin_lock, |
| priv->adapter->callbacks.moal_spin_unlock); |
| done: |
| LEAVE(); |
| return sta_ptr; |
| } |
| |
| /** |
| * @brief This function deletes iPhone entry from llde device list |
| * |
| * @param priv A pointer to mlan_private |
| * @param mac iPhone mac address to dekete in llde iPhone device list table |
| * |
| * @return void |
| */ |
| void wlan_delete_iPhone_entry(mlan_private *priv, t_u8 *mac) |
| { |
| t_u8 i = 0; |
| |
| /* validate devices which are in llde_iphonefilters list are available |
| */ |
| for (i = 0; i < MAX_IPHONE_FILTER_ENTRIES; i++) { |
| if (memcmp(priv->adapter, |
| &priv->adapter |
| ->llde_iphonefilters[i * |
| MLAN_MAC_ADDR_LENGTH], |
| mac, MLAN_MAC_ADDR_LENGTH) == 0) { |
| /* remove device as it is not available */ |
| // coverity[bad_memset: SUPPRESS] |
| memset(priv->adapter, |
| (t_u8 *)&priv->adapter->llde_iphonefilters |
| [i * MLAN_MAC_ADDR_LENGTH], |
| 0, MLAN_MAC_ADDR_LENGTH); |
| priv->adapter->llde_totalIPhones--; |
| break; |
| } |
| } |
| } |
| |
| /** |
| * @brief This function will delete a station entry from station list |
| * |
| * |
| * @param priv A pointer to mlan_private |
| * @param mac station's mac address |
| * |
| * @return N/A |
| */ |
| t_void wlan_delete_station_entry(mlan_private *priv, t_u8 *mac) |
| { |
| sta_node *sta_ptr = MNULL; |
| ENTER(); |
| sta_ptr = wlan_get_station_entry(priv, mac); |
| if (sta_ptr) { |
| if (sta_ptr->is_apple_sta) |
| wlan_delete_iPhone_entry(priv, mac); |
| util_unlink_list(priv->adapter->pmoal_handle, &priv->sta_list, |
| (pmlan_linked_list)sta_ptr, |
| priv->adapter->callbacks.moal_spin_lock, |
| priv->adapter->callbacks.moal_spin_unlock); |
| priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle, |
| (t_u8 *)sta_ptr); |
| } |
| |
| LEAVE(); |
| return; |
| } |
| |
| /** |
| * @brief Clean up wapi station list |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * |
| * @return N/A |
| */ |
| t_void wlan_delete_station_list(pmlan_private priv) |
| { |
| sta_node *sta_ptr; |
| |
| ENTER(); |
| while ((sta_ptr = (sta_node *)util_dequeue_list( |
| priv->adapter->pmoal_handle, &priv->sta_list, |
| priv->adapter->callbacks.moal_spin_lock, |
| priv->adapter->callbacks.moal_spin_unlock))) { |
| priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle, |
| (t_u8 *)sta_ptr); |
| } |
| LEAVE(); |
| return; |
| } |
| |
| /** |
| * @brief Get tdls peer list |
| * |
| * @param priv A pointer to mlan_private structure |
| * @param buf A pointer to tdls_peer_info buf |
| * @return number of tdls peer |
| */ |
| int wlan_get_tdls_list(mlan_private *priv, tdls_peer_info *buf) |
| { |
| tdls_peer_info *peer_info = buf; |
| sta_node *sta_ptr = MNULL; |
| int count = 0; |
| |
| ENTER(); |
| if (priv->bss_type != MLAN_BSS_TYPE_STA) { |
| LEAVE(); |
| return count; |
| } |
| sta_ptr = (sta_node *)util_peek_list( |
| priv->adapter->pmoal_handle, &priv->sta_list, |
| priv->adapter->callbacks.moal_spin_lock, |
| priv->adapter->callbacks.moal_spin_unlock); |
| if (!sta_ptr) { |
| LEAVE(); |
| return count; |
| } |
| while (sta_ptr != (sta_node *)&priv->sta_list) { |
| if (sta_ptr->status == TDLS_SETUP_COMPLETE) { |
| peer_info->snr = sta_ptr->snr; |
| peer_info->nf = sta_ptr->nf; |
| memcpy_ext(priv->adapter, peer_info->mac_addr, |
| sta_ptr->mac_addr, MLAN_MAC_ADDR_LENGTH, |
| MLAN_MAC_ADDR_LENGTH); |
| memcpy_ext(priv->adapter, peer_info->ht_cap, |
| &sta_ptr->HTcap, sizeof(IEEEtypes_HTCap_t), |
| sizeof(peer_info->ht_cap)); |
| memcpy_ext(priv->adapter, peer_info->ext_cap, |
| &sta_ptr->ExtCap, sizeof(IEEEtypes_ExtCap_t), |
| sizeof(peer_info->ext_cap)); |
| memcpy_ext(priv->adapter, peer_info->vht_cap, |
| &sta_ptr->vht_cap, |
| sizeof(IEEEtypes_VHTCap_t), |
| sizeof(peer_info->vht_cap)); |
| memcpy_ext(priv->adapter, peer_info->he_cap, |
| &sta_ptr->he_cap, sizeof(IEEEtypes_HECap_t), |
| sizeof(peer_info->he_cap)); |
| peer_info++; |
| count++; |
| } |
| sta_ptr = sta_ptr->pnext; |
| if (count >= MLAN_MAX_TDLS_PEER_SUPPORTED) |
| break; |
| } |
| LEAVE(); |
| return count; |
| } |
| |
| /** |
| * @brief Set the TDLS configuration to FW. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tdls_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| tdls_all_config *tdls_all_cfg = |
| (tdls_all_config *)misc->param.tdls_config.tdls_data; |
| t_u8 event_buf[100]; |
| mlan_event *pevent = (mlan_event *)event_buf; |
| tdls_tear_down_event *tdls_evt = |
| (tdls_tear_down_event *)pevent->event_buf; |
| sta_node *sta_ptr = MNULL; |
| MrvlIEtypes_Data_t *pMrvlTlv = MNULL; |
| t_u8 *pos = MNULL; |
| t_u16 remain_len = 0; |
| |
| ENTER(); |
| |
| if (misc->param.tdls_config.tdls_action == WLAN_TDLS_TEAR_DOWN_REQ) { |
| sta_ptr = wlan_get_station_entry( |
| pmpriv, tdls_all_cfg->u.tdls_tear_down.peer_mac_addr); |
| if (sta_ptr && sta_ptr->external_tdls) { |
| pevent->bss_index = pmpriv->bss_index; |
| pevent->event_id = MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ; |
| pevent->event_len = sizeof(tdls_tear_down_event); |
| memcpy_ext(pmpriv->adapter, |
| (t_u8 *)tdls_evt->peer_mac_addr, |
| tdls_all_cfg->u.tdls_tear_down.peer_mac_addr, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| tdls_evt->reason_code = |
| tdls_all_cfg->u.tdls_tear_down.reason_code; |
| wlan_recv_event(pmpriv, |
| MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ, |
| pevent); |
| LEAVE(); |
| return ret; |
| } |
| } |
| if (misc->param.tdls_config.tdls_action == WLAN_HOST_TDLS_CONFIG) { |
| pmpriv->host_tdls_uapsd_support = |
| tdls_all_cfg->u.host_tdls_cfg.uapsd_support; |
| pmpriv->host_tdls_cs_support = |
| tdls_all_cfg->u.host_tdls_cfg.cs_support; |
| pos = tdls_all_cfg->u.host_tdls_cfg.tlv_buffer; |
| remain_len = tdls_all_cfg->u.host_tdls_cfg.tlv_len; |
| while (remain_len > sizeof(MrvlIEtypesHeader_t)) { |
| remain_len -= sizeof(MrvlIEtypesHeader_t); |
| pMrvlTlv = (MrvlIEtypes_Data_t *)pos; |
| switch (pMrvlTlv->header.type) { |
| case SUPPORTED_CHANNELS: |
| pmpriv->chan_supp_len = (t_u8)MIN( |
| pMrvlTlv->header.len, MAX_IE_SIZE); |
| memset(pmadapter, pmpriv->chan_supp, 0, |
| sizeof(pmpriv->chan_supp)); |
| memcpy_ext(pmadapter, pmpriv->chan_supp, |
| pMrvlTlv->data, pMrvlTlv->header.len, |
| MAX_IE_SIZE); |
| DBG_HEXDUMP(MCMD_D, "TDLS supported channel", |
| pmpriv->chan_supp, |
| pmpriv->chan_supp_len); |
| break; |
| case REGULATORY_CLASS: |
| pmpriv->supp_regulatory_class_len = (t_u8)MIN( |
| pMrvlTlv->header.len, MAX_IE_SIZE); |
| memset(pmadapter, pmpriv->supp_regulatory_class, |
| 0, |
| sizeof(pmpriv->supp_regulatory_class)); |
| memcpy_ext(pmadapter, |
| pmpriv->supp_regulatory_class, |
| pMrvlTlv->data, pMrvlTlv->header.len, |
| MAX_IE_SIZE); |
| DBG_HEXDUMP(MCMD_D, |
| "TDLS supported regulatory class", |
| pmpriv->supp_regulatory_class, |
| pmpriv->supp_regulatory_class_len); |
| break; |
| default: |
| break; |
| } |
| remain_len -= pMrvlTlv->header.len; |
| pos += sizeof(MrvlIEtypesHeader_t) + |
| pMrvlTlv->header.len; |
| } |
| LEAVE(); |
| return ret; |
| } |
| pioctl_req->action = MLAN_ACT_SET; |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| &misc->param.tdls_config); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief enable tdls config for cs and uapsd. |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param enable MTRUE/MFALSE |
| * |
| * @return |
| */ |
| t_void wlan_tdls_config(pmlan_private pmpriv, t_u8 enable) |
| { |
| mlan_adapter *pmadapter = pmpriv->adapter; |
| mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; |
| mlan_ds_misc_tdls_config *tdls_config = MNULL; |
| tdls_all_config *tdls_all_cfg = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, |
| sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF, |
| (t_u8 **)&tdls_config); |
| if (ret != MLAN_STATUS_SUCCESS || !tdls_config) { |
| PRINTM(MERROR, "Memory allocation for tdls_config failed!\n"); |
| LEAVE(); |
| return; |
| } |
| tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data; |
| tdls_all_cfg->u.tdls_config.enable = enable; |
| tdls_config->tdls_action = WLAN_TDLS_CONFIG; |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, |
| HostCmd_ACT_GEN_SET, 0, MNULL, tdls_config); |
| if (ret) |
| PRINTM(MERROR, "Error sending cmd to FW\n"); |
| |
| PRINTM(MCMND, "tdls_config: enable=%d\n", enable); |
| |
| if (tdls_config) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config); |
| |
| LEAVE(); |
| } |
| |
| /** |
| * @brief set tdls channel switch parameters. |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * |
| * @return |
| */ |
| static t_void wlan_tdls_cs_param_config(pmlan_private pmpriv) |
| { |
| mlan_adapter *pmadapter = pmpriv->adapter; |
| mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; |
| mlan_ds_misc_tdls_config *tdls_config = MNULL; |
| tdls_all_config *tdls_all_cfg = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, |
| sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF, |
| (t_u8 **)&tdls_config); |
| if (ret != MLAN_STATUS_SUCCESS || !tdls_config) { |
| PRINTM(MERROR, "Memory allocation for tdls_config failed!\n"); |
| LEAVE(); |
| return; |
| } |
| |
| tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data; |
| tdls_config->tdls_action = WLAN_TDLS_CS_PARAMS; |
| tdls_all_cfg->u.tdls_cs_params.unit_time = 2; |
| tdls_all_cfg->u.tdls_cs_params.threshold_otherlink = 10; |
| tdls_all_cfg->u.tdls_cs_params.threshold_directlink = 0; |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, |
| HostCmd_ACT_GEN_SET, 0, MNULL, tdls_config); |
| if (ret) |
| PRINTM(MERROR, "Error sending cmd to FW\n"); |
| |
| if (tdls_config) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config); |
| |
| LEAVE(); |
| } |
| |
| /** |
| * @brief start tdls channel switch |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param peer_mac_addr A pointer to peer mac address |
| * @param pioctl_buf A pointer to ioctl request buffer |
| * |
| * @return |
| */ |
| static t_void wlan_tdls_cs_start(pmlan_private pmpriv, t_u8 *peer_mac_addr, |
| pmlan_ioctl_req pioctl_buf) |
| { |
| mlan_adapter *pmadapter = pmpriv->adapter; |
| mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; |
| mlan_ds_misc_tdls_config *tdls_config = MNULL; |
| tdls_all_config *tdls_all_cfg = MNULL; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, |
| sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF, |
| (t_u8 **)&tdls_config); |
| if (ret != MLAN_STATUS_SUCCESS || !tdls_config) { |
| PRINTM(MERROR, "Memory allocation for tdls_config failed!\n"); |
| LEAVE(); |
| return; |
| } |
| |
| if (pioctl_buf) { |
| misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; |
| memcpy_ext(pmpriv->adapter, tdls_config, |
| &misc->param.tdls_config, |
| sizeof(mlan_ds_misc_tdls_config), |
| sizeof(mlan_ds_misc_tdls_config)); |
| tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data; |
| if (tdls_all_cfg->u.tdls_chan_switch.primary_channel > 14) { |
| tdls_all_cfg->u.tdls_chan_switch |
| .secondary_channel_offset = |
| wlan_get_second_channel_offset( |
| pmpriv, tdls_all_cfg->u.tdls_chan_switch |
| .primary_channel); |
| } |
| PRINTM(MCMND, "Start TDLS CS: channel=%d\n", |
| tdls_all_cfg->u.tdls_chan_switch.primary_channel); |
| } else { |
| tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data; |
| tdls_config->tdls_action = WLAN_TDLS_INIT_CHAN_SWITCH; |
| memcpy_ext(pmpriv->adapter, |
| tdls_all_cfg->u.tdls_chan_switch.peer_mac_addr, |
| peer_mac_addr, MLAN_MAC_ADDR_LENGTH, |
| MLAN_MAC_ADDR_LENGTH); |
| tdls_all_cfg->u.tdls_chan_switch.primary_channel = |
| pmpriv->tdls_cs_channel; |
| if (pmpriv->tdls_cs_channel > 14) { |
| tdls_all_cfg->u.tdls_chan_switch.band = BAND_5GHZ; |
| tdls_all_cfg->u.tdls_chan_switch |
| .secondary_channel_offset = |
| wlan_get_second_channel_offset( |
| pmpriv, pmpriv->tdls_cs_channel); |
| } else { |
| tdls_all_cfg->u.tdls_chan_switch.band = BAND_2GHZ; |
| } |
| PRINTM(MCMND, "Start TDLS CS: channel=%d\n", |
| pmpriv->tdls_cs_channel); |
| } |
| tdls_all_cfg->u.tdls_chan_switch.switch_time = 10; |
| tdls_all_cfg->u.tdls_chan_switch.switch_timeout = 16; |
| tdls_all_cfg->u.tdls_chan_switch.regulatory_class = 12; |
| tdls_all_cfg->u.tdls_chan_switch.periodicity = 1; |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, |
| HostCmd_ACT_GEN_SET, 0, MNULL, tdls_config); |
| if (ret) |
| PRINTM(MERROR, "Error sending cmd to FW\n"); |
| |
| if (tdls_config) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config); |
| |
| LEAVE(); |
| } |
| |
| #if 0 |
| /** |
| * @brief stop tdls channel switch |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param peer_mac_addr A pointer to peer mac address |
| * @param pioctl_buf A pointer to command buffer |
| * @return |
| */ |
| static t_void wlan_tdls_cs_stop(pmlan_private pmpriv, t_u8 *peer_mac_addr) |
| { |
| mlan_adapter *pmadapter = pmpriv->adapter; |
| mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; |
| mlan_ds_misc_tdls_config *tdls_config = MNULL; |
| tdls_all_config *tdls_all_cfg = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, |
| sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF, |
| (t_u8 **)&tdls_config); |
| if (ret != MLAN_STATUS_SUCCESS || !tdls_config) { |
| PRINTM(MERROR, "Memory allocation for tdls_config failed!\n"); |
| LEAVE(); |
| return; |
| } |
| memset(pmadapter, (t_u8 *)tdls_config, 0, |
| sizeof(mlan_ds_misc_tdls_config)); |
| |
| tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data; |
| tdls_config->tdls_action = WLAN_TDLS_STOP_CHAN_SWITCH; |
| |
| memcpy_ext(pmpriv->adapter, |
| tdls_all_cfg->u.tdls_stop_chan_switch.peer_mac_addr, |
| peer_mac_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| PRINTM(MCMND, "Stop TDLS CS\n"); |
| /* Send command to firmware */ |
| wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, HostCmd_ACT_GEN_SET, |
| 0, MNULL, tdls_config); |
| |
| if (tdls_config) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config); |
| |
| LEAVE(); |
| } |
| #endif |
| |
| /** |
| * @brief Set/Get the TDLS off channel. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tdls_cs_channel(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| |
| if (MLAN_ACT_GET == pioctl_req->action) |
| misc->param.tdls_cs_channel = pmpriv->tdls_cs_channel; |
| else if (MLAN_ACT_SET == pioctl_req->action) { |
| pmpriv->tdls_cs_channel = misc->param.tdls_cs_channel; |
| } |
| LEAVE(); |
| return ret; |
| } |
| /** |
| * @brief Set/Get the TDLS idle time. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tdls_idle_time(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| |
| if (MLAN_ACT_GET == pioctl_req->action) { |
| misc->param.tdls_idle_time = pmpriv->tdls_idle_time; |
| } else if (MLAN_ACT_SET == pioctl_req->action) { |
| pmpriv->tdls_idle_time = misc->param.tdls_idle_time; |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set the TDLS operation to FW. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tdls_oper(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_ds_misc_tdls_oper *ptdls_oper = &misc->param.tdls_oper; |
| t_u8 event_buf[100]; |
| mlan_event *ptdls_event = (mlan_event *)event_buf; |
| tdls_tear_down_event *tdls_evt = |
| (tdls_tear_down_event *)ptdls_event->event_buf; |
| sta_node *sta_ptr = MNULL; |
| t_u8 i = 0; |
| |
| ENTER(); |
| sta_ptr = wlan_get_station_entry(pmpriv, ptdls_oper->peer_mac); |
| switch (ptdls_oper->tdls_action) { |
| case WLAN_TDLS_ENABLE_LINK: |
| if (sta_ptr && (sta_ptr->status != TDLS_SETUP_FAILURE)) { |
| PRINTM(MMSG, "TDLS: Enable link " MACSTR " success\n", |
| MAC2STR(ptdls_oper->peer_mac)); |
| sta_ptr->status = TDLS_SETUP_COMPLETE; |
| pmadapter->tdls_status = TDLS_IN_BASE_CHANNEL; |
| if (!pmpriv->txaggrctrl) |
| wlan_11n_send_delba_to_peer( |
| pmpriv, |
| pmpriv->curr_bss_params.bss_descriptor |
| .mac_address); |
| if (sta_ptr->HTcap.ieee_hdr.element_id == |
| HT_CAPABILITY) { |
| sta_ptr->is_11n_enabled = MTRUE; |
| if (GETHT_MAXAMSDU( |
| sta_ptr->HTcap.ht_cap.ht_cap_info)) |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_8K; |
| else |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_4K; |
| for (i = 0; i < MAX_NUM_TID; i++) { |
| if (sta_ptr->is_11n_enabled || |
| sta_ptr->is_11ax_enabled) |
| sta_ptr->ampdu_sta[i] = |
| pmpriv->aggr_prio_tbl[i] |
| .ampdu_user; |
| else |
| sta_ptr->ampdu_sta[i] = |
| BA_STREAM_NOT_ALLOWED; |
| } |
| memset(pmpriv->adapter, sta_ptr->rx_seq, 0xff, |
| sizeof(sta_ptr->rx_seq)); |
| } |
| wlan_restore_tdls_packets(pmpriv, ptdls_oper->peer_mac, |
| TDLS_SETUP_COMPLETE); |
| if (ISSUPP_EXTCAP_TDLS_CHAN_SWITCH( |
| sta_ptr->ExtCap.ext_cap)) { |
| wlan_tdls_config(pmpriv, MTRUE); |
| wlan_tdls_cs_param_config(pmpriv); |
| /**tdls cs start*/ |
| if (pmpriv->tdls_cs_channel && |
| pmpriv->tdls_cs_channel != |
| pmpriv->curr_bss_params |
| .bss_descriptor.channel) |
| wlan_tdls_cs_start(pmpriv, |
| ptdls_oper->peer_mac, |
| MNULL); |
| } |
| } else { |
| PRINTM(MMSG, "TDLS: Enable link " MACSTR " fail\n", |
| MAC2STR(ptdls_oper->peer_mac)); |
| /*for supplicant 2.0, we need send event to request |
| *teardown, *for latest supplicant, we only need return |
| *fail, and supplicant will send teardown packet and |
| *disable tdls link*/ |
| if (sta_ptr) { |
| ptdls_event->bss_index = pmpriv->bss_index; |
| ptdls_event->event_id = |
| MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ; |
| ptdls_event->event_len = |
| sizeof(tdls_tear_down_event); |
| memcpy_ext(pmpriv->adapter, |
| (t_u8 *)tdls_evt->peer_mac_addr, |
| ptdls_oper->peer_mac, |
| MLAN_MAC_ADDR_LENGTH, |
| MLAN_MAC_ADDR_LENGTH); |
| tdls_evt->reason_code = |
| MLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; |
| wlan_recv_event( |
| pmpriv, |
| MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ, |
| ptdls_event); |
| wlan_restore_tdls_packets(pmpriv, |
| ptdls_oper->peer_mac, |
| TDLS_TEAR_DOWN); |
| if (sta_ptr->is_11n_enabled || |
| sta_ptr->is_11ax_enabled) { |
| wlan_cleanup_reorder_tbl( |
| pmpriv, ptdls_oper->peer_mac); |
| wlan_11n_cleanup_txbastream_tbl( |
| pmpriv, ptdls_oper->peer_mac); |
| } |
| wlan_delete_station_entry(pmpriv, |
| ptdls_oper->peer_mac); |
| if (MTRUE == wlan_is_station_list_empty(pmpriv)) |
| pmadapter->tdls_status = TDLS_NOT_SETUP; |
| else |
| pmadapter->tdls_status = |
| TDLS_IN_BASE_CHANNEL; |
| } |
| ret = MLAN_STATUS_FAILURE; |
| } |
| wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, |
| MNULL); |
| break; |
| case WLAN_TDLS_DISABLE_LINK: |
| /* Send command to firmware to delete tdls link*/ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_OPERATION, |
| HostCmd_ACT_GEN_SET, 0, |
| (t_void *)pioctl_req, ptdls_oper); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| break; |
| case WLAN_TDLS_CREATE_LINK: |
| PRINTM(MIOCTL, "CREATE TDLS LINK\n"); |
| if (sta_ptr && sta_ptr->status == TDLS_SETUP_INPROGRESS) { |
| PRINTM(MIOCTL, "We already create the link\n"); |
| break; |
| } |
| if (!sta_ptr) |
| sta_ptr = wlan_add_station_entry( |
| pmpriv, misc->param.tdls_oper.peer_mac); |
| if (sta_ptr) { |
| sta_ptr->status = TDLS_SETUP_INPROGRESS; |
| sta_ptr->external_tdls = MTRUE; |
| wlan_hold_tdls_packets(pmpriv, |
| misc->param.tdls_oper.peer_mac); |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_OPERATION, |
| HostCmd_ACT_GEN_SET, 0, |
| (t_void *)pioctl_req, ptdls_oper); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| break; |
| case WLAN_TDLS_CONFIG_LINK: |
| if (!sta_ptr || sta_ptr->status == TDLS_SETUP_FAILURE) { |
| PRINTM(MERROR, "Can not CONFIG TDLS Link\n"); |
| ret = MLAN_STATUS_FAILURE; |
| break; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_OPERATION, |
| HostCmd_ACT_GEN_SET, 0, |
| (t_void *)pioctl_req, ptdls_oper); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| break; |
| case WLAN_TDLS_INIT_CHAN_SWITCH: |
| if (sta_ptr && |
| ISSUPP_EXTCAP_TDLS_CHAN_SWITCH(sta_ptr->ExtCap.ext_cap)) { |
| wlan_tdls_config(pmpriv, MTRUE); |
| wlan_tdls_cs_param_config(pmpriv); |
| /**tdls cs start*/ |
| wlan_tdls_cs_start(pmpriv, ptdls_oper->peer_mac, |
| pioctl_req); |
| } |
| wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, |
| MNULL); |
| break; |
| default: |
| break; |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get AP's ext capability |
| * |
| * @param pmpriv A pointer to mlan_adapter structure |
| * @param ext_cap A pointer to ExtCap_t structure |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| static void wlan_get_ap_ext_cap(mlan_private *pmpriv, ExtCap_t *ext_cap) |
| { |
| pmlan_adapter pmadapter = pmpriv->adapter; |
| BSSDescriptor_t *pbss_desc; |
| pbss_desc = &pmpriv->curr_bss_params.bss_descriptor; |
| memset(pmadapter, ext_cap, 0, sizeof(ExtCap_t)); |
| if (pbss_desc->pext_cap) { |
| memcpy_ext(pmadapter, (t_u8 *)ext_cap, |
| (t_u8 *)pbss_desc->pext_cap + |
| sizeof(IEEEtypes_Header_t), |
| pbss_desc->pext_cap->ieee_hdr.len, sizeof(ExtCap_t)); |
| } |
| return; |
| } |
| |
| /** |
| * @brief Set the TDLS operation to FW. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tdls_get_ies(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_ds_misc_tdls_ies *tdls_ies = &misc->param.tdls_ies; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| BSSDescriptor_t *pbss_desc; |
| t_u32 usr_dot_11n_dev_cap; |
| IEEEtypes_ExtCap_t *ext_cap = MNULL; |
| ExtCap_t ap_ext_cap; |
| IEEEtypes_HTCap_t *ht_cap = MNULL; |
| IEEEtypes_HTInfo_t *ht_info = MNULL; |
| IEEEtypes_VHTCap_t *vht_cap = MNULL; |
| IEEEtypes_VHTOprat_t *vht_oprat = MNULL; |
| IEEEtypes_AssocRsp_t *passoc_rsp = MNULL; |
| IEEEtypes_AID_t *aid_info = MNULL; |
| IEEEtypes_HECap_t *he_cap = MNULL; |
| IEEEtypes_HeOp_t *he_op = MNULL; |
| t_u8 supp_chan[] = {1, 11}; |
| t_u8 regulatory_class[] = {1, /**current class*/ |
| 1, 2, 3, 4, 12, 22, 23, 24, |
| 25, 27, 28, 29, 30, 32, 33}; /**list |
| regulatory |
| class*/ |
| IEEEtypes_Generic_t *pSupp_chan = MNULL, *pRegulatory_class = MNULL; |
| sta_node *sta_ptr = MNULL; |
| ENTER(); |
| |
| /* We don't need peer information for TDLS setup */ |
| if (!(tdls_ies->flags & TDLS_IE_FLAGS_SETUP)) |
| sta_ptr = wlan_get_station_entry(pmpriv, tdls_ies->peer_mac); |
| pbss_desc = &pmpriv->curr_bss_params.bss_descriptor; |
| wlan_get_ap_ext_cap(pmpriv, &ap_ext_cap); |
| if (pbss_desc->bss_band & BAND_A) |
| usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_a; |
| else |
| usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_bg; |
| |
| /** fill the extcap */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_EXTCAP) { |
| ext_cap = (IEEEtypes_ExtCap_t *)tdls_ies->ext_cap; |
| ext_cap->ieee_hdr.element_id = EXT_CAPABILITY; |
| ext_cap->ieee_hdr.len = sizeof(ExtCap_t); |
| SET_EXTCAP_TDLS(ext_cap->ext_cap); |
| RESET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap); |
| RESET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap->ext_cap); |
| |
| if (pmpriv->host_tdls_uapsd_support) { |
| /* uapsd in tdls confirm frame*/ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_HTINFO) { |
| if (sta_ptr && ISSUPP_EXTCAP_TDLS_UAPSD( |
| sta_ptr->ExtCap.ext_cap)) |
| SET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap); |
| } else { |
| SET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap); |
| } |
| } |
| /* channel switch support */ |
| if (pmpriv->host_tdls_cs_support && |
| !IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ap_ext_cap)) { |
| /* channel switch in tdls confirm frame*/ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_HTINFO) { |
| if (sta_ptr && ISSUPP_EXTCAP_TDLS_CHAN_SWITCH( |
| sta_ptr->ExtCap.ext_cap)) |
| SET_EXTCAP_TDLS_CHAN_SWITCH( |
| ext_cap->ext_cap); |
| } else { |
| SET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap->ext_cap); |
| } |
| } |
| |
| RESET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap->ext_cap); |
| if ((pmadapter->fw_bands & BAND_AAC) && |
| (MFALSE == wlan_is_ap_in_11ac_mode(pmpriv))) |
| SET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap->ext_cap); |
| /* if peer does not support wider bandwidth, don't set wider |
| * bandwidth*/ |
| if (sta_ptr && sta_ptr->rate_len && |
| !ISSUPP_EXTCAP_TDLS_WIDER_BANDWIDTH( |
| sta_ptr->ExtCap.ext_cap)) |
| RESET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap->ext_cap); |
| DBG_HEXDUMP(MCMD_D, "TDLS extcap", tdls_ies->ext_cap, |
| sizeof(IEEEtypes_ExtCap_t)); |
| } |
| |
| /** default qos info is 0xf, compare with peer device qos info for tdls |
| * confirm */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_QOS_INFO) { |
| if (sta_ptr && sta_ptr->rate_len) |
| tdls_ies->QosInfo = sta_ptr->qos_info & 0xf; |
| PRINTM(MCMND, "TDLS Qos info=0x%x\n", tdls_ies->QosInfo); |
| } |
| |
| /** fill the htcap based on hwspec */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_HTCAP) { |
| ht_cap = (IEEEtypes_HTCap_t *)tdls_ies->ht_cap; |
| memset(pmadapter, ht_cap, 0, sizeof(IEEEtypes_HTCap_t)); |
| if ((sta_ptr && !ISSUPP_EXTCAP_TDLS_CHAN_SWITCH( |
| sta_ptr->ExtCap.ext_cap)) || |
| IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ap_ext_cap)) |
| wlan_fill_ht_cap_ie(pmpriv, ht_cap, |
| pbss_desc->bss_band); |
| else if (pmpriv->host_tdls_cs_support && |
| (pmadapter->fw_bands & BAND_A)) |
| wlan_fill_ht_cap_ie(pmpriv, ht_cap, BAND_A); |
| else |
| wlan_fill_ht_cap_ie(pmpriv, ht_cap, |
| pbss_desc->bss_band); |
| DBG_HEXDUMP(MCMD_D, "TDLS htcap", tdls_ies->ht_cap, |
| sizeof(IEEEtypes_HTCap_t)); |
| } |
| /** if peer did not support 11AC, do not add vht related ie */ |
| if (sta_ptr && sta_ptr->rate_len && |
| (sta_ptr->vht_cap.ieee_hdr.element_id != VHT_CAPABILITY)) |
| tdls_ies->flags &= |
| ~(TDLS_IE_FLAGS_VHTCAP | TDLS_IE_FLAGS_VHTOPRAT | |
| TDLS_IE_FLAGS_AID); |
| /** fill the vhtcap based on hwspec */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_VHTCAP) { |
| vht_cap = (IEEEtypes_VHTCap_t *)tdls_ies->vht_cap; |
| memset(pmadapter, vht_cap, 0, sizeof(IEEEtypes_VHTCap_t)); |
| wlan_fill_vht_cap_ie(pmpriv, vht_cap, pbss_desc->bss_band); |
| if (ht_cap) |
| SETHT_SUPPCHANWIDTH(ht_cap->ht_cap.ht_cap_info); |
| DBG_HEXDUMP(MCMD_D, "TDLS VHT Cap IE", tdls_ies->vht_cap, |
| sizeof(IEEEtypes_VHTCap_t)); |
| } |
| /** fill the vhtoperation based on hwspec */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_VHTOPRAT) { |
| vht_oprat = (IEEEtypes_VHTOprat_t *)tdls_ies->vht_oprat; |
| memset(pmadapter, vht_oprat, 0, sizeof(IEEEtypes_VHTOprat_t)); |
| if (sta_ptr && |
| (sta_ptr->vht_cap.ieee_hdr.element_id == VHT_CAPABILITY) && |
| (pbss_desc->bss_band & BAND_A)) { |
| wlan_fill_tdls_vht_oprat_ie(pmpriv, vht_oprat, sta_ptr); |
| } |
| if (sta_ptr) |
| memcpy_ext(pmadapter, &sta_ptr->vht_oprat, |
| tdls_ies->vht_oprat, |
| sizeof(IEEEtypes_VHTOprat_t), |
| sizeof(IEEEtypes_VHTOprat_t)); |
| DBG_HEXDUMP(MCMD_D, "TDLS VHT Operation IE", |
| tdls_ies->vht_oprat, sizeof(IEEEtypes_VHTOprat_t)); |
| } |
| /** fill the AID info */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_AID) { |
| if (pmpriv->curr_bss_params.host_mlme) |
| passoc_rsp = (IEEEtypes_AssocRsp_t |
| *)(pmpriv->assoc_rsp_buf + |
| sizeof(IEEEtypes_MgmtHdr_t)); |
| else |
| passoc_rsp = |
| (IEEEtypes_AssocRsp_t *)pmpriv->assoc_rsp_buf; |
| aid_info = (IEEEtypes_AID_t *)tdls_ies->aid_info; |
| memset(pmadapter, aid_info, 0, sizeof(IEEEtypes_AID_t)); |
| aid_info->ieee_hdr.element_id = AID_INFO; |
| aid_info->ieee_hdr.len = sizeof(t_u16); |
| aid_info->AID = wlan_le16_to_cpu(passoc_rsp->a_id); |
| PRINTM(MCMND, "TDLS AID=0x%x\n", aid_info->AID); |
| } |
| /** fill the hecap based on hwspec */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_HECAP) { |
| he_cap = (IEEEtypes_HECap_t *)tdls_ies->he_cap; |
| memset(pmadapter, he_cap, 0, sizeof(IEEEtypes_HECap_t)); |
| wlan_fill_he_cap_ie(pmpriv, he_cap, pbss_desc->bss_band); |
| DBG_HEXDUMP(MCMD_D, "TDLS HE Cap IE", tdls_ies->he_cap, |
| sizeof(IEEEtypes_Header_t) + he_cap->ieee_hdr.len); |
| } |
| |
| if (tdls_ies->flags & TDLS_IE_FLAGS_HEOP) { |
| he_op = (IEEEtypes_HeOp_t *)tdls_ies->he_op; |
| memset(pmadapter, he_op, 0, sizeof(IEEEtypes_HeOp_t)); |
| wlan_fill_he_op_ie(pmpriv, he_op); |
| } |
| if (sta_ptr) { |
| memcpy_ext(pmadapter, &sta_ptr->he_op, tdls_ies->he_op, |
| sizeof(IEEEtypes_HeOp_t), sizeof(IEEEtypes_HeOp_t)); |
| DBG_HEXDUMP(MCMD_D, "TDLS HE Operation IE", tdls_ies->he_op, |
| sizeof(IEEEtypes_HeOp_t)); |
| } |
| /** fill the htinfo */ |
| if (tdls_ies->flags & TDLS_IE_FLAGS_HTINFO) { |
| ht_info = (IEEEtypes_HTInfo_t *)tdls_ies->ht_info; |
| pbss_desc = &pmpriv->curr_bss_params.bss_descriptor; |
| ht_info->ieee_hdr.element_id = HT_OPERATION; |
| ht_info->ieee_hdr.len = sizeof(HTInfo_t); |
| ht_info->ht_info.pri_chan = pbss_desc->channel; |
| /* follow AP's channel bandwidth */ |
| if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) && |
| pbss_desc->pht_info && |
| ISALLOWED_CHANWIDTH40( |
| pbss_desc->pht_info->ht_info.field2)) { |
| ht_info->ht_info.field2 = |
| pbss_desc->pht_info->ht_info.field2; |
| } else { |
| ht_info->ht_info.field2 = |
| wlan_get_second_channel_offset( |
| pmpriv, pbss_desc->channel); |
| } |
| if (vht_oprat && |
| vht_oprat->ieee_hdr.element_id == VHT_OPERATION) { |
| ht_info->ht_info.field2 = |
| wlan_get_second_channel_offset( |
| pmpriv, pbss_desc->channel); |
| ht_info->ht_info.field2 |= MBIT(2); |
| } |
| if (sta_ptr) |
| memcpy_ext(pmadapter, &sta_ptr->HTInfo, |
| tdls_ies->ht_info, |
| sizeof(IEEEtypes_HTInfo_t), |
| sizeof(IEEEtypes_HTInfo_t)); |
| DBG_HEXDUMP(MCMD_D, "TDLS htinfo", tdls_ies->ht_info, |
| sizeof(IEEEtypes_HTInfo_t)); |
| } |
| |
| /** supported channels andl regulatory IE*/ |
| if (pmpriv->host_tdls_cs_support && |
| (tdls_ies->flags & TDLS_IE_FLAGS_SUPP_CS_IE) && |
| !IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ap_ext_cap)) { |
| /** supported channels IE*/ |
| pSupp_chan = (IEEEtypes_Generic_t *)tdls_ies->supp_chan; |
| pSupp_chan->ieee_hdr.element_id = SUPPORTED_CHANNELS; |
| if (pmpriv->chan_supp_len) { |
| pSupp_chan->ieee_hdr.len = pmpriv->chan_supp_len; |
| memcpy_ext(pmadapter, pSupp_chan->data, |
| pmpriv->chan_supp, pmpriv->chan_supp_len, |
| sizeof(pSupp_chan->data)); |
| } else { |
| pSupp_chan->ieee_hdr.len = sizeof(supp_chan); |
| memcpy_ext(pmadapter, pSupp_chan->data, supp_chan, |
| sizeof(supp_chan), sizeof(pSupp_chan->data)); |
| } |
| DBG_HEXDUMP( |
| MCMD_D, "TDLS supported channel", tdls_ies->supp_chan, |
| pSupp_chan->ieee_hdr.len + sizeof(IEEEtypes_Header_t)); |
| |
| /**fill supported Regulatory Class IE*/ |
| pRegulatory_class = |
| (IEEEtypes_Generic_t *)tdls_ies->regulatory_class; |
| pRegulatory_class->ieee_hdr.element_id = REGULATORY_CLASS; |
| if (pmpriv->supp_regulatory_class_len) { |
| pRegulatory_class->ieee_hdr.len = |
| pmpriv->supp_regulatory_class_len; |
| memcpy_ext(pmadapter, pRegulatory_class->data, |
| pmpriv->supp_regulatory_class, |
| pmpriv->supp_regulatory_class_len, |
| sizeof(pRegulatory_class->data)); |
| } else { |
| pRegulatory_class->ieee_hdr.len = |
| sizeof(regulatory_class); |
| memcpy_ext(pmadapter, pRegulatory_class->data, |
| regulatory_class, sizeof(regulatory_class), |
| sizeof(pRegulatory_class->data)); |
| } |
| DBG_HEXDUMP(MCMD_D, "TDLS supported regulatory class", |
| tdls_ies->regulatory_class, |
| pRegulatory_class->ieee_hdr.len + |
| sizeof(IEEEtypes_Header_t)); |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set mimo switch configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_radio_ioctl_mimo_switch_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_radio_cfg *radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_MIMO_SWITCH, 0, 0, |
| (t_void *)pioctl_req, |
| &(radio_cfg->param.mimo_switch_cfg)); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get extended version information |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_get_info_ver_ext(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_get_info *pinfo = (mlan_ds_get_info *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| &pinfo->param.ver_ext.version_str_sel); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get link layer statistics |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_ioctl_link_statistic(mlan_private *pmpriv, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| /* Check buffer length of MLAN IOCTL */ |
| if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) { |
| PRINTM(MWARN, |
| "MLAN IOCTL information buffer length is too short.\n"); |
| pioctl_req->data_read_written = 0; |
| pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_RESOURCE; |
| goto exit; |
| } |
| |
| switch (pioctl_req->action) { |
| case MLAN_ACT_GET: |
| cmd_action = HostCmd_ACT_GEN_GET; |
| break; |
| case MLAN_ACT_SET: |
| cmd_action = HostCmd_ACT_GEN_SET; |
| break; |
| case MLAN_ACT_CLEAR: |
| cmd_action = HostCmd_ACT_GEN_REMOVE; |
| break; |
| default: |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_LINK_STATS, |
| cmd_action, 0, (t_void *)pioctl_req, MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief config rtt |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_config_rtt(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = MNULL; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!pioctl_req) { |
| PRINTM(MERROR, "MLAN IOCTL information is not present\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FTM_CONFIG_SESSION_PARAMS, |
| HostCmd_ACT_GEN_SET, OID_RTT_REQUEST, |
| (t_void *)pioctl_req, &(misc->param.rtt_params)); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief cancel rtt |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_cancel_rtt(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = MNULL; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!pioctl_req) { |
| PRINTM(MERROR, "MLAN IOCTL information is not present\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FTM_CONFIG_SESSION_PARAMS, |
| HostCmd_ACT_GEN_SET, OID_RTT_CANCEL, |
| (t_void *)pioctl_req, &(misc->param.rtt_cancel)); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief rtt responder cfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_rtt_responder_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = MNULL; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!pioctl_req) { |
| PRINTM(MERROR, "MLAN IOCTL information is not present\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FTM_CONFIG_RESPONDER, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| &(misc->param.rtt_rsp_cfg)); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get TX/RX histogram statistic |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_get_tx_rx_histogram(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RX_PKT_STATS, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| &(pmisc->param.tx_rx_histogram)); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef DEBUG_LEVEL1 |
| /** |
| * @brief Set driver debug bit masks in order to enhance performance |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_set_drvdbg(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) |
| { |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* Set driver debug bit masks */ |
| mlan_drvdbg = misc->param.drvdbg; |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Rx mgmt frame forward register |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_reg_rx_mgmt_ind(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* Set passthru mask for mgmt frame */ |
| pmpriv->mgmt_frame_passthru_mask = misc->param.mgmt_subtype_mask; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_MGMT_IND, |
| (t_u16)pioctl_req->action, 0, |
| (t_void *)pioctl_req, |
| &misc->param.mgmt_subtype_mask); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function processes the 802.11 mgmt Frame |
| * |
| * @param priv A pointer to mlan_private |
| * |
| * @param payload A pointer to the received buffer |
| * @param payload_len Length of the received buffer |
| * @param prx_pd A pointer to RxPD |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private *priv, t_u8 *payload, |
| t_u32 payload_len, RxPD *prx_pd) |
| { |
| pmlan_adapter pmadapter = priv->adapter; |
| pmlan_callbacks pcb = &pmadapter->callbacks; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| wlan_802_11_header *pieee_pkt_hdr = MNULL; |
| t_u16 sub_type = 0; |
| t_u8 *event_buf = MNULL; |
| mlan_event *pevent = MNULL; |
| t_u8 unicast = 0; |
| t_u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| IEEE80211_MGMT *mgmt = MNULL; |
| t_u8 category = 0; |
| t_u8 action_code = 0; |
| #ifdef UAP_SUPPORT |
| sta_node *sta_ptr = MNULL; |
| MrvlIETypes_MgmtFrameSet_t *tlv; |
| pmlan_buffer pmbuf; |
| #endif |
| |
| ENTER(); |
| if (payload_len > (MAX_EVENT_SIZE - sizeof(mlan_event))) { |
| PRINTM(MERROR, "Dropping large mgmt frame,len =%d\n", |
| payload_len); |
| LEAVE(); |
| return ret; |
| } |
| /* Check packet type-subtype and compare with mgmt_passthru_mask |
| * If event is needed to host, just eventify it */ |
| pieee_pkt_hdr = (wlan_802_11_header *)payload; |
| sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(pieee_pkt_hdr->frm_ctl); |
| if (((1 << sub_type) & priv->mgmt_frame_passthru_mask) == 0) { |
| PRINTM(MINFO, "Dropping mgmt frame for subtype %d snr=%d.\n", |
| sub_type, prx_pd->snr); |
| LEAVE(); |
| return ret; |
| } |
| switch (sub_type) { |
| case SUBTYPE_ASSOC_REQUEST: |
| case SUBTYPE_REASSOC_REQUEST: |
| #ifdef UAP_SUPPORT |
| if (priv->uap_host_based & UAP_FLAG_HOST_MLME) { |
| PRINTM_NETINTF(MMSG, priv); |
| if (!memcmp(pmadapter, pieee_pkt_hdr->addr3, |
| priv->curr_addr, MLAN_MAC_ADDR_LENGTH)) { |
| PRINTM(MMSG, |
| "wlan: HostMlme MICRO_AP_STA_ASSOC " MACSTR |
| "\n", |
| MAC2STR(pieee_pkt_hdr->addr2)); |
| mgmt = (IEEE80211_MGMT *)payload; |
| sta_ptr = wlan_add_station_entry( |
| priv, pieee_pkt_hdr->addr2); |
| if (sta_ptr) { |
| sta_ptr->capability = wlan_le16_to_cpu( |
| mgmt->u.assoc_req.capab_info); |
| pmbuf = wlan_alloc_mlan_buffer( |
| pmadapter, payload_len, 0, |
| MOAL_MALLOC_BUFFER); |
| if (pmbuf) { |
| PRINTM(MCMND, |
| "check sta capability\n"); |
| pmbuf->data_len = |
| ASSOC_EVENT_FIX_SIZE; |
| tlv = (MrvlIETypes_MgmtFrameSet_t |
| *)(pmbuf->pbuf + |
| pmbuf->data_offset + |
| pmbuf->data_len); |
| tlv->type = wlan_cpu_to_le16( |
| TLV_TYPE_MGMT_FRAME); |
| tlv->len = sizeof( |
| IEEEtypes_FrameCtl_t); |
| memcpy_ext( |
| pmadapter, |
| (t_u8 *)&tlv |
| ->frame_control, |
| &pieee_pkt_hdr->frm_ctl, |
| sizeof(IEEEtypes_FrameCtl_t), |
| sizeof(IEEEtypes_FrameCtl_t)); |
| pmbuf->data_len += sizeof( |
| MrvlIETypes_MgmtFrameSet_t); |
| memcpy_ext( |
| pmadapter, |
| pmbuf->pbuf + |
| pmbuf->data_offset + |
| pmbuf->data_len, |
| payload + |
| sizeof(wlan_802_11_header), |
| payload_len - |
| sizeof(wlan_802_11_header), |
| payload_len - |
| sizeof(wlan_802_11_header)); |
| pmbuf->data_len += |
| payload_len - |
| sizeof(wlan_802_11_header); |
| tlv->len += |
| payload_len - |
| sizeof(wlan_802_11_header); |
| tlv->len = wlan_cpu_to_le16( |
| tlv->len); |
| DBG_HEXDUMP( |
| MCMD_D, "assoc_req", |
| pmbuf->pbuf + |
| pmbuf->data_offset, |
| pmbuf->data_len); |
| wlan_check_sta_capability( |
| priv, pmbuf, sta_ptr); |
| wlan_free_mlan_buffer(pmadapter, |
| pmbuf); |
| } |
| } |
| } else { |
| PRINTM(MMSG, |
| "wlan: Drop MICRO_AP_STA_ASSOC " MACSTR |
| " from unknown BSSID " MACSTR "\n", |
| MAC2STR(pieee_pkt_hdr->addr2), |
| MAC2STR(pieee_pkt_hdr->addr3)); |
| } |
| } |
| unicast = MTRUE; |
| break; |
| #endif |
| case SUBTYPE_AUTH: |
| unicast = MTRUE; |
| PRINTM_NETINTF(MMSG, priv); |
| PRINTM(MMSG, "wlan: HostMlme Auth received from " MACSTR "\n", |
| MAC2STR(pieee_pkt_hdr->addr2)); |
| break; |
| case SUBTYPE_PROBE_RESP: |
| unicast = MTRUE; |
| break; |
| case SUBTYPE_DISASSOC: |
| case SUBTYPE_DEAUTH: |
| if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast, |
| MLAN_MAC_ADDR_LENGTH)) |
| unicast = MTRUE; |
| #ifdef UAP_SUPPORT |
| if (priv->uap_host_based & UAP_FLAG_HOST_MLME) { |
| if (!memcmp(pmadapter, pieee_pkt_hdr->addr3, |
| priv->curr_addr, MLAN_MAC_ADDR_LENGTH)) { |
| PRINTM_NETINTF(MMSG, priv); |
| PRINTM(MMSG, |
| "wlan: HostMlme Deauth Receive from " MACSTR |
| "\n", |
| MAC2STR(pieee_pkt_hdr->addr2)); |
| } |
| } |
| #endif |
| if (priv->bss_role == MLAN_BSS_ROLE_STA) { |
| /* Igone DeAuth/DisAssoc frame from OLD AP during |
| * Roaming */ |
| if (priv->curr_bss_params.host_mlme) { |
| if ((memcmp(pmadapter, pieee_pkt_hdr->addr3, |
| (t_u8 *)priv->curr_bss_params |
| .bss_descriptor.mac_address, |
| MLAN_MAC_ADDR_LENGTH)) || |
| !priv->assoc_rsp_size || |
| !memcmp(pmadapter, pieee_pkt_hdr->addr3, |
| (t_u8 *)priv->curr_bss_params |
| .prev_bssid, |
| MLAN_MAC_ADDR_LENGTH)) { |
| PRINTM(MCMND, |
| "Dropping Deauth frame from other bssid: type=%d " MACSTR |
| "\n", |
| sub_type, |
| MAC2STR(pieee_pkt_hdr->addr3)); |
| LEAVE(); |
| return ret; |
| } |
| PRINTM_NETINTF(MMSG, priv); |
| PRINTM(MMSG, |
| "wlan: HostMlme Disconnected: sub_type=%d " MACSTR |
| "\n", |
| sub_type, MAC2STR(pieee_pkt_hdr->addr3)); |
| pmadapter->pending_disconnect_priv = priv; |
| wlan_recv_event( |
| priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, |
| MNULL); |
| } |
| } |
| break; |
| case SUBTYPE_ACTION: |
| category = *(payload + sizeof(wlan_802_11_header)); |
| action_code = *(payload + sizeof(wlan_802_11_header) + 1); |
| if (category == IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK) { |
| PRINTM(MINFO, |
| "Drop BLOCK ACK action frame: action_code=%d\n", |
| action_code); |
| LEAVE(); |
| return ret; |
| } |
| if ((category == IEEE_MGMT_ACTION_CATEGORY_PUBLIC) && |
| (action_code == BSS_20_40_COEX)) { |
| PRINTM(MINFO, |
| "Drop 20/40 BSS Coexistence Management frame\n"); |
| LEAVE(); |
| return ret; |
| } |
| if ((category == CATEGORY_PUBLIC) && |
| (action_code == TDLS_DISCOVERY_RESPONSE)) { |
| pcb->moal_updata_peer_signal(pmadapter->pmoal_handle, |
| priv->bss_index, |
| pieee_pkt_hdr->addr2, |
| prx_pd->snr, prx_pd->nf); |
| PRINTM(MINFO, |
| "Rx: TDLS discovery response, nf=%d, snr=%d\n", |
| prx_pd->nf, prx_pd->snr); |
| } |
| if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast, |
| MLAN_MAC_ADDR_LENGTH) && |
| !is_mcast_addr(pieee_pkt_hdr->addr1)) |
| unicast = MTRUE; |
| break; |
| default: |
| break; |
| } |
| if (unicast == MTRUE) { |
| if (memcmp(pmadapter, pieee_pkt_hdr->addr1, priv->curr_addr, |
| MLAN_MAC_ADDR_LENGTH)) { |
| PRINTM(MINFO, |
| "Dropping mgmt frame for others: type=%d " MACSTR |
| "\n", |
| sub_type, MAC2STR(pieee_pkt_hdr->addr1)); |
| LEAVE(); |
| return ret; |
| } |
| } |
| /* Allocate memory for event buffer */ |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, |
| MLAN_MEM_DEF, &event_buf); |
| if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) { |
| PRINTM(MERROR, "Could not allocate buffer for event buf\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| pevent = (pmlan_event)event_buf; |
| pevent->bss_index = priv->bss_index; |
| mgmt = (IEEE80211_MGMT *)payload; |
| if (priv->bss_role == MLAN_BSS_ROLE_STA && |
| !priv->curr_bss_params.host_mlme && sub_type == SUBTYPE_ACTION && |
| mgmt->u.ft_resp.category == FT_CATEGORY && |
| mgmt->u.ft_resp.action == FT_ACTION_RESPONSE && |
| mgmt->u.ft_resp.status_code == 0) { |
| PRINTM(MCMND, "FT Action response received\n"); |
| #define FT_ACTION_HEAD_LEN (24 + 6 + 16) |
| pevent->event_id = MLAN_EVENT_ID_DRV_FT_RESPONSE; |
| pevent->event_len = |
| payload_len + MLAN_MAC_ADDR_LENGTH - FT_ACTION_HEAD_LEN; |
| memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf, |
| &mgmt->u.ft_resp.target_ap_addr, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| memcpy_ext(pmadapter, |
| (t_u8 *)(pevent->event_buf + MLAN_MAC_ADDR_LENGTH), |
| payload + FT_ACTION_HEAD_LEN, |
| payload_len - FT_ACTION_HEAD_LEN, |
| pevent->event_len - MLAN_MAC_ADDR_LENGTH); |
| } else if (priv->bss_role == MLAN_BSS_ROLE_STA && |
| !priv->curr_bss_params.host_mlme && |
| sub_type == SUBTYPE_AUTH && |
| mgmt->u.auth.auth_alg == MLAN_AUTH_MODE_FT && |
| mgmt->u.auth.auth_transaction == 2 && |
| mgmt->u.auth.status_code == 0) { |
| PRINTM(MCMND, "FT auth response received \n"); |
| #define AUTH_PACKET_LEN (24 + 6 + 6) |
| pevent->event_id = MLAN_EVENT_ID_DRV_FT_RESPONSE; |
| pevent->event_len = |
| payload_len + MLAN_MAC_ADDR_LENGTH - AUTH_PACKET_LEN; |
| memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf, mgmt->sa, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| memcpy_ext(pmadapter, |
| (t_u8 *)(pevent->event_buf + MLAN_MAC_ADDR_LENGTH), |
| payload + AUTH_PACKET_LEN, |
| payload_len - AUTH_PACKET_LEN, |
| pevent->event_len - MLAN_MAC_ADDR_LENGTH); |
| } else { |
| pevent->event_id = MLAN_EVENT_ID_DRV_MGMT_FRAME; |
| pevent->event_len = payload_len + sizeof(pevent->event_id); |
| memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf, |
| (t_u8 *)&pevent->event_id, sizeof(pevent->event_id), |
| pevent->event_len); |
| memcpy_ext( |
| pmadapter, |
| (t_u8 *)(pevent->event_buf + sizeof(pevent->event_id)), |
| payload, payload_len, payload_len); |
| } |
| wlan_recv_event(priv, pevent->event_id, pevent); |
| if (event_buf) |
| pcb->moal_mfree(pmadapter->pmoal_handle, event_buf); |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Extended capabilities configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ext_capa_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (MLAN_ACT_GET == pioctl_req->action) |
| memcpy_ext(pmpriv->adapter, &misc->param.ext_cap, |
| &pmpriv->def_ext_cap, sizeof(misc->param.ext_cap), |
| sizeof(misc->param.ext_cap)); |
| else if (MLAN_ACT_SET == pioctl_req->action) { |
| memcpy_ext(pmpriv->adapter, &pmpriv->ext_cap, |
| &misc->param.ext_cap, sizeof(misc->param.ext_cap), |
| sizeof(pmpriv->ext_cap)); |
| /* Save default Extended Capability */ |
| memcpy_ext(pmpriv->adapter, &pmpriv->def_ext_cap, |
| &pmpriv->ext_cap, sizeof(pmpriv->ext_cap), |
| sizeof(pmpriv->def_ext_cap)); |
| if (pmpriv->config_bands & BAND_AAC) |
| SET_EXTCAP_OPERMODENTF(pmpriv->ext_cap); |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Check whether Extended Capabilities IE support |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * |
| * @return MTRUE or MFALSE; |
| */ |
| t_u32 wlan_is_ext_capa_support(mlan_private *pmpriv) |
| { |
| ENTER(); |
| |
| if (ISSUPP_EXTCAP_TDLS(pmpriv->ext_cap) || |
| ISSUPP_EXTCAP_INTERWORKING(pmpriv->ext_cap) || |
| ISSUPP_EXTCAP_BSS_TRANSITION(pmpriv->ext_cap) || |
| ISSUPP_EXTCAP_QOS_MAP(pmpriv->ext_cap) || |
| ISSUPP_EXTCAP_OPERMODENTF(pmpriv->ext_cap)) { |
| LEAVE(); |
| return MTRUE; |
| } else { |
| LEAVE(); |
| return MFALSE; |
| } |
| } |
| |
| /** |
| * @brief Set hotspot enable/disable |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_hotspot_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (MLAN_ACT_GET == pioctl_req->action) |
| misc->param.hotspot_cfg = pmpriv->hotspot_cfg; |
| else if (MLAN_ACT_SET == pioctl_req->action) |
| pmpriv->hotspot_cfg = misc->param.hotspot_cfg; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set multi ap flag |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_multi_ap_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (MLAN_ACT_GET == pioctl_req->action) |
| misc->param.multi_ap_flag = pmpriv->multi_ap_flag; |
| else if (MLAN_ACT_SET == pioctl_req->action) { |
| if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) { |
| ret = wlan_prepare_cmd(pmpriv, |
| HostCmd_CMD_APCMD_SYS_CONFIGURE, |
| HostCmd_ACT_GEN_SET, 0, |
| (t_void *)pioctl_req, MNULL); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| } |
| pmpriv->multi_ap_flag = misc->param.multi_ap_flag; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief This function check if we should enable beacon protection support |
| * |
| * @param pbss_desc A pointer to BSSDescriptor_t structure |
| * |
| * @return MTRUE/MFALSE |
| */ |
| static t_u8 wlan_check_beacon_prot_supported(mlan_private *pmpriv, |
| BSSDescriptor_t *pbss_desc) |
| { |
| if (pbss_desc && pbss_desc->pext_cap) { |
| if (pbss_desc->pext_cap->ieee_hdr.len < 11) |
| return MFALSE; |
| if (!ISSUPP_EXTCAP_EXT_BEACON_PROT( |
| pbss_desc->pext_cap->ext_cap)) |
| return MFALSE; |
| } |
| if (!IS_FW_SUPPORT_BEACON_PROT(pmpriv->adapter)) |
| return MFALSE; |
| return MTRUE; |
| } |
| |
| /** |
| * @brief Add Extended Capabilities IE |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param pbss_desc A pointer to BSSDescriptor_t structure |
| * @param pptlv_out A pointer to TLV to fill in |
| * |
| * @return N/A |
| */ |
| void wlan_add_ext_capa_info_ie(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc, |
| t_u8 **pptlv_out) |
| { |
| MrvlIETypes_ExtCap_t *pext_cap = MNULL; |
| |
| ENTER(); |
| |
| pext_cap = (MrvlIETypes_ExtCap_t *)*pptlv_out; |
| memset(pmpriv->adapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t)); |
| pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY); |
| pext_cap->header.len = wlan_cpu_to_le16(sizeof(ExtCap_t)); |
| if (pmpriv->adapter->ecsa_enable) |
| SET_EXTCAP_EXT_CHANNEL_SWITCH(pmpriv->ext_cap); |
| else |
| RESET_EXTCAP_EXT_CHANNEL_SWITCH(pmpriv->ext_cap); |
| if (pmpriv->adapter->pcard_info->support_11mc) { |
| SET_EXTCAP_FTMI(pmpriv->ext_cap); |
| SET_EXTCAP_INTERNETWORKING(pmpriv->ext_cap); |
| } |
| if (pbss_desc && pbss_desc->multi_bssid_ap) |
| SET_EXTCAP_MULTI_BSSID(pmpriv->ext_cap); |
| if (wlan_check_11ax_twt_supported(pmpriv, pbss_desc)) |
| SET_EXTCAP_TWT_REQ(pmpriv->ext_cap); |
| |
| if (wlan_check_beacon_prot_supported(pmpriv, pbss_desc)) |
| SET_EXTCAP_BEACON_PROT(pmpriv->ext_cap); |
| |
| memcpy_ext(pmpriv->adapter, &pext_cap->ext_cap, &pmpriv->ext_cap, |
| sizeof(pmpriv->ext_cap), sizeof(pext_cap->ext_cap)); |
| *pptlv_out += sizeof(MrvlIETypes_ExtCap_t); |
| |
| LEAVE(); |
| } |
| #endif |
| |
| /** |
| * @brief Get OTP user data |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_otp_user_data(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| |
| ENTER(); |
| |
| if (misc->param.otp_user_data.user_data_length > |
| MAX_OTP_USER_DATA_LEN) { |
| PRINTM(MERROR, "Invalid OTP user data length\n"); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| LEAVE(); |
| return ret; |
| } |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_OTP_READ_USER_DATA, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| &misc->param.otp_user_data); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef UAP_SUPPORT |
| /** |
| * @brief Check 11B support Rates |
| * |
| * |
| * @param pmadapter Private mlan adapter structure |
| * |
| * @return MTRUE/MFALSE |
| * |
| */ |
| static t_u8 wlan_check_ie_11b_support_rates(pIEEEtypes_Generic_t prates) |
| { |
| int i; |
| t_u8 rate; |
| t_u8 ret = MTRUE; |
| for (i = 0; i < prates->ieee_hdr.len; i++) { |
| rate = prates->data[i] & 0x7f; |
| if ((rate != 0x02) && (rate != 0x04) && (rate != 0x0b) && |
| (rate != 0x16)) { |
| ret = MFALSE; |
| break; |
| } |
| } |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief This function adds iPhone entry into llde device list |
| * |
| * @param priv A pointer to mlan_private |
| * @param mac iPhone mac address to add in llde iPhone device list table |
| * |
| * @return void |
| */ |
| void wlan_add_iPhone_entry(mlan_private *priv, t_u8 *mac) |
| { |
| t_u8 null_mac_addr[MLAN_MAC_ADDR_LENGTH] = {0}; |
| t_u8 t_iphonefilters[MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH] = |
| {0}; |
| int i = 0, j = 0; |
| |
| /* reset count */ |
| priv->adapter->llde_totalIPhones = 0; |
| |
| if (MAX_IPHONE_FILTER_ENTRIES > 1) { |
| /* back up original list */ |
| memcpy_ext(priv->adapter, &t_iphonefilters, |
| &priv->adapter->llde_iphonefilters, |
| MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH, |
| MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH); |
| |
| /* clear original list */ |
| // coverity[bad_memset: SUPPRESS] |
| memset(priv->adapter, |
| (t_u8 *)&priv->adapter->llde_iphonefilters, 0, |
| MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH); |
| |
| /* copy valid entries into original list */ |
| for (i = 0, j = 1; i < MAX_IPHONE_FILTER_ENTRIES; i++) { |
| if (memcmp(priv->adapter, |
| &t_iphonefilters[i * MLAN_MAC_ADDR_LENGTH], |
| &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) { |
| memcpy_ext( |
| priv->adapter, |
| &priv->adapter->llde_iphonefilters |
| [j++ * MLAN_MAC_ADDR_LENGTH], |
| &t_iphonefilters[i * |
| MLAN_MAC_ADDR_LENGTH], |
| MLAN_MAC_ADDR_LENGTH, |
| MLAN_MAC_ADDR_LENGTH); |
| } |
| } |
| } |
| |
| /* add latest connected device entry at the start of list to get high |
| * priority while search in list */ |
| if (MAX_IPHONE_FILTER_ENTRIES) { |
| memcpy_ext(priv->adapter, &priv->adapter->llde_iphonefilters[0], |
| mac, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| } |
| |
| /* update connected device count */ |
| for (i = 0; i < MAX_IPHONE_FILTER_ENTRIES; i++) { |
| if (memcmp(priv->adapter, |
| &priv->adapter |
| ->llde_iphonefilters[i * |
| MLAN_MAC_ADDR_LENGTH], |
| &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) |
| priv->adapter->llde_totalIPhones++; |
| } |
| |
| return; |
| } |
| |
| /** |
| * @brief extracts all vendor specific oui's to pass it to fw in add_station |
| * cmd |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param sta_ptr A pointer to sta_node |
| * @param pbuf A pointer to IE buffer |
| * @param buf_len IE buffer len |
| * |
| * @return MTRUE/MFALSE |
| */ |
| static void wlan_check_sta_vendor_ies(pmlan_adapter pmadapter, |
| sta_node *sta_ptr, t_u8 *pbuf, |
| t_u16 buf_len) |
| { |
| t_u16 bytes_left = buf_len; |
| IEEEtypes_ElementId_e element_id; |
| t_u8 *pcurrent_ptr = pbuf; |
| t_u8 element_len, oui_pos = 0, index = 0, found_existing_oui = 0; |
| t_u16 total_ie_len; |
| IEEEtypes_VendorSpecific_t *pvendor_ie; |
| const t_u8 apple_oui[VENDOR_OUI_LEN] = {0x00, 0x17, 0xf2, 0x0a}; |
| |
| ENTER(); |
| |
| /* Process variable IE */ |
| while (bytes_left >= 2) { |
| element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); |
| element_len = *((t_u8 *)pcurrent_ptr + 1); |
| total_ie_len = element_len + sizeof(IEEEtypes_Header_t); |
| |
| if (bytes_left < total_ie_len) { |
| PRINTM(MERROR, "InterpretIE: Error in processing IE, " |
| "bytes left < IE length\n"); |
| bytes_left = 0; |
| continue; |
| } |
| switch (element_id) { |
| case VENDOR_SPECIFIC_221: |
| pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr; |
| if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, |
| apple_oui, sizeof(apple_oui))) { |
| sta_ptr->is_apple_sta = MTRUE; |
| } |
| found_existing_oui = 0; |
| /* check if oui already present in list */ |
| for (index = 0; index < sta_ptr->vendor_oui_count; |
| index++) { |
| oui_pos = index * VENDOR_OUI_LEN; |
| if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, |
| (t_u8 *)&sta_ptr |
| ->vendor_oui[oui_pos], |
| VENDOR_OUI_LEN)) { |
| found_existing_oui = 1; |
| break; |
| } |
| } |
| if ((found_existing_oui == 0) && |
| (sta_ptr->vendor_oui_count < MAX_VENDOR_OUI_NUM)) { |
| // add oui in list, sta_ptr->vendor_oui_count |
| // does not exceed MAX_VENDOR_OUI_NUM hence |
| // sta_ptr->vendor_oui buffer size does not |
| // exceed (MAX_VENDOR_OUI_NUM * VENDOR_OUI_LEN) |
| // coverity[overrun-buffer-arg: SUPPRESS] |
| memcpy_ext(pmadapter, |
| (t_u8 *)&sta_ptr->vendor_oui |
| [sta_ptr->vendor_oui_count * |
| VENDOR_OUI_LEN], |
| pvendor_ie->vend_hdr.oui, |
| VENDOR_OUI_LEN, VENDOR_OUI_LEN); |
| sta_ptr->vendor_oui_count++; |
| } |
| break; |
| default: |
| break; |
| } |
| pcurrent_ptr += element_len + 2; |
| /* Need to account for IE ID and IE Len */ |
| bytes_left -= (element_len + 2); |
| } |
| |
| LEAVE(); |
| return; |
| } |
| |
| /** |
| * @brief This function extracts multi-ap IE |
| * |
| * @param pmadapter A pointer to mlan_adapter |
| * @param pbuf A pointer to IE buffer |
| * @param buf_len IE buffer length |
| * @param multi_ap_ie A pointer to Vendor IE |
| * |
| * @return MTRUE - if multi-ap ie found, MFALSE - otherwise |
| */ |
| static t_u8 wlan_get_multi_ap_ie(pmlan_adapter pmadapter, t_u8 *pbuf, |
| t_u16 buf_len, |
| IEEEtypes_Generic_t *multi_ap_ie) |
| { |
| t_u16 bytes_left = buf_len; |
| IEEEtypes_ElementId_e element_id; |
| t_u8 *pcurrent_ptr = pbuf; |
| t_u8 element_len; |
| t_u16 total_ie_len; |
| IEEEtypes_Generic_t *pvendor_ie; |
| const t_u8 multi_ap_oui[3] = {0x50, 0x6f, 0x9a}; |
| |
| ENTER(); |
| |
| /* Process variable IE */ |
| while (bytes_left >= 2) { |
| element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); |
| element_len = *((t_u8 *)pcurrent_ptr + 1); |
| total_ie_len = element_len + sizeof(IEEEtypes_Header_t); |
| |
| if (bytes_left < total_ie_len) { |
| PRINTM(MERROR, "InterpretIE: Error in processing IE, " |
| "bytes left < IE length\n"); |
| bytes_left = 0; |
| continue; |
| } |
| |
| if (element_id == VENDOR_SPECIFIC_221) { |
| pvendor_ie = (IEEEtypes_Generic_t *)pcurrent_ptr; |
| if (!memcmp(pmadapter, pvendor_ie->data, multi_ap_oui, |
| sizeof(multi_ap_oui))) { |
| memcpy_ext(pmadapter, multi_ap_ie, pvendor_ie, |
| pvendor_ie->ieee_hdr.len + |
| sizeof(IEEEtypes_Header_t), |
| sizeof(IEEEtypes_Generic_t)); |
| return MTRUE; |
| } |
| } |
| |
| pcurrent_ptr += element_len + 2; |
| /* Need to account for IE ID and IE Len */ |
| bytes_left -= (element_len + 2); |
| } |
| |
| LEAVE(); |
| return MFALSE; |
| } |
| |
| /** |
| * @brief This function will search for the specific ie |
| * |
| * @param priv A pointer to mlan_private |
| * @param pevent A pointer to event buf |
| * @param sta_ptr A pointer to sta_node |
| * |
| * @return N/A |
| */ |
| void wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent, |
| sta_node *sta_ptr) |
| { |
| t_u16 tlv_type, tlv_len; |
| t_u16 frame_control, frame_sub_type = 0; |
| t_u8 *assoc_req_ie = MNULL; |
| t_u8 ie_len = 0, assoc_ie_len = 0; |
| IEEEtypes_HTCap_t *pht_cap = MNULL; |
| IEEEtypes_VHTCap_t *pvht_cap = MNULL; |
| IEEEtypes_Extension_t *phe_cap = MNULL; |
| #ifdef UAP_SUPPORT |
| t_u8 *rate = MNULL; |
| t_u8 b_only = MFALSE; |
| #endif |
| t_u8 maxIPhoneEntries = MAX_IPHONE_FILTER_ENTRIES; |
| |
| int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE; |
| MrvlIEtypesHeader_t *tlv = |
| (MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset + |
| ASSOC_EVENT_FIX_SIZE); |
| MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL; |
| |
| ENTER(); |
| while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) { |
| tlv_type = wlan_le16_to_cpu(tlv->type); |
| tlv_len = wlan_le16_to_cpu(tlv->len); |
| if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) > |
| (unsigned int)tlv_buf_left) { |
| PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", |
| tlv_len, tlv_buf_left); |
| break; |
| } |
| if (tlv_type == TLV_TYPE_MGMT_FRAME) { |
| mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *)tlv; |
| memcpy_ext(priv->adapter, &frame_control, |
| (t_u8 *)&(mgmt_tlv->frame_control), |
| sizeof(frame_control), |
| sizeof(frame_control)); |
| frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE( |
| frame_control); |
| if ((mgmt_tlv->frame_control.type == 0) && |
| ((frame_sub_type == SUBTYPE_BEACON) |
| #ifdef UAP_SUPPORT |
| || (frame_sub_type == SUBTYPE_ASSOC_REQUEST) || |
| (frame_sub_type == SUBTYPE_REASSOC_REQUEST) |
| #endif |
| )) { |
| if (frame_sub_type == SUBTYPE_BEACON) |
| assoc_ie_len = |
| sizeof(IEEEtypes_Beacon_t); |
| #ifdef UAP_SUPPORT |
| else if (frame_sub_type == |
| SUBTYPE_ASSOC_REQUEST) |
| assoc_ie_len = |
| sizeof(IEEEtypes_AssocRqst_t); |
| else if (frame_sub_type == |
| SUBTYPE_REASSOC_REQUEST) |
| assoc_ie_len = |
| sizeof(IEEEtypes_ReAssocRqst_t); |
| #endif |
| ie_len = tlv_len - |
| sizeof(IEEEtypes_FrameCtl_t) - |
| assoc_ie_len; |
| assoc_req_ie = |
| (t_u8 *)tlv + |
| sizeof(MrvlIETypes_MgmtFrameSet_t) + |
| assoc_ie_len; |
| sta_ptr->is_wmm_enabled = |
| wlan_is_wmm_ie_present(priv->adapter, |
| assoc_req_ie, |
| ie_len); |
| PRINTM(MCMND, "STA: is_wmm_enabled=%d\n", |
| sta_ptr->is_wmm_enabled); |
| |
| wlan_check_sta_vendor_ies(priv->adapter, |
| sta_ptr, assoc_req_ie, |
| ie_len); |
| if (sta_ptr->is_apple_sta && maxIPhoneEntries) { |
| wlan_add_iPhone_entry( |
| priv, sta_ptr->mac_addr); |
| } |
| pht_cap = (IEEEtypes_HTCap_t *) |
| wlan_get_specific_ie(priv, assoc_req_ie, |
| ie_len, |
| HT_CAPABILITY, 0); |
| if (pht_cap) { |
| PRINTM(MCMND, "STA supports 11n\n"); |
| sta_ptr->is_11n_enabled = MTRUE; |
| memcpy_ext(priv->adapter, |
| (t_u8 *)&sta_ptr->HTcap, |
| pht_cap, |
| sizeof(IEEEtypes_HTCap_t), |
| sizeof(IEEEtypes_HTCap_t)); |
| if (GETHT_MAXAMSDU(wlan_le16_to_cpu( |
| pht_cap->ht_cap |
| .ht_cap_info))) |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_8K; |
| else |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_4K; |
| } else { |
| PRINTM(MCMND, |
| "STA doesn't support 11n\n"); |
| } |
| pvht_cap = (IEEEtypes_VHTCap_t *) |
| wlan_get_specific_ie(priv, assoc_req_ie, |
| ie_len, |
| VHT_CAPABILITY, 0); |
| if (pvht_cap && |
| (priv->is_11ac_enabled == MTRUE)) { |
| PRINTM(MCMND, "STA supports 11ac\n"); |
| sta_ptr->is_11ac_enabled = MTRUE; |
| if (GET_VHTCAP_MAXMPDULEN(wlan_le32_to_cpu( |
| pvht_cap->vht_cap |
| .vht_cap_info)) == |
| 2) |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_12K; |
| else if (GET_VHTCAP_MAXMPDULEN(wlan_le32_to_cpu( |
| pvht_cap->vht_cap |
| .vht_cap_info)) == |
| 1) |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_8K; |
| else |
| sta_ptr->max_amsdu = |
| MLAN_TX_DATA_BUF_SIZE_4K; |
| } else { |
| PRINTM(MCMND, |
| "STA doesn't support 11ac\n"); |
| } |
| phe_cap = (IEEEtypes_Extension_t *) |
| wlan_get_specific_ie(priv, assoc_req_ie, |
| ie_len, EXTENSION, |
| HE_CAPABILITY); |
| if (phe_cap && |
| (priv->is_11ax_enabled == MTRUE)) { |
| PRINTM(MCMND, "STA supports 11ax\n"); |
| sta_ptr->is_11ax_enabled = MTRUE; |
| memcpy_ext( |
| priv->adapter, |
| (t_u8 *)&sta_ptr->he_cap, |
| phe_cap, |
| phe_cap->ieee_hdr.len + |
| sizeof(IEEEtypes_Header_t), |
| sizeof(IEEEtypes_HECap_t)); |
| sta_ptr->he_cap.ieee_hdr.len = MIN( |
| phe_cap->ieee_hdr.len, |
| sizeof(IEEEtypes_HECap_t) - |
| sizeof(IEEEtypes_Header_t)); |
| } else { |
| PRINTM(MCMND, |
| "STA doesn't support 11ax\n"); |
| } |
| #ifdef UAP_SUPPORT |
| /* Note: iphone6 does not have ERP_INFO */ |
| rate = wlan_get_specific_ie(priv, assoc_req_ie, |
| ie_len, |
| SUPPORTED_RATES, 0); |
| if (rate) |
| b_only = wlan_check_ie_11b_support_rates( |
| (pIEEEtypes_Generic_t)rate); |
| if (sta_ptr->is_11ax_enabled) { |
| if (priv->uap_channel <= 14) |
| sta_ptr->bandmode = BAND_GAX; |
| else |
| sta_ptr->bandmode = BAND_AAX; |
| } else if (sta_ptr->is_11ac_enabled) { |
| if (priv->uap_channel <= 14) |
| sta_ptr->bandmode = BAND_GAC; |
| else |
| sta_ptr->bandmode = BAND_AAC; |
| } else if (sta_ptr->is_11n_enabled) { |
| if (priv->uap_channel <= 14) |
| sta_ptr->bandmode = BAND_GN; |
| else |
| sta_ptr->bandmode = BAND_AN; |
| } else if (priv->uap_channel <= 14) { |
| if (b_only) |
| sta_ptr->bandmode = BAND_B; |
| else |
| sta_ptr->bandmode = BAND_G; |
| } else |
| sta_ptr->bandmode = BAND_A; |
| sta_ptr->is_multi_ap = wlan_get_multi_ap_ie( |
| priv->adapter, assoc_req_ie, ie_len, |
| &sta_ptr->multi_ap_ie); |
| #endif |
| break; |
| } |
| } |
| tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len); |
| tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + |
| sizeof(MrvlIEtypesHeader_t)); |
| } |
| LEAVE(); |
| |
| return; |
| } |
| |
| /** |
| * @brief check if WMM ie present. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pbuf A pointer to IE buffer |
| * @param buf_len IE buffer len |
| * |
| * @return MTRUE/MFALSE |
| */ |
| t_u8 wlan_is_wmm_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, t_u16 buf_len) |
| { |
| t_u16 bytes_left = buf_len; |
| IEEEtypes_ElementId_e element_id; |
| t_u8 *pcurrent_ptr = pbuf; |
| t_u8 element_len; |
| t_u16 total_ie_len; |
| IEEEtypes_VendorSpecific_t *pvendor_ie; |
| const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02}; |
| t_u8 find_wmm_ie = MFALSE; |
| |
| ENTER(); |
| |
| /* Process variable IE */ |
| while (bytes_left >= 2) { |
| element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); |
| element_len = *((t_u8 *)pcurrent_ptr + 1); |
| total_ie_len = element_len + sizeof(IEEEtypes_Header_t); |
| |
| if (bytes_left < total_ie_len) { |
| PRINTM(MERROR, "InterpretIE: Error in processing IE, " |
| "bytes left < IE length\n"); |
| bytes_left = 0; |
| continue; |
| } |
| switch (element_id) { |
| case VENDOR_SPECIFIC_221: |
| pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr; |
| if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, |
| wmm_oui, sizeof(wmm_oui))) { |
| find_wmm_ie = MTRUE; |
| PRINTM(MINFO, "find WMM IE\n"); |
| } |
| break; |
| default: |
| break; |
| } |
| pcurrent_ptr += element_len + 2; |
| /* Need to account for IE ID and IE Len */ |
| bytes_left -= (element_len + 2); |
| if (find_wmm_ie) |
| break; |
| } |
| |
| LEAVE(); |
| return find_wmm_ie; |
| } |
| |
| /** |
| * @brief This function will search for the specific ie |
| * |
| * |
| * @param priv A pointer to mlan_private |
| * @param ie_buf A pointer to ie_buf |
| * @param ie_len total ie length |
| * @param id ie's id |
| * @param ext_id ie's extension id |
| * |
| * @return ie's poiner or MNULL |
| */ |
| t_u8 *wlan_get_specific_ie(pmlan_private priv, t_u8 *ie_buf, t_u16 ie_len, |
| IEEEtypes_ElementId_e id, t_u8 ext_id) |
| { |
| t_u32 bytes_left = ie_len; |
| t_u8 *pcurrent_ptr = ie_buf; |
| t_u16 total_ie_len; |
| t_u8 *ie_ptr = MNULL; |
| IEEEtypes_ElementId_e element_id; |
| t_u8 element_len; |
| t_u8 element_eid; |
| |
| ENTER(); |
| |
| DBG_HEXDUMP(MDAT_D, "ie", ie_buf, ie_len); |
| while (bytes_left >= 2) { |
| element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); |
| element_len = *((t_u8 *)pcurrent_ptr + 1); |
| element_eid = *((t_u8 *)pcurrent_ptr + 2); |
| total_ie_len = element_len + sizeof(IEEEtypes_Header_t); |
| if (bytes_left < total_ie_len) { |
| PRINTM(MERROR, "InterpretIE: Error in processing IE, " |
| "bytes left < IE length\n"); |
| break; |
| } |
| if ((!ext_id && element_id == id) || |
| (id == EXTENSION && element_id == id && |
| ext_id == element_eid)) { |
| PRINTM(MCMND, "Find IE: id=%d ext_id=%d\n", id, ext_id); |
| DBG_HEXDUMP(MCMD_D, "IE", pcurrent_ptr, total_ie_len); |
| ie_ptr = pcurrent_ptr; |
| break; |
| } |
| pcurrent_ptr += element_len + 2; |
| /* Need to account for IE ID and IE Len */ |
| bytes_left -= (element_len + 2); |
| } |
| |
| LEAVE(); |
| |
| return ie_ptr; |
| } |
| |
| /** |
| * @brief Get pm info |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success |
| */ |
| mlan_status wlan_get_pm_info(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_pm_cfg *pm_cfg = MNULL; |
| |
| ENTER(); |
| |
| pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf; |
| pm_cfg->param.ps_info.is_suspend_allowed = MTRUE; |
| wlan_request_cmd_lock(pmadapter); |
| if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, |
| MNULL, MNULL) || |
| pmadapter->curr_cmd || !wlan_bypass_tx_list_empty(pmadapter) || |
| !wlan_wmm_lists_empty(pmadapter) |
| #if defined(SDIO) || defined(PCIE) |
| || wlan_pending_interrupt(pmadapter) |
| #endif |
| ) { |
| pm_cfg->param.ps_info.is_suspend_allowed = MFALSE; |
| #if defined(SDIO) || defined(PCIE) |
| PRINTM(MIOCTL, |
| "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d irq_pending=%d\n", |
| util_peek_list(pmadapter->pmoal_handle, |
| &pmadapter->cmd_pending_q, MNULL, MNULL), |
| pmadapter->curr_cmd, wlan_wmm_lists_empty(pmadapter), |
| wlan_bypass_tx_list_empty(pmadapter), |
| wlan_pending_interrupt(pmadapter)); |
| #else |
| PRINTM(MIOCTL, |
| "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d\n", |
| util_peek_list(pmadapter->pmoal_handle, |
| &pmadapter->cmd_pending_q, MNULL, MNULL), |
| pmadapter->curr_cmd, wlan_wmm_lists_empty(pmadapter), |
| wlan_bypass_tx_list_empty(pmadapter)); |
| #endif |
| } |
| wlan_release_cmd_lock(pmadapter); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get hs wakeup reason |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success |
| */ |
| mlan_status wlan_get_hs_wakeup_reason(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| pmlan_ds_pm_cfg pm_cfg = MNULL; |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| |
| ENTER(); |
| |
| pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf; |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_HS_WAKEUP_REASON, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| &pm_cfg->param.wakeup_reason); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get radio status |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_radio_ioctl_radio_ctl(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_radio_cfg *radio_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| if (pmadapter->radio_on == radio_cfg->param.radio_on_off) { |
| ret = MLAN_STATUS_SUCCESS; |
| goto exit; |
| } else { |
| if (pmpriv->media_connected == MTRUE) { |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } |
| } else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RADIO_CONTROL, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &radio_cfg->param.radio_on_off); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get antenna configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_radio_cfg *radio_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_ds_ant_cfg *ant_cfg = MNULL; |
| mlan_ds_ant_cfg_1x1 *ant_cfg_1x1 = MNULL; |
| |
| ENTER(); |
| |
| radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf; |
| if (IS_STREAM_2X2(pmadapter->feature_control)) |
| ant_cfg = &radio_cfg->param.ant_cfg; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| /* User input validation */ |
| if (IS_STREAM_2X2(pmadapter->feature_control)) { |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| if (IS_CARDAW693(pmadapter->card_type) && |
| ant_cfg->tx_antenna == RF_ANTENNA_AUTO) { |
| PRINTM(MCMND, |
| "user_htstream=0x%x, tx_antenna=0x%x >rx_antenna=0x%x\n", |
| pmadapter->user_htstream, |
| ant_cfg->tx_antenna, |
| ant_cfg->rx_antenna); |
| } else if (IS_CARD9098(pmadapter->card_type) || |
| IS_CARD9097(pmadapter->card_type) || |
| IS_CARDAW693(pmadapter->card_type) || |
| IS_CARDIW624(pmadapter->card_type)) { |
| ant_cfg->tx_antenna &= 0x0303; |
| ant_cfg->rx_antenna &= 0x0303; |
| /** 2G antcfg TX */ |
| if (ant_cfg->tx_antenna & 0x00FF) { |
| pmadapter->user_htstream &= ~0xF0; |
| pmadapter->user_htstream |= |
| (bitcount(ant_cfg->tx_antenna & |
| 0x00FF) |
| << 4); |
| } |
| /* 5G antcfg tx */ |
| if (ant_cfg->tx_antenna & 0xFF00) { |
| pmadapter->user_htstream &= ~0xF000; |
| pmadapter->user_htstream |= |
| (bitcount(ant_cfg->tx_antenna & |
| 0xFF00) |
| << 12); |
| } |
| /* 2G antcfg RX */ |
| if (ant_cfg->rx_antenna & 0x00FF) { |
| pmadapter->user_htstream &= ~0xF; |
| pmadapter->user_htstream |= bitcount( |
| ant_cfg->rx_antenna & 0x00FF); |
| } |
| /* 5G antcfg RX */ |
| if (ant_cfg->rx_antenna & 0xFF00) { |
| pmadapter->user_htstream &= ~0xF00; |
| pmadapter->user_htstream |= |
| (bitcount(ant_cfg->rx_antenna & |
| 0xFF00) |
| << 8); |
| } |
| PRINTM(MCMND, |
| "user_htstream=0x%x, tx_antenna=0x%x >rx_antenna=0x%x\n", |
| pmadapter->user_htstream, |
| ant_cfg->tx_antenna, |
| ant_cfg->rx_antenna); |
| } else { |
| #endif |
| |
| ant_cfg->tx_antenna &= 0x0003; |
| ant_cfg->rx_antenna &= 0x0003; |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| } |
| #endif |
| if (!ant_cfg->tx_antenna || |
| (ant_cfg->tx_antenna != RF_ANTENNA_AUTO && |
| (bitcount(ant_cfg->tx_antenna & 0x00FF) > |
| pmadapter->number_of_antenna || |
| bitcount(ant_cfg->tx_antenna & 0xFF00) > |
| pmadapter->number_of_antenna))) { |
| PRINTM(MERROR, |
| "Invalid TX antenna setting: 0x%x\n", |
| ant_cfg->tx_antenna); |
| pioctl_req->status_code = |
| MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| if (ant_cfg->rx_antenna) { |
| if (bitcount(ant_cfg->rx_antenna & 0x00FF) > |
| pmadapter->number_of_antenna || |
| bitcount(ant_cfg->rx_antenna & 0xFF00) > |
| pmadapter->number_of_antenna) { |
| PRINTM(MERROR, |
| "Invalid RX antenna setting: 0x%x\n", |
| ant_cfg->rx_antenna); |
| pioctl_req->status_code = |
| MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| } else { |
| if (ant_cfg->tx_antenna != RF_ANTENNA_AUTO) |
| ant_cfg->rx_antenna = |
| ant_cfg->tx_antenna; |
| } |
| } else if (!radio_cfg->param.ant_cfg_1x1.antenna || |
| ((radio_cfg->param.ant_cfg_1x1.antenna != |
| RF_ANTENNA_AUTO) && |
| (radio_cfg->param.ant_cfg_1x1.antenna & 0xFFFC))) { |
| PRINTM(MERROR, "Invalid antenna setting\n"); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Cast it to t_u16, antenna mode for command |
| * HostCmd_CMD_802_11_RF_ANTENNA requires 2 bytes */ |
| if (!IS_STREAM_2X2(pmadapter->feature_control)) |
| ant_cfg_1x1 = &radio_cfg->param.ant_cfg_1x1; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA, |
| cmd_action, 0, (t_void *)pioctl_req, |
| (IS_STREAM_2X2(pmadapter->feature_control)) ? |
| (t_void *)ant_cfg : |
| (t_void *)ant_cfg_1x1); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set antenna configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_handle_antcfg(mlan_private *pmpriv, t_u32 init_antcfg) |
| { |
| mlan_ds_ant_cfg ant_cfg; |
| mlan_ds_ant_cfg_1x1 ant_cfg_1x1; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_adapter pmadapter = pmpriv->adapter; |
| ENTER(); |
| |
| memset(pmadapter, &ant_cfg, 0, sizeof(ant_cfg)); |
| memset(pmadapter, &ant_cfg_1x1, 0, sizeof(ant_cfg_1x1)); |
| if (IS_STREAM_2X2(pmadapter->feature_control)) { |
| if (IS_CARD9098(pmadapter->card_type) || |
| IS_CARD9097(pmadapter->card_type) || |
| IS_CARDIW624(pmadapter->card_type) || |
| IS_CARDAW693(pmadapter->card_type)) { |
| ant_cfg.tx_antenna = ant_cfg.rx_antenna = init_antcfg; |
| } else { |
| ant_cfg.tx_antenna = (init_antcfg & 0x0030) >> 4; |
| ant_cfg.rx_antenna = init_antcfg & 0x0003; |
| } |
| } else |
| ant_cfg_1x1.antenna = init_antcfg; |
| |
| /* User input validation */ |
| if (IS_STREAM_2X2(pmadapter->feature_control)) { |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| if (IS_CARD9098(pmadapter->card_type) || |
| IS_CARD9097(pmadapter->card_type) || |
| IS_CARDAW693(pmadapter->card_type) || |
| IS_CARDIW624(pmadapter->card_type)) { |
| ant_cfg.tx_antenna &= 0x0303; |
| ant_cfg.rx_antenna &= 0x0303; |
| /** 2G antcfg TX */ |
| if (ant_cfg.tx_antenna & 0x00FF) { |
| pmadapter->user_htstream &= ~0xF0; |
| pmadapter->user_htstream |= |
| (bitcount(ant_cfg.tx_antenna & 0x00FF) |
| << 4); |
| } |
| /* 5G antcfg tx */ |
| if (ant_cfg.tx_antenna & 0xFF00) { |
| pmadapter->user_htstream &= ~0xF000; |
| pmadapter->user_htstream |= |
| (bitcount(ant_cfg.tx_antenna & 0xFF00) |
| << 12); |
| } |
| /* 2G antcfg RX */ |
| if (ant_cfg.rx_antenna & 0x00FF) { |
| pmadapter->user_htstream &= ~0xF; |
| pmadapter->user_htstream |= |
| bitcount(ant_cfg.rx_antenna & 0x00FF); |
| } |
| /* 5G antcfg RX */ |
| if (ant_cfg.rx_antenna & 0xFF00) { |
| pmadapter->user_htstream &= ~0xF00; |
| pmadapter->user_htstream |= |
| (bitcount(ant_cfg.rx_antenna & 0xFF00) |
| << 8); |
| } |
| PRINTM(MCMND, |
| "user_htstream=0x%x, tx_antenna=0x%x >rx_antenna=0x%x\n", |
| pmadapter->user_htstream, ant_cfg.tx_antenna, |
| ant_cfg.rx_antenna); |
| } else { |
| #endif |
| ant_cfg.tx_antenna &= 0x0003; |
| ant_cfg.rx_antenna &= 0x0003; |
| #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ |
| defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ |
| defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ |
| defined(USBIW624) || defined(SD9097) |
| } |
| #endif |
| if (!ant_cfg.tx_antenna || |
| bitcount(ant_cfg.tx_antenna & 0x00FF) > |
| pmadapter->number_of_antenna || |
| bitcount(ant_cfg.tx_antenna & 0xFF00) > |
| pmadapter->number_of_antenna) { |
| PRINTM(MERROR, "Invalid TX antenna setting: 0x%x\n", |
| ant_cfg.tx_antenna); |
| goto exit; |
| } |
| if (ant_cfg.rx_antenna) { |
| if (bitcount(ant_cfg.rx_antenna & 0x00FF) > |
| pmadapter->number_of_antenna || |
| bitcount(ant_cfg.rx_antenna & 0xFF00) > |
| pmadapter->number_of_antenna) { |
| PRINTM(MERROR, |
| "Invalid RX antenna setting: 0x%x\n", |
| ant_cfg.rx_antenna); |
| goto exit; |
| } |
| } else |
| ant_cfg.rx_antenna = ant_cfg.tx_antenna; |
| } else if (!ant_cfg_1x1.antenna || |
| ((ant_cfg_1x1.antenna != RF_ANTENNA_AUTO) && |
| (ant_cfg_1x1.antenna & 0xFFFC))) { |
| PRINTM(MERROR, "Invalid antenna setting\n"); |
| goto exit; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA, |
| HostCmd_ACT_GEN_SET, 0, MNULL, |
| (IS_STREAM_2X2(pmadapter->feature_control)) ? |
| (t_void *)&ant_cfg : |
| (t_void *)&ant_cfg_1x1); |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get rate bitmap |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| static mlan_status wlan_rate_ioctl_get_rate_bitmap(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| MNULL); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set rate bitmap |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| static mlan_status wlan_rate_ioctl_set_rate_bitmap(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_ds_rate *ds_rate = MNULL; |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| t_u16 *bitmap_rates = MNULL; |
| |
| ENTER(); |
| |
| ds_rate = (mlan_ds_rate *)pioctl_req->pbuf; |
| bitmap_rates = ds_rate->param.rate_cfg.bitmap_rates; |
| |
| PRINTM(MINFO, |
| "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x" |
| "%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, " |
| "IsRateAuto=%d, DataRate=%d\n", |
| bitmap_rates[17], bitmap_rates[16], bitmap_rates[15], |
| bitmap_rates[14], bitmap_rates[13], bitmap_rates[12], |
| bitmap_rates[11], bitmap_rates[10], bitmap_rates[9], |
| bitmap_rates[8], bitmap_rates[7], bitmap_rates[6], |
| bitmap_rates[5], bitmap_rates[4], bitmap_rates[3], |
| bitmap_rates[2], bitmap_rates[1], bitmap_rates[0], |
| pmpriv->is_data_rate_auto, pmpriv->data_rate); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| (t_void *)bitmap_rates); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get rate value |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| static mlan_status wlan_rate_ioctl_get_rate_value(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_ds_rate *rate = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| rate = (mlan_ds_rate *)pioctl_req->pbuf; |
| rate->param.rate_cfg.is_rate_auto = pmpriv->is_data_rate_auto; |
| pioctl_req->data_read_written = |
| sizeof(mlan_rate_cfg_t) + MLAN_SUB_COMMAND_SIZE; |
| |
| /* If not connected, set rate to the lowest in each band */ |
| if (pmpriv->media_connected != MTRUE) { |
| if (pmpriv->config_bands & (BAND_B | BAND_G)) { |
| /* Return the lowest supported rate for BG band */ |
| rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f; |
| } else if (pmpriv->config_bands & (BAND_A | BAND_B)) { |
| /* Return the lowest supported rate for A band */ |
| rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f; |
| } else if (pmpriv->config_bands & BAND_A) { |
| /* Return the lowest supported rate for A band */ |
| rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f; |
| } else if (pmpriv->config_bands & BAND_G) { |
| /* Return the lowest supported rate for G band */ |
| rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f; |
| } else if (pmpriv->config_bands & BAND_B) { |
| /* Return the lowest supported rate for B band */ |
| rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f; |
| } else if (pmpriv->config_bands & BAND_GN) { |
| /* Return the lowest supported rate for N band */ |
| rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f; |
| } else { |
| PRINTM(MMSG, "Invalid Band 0x%x\n", |
| pmpriv->config_bands); |
| } |
| |
| } else { |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY, |
| HostCmd_ACT_GEN_GET, 0, |
| (t_void *)pioctl_req, MNULL); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set rate value |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| static mlan_status wlan_rate_ioctl_set_rate_value(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_ds_rate *ds_rate = MNULL; |
| WLAN_802_11_RATES rates; |
| t_u8 *rate = MNULL; |
| int rate_index = 0; |
| t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; |
| t_u32 i = 0; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| ds_rate = (mlan_ds_rate *)pioctl_req->pbuf; |
| |
| if (ds_rate->param.rate_cfg.is_rate_auto) { |
| memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates)); |
| /* Support all HR/DSSS rates */ |
| bitmap_rates[0] = 0x000F; |
| /* Support all OFDM rates */ |
| bitmap_rates[1] = 0x00FF; |
| /* Rates talbe [0] HR/DSSS,[1] OFDM,[2..9] HT,[10..17] VHT */ |
| /* Support all HT-MCSs rate */ |
| for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3 - 8; i++) |
| bitmap_rates[i + 2] = 0xFFFF; |
| bitmap_rates[9] = 0x3FFF; |
| /* Support all VHT-MCSs rate */ |
| for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 10; i++) |
| bitmap_rates[i + 10] = 0x03FF; /* 10 Bits valid */ |
| } else { |
| memset(pmadapter, rates, 0, sizeof(rates)); |
| wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode, |
| pmpriv->config_bands, rates); |
| rate = rates; |
| for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) { |
| PRINTM(MINFO, "Rate=0x%X Wanted=0x%X\n", rate[i], |
| ds_rate->param.rate_cfg.rate); |
| if ((rate[i] & 0x7f) == |
| (ds_rate->param.rate_cfg.rate & 0x7f)) |
| break; |
| } |
| if ((i < WLAN_SUPPORTED_RATES && !rate[i]) || |
| (i == WLAN_SUPPORTED_RATES)) { |
| PRINTM(MERROR, |
| "The fixed data rate 0x%X is out " |
| "of range\n", |
| ds_rate->param.rate_cfg.rate); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates)); |
| rate_index = wlan_data_rate_to_index( |
| pmadapter, ds_rate->param.rate_cfg.rate); |
| /* Only allow b/g rates to be set */ |
| if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 && |
| rate_index <= MLAN_RATE_INDEX_HRDSSS3) |
| bitmap_rates[0] = 1 << rate_index; |
| else { |
| rate_index -= 1; /* There is a 0x00 in the table */ |
| if (rate_index >= MLAN_RATE_INDEX_OFDM0 && |
| rate_index <= MLAN_RATE_INDEX_OFDM7) |
| bitmap_rates[1] = 1 << (rate_index - |
| MLAN_RATE_INDEX_OFDM0); |
| } |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| bitmap_rates); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get rate index |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| static mlan_status wlan_rate_ioctl_get_rate_index(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| MNULL); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set rate index |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| static mlan_status wlan_rate_ioctl_set_rate_index(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| t_u32 rate_index; |
| t_u32 rate_format; |
| t_u32 nss; |
| t_u32 i; |
| mlan_ds_rate *ds_rate = MNULL; |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; |
| int tx_mcs_supp = GET_TXMCSSUPP(pmpriv->usr_dev_mcs_support); |
| |
| ENTER(); |
| |
| ds_rate = (mlan_ds_rate *)pioctl_req->pbuf; |
| rate_format = ds_rate->param.rate_cfg.rate_format; |
| nss = ds_rate->param.rate_cfg.nss; |
| rate_index = ds_rate->param.rate_cfg.rate; |
| |
| if (ds_rate->param.rate_cfg.is_rate_auto) { |
| memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates)); |
| /* Rates talbe [0]: HR/DSSS;[1]: OFDM; [2..9] HT; */ |
| /* Support all HR/DSSS rates */ |
| bitmap_rates[0] = 0x000F; |
| /* Support all OFDM rates */ |
| bitmap_rates[1] = 0x00FF; |
| /* Support all HT-MCSs rate */ |
| for (i = 2; i < 9; i++) |
| bitmap_rates[i] = 0xFFFF; |
| bitmap_rates[9] = 0x3FFF; |
| /* [10..17] VHT */ |
| /* Support all VHT-MCSs rate for NSS 1 and 2 */ |
| for (i = 10; i < 12; i++) |
| bitmap_rates[i] = 0x03FF; /* 10 Bits valid */ |
| /* Set to 0 as default value for all other NSSs */ |
| for (i = 12; i < 17; i++) |
| bitmap_rates[i] = 0x0; |
| /* [18..25] HE */ |
| /* Support all HE-MCSs rate for NSS1 and 2 */ |
| for (i = 18; i < 20; i++) |
| bitmap_rates[i] = 0x0FFF; |
| for (i = 20; i < NELEMENTS(bitmap_rates); i++) |
| bitmap_rates[i] = 0x0; |
| } else { |
| PRINTM(MINFO, "Rate index is %d\n", rate_index); |
| if ((rate_format == MLAN_RATE_FORMAT_HT) && |
| (rate_index > MLAN_RATE_INDEX_MCS7 && |
| rate_index <= MLAN_RATE_INDEX_MCS15) && |
| (tx_mcs_supp < 2)) { |
| PRINTM(MERROR, |
| "HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n", |
| rate_index, pmpriv->usr_dev_mcs_support); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates)); |
| if (rate_format == MLAN_RATE_FORMAT_LG) { |
| /* Bitmap of HR/DSSS rates */ |
| if (rate_index <= MLAN_RATE_INDEX_HRDSSS3) { |
| bitmap_rates[0] = 1 << rate_index; |
| ret = MLAN_STATUS_SUCCESS; |
| /* Bitmap of OFDM rates */ |
| } else if ((rate_index >= MLAN_RATE_INDEX_OFDM0) && |
| (rate_index <= MLAN_RATE_INDEX_OFDM7)) { |
| bitmap_rates[1] = 1 << (rate_index - |
| MLAN_RATE_INDEX_OFDM0); |
| ret = MLAN_STATUS_SUCCESS; |
| } |
| } else if (rate_format == MLAN_RATE_FORMAT_HT) { |
| if (rate_index <= MLAN_RATE_INDEX_MCS32) { |
| bitmap_rates[2 + (rate_index / 16)] = |
| 1 << (rate_index % 16); |
| ret = MLAN_STATUS_SUCCESS; |
| } |
| } |
| if (rate_format == MLAN_RATE_FORMAT_VHT) { |
| if ((rate_index <= MLAN_RATE_INDEX_MCS9) && |
| (MLAN_RATE_NSS1 <= nss) && |
| (nss <= MLAN_RATE_NSS2)) { |
| bitmap_rates[10 + nss - MLAN_RATE_NSS1] = |
| (1 << rate_index); |
| ret = MLAN_STATUS_SUCCESS; |
| } |
| } |
| if (rate_format == MLAN_RATE_FORMAT_HE) { |
| if (IS_FW_SUPPORT_11AX(pmadapter)) { |
| if ((rate_index <= MLAN_RATE_INDEX_MCS11) && |
| (MLAN_RATE_NSS1 <= nss) && |
| (nss <= MLAN_RATE_NSS2)) { |
| bitmap_rates[18 + nss - MLAN_RATE_NSS1] = |
| (1 << rate_index); |
| ret = MLAN_STATUS_SUCCESS; |
| } |
| } else { |
| PRINTM(MERROR, |
| "Error! Fw doesn't support 11AX\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| } |
| |
| if (ret == MLAN_STATUS_FAILURE) { |
| PRINTM(MERROR, "Invalid MCS index=%d. \n", rate_index); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| } |
| |
| PRINTM(MINFO, |
| "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x" |
| "%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, " |
| "IsRateAuto=%d, DataRate=%d\n", |
| bitmap_rates[17], bitmap_rates[16], bitmap_rates[15], |
| bitmap_rates[14], bitmap_rates[13], bitmap_rates[12], |
| bitmap_rates[11], bitmap_rates[10], bitmap_rates[9], |
| bitmap_rates[8], bitmap_rates[7], bitmap_rates[6], |
| bitmap_rates[5], bitmap_rates[4], bitmap_rates[3], |
| bitmap_rates[2], bitmap_rates[1], bitmap_rates[0], |
| pmpriv->is_data_rate_auto, pmpriv->data_rate); |
| |
| /* Send request to firmware */ |
| if (ds_rate->auto_null_fixrate_enable == 1) { |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_SPC_AUTO_SET, 0, |
| (t_void *)pioctl_req, |
| (t_void *)bitmap_rates); |
| ds_rate->auto_null_fixrate_enable = 0xff; |
| } else if (ds_rate->auto_null_fixrate_enable == 0) { |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_SPC_AUTO_NOSET, 0, |
| (t_void *)pioctl_req, |
| (t_void *)bitmap_rates); |
| ds_rate->auto_null_fixrate_enable = 0xff; |
| } else |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG, |
| HostCmd_ACT_GEN_SET, 0, |
| (t_void *)pioctl_req, |
| (t_void *)bitmap_rates); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Rate configuration command handler |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, |
| * otherwise fail |
| */ |
| mlan_status wlan_rate_ioctl_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_ds_rate *rate = MNULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| rate = (mlan_ds_rate *)pioctl_req->pbuf; |
| if (rate->param.rate_cfg.rate_type == MLAN_RATE_BITMAP) { |
| if (pioctl_req->action == MLAN_ACT_GET) |
| status = wlan_rate_ioctl_get_rate_bitmap(pmadapter, |
| pioctl_req); |
| else |
| status = wlan_rate_ioctl_set_rate_bitmap(pmadapter, |
| pioctl_req); |
| } else if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) { |
| if (pioctl_req->action == MLAN_ACT_GET) |
| status = wlan_rate_ioctl_get_rate_value(pmadapter, |
| pioctl_req); |
| else |
| status = wlan_rate_ioctl_set_rate_value(pmadapter, |
| pioctl_req); |
| } else { |
| if (pioctl_req->action == MLAN_ACT_GET) |
| status = wlan_rate_ioctl_get_rate_index(pmadapter, |
| pioctl_req); |
| else |
| status = wlan_rate_ioctl_set_rate_index(pmadapter, |
| pioctl_req); |
| } |
| |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @brief Get data rates |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_rate_ioctl_get_data_rate(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (pioctl_req->action != MLAN_ACT_GET) { |
| ret = MLAN_STATUS_FAILURE; |
| goto exit; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY, |
| HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req, |
| MNULL); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| exit: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get remain on channel setting |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_radio_ioctl_remain_chan_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_radio_cfg *radio_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| if (pmpriv->adapter->remain_on_channel && |
| !radio_cfg->param.remain_chan.remove) { |
| PRINTM(MCMND, "Ignore New Remain on channe: chan=%d\n", |
| radio_cfg->param.remain_chan.channel); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_REMAIN_ON_CHANNEL, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &radio_cfg->param.remain_chan); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef WIFI_DIRECT_SUPPORT |
| /** |
| * @brief Set/Get wifi_direct_mode |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_bss_ioctl_wifi_direct_mode(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_bss *bss = MNULL; |
| |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| bss = (mlan_ds_bss *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WIFI_DIRECT_MODE_CONFIG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &bss->param.wfd_mode); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get p2p config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_p2p_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_P2P_PARAMS_CONFIG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc_cfg->param.p2p_config); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set/Get GPIO TSF Latch config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_gpio_tsf_latch_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GPIO_TSF_LATCH_PARAM_CONFIG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc_cfg->param.gpio_tsf_latch_config); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get TSF info |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_get_tsf_info(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GPIO_TSF_LATCH_PARAM_CONFIG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc_cfg->param.tsf_info); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get CROSS CHIP SYNCH config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_cross_chip_synch(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CROSS_CHIP_SYNCH, cmd_action, |
| 0, (t_void *)pioctl_req, |
| &misc_cfg->param.gpio_tsf_latch_config); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get TSP config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tsp_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TSP_CFG, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &misc_cfg->param.gpio_tsf_latch_config); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set coalesce config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_coalesce_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_COALESCE_CFG, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &misc_cfg->param.coalesce_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set USB packet aggregation parameters |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_aggr_ctrl(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_PACKET_AGGR_CTRL, cmd_action, |
| 0, (t_void *)pioctl_req, |
| &misc->param.aggr_params); |
| |
| if (ret == MLAN_STATUS_SUCCESS) { |
| ret = MLAN_STATUS_PENDING; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef USB |
| /** |
| * @brief Get/Set USB packet aggregation parameters |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_usb_aggr_ctrl(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| if (pmadapter->pcard_usb->fw_usb_aggr == MFALSE) { |
| PRINTM(MERROR, "USB aggregation not supported by FW\n"); |
| pioctl_req->status_code = MLAN_ERROR_CMD_INVALID; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, |
| HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc->param.usb_aggr_params); |
| |
| if (ret == MLAN_STATUS_SUCCESS) { |
| ret = MLAN_STATUS_PENDING; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Get/Set Tx control configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_txcontrol(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| pmpriv->pkt_tx_ctrl = misc->param.tx_control; |
| else |
| misc->param.tx_control = pmpriv->pkt_tx_ctrl; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set channel time and buffer weight configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_multi_chan_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MULTI_CHAN_CONFIG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc->param.multi_chan_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set multi-channel policy setting |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_multi_chan_policy(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| if (pmadapter->dfs_repeater) { |
| PRINTM(MMSG, |
| "DFS-Repeater is on, can not enable DRCS\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto fail; |
| } |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } else { |
| cmd_action = HostCmd_ACT_GEN_GET; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MULTI_CHAN_POLICY, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc->param.multi_chan_policy); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| fail: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set DRCS configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_drcs_config(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DRCS_CONFIG, cmd_action, 0, |
| (t_void *)pioctl_req, &misc->param.drcs_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Is any uAP started or STA connected? |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * |
| * @return MTRUE/MFALSE |
| */ |
| t_bool wlan_check_interface_active(mlan_adapter *pmadapter) |
| { |
| t_bool ret = MFALSE; |
| pmlan_private pmpriv; |
| int i; |
| |
| if (pmadapter == MNULL) |
| return MFALSE; |
| |
| for (i = 0; i < pmadapter->priv_num; i++) { |
| pmpriv = pmadapter->priv[i]; |
| if (pmpriv) { |
| #ifdef UAP_SUPPORT |
| if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) |
| ret = pmpriv->uap_bss_started; |
| else |
| #endif |
| if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) |
| ret = pmpriv->media_connected; |
| } |
| if (ret) |
| return MTRUE; |
| } |
| |
| return MFALSE; |
| } |
| |
| /** |
| * @brief Get/Set DFS REPEATER mode |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_dfs_repeater_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| /* Make sure no interface is active |
| * before setting the dfs repeater mode |
| */ |
| if (wlan_check_interface_active(pmadapter)) { |
| PRINTM(MMSG, "DFS-Repeater active priv found," |
| " skip enabling the mode.\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| /* If DRCS is on then we should not set |
| * DFS-repeater mode */ |
| if (pmadapter->mc_policy) { |
| PRINTM(MERROR, |
| "DFS-repeater cannot be started when DRCS is on\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } else { |
| cmd_action = HostCmd_ACT_GEN_GET; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DFS_REPEATER_MODE, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc->param.dfs_repeater); |
| |
| done: |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Low Power Mode |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_low_pwr_mode(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CONFIG_LOW_POWER_MODE, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| &misc->param.low_pwr_mode); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configure PMIC in Firmware |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_pmic_configure(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_PMIC_CONFIGURE, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief push value to stack |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param len Length of value |
| * @param val A pointer to value |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| inline mlan_status push_n(pmlan_adapter pmadapter, mef_stack *s, t_u8 len, |
| t_u8 *val) |
| { |
| if ((s->sp + len) <= MAX_NUM_STACK_BYTES) { |
| memcpy_ext(pmadapter, s->byte + s->sp, val, len, |
| MAX_NUM_STACK_BYTES - s->sp); |
| s->sp += len; |
| return MLAN_STATUS_SUCCESS; |
| } else { |
| PRINTM(MERROR, "Stack is full\n"); |
| return MLAN_STATUS_FAILURE; |
| } |
| } |
| |
| /** |
| * @brief push value to stack accoring to operand type |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param op A pointer to mef_op |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| inline mlan_status mef_push(pmlan_adapter pmadapter, mef_stack *s, mef_op *op) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u8 nbytes; |
| switch (op->operand_type) { |
| case OPERAND_DNUM: |
| ret = push_n(pmadapter, s, 4, op->val); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = push_n(pmadapter, s, 1, &op->operand_type); |
| else |
| ret = MLAN_STATUS_FAILURE; |
| break; |
| case OPERAND_BYTE_SEQ: |
| nbytes = op->val[0]; |
| if (MLAN_STATUS_SUCCESS == |
| push_n(pmadapter, s, nbytes, op->val + 1) && |
| MLAN_STATUS_SUCCESS == push_n(pmadapter, s, 1, op->val) && |
| MLAN_STATUS_SUCCESS == |
| push_n(pmadapter, s, 1, &op->operand_type)) |
| ret = MLAN_STATUS_SUCCESS; |
| else |
| ret = MLAN_STATUS_FAILURE; |
| break; |
| default: |
| ret = push_n(pmadapter, s, 1, &op->operand_type); |
| break; |
| } |
| return ret; |
| } |
| |
| /** |
| * @brief push dnum filter to stack |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param filter A pointer to filter item |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| static mlan_status push_filter_dnum_eq(pmlan_adapter pmadapter, mef_stack *s, |
| mef_filter_t *filter) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u32 dnum; |
| mef_op op; |
| |
| ENTER(); |
| |
| if (!filter) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| if (filter->fill_flag != (FILLING_TYPE | FILLING_PATTERN | |
| FILLING_OFFSET | FILLING_NUM_BYTES)) { |
| PRINTM(MERROR, "Filter item fill error\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| /* Format of decimal num: |
| * | 5 bytes | 5 bytes | 5 bytes | 1 byte | | |
| * pattern | offset | num of bytes | type (TYPE_DNUM_EQ) | |
| */ |
| |
| /* push pattern */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_DNUM; |
| dnum = filter->pattern; |
| memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val)); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push offset */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_DNUM; |
| dnum = filter->offset; |
| memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val)); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push num of bytes */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_DNUM; |
| dnum = filter->num_bytes; |
| memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val)); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push type */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = TYPE_DNUM_EQ; |
| ret = mef_push(pmadapter, s, &op); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief push byte_eq filter to stack |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param filter A pointer to filter item |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| static mlan_status push_filter_byte_eq(pmlan_adapter pmadapter, mef_stack *s, |
| mef_filter_t *filter) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u32 dnum; |
| mef_op op; |
| |
| ENTER(); |
| |
| if (!filter) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| if (filter->fill_flag != (FILLING_TYPE | FILLING_REPEAT | |
| FILLING_BYTE_SEQ | FILLING_OFFSET)) { |
| PRINTM(MERROR, "Filter item fill error\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| /* Format of decimal num: |
| * | 5 bytes | val | 5 bytes | 1 byte | | |
| * repeat | bytes seq | offset | type (TYPE_BYTE_EQ) | |
| */ |
| |
| /* push repeat */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_DNUM; |
| dnum = filter->repeat; |
| memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val)); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push bytes seq */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_BYTE_SEQ; |
| op.val[0] = filter->num_byte_seq; |
| memcpy_ext(pmadapter, &op.val[1], filter->byte_seq, |
| filter->num_byte_seq, MAX_NUM_BYTE_SEQ); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push offset */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_DNUM; |
| dnum = filter->offset; |
| memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val)); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push type */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = TYPE_BYTE_EQ; |
| ret = mef_push(pmadapter, s, &op); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief push bite_eq filter to stack |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param filter A pointer to filter item |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| static mlan_status push_filter_bit_eq(pmlan_adapter pmadapter, mef_stack *s, |
| mef_filter_t *filter) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u32 dnum; |
| mef_op op; |
| |
| ENTER(); |
| |
| if (!filter) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| if (filter->fill_flag != (FILLING_TYPE | FILLING_REPEAT | |
| FILLING_BYTE_SEQ | FILLING_OFFSET)) { |
| PRINTM(MERROR, "Filter item fill error\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| /* Format of decimal num: |
| * | val | 5 bytes | val | 1 byte | | |
| * bytes seq | offset | mask seq | type (TYPE_BIT_EQ) | |
| */ |
| |
| /* push bytes seq */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_BYTE_SEQ; |
| op.val[0] = filter->num_byte_seq; |
| memcpy_ext(pmadapter, &op.val[1], filter->byte_seq, |
| filter->num_byte_seq, MAX_NUM_BYTE_SEQ); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push offset */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_DNUM; |
| dnum = filter->offset; |
| memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val)); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push mask seq */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = OPERAND_BYTE_SEQ; |
| op.val[0] = filter->num_mask_seq; |
| memcpy_ext(pmadapter, &op.val[1], filter->mask_seq, |
| filter->num_mask_seq, MAX_NUM_BYTE_SEQ); |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* push type */ |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = TYPE_BIT_EQ; |
| ret = mef_push(pmadapter, s, &op); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief push filter to stack |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param filter A pointer to filter item |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| static mlan_status wlan_push_filter(pmlan_adapter pmadapter, mef_stack *s, |
| mef_filter_t *filter) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| switch (filter->type) { |
| case TYPE_DNUM_EQ: |
| ret = push_filter_dnum_eq(pmadapter, s, filter); |
| break; |
| case TYPE_BYTE_EQ: |
| ret = push_filter_byte_eq(pmadapter, s, filter); |
| break; |
| case TYPE_BIT_EQ: |
| ret = push_filter_bit_eq(pmadapter, s, filter); |
| break; |
| default: |
| PRINTM(MERROR, "Invalid filter type\n"); |
| ret = MLAN_STATUS_FAILURE; |
| break; |
| } |
| return ret; |
| } |
| |
| /** |
| * @brief generate mef data |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param s A pointer to mef_stack |
| * @param entry A pointer to mef_entry_t |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| static mlan_status wlan_generate_mef_filter_stack(pmlan_adapter pmadapter, |
| mef_stack *s, |
| mef_entry_t *entry) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mef_op op; |
| int i; |
| |
| ENTER(); |
| |
| for (i = 0; i < entry->filter_num; i++) { |
| ret = wlan_push_filter(pmadapter, s, &entry->filter_item[i]); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "push filter to stack error\n"); |
| goto done; |
| } |
| if (i != 0) { |
| memset(pmadapter, &op, 0, sizeof(op)); |
| op.operand_type = entry->rpn[i]; |
| ret = mef_push(pmadapter, s, &op); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "push filter rpn error\n"); |
| goto done; |
| } |
| } |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set the mef entries to firmware |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pmef A pointer to mef_cfg structure |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| mlan_status wlan_set_mef_entry(mlan_private *pmpriv, pmlan_adapter pmadapter, |
| mef_cfg_data *pmef) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cmd *hostcmd; |
| HostCmd_DS_GEN *hostcmd_hdr; |
| HostCmd_DS_MEF_CFG *mef_hdr; |
| mef_entry_header *entry_hdr; |
| mef_stack *stack; |
| mef_entry_t *pentry; |
| t_u8 *buf; |
| t_u32 i, buf_len; |
| pmlan_callbacks pcb; |
| |
| ENTER(); |
| |
| if (pmef->entry_num > MAX_NUM_ENTRIES) { |
| PRINTM(MERROR, "Too many entries\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| pcb = &pmadapter->callbacks; |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, |
| sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF, |
| (t_u8 **)&hostcmd); |
| if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) { |
| PRINTM(MERROR, "Failed to allocate cmd data buffer\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto err_handle; |
| } |
| |
| /** Fill the cmd header data*/ |
| buf = hostcmd->cmd; |
| hostcmd_hdr = (HostCmd_DS_GEN *)buf; |
| hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG); |
| buf_len = S_DS_GEN; |
| |
| /** Fill HostCmd_DS_MEF_CFG*/ |
| mef_hdr = (HostCmd_DS_MEF_CFG *)(buf + buf_len); |
| mef_hdr->criteria = wlan_cpu_to_le32(pmef->criteria); |
| mef_hdr->nentries = wlan_cpu_to_le16(pmef->entry_num); |
| buf_len += sizeof(HostCmd_DS_MEF_CFG); |
| |
| /** generate mef entry data*/ |
| for (i = 0, pentry = pmef->pentry; i < pmef->entry_num; i++, pentry++) { |
| /** Fill entry header data*/ |
| entry_hdr = (mef_entry_header *)(buf + buf_len); |
| entry_hdr->mode = pentry->mode; |
| entry_hdr->action = pentry->action; |
| buf_len += sizeof(mef_entry_header); |
| |
| /** Fill Stack data*/ |
| stack = (mef_stack *)(buf + buf_len); |
| ret = wlan_generate_mef_filter_stack(pmadapter, stack, pentry); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "Generate mef data error\n"); |
| goto err_handle; |
| } |
| buf_len += (stack->sp + sizeof(stack->sp)); |
| } |
| hostcmd_hdr->size = wlan_cpu_to_le16(buf_len); |
| hostcmd->len = wlan_cpu_to_le32(buf_len); |
| |
| DBG_HEXDUMP(MCMD_D, "MEF DATA", (t_u8 *)hostcmd, buf_len + 4); |
| |
| /** Send command to firmware*/ |
| ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)MNULL, |
| (t_void *)hostcmd); |
| |
| err_handle: |
| if (hostcmd) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd); |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief generate Host_CMD_MEF_CFG cmd data to firmware |
| * |
| * @param pmpriv A pointer to mlan_private structure |
| * @param pmadapter A pointer to mlan_adapter structure |
| * |
| * @return MLAN_STATUS_SUCCESS or FAIL |
| */ |
| mlan_status wlan_process_mef_cfg_cmd(mlan_private *pmpriv, |
| pmlan_adapter pmadapter) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_callbacks pcb; |
| mef_cfg_data mef; |
| mef_entry_t *pentry = MNULL; |
| mef_entry *pmef; |
| t_u16 entry_num = 0; |
| |
| ENTER(); |
| |
| pcb = &pmadapter->callbacks; |
| memset(pmadapter, &mef, 0, sizeof(mef_cfg_data)); |
| |
| /** check how many entries in adapter*/ |
| pmef = &pmadapter->entry_cfg; |
| entry_num += pmef->enable_autoarp_entry; |
| entry_num += pmef->num_wowlan_entry; |
| entry_num += pmef->num_ipv6_ns_offload; |
| if (!entry_num && !pmef->clear_mef_entry) { |
| PRINTM(MIOCTL, "No filter entries\n"); |
| goto done; |
| } |
| if (entry_num) { |
| ret = pcb->moal_malloc(pmadapter->pmoal_handle, |
| sizeof(mef_entry_t) * entry_num, |
| MLAN_MEM_DEF, (t_u8 **)&mef.pentry); |
| if (ret != MLAN_STATUS_SUCCESS || mef.pentry == MNULL) { |
| PRINTM(MERROR, "Failed to allocate cmd data buffer\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto err_handle; |
| } |
| } |
| |
| /** Fill mef_cfg structure*/ |
| mef.criteria = pmef->criteria; |
| mef.entry_num = entry_num; |
| pentry = mef.pentry; |
| /** Fill mef_entry_t structure*/ |
| /** Copy Auto arp response entry*/ |
| if (pmef->enable_autoarp_entry) { |
| memcpy_ext(pmadapter, pentry, &pmef->entry[5], |
| sizeof(mef_entry_t), sizeof(mef_entry_t)); |
| pentry += pmef->enable_autoarp_entry; |
| } |
| /** Copy wowlan entry*/ |
| if (pmef->num_wowlan_entry) { |
| memcpy_ext(pmadapter, pentry, &pmef->entry[6], |
| sizeof(mef_entry_t), sizeof(mef_entry_t)); |
| pentry += pmef->num_wowlan_entry; |
| } |
| /** Copy IPv6 NS message offload entry */ |
| if (pmef->num_ipv6_ns_offload) |
| memcpy_ext(pmadapter, pentry, &pmef->entry[7], |
| sizeof(mef_entry_t), sizeof(mef_entry_t)); |
| |
| /** Set Entries to firmware*/ |
| ret = wlan_set_mef_entry(pmpriv, pmadapter, &mef); |
| if (ret != MLAN_STATUS_SUCCESS) |
| PRINTM(MERROR, "Set MEF entries error\n"); |
| |
| err_handle: |
| if (mef.pentry) |
| pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)mef.pentry); |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /* @brief Get/Set NV-FLT-CONFIG parameters |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status wlan_misc_ioctl_mef_flt_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| mlan_ds_misc_mef_flt_cfg *mef_cfg = MNULL; |
| mef_entry *pmef = MNULL; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mef_cfg = &misc_cfg->param.mef_flt_cfg; |
| pmef = &pmadapter->entry_cfg; |
| switch (pioctl_req->action) { |
| case MLAN_ACT_SET: |
| if (mef_cfg->mef_act_type == MEF_ACT_WOWLAN) { |
| pmef->num_wowlan_entry = 1; |
| pmef->criteria |= mef_cfg->criteria; |
| memcpy_ext(pmadapter, &pmef->entry[6], |
| &mef_cfg->mef_entry, sizeof(mef_entry_t), |
| sizeof(mef_entry_t)); |
| } |
| if (mef_cfg->mef_act_type == MEF_ACT_IPV6_NS) { |
| pmef->num_ipv6_ns_offload = 1; |
| pmef->criteria |= mef_cfg->criteria; |
| memcpy_ext(pmadapter, &pmef->entry[7], |
| &mef_cfg->mef_entry, sizeof(mef_entry_t), |
| sizeof(mef_entry_t)); |
| } |
| /** Set AUTO ARP Entry to adapter*/ |
| if (mef_cfg->mef_act_type == MEF_ACT_AUTOARP) { |
| if (mef_cfg->op_code & MLAN_IPADDR_OP_AUTO_ARP_RESP) { |
| pmef->enable_autoarp_entry = 1; |
| pmef->criteria |= mef_cfg->criteria; |
| memcpy_ext(pmadapter, &pmef->entry[5], |
| &mef_cfg->mef_entry, |
| sizeof(mef_entry_t), |
| sizeof(mef_entry_t)); |
| if (MLAN_STATUS_SUCCESS != |
| wlan_process_mef_cfg_cmd( |
| pmadapter |
| ->priv[pioctl_req->bss_index], |
| pmadapter)) |
| PRINTM(MERROR, |
| "Set MEF Entries Error\n"); |
| } else if (mef_cfg->op_code == |
| MLAN_IPADDR_OP_IP_REMOVE) { |
| pmef->enable_autoarp_entry = 0; |
| pmef->num_wowlan_entry = 0; |
| pmef->num_ipv6_ns_offload = 0; |
| pmef->clear_mef_entry = 1; |
| memset(pmadapter, &pmef->entry[5], 0, |
| sizeof(mef_entry_t)); |
| memset(pmadapter, &pmef->entry[6], 0, |
| sizeof(mef_entry_t)); |
| memset(pmadapter, &pmef->entry[7], 0, |
| sizeof(mef_entry_t)); |
| if (MLAN_STATUS_SUCCESS != |
| wlan_process_mef_cfg_cmd( |
| pmadapter |
| ->priv[pioctl_req->bss_index], |
| pmadapter)) |
| PRINTM(MERROR, |
| "Clear MEF Entries Error\n"); |
| } |
| } |
| break; |
| case MLAN_ACT_GET: |
| if (mef_cfg->mef_act_type == MEF_ACT_WOWLAN) |
| memcpy_ext(pmadapter, &mef_cfg->mef_entry, |
| &pmef->entry[6], sizeof(mef_entry_t), |
| sizeof(mef_entry_t)); |
| break; |
| default: |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID; |
| ret = MLAN_STATUS_FAILURE; |
| break; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get WPA passphrase for esupplicant |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_sec_ioctl_passphrase(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_sec_cfg *sec = MNULL; |
| t_u16 cmd_action = 0; |
| #ifdef STA_SUPPORT |
| BSSDescriptor_t *pbss_desc; |
| int i = 0; |
| #endif |
| ENTER(); |
| |
| sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf; |
| |
| if (!IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) { |
| LEAVE(); |
| return ret; |
| } |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR) |
| cmd_action = HostCmd_ACT_GEN_REMOVE; |
| else |
| cmd_action = HostCmd_ACT_GEN_SET; |
| } else if (pioctl_req->action == MLAN_ACT_CLEAR) { |
| cmd_action = HostCmd_ACT_GEN_REMOVE; |
| } else { |
| if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) { |
| #ifdef STA_SUPPORT |
| if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA && |
| sec->param.passphrase.ssid.ssid_len == 0) { |
| i = wlan_find_bssid_in_list( |
| pmpriv, |
| (t_u8 *)&sec->param.passphrase.bssid, |
| MLAN_BSS_MODE_AUTO); |
| if (i >= 0) { |
| pbss_desc = &pmadapter->pscan_table[i]; |
| memcpy_ext(pmadapter, |
| &sec->param.passphrase.ssid, |
| &pbss_desc->ssid, |
| sizeof(mlan_802_11_ssid), |
| sizeof(mlan_802_11_ssid)); |
| memset(pmadapter, |
| &sec->param.passphrase.bssid, 0, |
| MLAN_MAC_ADDR_LENGTH); |
| PRINTM(MINFO, |
| "PSK_QUERY: found ssid=%s\n", |
| sec->param.passphrase.ssid.ssid); |
| } |
| } else |
| #endif |
| memset(pmadapter, &sec->param.passphrase.bssid, |
| 0, MLAN_MAC_ADDR_LENGTH); |
| } |
| cmd_action = HostCmd_ACT_GEN_GET; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PMK, cmd_action, |
| 0, (t_void *)pioctl_req, (t_void *)sec); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set per packet Txctl and Rxinfo configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_per_pkt_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| pmpriv->rx_pkt_info = MFALSE; |
| if (misc->param.txrx_pkt_ctrl & RX_PKT_INFO) |
| pmpriv->rx_pkt_info = MTRUE; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get region code |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_region(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| int i; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| misc->param.region_code = pmadapter->region_code; |
| } else { |
| if (pmadapter->otp_region && pmadapter->otp_region->force_reg) { |
| PRINTM(MERROR, |
| "ForceRegionRule is set in the on-chip OTP" |
| " memory\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { |
| /* Use the region code to search for the index */ |
| if (misc->param.region_code == region_code_index[i]) { |
| pmadapter->region_code = |
| (t_u16)misc->param.region_code; |
| break; |
| } |
| } |
| /* It's unidentified region code */ |
| if (i >= MRVDRV_MAX_REGION_CODE) { |
| PRINTM(MERROR, "Region Code not identified\n"); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| pmadapter->cfp_code_bg = misc->param.region_code; |
| pmadapter->cfp_code_a = misc->param.region_code; |
| if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code, |
| pmadapter->config_bands)) { |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| ret = MLAN_STATUS_FAILURE; |
| } |
| } |
| pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configure GPIO independent reset |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_ind_rst_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else |
| cmd_action = HostCmd_ACT_GEN_SET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_INDEPENDENT_RESET_CFG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| (t_void *)&misc->param.ind_rst_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get timestamp from firmware |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_get_tsf(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "No support set tsf!"); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_TSF, cmd_action, 0, |
| (t_void *)pioctl_req, MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Create custom regulatory cfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_region_power_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| ENTER(); |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_REGION_POWER_CFG, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Create custom regulatory cfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_chan_reg_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc_cfg = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| cmd_action = HostCmd_ACT_GEN_GET; |
| if (misc_cfg && |
| misc_cfg->param.custom_reg_domain.region.country_code[0] != |
| '\0' && |
| misc_cfg->param.custom_reg_domain.region.country_code[1] != |
| '\0') { |
| /* Copy the driver country code in the |
| * custom_reg_domain. The cmd response handler will use |
| * it to compare with the FW country code |
| */ |
| pmadapter->country_code[0] = |
| misc_cfg->param.custom_reg_domain.region |
| .country_code[0]; |
| pmadapter->country_code[1] = |
| misc_cfg->param.custom_reg_domain.region |
| .country_code[1]; |
| pmadapter->country_code[2] = '\0'; |
| } |
| /* Send 2G/5G/6G CFP table request to the firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| MNULL); |
| } else { |
| cmd_action = HostCmd_ACT_GEN_SET; |
| /* Send 2G/5G/6G CFP table to the firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc_cfg->param.chan_attr_cfg); |
| } |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Check operating class validation |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_operclass_validation(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u8 channel, oper_class; |
| t_u8 bandwidth; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| channel = misc->param.bw_chan_oper.channel; |
| oper_class = misc->param.bw_chan_oper.oper_class; |
| bandwidth = misc->param.bw_chan_oper.bandwidth; |
| |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| ret = wlan_check_operclass_validation(pmpriv, channel, |
| oper_class, bandwidth); |
| } else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get Region channel power setting |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_get_rgchnpwr_cfg(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, cmd_action, |
| 0, (t_void *)pioctl_req, MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set mc_aggr_cfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_mc_aggr_cfg(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| cmd_action = pioctl_req->action; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MC_AGGR_CFG, cmd_action, 0, |
| (t_void *)pioctl_req, |
| (t_void *)&misc->param.mc_aggr_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| /** |
| * @brief get channel load results |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_ch_load_results(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_private *pmpriv = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| if (pioctl_req == MNULL) |
| return MLAN_STATUS_FAILURE; |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| cmd_action = pioctl_req->action; |
| |
| /* Send request to firmware */ |
| if (pmpriv->ch_load_param == 255) { |
| return MLAN_STATUS_FAILURE; |
| } else { |
| misc->param.ch_load.ch_load_param = pmpriv->ch_load_param; |
| misc->param.ch_load.noise = pmpriv->noise; |
| misc->param.ch_load.rx_quality = pmpriv->rx_quality; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief get channel load |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_ch_load(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_private *pmpriv = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| if (pioctl_req == MNULL) |
| return MLAN_STATUS_FAILURE; |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| cmd_action = (t_u16)pioctl_req->action; |
| |
| /* Send request to firmware */ |
| pmpriv->ch_load_param = 255; /* Default value for identifying |
| update/non-updated value*/ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_CH_LOAD, cmd_action, 0, |
| (t_void *)pioctl_req, |
| (t_void *)&misc->param.ch_load); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get CHAN_TPRC setting |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_get_chan_trpc_cfg(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| mlan_ds_misc_cfg *misc = MNULL; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHANNEL_TRPC_CONFIG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| (t_void *)&misc->param.trpc_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get non-global operating class |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_oper_class(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u8 channel, bandwidth, oper_class = 0; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| channel = misc->param.bw_chan_oper.channel; |
| switch (misc->param.bw_chan_oper.bandwidth) { |
| case 20: |
| bandwidth = BW_20MHZ; |
| break; |
| case 40: |
| bandwidth = BW_40MHZ; |
| break; |
| case 80: |
| bandwidth = BW_80MHZ; |
| break; |
| default: |
| bandwidth = BW_20MHZ; |
| break; |
| } |
| |
| if (pioctl_req->action == MLAN_ACT_GET) { |
| ret = wlan_get_curr_oper_class(pmpriv, channel, bandwidth, |
| &oper_class); |
| misc->param.bw_chan_oper.oper_class = oper_class; |
| } else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief config dynamic bandwidth |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_fw_dump_event(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| t_u16 cmd_action = 0; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FW_DUMP_EVENT, cmd_action, 0, |
| (t_void *)pioctl_req, MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get the network monitor configuration. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_net_monitor(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv; |
| mlan_ds_misc_cfg *misc; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (!pioctl_req) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| /* Send command to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_NET_MONITOR, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &misc->param.net_mon); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief config gpio cfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_gpiocfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else |
| cmd_action = HostCmd_ACT_GEN_SET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GPIO_CFG, cmd_action, 0, |
| (t_void *)pioctl_req, (t_void *)misc); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief config boot sleep |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_bootsleep(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action 0x%x\n", |
| pioctl_req->action); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_BOOT_SLEEP, cmd_action, 0, |
| (t_void *)pioctl_req, &misc->param.boot_sleep); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Infra/Ad-hoc band configuration |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| mlan_status wlan_radio_ioctl_band_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| t_u32 i, global_band = 0; |
| t_u32 infra_band = 0; |
| mlan_ds_radio_cfg *radio_cfg = MNULL; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf; |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| infra_band = radio_cfg->param.band_cfg.config_bands; |
| |
| /* SET Infra band */ |
| if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) { |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| for (i = 0; i < pmadapter->priv_num; i++) { |
| if (pmadapter->priv[i] && |
| pmadapter->priv[i] != pmpriv && |
| GET_BSS_ROLE(pmadapter->priv[i]) == |
| MLAN_BSS_ROLE_STA) |
| global_band |= |
| (t_u32)pmadapter->priv[i]->config_bands; |
| } |
| global_band |= infra_band; |
| |
| if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code, |
| global_band)) { |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| #ifdef STA_SUPPORT |
| if (wlan_11d_set_universaltable(pmpriv, global_band)) { |
| pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| #endif |
| pmpriv->config_bands = infra_band; |
| pmadapter->config_bands = global_band; |
| |
| #ifdef STA_SUPPORT |
| #endif |
| |
| } else { |
| /* Infra Bands */ |
| radio_cfg->param.band_cfg.config_bands = pmpriv->config_bands; |
| /* FW support Bands */ |
| radio_cfg->param.band_cfg.fw_bands = pmadapter->fw_bands; |
| PRINTM(MINFO, "Global config band = %d\n", |
| pmadapter->config_bands); |
| #ifdef STA_SUPPORT |
| #endif |
| } |
| |
| LEAVE(); |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief Rx Abort Cfg |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_rxabortcfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_ABORT_CFG, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &(pmisc->param.rx_abort_cfg)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief OFDM DESENSE CFG |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_ofdmdesense_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_OFDM_DESENSE_CFG, cmd_action, |
| 0, (t_void *)pioctl_req, |
| &(pmisc->param.ofdm_desense_cfg)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| /** |
| * @brief Rx Abort Cfg ext |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_rxabortcfg_ext(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_ABORT_CFG_EXT, cmd_action, |
| 0, (t_void *)pioctl_req, |
| &(pmisc->param.rx_abort_cfg_ext)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief nav mitigation parameter |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_nav_mitigation(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_NAV_MITIGATION_CFG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.nav_mitigation)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief led config parameter |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_led(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_LED_CONTROL, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.led_config)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Dot11mc unassociated FTM CFG |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_dot11mc_unassoc_ftm_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.dot11mc_unassoc_ftm_cfg)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Tx ampdu protection mode |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_tx_ampdu_prot_mode(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_AMPDU_PROT_MODE, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.tx_ampdu_prot_mode)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Rate adapt config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_rate_adapt_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RATE_ADAPT_CFG, cmd_action, |
| 0, (t_void *)pioctl_req, |
| &(pmisc->param.rate_adapt_cfg)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief CCK Desense config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_cck_desense_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CCK_DESENSE_CFG, cmd_action, |
| 0, (t_void *)pioctl_req, |
| &(pmisc->param.cck_desense_cfg)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief config dynamic bandwidth |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_dyn_bw(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action = 0; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DYN_BW, cmd_action, 0, |
| (t_void *)pioctl_req, &misc->param.dyn_bw); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get low power mode configuration parameter |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success |
| */ |
| mlan_status wlan_power_ioctl_set_get_lpm(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_power_cfg *pm_cfg = MNULL; |
| t_u16 cmd_action = 0, lpm = 0; |
| |
| ENTER(); |
| |
| pm_cfg = (mlan_ds_power_cfg *)pioctl_req->pbuf; |
| cmd_action = HostCmd_ACT_GEN_GET; |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| cmd_action = HostCmd_ACT_GEN_SET; |
| lpm = pm_cfg->param.lpm; |
| } |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_LOW_POWER_MODE_CFG, |
| cmd_action, 0, (t_void *)pioctl_req, &lpm); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief RF Test Mode config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_rf_test_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = MNULL; |
| mlan_ds_misc_cfg *pmisc = MNULL; |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (!pioctl_req) |
| goto done; |
| |
| pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| switch (pmisc->sub_command) { |
| case MLAN_OID_MISC_RF_TEST_GENERIC: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_generic_cfg)); |
| break; |
| case MLAN_OID_MISC_RF_TEST_TX_CONT: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_tx_cont)); |
| break; |
| case MLAN_OID_MISC_RF_TEST_TX_FRAME: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_tx_frame2)); |
| break; |
| case MLAN_OID_MISC_RF_TEST_CONFIG_TRIGGER_FRAME: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_tx_trigger_config)); |
| break; |
| |
| case MLAN_OID_MISC_RF_TEST_HE_POWER: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_he_power)); |
| break; |
| |
| case MLAN_OID_MISC_OTP_MAC_RD_WR: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_otp_mac_addr_rd_wr)); |
| break; |
| |
| case MLAN_OID_MISC_OTP_CAL_DATA_RD_WR: |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, "Unsupported cmd_action\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, |
| cmd_action, 0, (t_void *)pioctl_req, |
| &(pmisc->param.mfg_otp_cal_data_rd_wr)); |
| break; |
| } |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Range ext mode config |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_range_ext(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RANGE_EXT, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &(pmisc->param.range_ext_mode)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief twt_report cmd |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_twt_report(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| |
| ENTER(); |
| |
| cmd_action = HostCmd_ACT_GEN_GET; |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TWT_CFG, cmd_action, 0, |
| (t_void *)pioctl_req, |
| &(pmisc->param.twt_report_info)); |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Perform warm reset |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_warm_reset(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_callbacks pcb = &pmadapter->callbacks; |
| pmlan_buffer pmbuf; |
| t_s32 i = 0; |
| t_u16 mc_policy = pmadapter->mc_policy; |
| mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| ENTER(); |
| mlan_block_rx_process(pmadapter, MTRUE); |
| |
| /* Cancel all pending commands and complete ioctls */ |
| if (misc->param.fw_reload) |
| wlan_cancel_all_pending_cmd(pmadapter, MTRUE); |
| |
| /** Init all the head nodes and free all the locks here */ |
| for (i = 0; i < pmadapter->priv_num; i++) |
| wlan_free_priv(pmadapter->priv[i]); |
| |
| while ((pmbuf = (pmlan_buffer)util_dequeue_list( |
| pmadapter->pmoal_handle, &pmadapter->rx_data_queue, |
| pcb->moal_spin_lock, pcb->moal_spin_unlock))) { |
| pmadapter->ops.data_complete(pmadapter, pmbuf, |
| MLAN_STATUS_FAILURE); |
| } |
| pmadapter->rx_pkts_queued = 0; |
| |
| /* Initialize adapter structure */ |
| wlan_init_adapter(pmadapter); |
| pmadapter->hw_status = WlanHardwareStatusInitializing; |
| |
| /* Initialize private structures */ |
| for (i = 0; i < pmadapter->priv_num; i++) { |
| if (pmadapter->priv[i]) { |
| /* Reset to sta role */ |
| #ifdef WIFI_DIRECT_SUPPORT |
| if (pmadapter->priv[i]->bss_type == |
| MLAN_BSS_TYPE_WIFIDIRECT) |
| pmadapter->priv[i]->bss_role = |
| MLAN_BSS_ROLE_STA; |
| #endif |
| wlan_init_priv(pmadapter->priv[i]); |
| } |
| } |
| mlan_block_rx_process(pmadapter, MFALSE); |
| |
| if (misc->param.fw_reload != MTRUE) { |
| /* Restart the firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN, |
| HostCmd_ACT_GEN_SET, 0, MNULL, MNULL); |
| if (ret) |
| goto done; |
| } |
| |
| /* Issue firmware initialize commands for first BSS, |
| * for other interfaces it will be called after getting |
| * the last init command response of previous interface |
| */ |
| pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); |
| if (!pmpriv) { |
| ret = MLAN_STATUS_FAILURE; |
| LEAVE(); |
| return ret; |
| } |
| ret = wlan_adapter_get_hw_spec(pmpriv->adapter); |
| if (ret == MLAN_STATUS_FAILURE) { |
| LEAVE(); |
| return ret; |
| } |
| ret = pmpriv->ops.init_cmd(pmpriv, MTRUE); |
| if (ret == MLAN_STATUS_FAILURE) { |
| LEAVE(); |
| return ret; |
| } |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MULTI_CHAN_POLICY, |
| HostCmd_ACT_GEN_SET, 0, MNULL, &mc_policy); |
| if (ret == MLAN_STATUS_FAILURE) { |
| LEAVE(); |
| return ret; |
| } |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| if (ret == MLAN_STATUS_PENDING) |
| pmadapter->pwarm_reset_ioctl_req = pioctl_req; |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef UAP_SUPPORT |
| /** |
| * @brief set wacp mode |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req A pointer to ioctl request buffer |
| * |
| * @return MLAN_STATUS_PENDING --success, otherwise fail |
| */ |
| mlan_status wlan_misc_ioctl_wacp_mode(IN pmlan_adapter pmadapter, |
| IN pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_cfg *misc = MNULL; |
| t_u16 cmd_action; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) |
| cmd_action = HostCmd_ACT_GEN_SET; |
| else |
| cmd_action = HostCmd_ACT_GEN_GET; |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_APCMD_SYS_CONFIGURE, |
| cmd_action, 0, (t_void *)pioctl_req, |
| (t_void *)&misc->param.wacp_mode); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| mlan_status wlan_misc_ioctl_get_sensor_temp(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u16 cmd_action = 0; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| if (pioctl_req->action == MLAN_ACT_GET) |
| cmd_action = HostCmd_ACT_GEN_GET; |
| else { |
| PRINTM(MERROR, " Sensor temp only support get operation \n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Send request to firmware */ |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DS_GET_SENSOR_TEMP, |
| cmd_action, 0, (t_void *)pioctl_req, MNULL); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function sets up country code and downloads CMD to FW |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_country_code(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| mlan_ds_misc_country_code *country_code = MNULL; |
| mlan_ds_misc_cfg *cfg_misc = MNULL; |
| t_u8 cfp_bg = 0, cfp_a = 0; |
| |
| ENTER(); |
| |
| cfg_misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| country_code = &cfg_misc->param.country_code; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| if (pmadapter->otp_region && pmadapter->otp_region->force_reg) { |
| PRINTM(MERROR, |
| "ForceRegionRule is set in the on-chip OTP" |
| "memory\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| /* Update region code and table based on country code */ |
| if (wlan_misc_country_2_cfp_table_code( |
| pmadapter, country_code->country_code, &cfp_bg, |
| &cfp_a)) { |
| PRINTM(MERROR, "Country code not found!\n"); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| pmadapter->cfp_code_bg = cfp_bg; |
| pmadapter->cfp_code_a = cfp_a; |
| if (cfp_a) |
| pmadapter->region_code = cfp_a; |
| else if (cfp_bg) |
| pmadapter->region_code = cfp_bg; |
| else |
| pmadapter->region_code = 0; |
| if (wlan_set_regiontable(pmpriv, pmadapter->region_code, |
| pmadapter->config_bands)) { |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| memcpy_ext(pmadapter, pmadapter->country_code, |
| country_code->country_code, COUNTRY_CODE_LEN, |
| COUNTRY_CODE_LEN); |
| } else { |
| /* GET operation */ |
| memcpy_ext(pmadapter, country_code->country_code, |
| pmadapter->country_code, COUNTRY_CODE_LEN, |
| COUNTRY_CODE_LEN); |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief get/set rx flush time |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_reorder_flush_time(pmlan_adapter pmadapter, |
| mlan_ioctl_req *pioctl_req) |
| { |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (pioctl_req->action == MLAN_ACT_SET) { |
| if (misc->param.flush_time.flush_time_ac_be_bk >= |
| MIN_FLUSH_TIME) |
| pmadapter->flush_time_ac_be_bk = |
| misc->param.flush_time.flush_time_ac_be_bk; |
| if (misc->param.flush_time.flush_time_ac_vi_vo >= |
| MIN_FLUSH_TIME) |
| pmadapter->flush_time_ac_vi_vo = |
| misc->param.flush_time.flush_time_ac_vi_vo; |
| } |
| misc->param.flush_time.flush_time_ac_be_bk = |
| pmadapter->flush_time_ac_be_bk; |
| misc->param.flush_time.flush_time_ac_vi_vo = |
| pmadapter->flush_time_ac_vi_vo; |
| PRINTM(MCMND, "flush time: BE/BK=%d ms VI/VO=%d ms\n", |
| pmadapter->flush_time_ac_be_bk, pmadapter->flush_time_ac_vi_vo); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief configure edmac parameters |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pioctl_req Pointer to the IOCTL request buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status wlan_misc_ioctl_edmac_cfg(pmlan_adapter pmadapter, |
| pmlan_ioctl_req pioctl_req) |
| { |
| mlan_ds_misc_cfg *misc = MNULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; |
| |
| ENTER(); |
| |
| misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; |
| |
| if (MLAN_ACT_SET == pioctl_req->action) { |
| if (IS_CARD9098(pmadapter->card_type) || |
| IS_CARD9097(pmadapter->card_type) || |
| IS_CARDAW693(pmadapter->card_type) || |
| IS_CARDIW624(pmadapter->card_type) || |
| IS_CARDIW610(pmadapter->card_type)) { |
| misc->param.edmac_cfg.ed_ctrl_2g = 0x1; |
| misc->param.edmac_cfg.ed_offset_2g = 0x8; |
| misc->param.edmac_cfg.ed_ctrl_5g = 0x1; |
| misc->param.edmac_cfg.ed_offset_5g = 0x8; |
| misc->param.edmac_cfg.ed_bitmap_txq_lock = 0x1e00FF; |
| } else if (IS_CARD9177(pmadapter->card_type)) { |
| // from config/ed_mac_ctrl_V2_nw61x.conf |
| misc->param.edmac_cfg.ed_ctrl_2g = 0x1; |
| misc->param.edmac_cfg.ed_offset_2g = 0xA; |
| misc->param.edmac_cfg.ed_ctrl_5g = 0x1; |
| misc->param.edmac_cfg.ed_offset_5g = 0xA; |
| misc->param.edmac_cfg.ed_bitmap_txq_lock = 0x1e00FF; |
| } else if (IS_CARD8997(pmadapter->card_type)) { |
| // from config/ed_mac_ctrl_V2_8997.conf |
| misc->param.edmac_cfg.ed_ctrl_2g = 0x1; |
| misc->param.edmac_cfg.ed_offset_2g = 0x0; |
| misc->param.edmac_cfg.ed_ctrl_5g = 0x1; |
| misc->param.edmac_cfg.ed_offset_5g = 0x4; |
| misc->param.edmac_cfg.ed_bitmap_txq_lock = 0xFF; |
| } else if (IS_CARD8978(pmadapter->card_type)) { |
| // from config/ed_mac_ctrl_V2_iw416.conf |
| misc->param.edmac_cfg.ed_ctrl_2g = 0x1; |
| misc->param.edmac_cfg.ed_offset_2g = 0x9; |
| misc->param.edmac_cfg.ed_ctrl_5g = 0x1; |
| misc->param.edmac_cfg.ed_offset_5g = 0xC; |
| misc->param.edmac_cfg.ed_bitmap_txq_lock = 0xFF; |
| } else { |
| PRINTM(MERROR, "Failed to configure edmac param"); |
| pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; |
| return MLAN_STATUS_FAILURE; |
| } |
| } else { |
| misc->param.edmac_cfg.ed_ctrl_2g = 0x0; |
| misc->param.edmac_cfg.ed_ctrl_5g = 0x0; |
| } |
| |
| ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_EDMAC_CFG, |
| HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, |
| (t_void *)&misc->param.edmac_cfg); |
| |
| if (ret == MLAN_STATUS_SUCCESS) |
| ret = MLAN_STATUS_PENDING; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Add 2 variables securely, to prevent overflow. |
| * |
| * @param datain Pointer to 1st variable |
| * @param add 2nd variable value to add to 1st variable |
| * @param dataout Pointer to variable where sum is to be stored |
| * @param type Datatype of 1st and 2nd variable |
| * |
| * @return MTRUE if success or MFALSE if overflow error |
| */ |
| t_bool wlan_secure_add(t_void *datain, t_s32 add, t_void *dataout, |
| data_type type) |
| { |
| t_bool status = MTRUE; |
| |
| switch (type) { |
| case TYPE_SINT8: |
| if (add > SINT8_MAX || *(t_s8 *)datain > SINT8_MAX - add) |
| goto fail; |
| else |
| *(t_s8 *)dataout = *(t_s8 *)datain + add; |
| break; |
| |
| case TYPE_UINT8: |
| if (add > UINT8_MAX || *(t_u8 *)datain > UINT8_MAX - add) |
| goto fail; |
| else |
| *(t_u8 *)dataout = *(t_u8 *)datain + add; |
| break; |
| |
| case TYPE_SINT16: |
| if (add > SINT16_MAX || *(t_s16 *)datain > SINT16_MAX - add) |
| goto fail; |
| else |
| *(t_s16 *)dataout = *(t_s16 *)datain + add; |
| break; |
| |
| case TYPE_UINT16: |
| if (add > UINT16_MAX || *(t_u16 *)datain > UINT16_MAX - add) |
| goto fail; |
| else |
| *(t_u16 *)dataout = *(t_u16 *)datain + add; |
| break; |
| |
| case TYPE_SINT32: |
| if (*(t_s32 *)datain > SINT32_MAX - add) |
| goto fail; |
| else |
| *(t_s32 *)dataout = *(t_s32 *)datain + add; |
| break; |
| |
| case TYPE_UINT32: |
| if (*(t_u32 *)datain > UINT32_MAX - add) |
| goto fail; |
| else |
| *(t_u32 *)dataout = *(t_u32 *)datain + add; |
| break; |
| |
| case TYPE_SINT64: |
| if (*(t_s64 *)datain > SINT64_MAX - add) |
| goto fail; |
| else |
| *(t_s64 *)dataout = *(t_s64 *)datain + add; |
| break; |
| |
| case TYPE_UINT64: |
| if (*(t_u64 *)datain > UINT64_MAX - add) |
| goto fail; |
| else |
| *(t_u64 *)dataout = *(t_u64 *)datain + add; |
| break; |
| |
| case TYPE_PTR: |
| if (*(t_ptr *)datain > PTR_MAX - add) |
| goto fail; |
| else |
| *(t_ptr *)dataout = *(t_ptr *)datain + add; |
| break; |
| |
| default: |
| status = MFALSE; |
| break; |
| } |
| ret: |
| return status; |
| |
| fail: |
| status = MFALSE; |
| goto ret; |
| } |
| |
| /** |
| * @brief Subtract 2 variables securely, to prevent underflow. |
| * |
| * @param datain Pointer to 1st variable |
| * @param add 2nd variable value to subtract from 1st variable |
| * @param dataout Pointer to variable where diff is to be stored |
| * @param type Datatype of 1st and 2nd variable |
| * |
| * @return MTRUE if success or MFALSE if underflow error |
| */ |
| t_bool wlan_secure_sub(t_void *datain, t_s32 sub, t_void *dataout, |
| data_type type) |
| { |
| t_u8 status = MTRUE; |
| |
| switch (type) { |
| case TYPE_SINT8: |
| if (*(t_s8 *)datain >= (t_s8)SINT8_MIN + sub) |
| *(t_s8 *)dataout = *(t_s8 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_UINT8: |
| if (*(t_u8 *)datain >= sub) |
| *(t_u8 *)dataout = *(t_u8 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_SINT16: |
| if (*(t_s16 *)datain >= (t_s16)SINT16_MIN + sub) |
| *(t_s16 *)dataout = *(t_s16 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_UINT16: |
| if (*(t_u16 *)datain >= sub) |
| *(t_u16 *)dataout = *(t_u16 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_SINT32: |
| if (*(t_s32 *)datain >= (t_s32)SINT32_MIN + sub) |
| *(t_s32 *)dataout = *(t_s32 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_UINT32: |
| if (*(t_u32 *)datain >= sub) |
| *(t_u32 *)dataout = *(t_u32 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_SINT64: |
| if (*(t_s64 *)datain >= (t_s64)SINT64_MIN + sub) |
| *(t_s64 *)dataout = *(t_s64 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_UINT64: |
| if (*(t_u64 *)datain >= sub) |
| *(t_u64 *)dataout = *(t_u64 *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| case TYPE_PTR: |
| if (*(t_ptr *)datain >= sub) |
| *(t_ptr *)dataout = *(t_ptr *)datain - sub; |
| else |
| goto fail; |
| break; |
| |
| default: |
| status = MFALSE; |
| break; |
| } |
| ret: |
| return status; |
| |
| fail: |
| status = MFALSE; |
| goto ret; |
| } |
| |
| /** |
| * @brief Prints verbose msg of 6G chan_switch block event for the reason_code |
| * |
| * @param reason_code Reason code contained in event body |
| * |
| * @return N/A |
| */ |
| void print_chan_switch_block_event(t_u16 reason_code) |
| { |
| ENTER(); |
| switch (reason_code) { |
| case BLOCK_6G_CHAN_SWITCH_REASON_STA_RX_ECSA: |
| PRINTM(MEVENT, |
| "EVENT: Mobile-AP does not support HE-Cap/WPA3" |
| " to switch to 6Ghz, leading to RX ECSA Failure of STA\n"); |
| break; |
| case BLOCK_6G_CHAN_SWITCH_REASON_MMH_STA: |
| PRINTM(MEVENT, |
| "EVENT: Mobile-AP does not support HE-Cap/WPA3" |
| " to switch to 6Ghz, leading to 6Ghz Assoc Failure of STA\n"); |
| break; |
| case BLOCK_6G_CHAN_SWITCH_REASON_STA_MMH: |
| PRINTM(MEVENT, |
| "EVENT: Mobile-AP does not support HE-Cap/WPA3" |
| " to switch to 6Ghz channel same as STA, leading to bss start failure"); |
| break; |
| case BLOCK_6G_CHAN_SWITCH_REASON_MMH: |
| PRINTM(MEVENT, |
| "EVENT: Mobile-AP does not support HE-Cap/WPA3" |
| " to switch to 6Ghz channel, leading to chan_switch failure"); |
| break; |
| default: |
| break; |
| } |
| LEAVE(); |
| return; |
| } |