diff options
Diffstat (limited to 'drivers/net/wireless/sd8797/mlan/mlan_misc.c')
-rw-r--r-- | drivers/net/wireless/sd8797/mlan/mlan_misc.c | 2153 |
1 files changed, 2153 insertions, 0 deletions
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_misc.c b/drivers/net/wireless/sd8797/mlan/mlan_misc.c new file mode 100644 index 000000000000..4054950f58f0 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlan/mlan_misc.c @@ -0,0 +1,2153 @@ +/** + * @file mlan_misc.c + * + * @brief This file include miscellaneous functions for MLAN module + * + * Copyright (C) 2009-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +/************************************************************* +Change Log: + 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_sdio.h" +#ifdef UAP_SUPPORT +#include "mlan_uap.h" +#endif + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +extern mlan_operations *mlan_ops[]; +#endif +extern t_u8 ac_to_tid[4][2]; + +/******************************************************** + Local Functions +********************************************************/ + +/** 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 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(IN pmlan_private pmpriv, IN 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(IN pmlan_private pmpriv, + IN pmlan_ioctl_req pioctl_req, + IN t_u16 mask, + IN custom_ie * ie_data, OUT 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 < pmpriv->adapter->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(MERROR, + "IE with the same mask exists at index %d\n", + index); + *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 < pmpriv->adapter->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(IN pmlan_private pmpriv, + IN pmlan_ioctl_req pioctl_req, + IN custom_ie * ie_data, IN 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]; + t_s32 cnt, tmp_len = 0; + t_u8 *tmp_ie; + + ENTER(); + memset(pmpriv->adapter, del_ie, 0, MAX_IE_SIZE); + memcpy(pmpriv->adapter, del_ie, ie_data->ie_buffer, + MIN(MAX_IE_SIZE, ie_data->ie_length)); + del_len = MIN(MAX_IE_SIZE, ie_data->ie_length); + + for (index = 0; index < pmadapter->max_mgmt_ie_index; index++) { + if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx) + 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(pmpriv->adapter, ie, pmpriv->mgmt_ie[index].ie_buffer, + cnt); + if (pmpriv->mgmt_ie[index].ie_length > (cnt + del_len)) + memcpy(pmpriv->adapter, &ie[cnt], + &pmpriv->mgmt_ie[index].ie_buffer[cnt + del_len], + (pmpriv->mgmt_ie[index].ie_length - + (cnt + del_len))); + memset(pmpriv->adapter, &pmpriv->mgmt_ie[index].ie_buffer, 0, + sizeof(pmpriv->mgmt_ie[index].ie_buffer)); + memcpy(pmpriv->adapter, &pmpriv->mgmt_ie[index].ie_buffer, ie, + pmpriv->mgmt_ie[index].ie_length - del_len); + pmpriv->mgmt_ie[index].ie_length -= del_len; + 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 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(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; + + 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 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(IN pmlan_adapter pmadapter, + IN 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(IN pmlan_adapter pmadapter, + IN 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; + t_u8 *ptid; + + ENTER(); + + info = (mlan_ds_get_info *) pioctl_req->pbuf; + + if (pioctl_req->action == MLAN_ACT_SET) { + pmadapter->max_tx_buf_size = + (t_u16) info->param.debug_info.max_tx_buf_size; + pmadapter->tx_buf_size = (t_u16) info->param.debug_info.tx_buf_size; + pmadapter->curr_tx_buf_size = + (t_u16) info->param.debug_info.curr_tx_buf_size; + pmadapter->ps_mode = info->param.debug_info.ps_mode; + pmadapter->ps_state = info->param.debug_info.ps_state; +#ifdef STA_SUPPORT + pmadapter->is_deep_sleep = info->param.debug_info.is_deep_sleep; +#endif /* STA_SUPPORT */ + pmadapter->pm_wakeup_card_req = + info->param.debug_info.pm_wakeup_card_req; + pmadapter->pm_wakeup_fw_try = info->param.debug_info.pm_wakeup_fw_try; + pmadapter->is_hs_configured = info->param.debug_info.is_hs_configured; + pmadapter->hs_activated = info->param.debug_info.hs_activated; + pmadapter->pps_uapsd_mode = info->param.debug_info.pps_uapsd_mode; + pmadapter->sleep_period.period = info->param.debug_info.sleep_pd; + pmpriv->wmm_qosinfo = info->param.debug_info.qos_cfg; + pmadapter->tx_lock_flag = info->param.debug_info.tx_lock_flag; + pmpriv->port_open = info->param.debug_info.port_open; + pmadapter->scan_processing = info->param.debug_info.scan_processing; + + pmadapter->dbg.num_cmd_host_to_card_failure = + info->param.debug_info.num_cmd_host_to_card_failure; + pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure = + info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure; + pmadapter->dbg.num_tx_host_to_card_failure = + info->param.debug_info.num_tx_host_to_card_failure; + pmadapter->dbg.num_cmdevt_card_to_host_failure = + info->param.debug_info.num_cmdevt_card_to_host_failure; + pmadapter->dbg.num_rx_card_to_host_failure = + info->param.debug_info.num_rx_card_to_host_failure; + pmadapter->dbg.num_int_read_failure = + info->param.debug_info.num_int_read_failure; + pmadapter->dbg.last_int_status = info->param.debug_info.last_int_status; + pmadapter->dbg.num_event_deauth = + info->param.debug_info.num_event_deauth; + pmadapter->dbg.num_event_disassoc = + info->param.debug_info.num_event_disassoc; + pmadapter->dbg.num_event_link_lost = + info->param.debug_info.num_event_link_lost; + pmadapter->dbg.num_cmd_deauth = info->param.debug_info.num_cmd_deauth; + pmadapter->dbg.num_cmd_assoc_success = + info->param.debug_info.num_cmd_assoc_success; + pmadapter->dbg.num_cmd_assoc_failure = + info->param.debug_info.num_cmd_assoc_failure; + pmadapter->dbg.num_tx_timeout = info->param.debug_info.num_tx_timeout; + pmadapter->dbg.num_cmd_timeout = info->param.debug_info.num_cmd_timeout; + pmadapter->dbg.timeout_cmd_id = info->param.debug_info.timeout_cmd_id; + pmadapter->dbg.timeout_cmd_act = info->param.debug_info.timeout_cmd_act; + memcpy(pmadapter, pmadapter->dbg.last_cmd_id, + info->param.debug_info.last_cmd_id, + sizeof(pmadapter->dbg.last_cmd_id)); + memcpy(pmadapter, pmadapter->dbg.last_cmd_act, + info->param.debug_info.last_cmd_act, + sizeof(pmadapter->dbg.last_cmd_act)); + pmadapter->dbg.last_cmd_index = info->param.debug_info.last_cmd_index; + memcpy(pmadapter, pmadapter->dbg.last_cmd_resp_id, + info->param.debug_info.last_cmd_resp_id, + sizeof(pmadapter->dbg.last_cmd_resp_id)); + pmadapter->dbg.last_cmd_resp_index = + info->param.debug_info.last_cmd_resp_index; + memcpy(pmadapter, pmadapter->dbg.last_event, + info->param.debug_info.last_event, + sizeof(pmadapter->dbg.last_event)); + pmadapter->dbg.last_event_index = + info->param.debug_info.last_event_index; + + pmadapter->data_sent = info->param.debug_info.data_sent; + pmadapter->cmd_sent = info->param.debug_info.cmd_sent; + pmadapter->mp_rd_bitmap = info->param.debug_info.mp_rd_bitmap; + pmadapter->mp_wr_bitmap = info->param.debug_info.mp_wr_bitmap; + pmadapter->curr_rd_port = info->param.debug_info.curr_rd_port; + pmadapter->curr_wr_port = info->param.debug_info.curr_wr_port; + pmadapter->cmd_resp_received = info->param.debug_info.cmd_resp_received; +#ifdef UAP_SUPPORT + pmadapter->pending_bridge_pkts = info->param.debug_info.num_bridge_pkts; + pmpriv->num_drop_pkts = info->param.debug_info.num_drop_pkts; +#endif + } else { /* MLAN_ACT_GET */ + ptid = ac_to_tid[WMM_AC_BK]; + info->param.debug_info.wmm_ac_bk = + pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]]; + ptid = ac_to_tid[WMM_AC_BE]; + info->param.debug_info.wmm_ac_be = + pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]]; + ptid = ac_to_tid[WMM_AC_VI]; + info->param.debug_info.wmm_ac_vi = + pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]]; + ptid = ac_to_tid[WMM_AC_VO]; + info->param.debug_info.wmm_ac_vo = + pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]]; + info->param.debug_info.max_tx_buf_size = + (t_u32) pmadapter->max_tx_buf_size; + info->param.debug_info.tx_buf_size = (t_u32) pmadapter->tx_buf_size; + info->param.debug_info.curr_tx_buf_size = + (t_u32) pmadapter->curr_tx_buf_size; + info->param.debug_info.rx_tbl_num = + wlan_get_rxreorder_tbl(pmpriv, info->param.debug_info.rx_tbl); + info->param.debug_info.tx_tbl_num = + wlan_get_txbastream_tbl(pmpriv, info->param.debug_info.tx_tbl); + info->param.debug_info.ps_mode = pmadapter->ps_mode; + info->param.debug_info.ps_state = pmadapter->ps_state; +#ifdef STA_SUPPORT + info->param.debug_info.is_deep_sleep = pmadapter->is_deep_sleep; +#endif /* STA_SUPPORT */ + info->param.debug_info.pm_wakeup_card_req = + pmadapter->pm_wakeup_card_req; + info->param.debug_info.pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try; + info->param.debug_info.is_hs_configured = pmadapter->is_hs_configured; + info->param.debug_info.hs_activated = pmadapter->hs_activated; + info->param.debug_info.pps_uapsd_mode = pmadapter->pps_uapsd_mode; + info->param.debug_info.sleep_pd = pmadapter->sleep_period.period; + info->param.debug_info.qos_cfg = pmpriv->wmm_qosinfo; + info->param.debug_info.tx_lock_flag = pmadapter->tx_lock_flag; + info->param.debug_info.port_open = pmpriv->port_open; + info->param.debug_info.scan_processing = pmadapter->scan_processing; + + info->param.debug_info.num_cmd_host_to_card_failure + = pmadapter->dbg.num_cmd_host_to_card_failure; + info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure + = pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; + info->param.debug_info.num_tx_host_to_card_failure + = pmadapter->dbg.num_tx_host_to_card_failure; + info->param.debug_info.num_cmdevt_card_to_host_failure + = pmadapter->dbg.num_cmdevt_card_to_host_failure; + info->param.debug_info.num_rx_card_to_host_failure + = pmadapter->dbg.num_rx_card_to_host_failure; + info->param.debug_info.num_int_read_failure = + pmadapter->dbg.num_int_read_failure; + info->param.debug_info.last_int_status = pmadapter->dbg.last_int_status; + info->param.debug_info.num_event_deauth = + pmadapter->dbg.num_event_deauth; + info->param.debug_info.num_event_disassoc = + pmadapter->dbg.num_event_disassoc; + info->param.debug_info.num_event_link_lost = + pmadapter->dbg.num_event_link_lost; + info->param.debug_info.num_cmd_deauth = pmadapter->dbg.num_cmd_deauth; + info->param.debug_info.num_cmd_assoc_success = + pmadapter->dbg.num_cmd_assoc_success; + info->param.debug_info.num_cmd_assoc_failure = + pmadapter->dbg.num_cmd_assoc_failure; + info->param.debug_info.num_tx_timeout = pmadapter->dbg.num_tx_timeout; + info->param.debug_info.num_cmd_timeout = pmadapter->dbg.num_cmd_timeout; + info->param.debug_info.timeout_cmd_id = pmadapter->dbg.timeout_cmd_id; + info->param.debug_info.timeout_cmd_act = pmadapter->dbg.timeout_cmd_act; + memcpy(pmadapter, info->param.debug_info.last_cmd_id, + pmadapter->dbg.last_cmd_id, sizeof(pmadapter->dbg.last_cmd_id)); + memcpy(pmadapter, info->param.debug_info.last_cmd_act, + pmadapter->dbg.last_cmd_act, + sizeof(pmadapter->dbg.last_cmd_act)); + info->param.debug_info.last_cmd_index = pmadapter->dbg.last_cmd_index; + memcpy(pmadapter, info->param.debug_info.last_cmd_resp_id, + pmadapter->dbg.last_cmd_resp_id, + sizeof(pmadapter->dbg.last_cmd_resp_id)); + info->param.debug_info.last_cmd_resp_index = + pmadapter->dbg.last_cmd_resp_index; + memcpy(pmadapter, info->param.debug_info.last_event, + pmadapter->dbg.last_event, sizeof(pmadapter->dbg.last_event)); + info->param.debug_info.last_event_index = + pmadapter->dbg.last_event_index; + + info->param.debug_info.mp_rd_bitmap = pmadapter->mp_rd_bitmap; + info->param.debug_info.mp_wr_bitmap = pmadapter->mp_wr_bitmap; + info->param.debug_info.curr_rd_port = pmadapter->curr_rd_port; + info->param.debug_info.curr_wr_port = pmadapter->curr_wr_port; + info->param.debug_info.data_sent = pmadapter->data_sent; + info->param.debug_info.cmd_sent = pmadapter->cmd_sent; + info->param.debug_info.cmd_resp_received = pmadapter->cmd_resp_received; + info->param.debug_info.tx_pkts_queued = + util_scalar_read(pmadapter->pmoal_handle, + &pmpriv->wmm.tx_pkts_queued, MNULL, MNULL); +#ifdef UAP_SUPPORT + info->param.debug_info.num_bridge_pkts = pmadapter->pending_bridge_pkts; + info->param.debug_info.num_drop_pkts = pmpriv->num_drop_pkts; +#endif + } + + pioctl_req->data_read_written = + sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE; + + LEAVE(); + return ret; +} + +/** + * @brief This function wakes up the card. + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +wlan_pm_wakeup_card(IN pmlan_adapter pmadapter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + pmlan_callbacks pcb = &pmadapter->callbacks; + + ENTER(); + PRINTM(MEVENT, "Wakeup device...\n"); + ret = + pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG, + HOST_POWER_UP); + LEAVE(); + return ret; +} + +/** + * @brief This function resets the PM setting of the card. + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +wlan_pm_reset_card(IN pmlan_adapter pmadapter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + pmlan_callbacks pcb = &pmadapter->callbacks; + + ENTER(); + + ret = + pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG, 0); + + LEAVE(); + return ret; +} + +/** + * @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(IN pmlan_adapter pmadapter, IN 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; + } + 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; + break; + default: + pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID; + status = MLAN_STATUS_FAILURE; + break; + } + + LEAVE(); + return status; +} + +/** + * @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; + + ENTER(); + + /* make sure that the data length is at least SDIO block size */ + data_len = ALIGN_SZ(data_len, MLAN_SDIO_BLOCK_SIZE); + + /* head_room is not implemented for malloc mlan buffer */ + if (malloc_flag == MTRUE) { + buf_size = sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT; + ret = + pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, + MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & pmbuf); + if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) { + pmbuf = MNULL; + goto exit; + } + memset(pmadapter, pmbuf, 0, sizeof(mlan_buffer)); + + 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 { + /* 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_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; + 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; +} + +#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_SUCCESS --success, MLAN_STATUS_PENDING --pending + */ +mlan_status +wlan_bss_ioctl_bss_role(IN pmlan_adapter pmadapter, + IN 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; +#if defined(WIFI_DIRECT_SUPPORT) + t_u8 bss_mode; +#endif + t_u8 i, 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 { + /** Switch BSS role */ + wlan_free_priv(pmpriv); + + 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); + + /* Initialize function table */ + for (j = 0; mlan_ops[j]; j++) { + if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmpriv)) { + memcpy(pmadapter, &pmpriv->ops, mlan_ops[j], + 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 | pmadapter-> + adhoc_start_band)) { + pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + if (wlan_11d_set_universaltable + (pmpriv, global_band | pmadapter->adhoc_start_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; + wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, MNULL, &bss_mode); +#endif + pmpriv->ops.init_cmd(pmpriv, MFALSE); + + /* Issue dummy Get command to complete the ioctl */ + memset(pmadapter, &dummy, 0, sizeof(HostCmd_DS_VERSION_EXT)); + wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, HostCmd_ACT_GEN_GET, + 0, (t_void *) pioctl_req, (t_void *) & dummy); + ret = MLAN_STATUS_PENDING; + } + + 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(IN pmlan_adapter pmadapter, + IN pmlan_ioctl_req pioctl_req, + IN 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, 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; + } 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; + if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) { /* Need to be + Autohandled */ + if (mask == MLAN_CUSTOM_IE_DELETE_MASK) { /* Automatic + Deletion */ + 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); + len = 0; + for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) { + memcpy(pmadapter, (t_u8 *) ie_data + len, &i, + sizeof(ie_data->ie_index)); + len += sizeof(ie_data->ie_index); + memcpy(pmadapter, (t_u8 *) ie_data + len, + &pmpriv->mgmt_ie[i].mgmt_subtype_mask, + sizeof(ie_data->mgmt_subtype_mask)); + len += sizeof(ie_data->mgmt_subtype_mask); + memcpy(pmadapter, (t_u8 *) ie_data + len, + &pmpriv->mgmt_ie[i].ie_length, + sizeof(ie_data->ie_length)); + len += sizeof(ie_data->ie_length); + if (pmpriv->mgmt_ie[i].ie_length) { + memcpy(pmadapter, (t_u8 *) ie_data + len, + &pmpriv->mgmt_ie[i].ie_buffer, + 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; + } + if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) { + ret = MLAN_STATUS_SUCCESS; + goto done; + } + tmp_ie = (t_u8 *) & pmpriv->mgmt_ie[index].ie_buffer; + memcpy(pmadapter, tmp_ie + pmpriv->mgmt_ie[index].ie_length, + &ie_data->ie_buffer, 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(pmadapter, &ie_data->ie_buffer, + &pmpriv->mgmt_ie[index].ie_buffer, + pmpriv->mgmt_ie[index].ie_length); + misc->param.cust_ie.len += + pmpriv->mgmt_ie[index].ie_length + + MLAN_CUSTOM_IE_HDR_SIZE; + } + } else { + if (index >= pmadapter->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); + memcpy(pmadapter, (t_u8 *) ie_data, &pmpriv->mgmt_ie[index], + 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].ie_length == + ie_data->ie_length) && + !memcmp(pmpriv->adapter, + pmpriv->mgmt_ie[index].ie_buffer, + ie_data->ie_buffer, + pmpriv->mgmt_ie[index].ie_length)) { + PRINTM(MIOCTL, + "same customer ie already configured!\n"); + goto done; + } + } + memset(pmadapter, &pmpriv->mgmt_ie[index], 0, + sizeof(custom_ie)); + memcpy(pmadapter, &pmpriv->mgmt_ie[index], ie_data, + 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, + HOST_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 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; + } + if (!(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))) { + LEAVE(); + return MNULL; + } + while (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; + mlan_adapter *pmadapter = priv->adapter; + + ENTER(); + pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, + priv->wmm.ra_list_spinlock); + + 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; + } + memset(priv->adapter, sta_ptr, 0, sizeof(sta_node)); + memcpy(priv->adapter, sta_ptr->mac_addr, mac, 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: + pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, + priv->wmm.ra_list_spinlock); + LEAVE(); + return sta_ptr; +} + +/** + * @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; + mlan_adapter *pmadapter = priv->adapter; + ENTER(); + pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, + priv->wmm.ra_list_spinlock); + if ((sta_ptr = wlan_get_station_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); + } + pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, + priv->wmm.ra_list_spinlock); + 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 This function will return the pointer to station entry in station list + * table which in tx_pause state + * + * @param priv A pointer to mlan_private + * + * @return A pointer to structure sta_node + */ +sta_node * +wlan_get_tx_pause_station_entry(mlan_private * priv) +{ + sta_node *sta_ptr; + + ENTER(); + + if (!(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))) { + LEAVE(); + return MNULL; + } + while (sta_ptr != (sta_node *) & priv->sta_list) { + if (sta_ptr->tx_pause) { + LEAVE(); + return sta_ptr; + } + sta_ptr = sta_ptr->pnext; + } + LEAVE(); + return MNULL; +} + +/** + * @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(IN pmlan_adapter pmadapter, IN 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; +} + +#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(IN pmlan_adapter pmadapter, IN 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 */ + 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(IN pmlan_adapter pmadapter, IN 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, + 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 + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +wlan_process_802dot11_mgmt_pkt(IN mlan_private * priv, + IN t_u8 * payload, IN t_u32 payload_len) +{ + 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; + + 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.\n", sub_type); + LEAVE(); + return ret; + } + switch (sub_type) { + case SUBTYPE_ASSOC_REQUEST: + case SUBTYPE_REASSOC_REQUEST: + case SUBTYPE_DISASSOC: + case SUBTYPE_DEAUTH: + case SUBTYPE_ACTION: + case SUBTYPE_AUTH: + case SUBTYPE_PROBE_RESP: + 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 %02x:%02x:%02x:%02x:%02x:%02x\n", + sub_type, pieee_pkt_hdr->addr1[0], pieee_pkt_hdr->addr1[1], + pieee_pkt_hdr->addr1[2], pieee_pkt_hdr->addr1[3], + pieee_pkt_hdr->addr1[4], pieee_pkt_hdr->addr1[5]); + 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; + pevent->event_id = MLAN_EVENT_ID_DRV_MGMT_FRAME; + pevent->event_len = payload_len + sizeof(pevent->event_id); + memcpy(pmadapter, (t_u8 *) pevent->event_buf, + (t_u8 *) & pevent->event_id, sizeof(pevent->event_id)); + memcpy(pmadapter, (t_u8 *) (pevent->event_buf + sizeof(pevent->event_id)), + payload, payload_len); + wlan_recv_event(priv, MLAN_EVENT_ID_DRV_MGMT_FRAME, pevent); + + if (event_buf) + pcb->moal_mfree(pmadapter->pmoal_handle, event_buf); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @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 + * + * @return ie's poiner or MNULL + */ +t_u8 * +wlan_get_specific_ie(pmlan_private priv, t_u8 * ie_buf, t_u8 ie_len, + IEEEtypes_ElementId_e 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; + + ENTER(); + + DBG_HEXDUMP(MCMD_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); + 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 (element_id == id) { + PRINTM(MCMND, "Find IE: id=%d\n", id); + DBG_HEXDUMP(MCMND, "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(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_pm_cfg *pm_cfg = MNULL; + pmlan_callbacks pcb = &pmadapter->callbacks; + + ENTER(); + + pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf; + pm_cfg->param.ps_info.is_suspend_allowed = MTRUE; + if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, + pcb->moal_spin_lock, pcb->moal_spin_unlock) + || pmadapter->curr_cmd || !wlan_bypass_tx_list_empty(pmadapter) + || !wlan_wmm_lists_empty(pmadapter) + || pmadapter->sdio_ireg) { + pm_cfg->param.ps_info.is_suspend_allowed = MFALSE; + PRINTM(MIOCTL, + "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d sdio_ireg=0x%x\n", + util_peek_list(pmadapter->pmoal_handle, + &pmadapter->cmd_pending_q, pcb->moal_spin_lock, + pcb->moal_spin_unlock), pmadapter->curr_cmd, + wlan_wmm_lists_empty(pmadapter), + wlan_bypass_tx_list_empty(pmadapter), pmadapter->sdio_ireg); + } + 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(IN pmlan_adapter pmadapter, + IN 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(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_radio_cfg *radio_cfg = MNULL; + t_u16 cmd_action = 0; + mlan_ds_ant_cfg *ant_cfg; + + ENTER(); + + radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf; + ant_cfg = &radio_cfg->param.ant_cfg; + + if (pioctl_req->action == MLAN_ACT_SET) { + /* User input validation */ + if (!ant_cfg->tx_antenna || + ant_cfg->tx_antenna & ~RF_ANTENNA_MASK(pmadapter-> + number_of_antenna)) { + PRINTM(MERROR, "Invalid antenna setting\n"); + pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; + ret = MLAN_STATUS_FAILURE; + goto exit; + } + if (ant_cfg->rx_antenna) { + if (ant_cfg-> + rx_antenna & ~RF_ANTENNA_MASK(pmadapter->number_of_antenna)) { + PRINTM(MERROR, "Invalid antenna setting\n"); + pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; + ret = MLAN_STATUS_FAILURE; + goto exit; + } + } else + ant_cfg->rx_antenna = ant_cfg->tx_antenna; + 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_RF_ANTENNA, + cmd_action, + 0, (t_void *) pioctl_req, (t_void *) ant_cfg); + + if (ret == MLAN_STATUS_SUCCESS) + ret = MLAN_STATUS_PENDING; + + exit: + 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(IN pmlan_adapter pmadapter, + IN 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 (pmadapter->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 (pmadapter->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 (pmadapter->config_bands & BAND_A) { + /* Return the lowest supported rate for A band */ + rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f; + } else if (pmadapter->config_bands & BAND_G) { + /* Return the lowest supported rate for G band */ + rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f; + } else if (pmadapter->config_bands & BAND_B) { + /* Return the lowest supported rate for B band */ + rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f; + } else if (pmadapter->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", pmadapter->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(IN pmlan_adapter pmadapter, + IN 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; + /* Support all HT-MCSs rate */ + for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3; i++) + bitmap_rates[i + 2] = 0xFFFF; + bitmap_rates[9] = 0x3FFF; + } else { + memset(pmadapter, rates, 0, sizeof(rates)); + wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode, + (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ? + pmadapter->config_bands : pmadapter-> + adhoc_start_band, 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 (!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(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]; + + 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(IN pmlan_adapter pmadapter, + IN pmlan_ioctl_req pioctl_req) +{ + t_u32 rate_index; + 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(pmadapter->usr_dev_mcs_support); + + ENTER(); + + ds_rate = (mlan_ds_rate *) pioctl_req->pbuf; + 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; + } else { + PRINTM(MINFO, "Rate index is %d\n", rate_index); + if ((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, pmadapter->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)); + /* Bitmap of HR/DSSS rates */ + if ((rate_index >= MLAN_RATE_INDEX_HRDSSS0) && + (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; + } + if ((rate_index >= MLAN_RATE_INDEX_MCS0) && + (rate_index <= MLAN_RATE_INDEX_MCS32)) { + rate_index -= MLAN_RATE_INDEX_MCS0; + bitmap_rates[2 + (rate_index / 16)] = 1 << (rate_index % 16); + ret = MLAN_STATUS_SUCCESS; + } + + 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, " + "IsRateAuto=%d, DataRate=%d\n", + 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 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(IN pmlan_adapter pmadapter, IN 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_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 This function prepares command of rf_antenna. + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action The action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +wlan_cmd_802_11_rf_antenna(IN pmlan_private pmpriv, + IN HostCmd_DS_COMMAND * cmd, + IN t_u16 cmd_action, IN t_void * pdata_buf) +{ + HostCmd_DS_802_11_RF_ANTENNA *pantenna = &cmd->params.antenna; + mlan_ds_ant_cfg *ant_cfg = (mlan_ds_ant_cfg *) pdata_buf; + + ENTER(); + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA); + cmd->size = + wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_SET) { + pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_SET_TX); + pantenna->tx_antenna_mode = + wlan_cpu_to_le16((t_u16) ant_cfg->tx_antenna); + pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_SET_RX); + pantenna->rx_antenna_mode = + wlan_cpu_to_le16((t_u16) ant_cfg->rx_antenna); + } else { + pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_GET_TX); + pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_GET_RX); + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of rf_antenna + * + * @param pmpriv A pointer to mlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @param pioctl_buf A pointer to mlan_ioctl_req structure + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +wlan_ret_802_11_rf_antenna(IN pmlan_private pmpriv, + IN HostCmd_DS_COMMAND * resp, + IN mlan_ioctl_req * pioctl_buf) +{ + HostCmd_DS_802_11_RF_ANTENNA *pantenna = &resp->params.antenna; + t_u16 tx_ant_mode = wlan_le16_to_cpu(pantenna->tx_antenna_mode); + t_u16 rx_ant_mode = wlan_le16_to_cpu(pantenna->rx_antenna_mode); + mlan_ds_radio_cfg *radio = MNULL; + + ENTER(); + + PRINTM(MINFO, "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x" + " Rx action = 0x%x, Rx Mode = 0x%04x\n", + wlan_le16_to_cpu(pantenna->action_tx), tx_ant_mode, + wlan_le16_to_cpu(pantenna->action_rx), rx_ant_mode); + + if (pioctl_buf) { + radio = (mlan_ds_radio_cfg *) pioctl_buf->pbuf; + radio->param.ant_cfg.tx_antenna = tx_ant_mode; + radio->param.ant_cfg.rx_antenna = rx_ant_mode; + } + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +#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(IN pmlan_adapter pmadapter, + IN 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, + HOST_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 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(IN pmlan_adapter pmadapter, + IN 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; + + /* 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; +} +#endif |