blob: da49444ba0610a46958cf964ea5d6e9b7d497068 [file] [log] [blame]
/**
* @file mlan_misc.c
*
* @brief This file include miscellaneous functions for MLAN module
*
* Copyright (C) 2009-2014, 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 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(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(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 < 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);
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx)
ie_data->ie_index = 0;
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;
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 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;
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->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->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->bypass_pkt_count = pmadapter->bypass_pkt_count;
debug_info->scan_processing = pmadapter->scan_processing;
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_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->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_tx_timeout = pmadapter->dbg.num_tx_timeout;
debug_info->num_cmd_timeout = pmadapter->dbg.num_cmd_timeout;
debug_info->timeout_cmd_id = pmadapter->dbg.timeout_cmd_id;
debug_info->timeout_cmd_act = pmadapter->dbg.timeout_cmd_act;
memcpy(pmadapter, debug_info->last_cmd_id,
pmadapter->dbg.last_cmd_id,
sizeof(pmadapter->dbg.last_cmd_id));
memcpy(pmadapter, debug_info->last_cmd_act,
pmadapter->dbg.last_cmd_act,
sizeof(pmadapter->dbg.last_cmd_act));
debug_info->last_cmd_index = pmadapter->dbg.last_cmd_index;
memcpy(pmadapter, debug_info->last_cmd_resp_id,
pmadapter->dbg.last_cmd_resp_id,
sizeof(pmadapter->dbg.last_cmd_resp_id));
debug_info->last_cmd_resp_index =
pmadapter->dbg.last_cmd_resp_index;
memcpy(pmadapter, debug_info->last_event,
pmadapter->dbg.last_event,
sizeof(pmadapter->dbg.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;
debug_info->mp_rd_bitmap = pmadapter->mp_rd_bitmap;
debug_info->mp_wr_bitmap = pmadapter->mp_wr_bitmap;
debug_info->curr_rd_port = pmadapter->curr_rd_port;
debug_info->curr_wr_port = pmadapter->curr_wr_port;
#ifdef SDIO_MULTI_PORT_TX_AGGR
memcpy(pmadapter, debug_info->mpa_tx_count,
pmadapter->mpa_tx_count,
sizeof(pmadapter->mpa_tx_count));
debug_info->mpa_sent_last_pkt = pmadapter->mpa_sent_last_pkt;
debug_info->mpa_sent_no_ports = pmadapter->mpa_sent_no_ports;
debug_info->last_recv_wr_bitmap =
pmadapter->last_recv_wr_bitmap;
debug_info->last_mp_index = pmadapter->last_mp_index;
memcpy(pmadapter, debug_info->last_mp_wr_bitmap,
pmadapter->last_mp_wr_bitmap,
sizeof(pmadapter->last_mp_wr_bitmap));
memcpy(pmadapter, debug_info->last_mp_wr_ports,
pmadapter->last_mp_wr_ports,
sizeof(pmadapter->last_mp_wr_ports));
memcpy(pmadapter, debug_info->last_mp_wr_len,
pmadapter->last_mp_wr_len,
sizeof(pmadapter->last_mp_wr_len));
memcpy(pmadapter, debug_info->last_mp_wr_info,
pmadapter->last_mp_wr_info,
sizeof(pmadapter->last_mp_wr_info));
memcpy(pmadapter, debug_info->last_curr_wr_port,
pmadapter->last_curr_wr_port,
sizeof(pmadapter->last_curr_wr_port));
#endif
#ifdef SDIO_MULTI_PORT_RX_AGGR
memcpy(pmadapter, debug_info->mpa_rx_count,
pmadapter->mpa_rx_count,
sizeof(pmadapter->mpa_rx_count));
#endif
debug_info->data_sent = pmadapter->data_sent;
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 = pmadapter->pending_bridge_pkts;
debug_info->num_drop_pkts = pmpriv->num_drop_pkts;
#endif
debug_info->mlan_processing = pmadapter->mlan_processing;
debug_info->mlan_rx_processing = pmadapter->mlan_rx_processing;
debug_info->rx_pkts_queued =
util_scalar_read(pmadapter->pmoal_handle,
&pmadapter->rx_pkts_queued, MNULL,
MNULL);
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(IN pmlan_adapter pmadapter,
IN 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 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;
t_u32 age_ts_usec;
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
PRINTM(MEVENT, "Wakeup device...\n");
pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
&pmadapter->pm_wakeup_in_secs,
&age_ts_usec);
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 =
(data_len + MLAN_SDIO_BLOCK_SIZE -
1) / MLAN_SDIO_BLOCK_SIZE * MLAN_SDIO_BLOCK_SIZE;
/* head_room is not implemented for malloc mlan buffer */
switch (malloc_flag) {
case MOAL_MALLOC_BUFFER:
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;
break;
case 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;
break;
}
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)
pmadapter->pending_bridge_pkts--;
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;
}
/**
* @brief Send coalescing status 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_coalescing_status(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 = MNULL;
t_u16 cmd_action = 0;
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_802_11_IBSS_COALESCING_STATUS,
cmd_action,
0,
(t_void *) pioctl_req,
&misc->param.coalescing_status);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @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(IN pmlan_adapter pmadapter,
IN 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(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 {
if (GET_BSS_ROLE(pmpriv) == bss->param.bss_role) {
PRINTM(MIOCTL, "BSS ie already in the desired role!\n");
goto done;
}
/** 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;
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(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;
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;
} 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(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;
}
mask &= ~MLAN_CUSTOM_IE_NEW_MASK;
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_TO_FW);
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].
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(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 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(IN pmlan_adapter pmadapter,
IN 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:
cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
break;
case MLAN_REG_BBP:
cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
break;
case MLAN_REG_RF:
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;
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 *) & reg_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(IN pmlan_adapter pmadapter,
IN 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 *) & reg_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(IN pmlan_adapter pmadapter,
IN 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 *) & reg_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,
priv->adapter->callbacks.
moal_spin_lock,
priv->adapter->callbacks.
moal_spin_unlock);
if (!sta_ptr) {
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);
sta_ptr = wlan_get_station_entry(priv, mac);
if (sta_ptr) {
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 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(priv->adapter, peer_info->mac_addr, sta_ptr->mac_addr,
MLAN_MAC_ADDR_LENGTH);
memcpy(priv->adapter, peer_info->ht_cap, &sta_ptr->HTcap,
sizeof(IEEEtypes_HTCap_t));
memcpy(priv->adapter, peer_info->ext_cap, &sta_ptr->ExtCap,
sizeof(IEEEtypes_ExtCap_t));
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(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 = (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;
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(pmpriv->adapter,
(t_u8 *) tdls_evt->peer_mac_addr,
tdls_all_cfg->u.tdls_tear_down.peer_mac_addr,
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;
}
}
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 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(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 = (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->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);
} 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(pmpriv->adapter,
(t_u8 *) tdls_evt->peer_mac_addr,
ptdls_oper->peer_mac,
MLAN_MAC_ADDR_LENGTH);
tdls_evt->reason_code =
WLAN_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) {
wlan_cleanup_reorder_tbl(pmpriv,
ptdls_oper->
peer_mac);
pmadapter->callbacks.
moal_spin_lock(pmadapter->
pmoal_handle,
pmpriv->wmm.
ra_list_spinlock);
wlan_11n_cleanup_txbastream_tbl(pmpriv,
ptdls_oper->
peer_mac);
pmadapter->callbacks.
moal_spin_unlock(pmadapter->
pmoal_handle,
pmpriv->wmm.
ra_list_spinlock);
}
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:
if (sta_ptr) {
wlan_restore_tdls_packets(pmpriv, ptdls_oper->peer_mac,
TDLS_TEAR_DOWN);
if (sta_ptr->is_11n_enabled) {
wlan_cleanup_reorder_tbl(pmpriv,
ptdls_oper->peer_mac);
pmadapter->callbacks.moal_spin_lock(pmadapter->
pmoal_handle,
pmpriv->wmm.
ra_list_spinlock);
wlan_11n_cleanup_txbastream_tbl(pmpriv,
ptdls_oper->
peer_mac);
pmadapter->callbacks.
moal_spin_unlock(pmadapter->
pmoal_handle,
pmpriv->wmm.
ra_list_spinlock);
}
if (sta_ptr->status >= TDLS_SETUP_INPROGRESS)
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;
/* 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;
default:
break;
}
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_get_ies(IN pmlan_adapter pmadapter,
IN 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;
IEEEtypes_HTCap_t *ht_cap = MNULL;
IEEEtypes_HTInfo_t *ht_info = MNULL;
sta_node *sta_ptr = MNULL;
ENTER();
sta_ptr = wlan_get_station_entry(pmpriv, tdls_ies->peer_mac);
pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
if (pbss_desc->bss_band & BAND_A)
usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
else
usr_dot_11n_dev_cap = pmadapter->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);
/* TODO UAPSD need be enabled */
RESET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap);
RESET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap->ext_cap);
DBG_HEXDUMP(MCMD_D, "TDLS extcap", tdls_ies->ext_cap,
sizeof(IEEEtypes_ExtCap_t));
}
/** 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));
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));
}
/** 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;
}
if (sta_ptr)
memcpy(pmadapter, &sta_ptr->HTInfo, tdls_ies->ht_info,
sizeof(IEEEtypes_HTInfo_t));
DBG_HEXDUMP(MCMD_D, "TDLS htinfo", tdls_ies->ht_info,
sizeof(IEEEtypes_HTInfo_t));
}
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(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 */
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(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 " 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;
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, pevent->event_id, pevent);
if (event_buf)
pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#ifdef STA_SUPPORT
/**
* @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(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();
if (MLAN_ACT_GET == pioctl_req->action)
memcpy(pmpriv->adapter, &misc->param.ext_cap, &pmpriv->ext_cap,
sizeof(misc->param.ext_cap));
else if (MLAN_ACT_SET == pioctl_req->action) {
memcpy(pmpriv->adapter, &pmpriv->ext_cap, &misc->param.ext_cap,
sizeof(misc->param.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();
/* So far there are only three bits are meaningful */
if (ISSUPP_EXTCAP_TDLS(pmpriv->ext_cap)
|| ISSUPP_EXTCAP_INTERWORKING(pmpriv->ext_cap)
) {
LEAVE();
return MTRUE;
} else {
LEAVE();
return MFALSE;
}
}
#endif
/**
* @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(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();
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;
}
#ifdef STA_SUPPORT
/**
* @brief Add Extended Capabilities IE
*
* @param pmpriv A pointer to mlan_private structure
* @param pptlv_out A pointer to TLV to fill in
*
* @return N/A
*/
void
wlan_add_ext_capa_info_ie(IN mlan_private * pmpriv, OUT 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));
memcpy(pmpriv->adapter, &pext_cap->ext_cap, &pmpriv->ext_cap,
sizeof(pmpriv->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(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_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;
}
/**
* @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
*
* @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 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(IN pmlan_adapter pmadapter,
IN 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(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;
t_u16 *ant_cfg;
ENTER();
radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
/* User input validation */
if ((!radio_cfg->param.antenna ||
radio_cfg->param.antenna & ~RF_ANTENNA_MASK(pmadapter->
number_of_antenna))
&& (radio_cfg->param.antenna != RF_ANTENNA_AUTO ||
pmadapter->number_of_antenna <= 1)) {
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 */
ant_cfg = (t_u16 *) & radio_cfg->param.antenna;
/* 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 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(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 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(IN pmlan_adapter pmadapter,
IN 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, "
"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 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 (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(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) ? pmpriv->
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];
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);
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_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(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;
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;
}
#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;
}
/**
* @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(IN pmlan_adapter pmadapter, IN 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,
HOST_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 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(IN pmlan_adapter pmadapter,
IN 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;
}