blob: 6f1bb4861dc94de1121a80ca1535749fa3ee954f [file] [log] [blame]
/** @file mlan_uap_ioctl.c
*
* @brief This file contains the handling of AP mode ioctls
*
* 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:
02/05/2009: initial version
********************************************************/
#include "mlan.h"
#include "mlan_util.h"
#include "mlan_fw.h"
#ifdef STA_SUPPORT
#include "mlan_join.h"
#endif
#include "mlan_main.h"
#include "mlan_uap.h"
#include "mlan_sdio.h"
#include "mlan_11n.h"
#include "mlan_fw.h"
#include "mlan_11h.h"
/********************************************************
Global Variables
********************************************************/
extern t_u8 tos_to_tid_inv[];
/********************************************************
Local Functions
********************************************************/
/**
* @brief Stop BSS
*
* @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_uap_bss_ioctl_stop(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
ret = wlan_prepare_cmd(pmpriv,
HOST_CMD_APCMD_BSS_STOP,
HostCmd_ACT_GEN_SET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Callback to finish BSS IOCTL START
* Not to be called directly to initiate bss_start
*
* @param priv A pointer to mlan_private structure (cast from t_void*)
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
* @sa wlan_uap_bss_ioctl_start
*/
static mlan_status
wlan_uap_callback_bss_ioctl_start(IN t_void * priv)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = (mlan_private *) priv;
mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
t_u8 old_channel;
ENTER();
/* clear callback now that we're here */
puap_state_chan_cb->get_chan_callback = MNULL;
/*
* Check if the region and channel requires we check for radar.
*/
if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
wlan_11h_radar_detect_required(pmpriv,
puap_state_chan_cb->channel)) {
/* first check if channel is under NOP */
if (wlan_11h_is_channel_under_nop(pmpriv->adapter,
puap_state_chan_cb->
channel)) {
/* recently we've seen radar on this channel */
ret = MLAN_STATUS_FAILURE;
}
/* Check cached radar check on the channel */
if (ret == MLAN_STATUS_SUCCESS)
ret = wlan_11h_check_chan_report(pmpriv,
puap_state_chan_cb->
channel);
/* Found radar: try to switch to a non-dfs channel */
if (ret != MLAN_STATUS_SUCCESS) {
old_channel = puap_state_chan_cb->channel;
ret = wlan_11h_switch_non_dfs_chan(pmpriv,
&puap_state_chan_cb->
channel);
if (ret == MLAN_STATUS_SUCCESS) {
ret = wlan_uap_set_channel(pmpriv,
pmpriv->
uap_state_chan_cb.
band_config,
puap_state_chan_cb->
channel);
if (ret == MLAN_STATUS_SUCCESS) {
PRINTM(MMSG,
"Radar found on channel %d,"
"switch to new channel %d.\n",
old_channel,
puap_state_chan_cb->channel);
} else {
PRINTM(MMSG,
"Radar found on channel %d,"
" switch to new channel %d failed.\n",
old_channel,
puap_state_chan_cb->channel);
pcb->moal_ioctl_complete(pmpriv->
adapter->
pmoal_handle,
puap_state_chan_cb->
pioctl_req_curr,
MLAN_STATUS_FAILURE);
goto done;
}
} else {
PRINTM(MMSG,
"Radar found on channel %d, no switch channel available.\n",
old_channel);
/* No command sent with the ioctl, need
manually signal completion */
pcb->moal_ioctl_complete(pmpriv->adapter->
pmoal_handle,
puap_state_chan_cb->
pioctl_req_curr,
MLAN_STATUS_FAILURE);
goto done;
}
} else {
PRINTM(MINFO, "No Radar found on channel %d\n",
puap_state_chan_cb->channel);
}
}
/* else okay to send command: not DFS channel or no radar */
ret = wlan_prepare_cmd(pmpriv,
HOST_CMD_APCMD_BSS_START,
HostCmd_ACT_GEN_SET,
0,
(t_void *) puap_state_chan_cb->pioctl_req_curr,
MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
done:
puap_state_chan_cb->pioctl_req_curr = MNULL; /* prevent re-use */
LEAVE();
return ret;
}
/**
* @brief Start BSS
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
/**
* @sa wlan_uap_callback_bss_ioctl_start
*/
static mlan_status
wlan_uap_bss_ioctl_start(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
/* First check channel report, defer BSS_START CMD to callback. */
/* store params, issue command to get UAP channel, whose CMD_RESP will
callback remainder of bss_start handling */
pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
pmpriv->uap_state_chan_cb.get_chan_callback =
wlan_uap_callback_bss_ioctl_start;
ret = wlan_uap_get_channel(pmpriv);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief reset BSS
*
* @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_uap_bss_ioctl_reset(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
t_u8 i = 0;
ENTER();
/*
* Reset any uap private parameters here
*/
for (i = 0; i < pmadapter->max_mgmt_ie_index; i++)
memset(pmadapter, &pmpriv->mgmt_ie[i], 0, sizeof(custom_ie));
pmpriv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
pmpriv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
pmpriv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
for (i = 0; i < MAX_NUM_TID; i++) {
pmpriv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
pmpriv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
pmpriv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
}
pmpriv->aggr_prio_tbl[6].ampdu_user =
pmpriv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
/* hs_configured, hs_activated are reset by main loop */
pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
ret = wlan_prepare_cmd(pmpriv,
HOST_CMD_APCMD_SYS_RESET,
HostCmd_ACT_GEN_SET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get MAC address
*
* @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_uap_bss_ioctl_mac_address(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;
t_u16 cmd_action = 0;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
memcpy(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
MLAN_MAC_ADDR_LENGTH);
cmd_action = HostCmd_ACT_GEN_SET;
} else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
cmd_action, 0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get Uap statistics
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_uap_get_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_GET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get AP config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_uap_bss_ioctl_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;
t_u16 cmd_action = 0;
ENTER();
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
cmd_action, 0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief deauth sta
*
* @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_uap_bss_ioctl_deauth_sta(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_bss *bss = MNULL;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
ret = wlan_prepare_cmd(pmpriv,
HOST_CMD_APCMD_STA_DEAUTH,
HostCmd_ACT_GEN_SET,
0,
(t_void *) pioctl_req,
(t_void *) & bss->param.deauth_param);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get station list
*
* @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_uap_get_sta_list(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;
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HOST_CMD_APCMD_STA_LIST,
HostCmd_ACT_GEN_GET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief soft_reset
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_uap_misc_ioctl_soft_reset(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();
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_SOFT_RESET,
HostCmd_ACT_GEN_SET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Tx data pause
*
* @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_uap_misc_ioctl_txdatapause(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_CFG_TX_DATA_PAUSE,
cmd_action,
0,
(t_void *) pioctl_req,
&(pmisc->param.tx_datapause));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get Power mode
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_uap_pm_ioctl_mode(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 ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
t_u32 cmd_oid = 0;
ENTER();
pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
if (pm->param.ps_mgmt.ps_mode == PS_MODE_INACTIVITY) {
cmd_action = EN_AUTO_PS;
cmd_oid = BITMAP_UAP_INACT_PS;
} else if (pm->param.ps_mgmt.ps_mode == PS_MODE_PERIODIC_DTIM) {
cmd_action = EN_AUTO_PS;
cmd_oid = BITMAP_UAP_DTIM_PS;
} else {
cmd_action = DIS_AUTO_PS;
cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
}
} else {
cmd_action = GET_PS;
cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_PS_MODE_ENH,
cmd_action, cmd_oid, (t_void *) pioctl_req,
(t_void *) & pm->param.ps_mgmt);
if ((ret == MLAN_STATUS_SUCCESS) &&
(pioctl_req->action == MLAN_ACT_SET) &&
(cmd_action == DIS_AUTO_PS)) {
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
0, MNULL, MNULL);
}
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set WAPI IE
*
* @param priv A pointer to mlan_private structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_uap_set_wapi_ie(mlan_private * priv, pmlan_ioctl_req pioctl_req)
{
mlan_ds_misc_cfg *misc = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
if (misc->param.gen_ie.len) {
if (misc->param.gen_ie.len > sizeof(priv->wapi_ie)) {
PRINTM(MWARN, "failed to copy WAPI IE, too big\n");
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
memcpy(priv->adapter, priv->wapi_ie, misc->param.gen_ie.ie_data,
misc->param.gen_ie.len);
priv->wapi_ie_len = misc->param.gen_ie.len;
PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
priv->wapi_ie[0]);
DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie,
priv->wapi_ie_len);
if (priv->wapi_ie[0] == WAPI_IE)
priv->sec_info.wapi_enabled = MTRUE;
} else {
memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
priv->wapi_ie_len = misc->param.gen_ie.len;
PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n",
priv->wapi_ie_len, priv->wapi_ie[0]);
priv->sec_info.wapi_enabled = MFALSE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(priv, HOST_CMD_APCMD_SYS_CONFIGURE,
HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req,
MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set generic IE
*
* @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_uap_misc_ioctl_gen_ie(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;
IEEEtypes_VendorHeader_t *pvendor_ie = MNULL;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
if ((misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE) &&
(pioctl_req->action == MLAN_ACT_SET)) {
if (misc->param.gen_ie.len) {
pvendor_ie =
(IEEEtypes_VendorHeader_t *) misc->param.gen_ie.
ie_data;
if (pvendor_ie->element_id == WAPI_IE) {
/* IE is a WAPI IE so call set_wapi function */
ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
}
} else {
/* clear WAPI IE */
ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
}
}
LEAVE();
return ret;
}
/**
* @brief Set/Get WAPI status
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success
*/
static mlan_status
wlan_uap_sec_ioctl_wapi_enable(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_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
if (pmpriv->wapi_ie_len)
sec->param.wapi_enabled = MTRUE;
else
sec->param.wapi_enabled = MFALSE;
} else {
if (sec->param.wapi_enabled == MFALSE) {
memset(pmpriv->adapter, pmpriv->wapi_ie, 0,
sizeof(pmpriv->wapi_ie));
pmpriv->wapi_ie_len = 0;
PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n",
pmpriv->wapi_ie_len, pmpriv->wapi_ie[0]);
pmpriv->sec_info.wapi_enabled = MFALSE;
}
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set encrypt key
*
* @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_uap_sec_ioctl_set_encrypt_key(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_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action != MLAN_ACT_SET) {
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (!sec->param.encrypt_key.key_remove &&
!sec->param.encrypt_key.key_len) {
PRINTM(MCMND, "Skip set key with key_len = 0\n");
LEAVE();
return ret;
}
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET,
KEY_INFO_ENABLED,
(t_void *) pioctl_req, &sec->param.encrypt_key);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get BSS information
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success
*/
static mlan_status
wlan_uap_get_bss_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;
ENTER();
info = (mlan_ds_get_info *) pioctl_req->pbuf;
/* Connection status */
info->param.bss_info.media_connected = pmpriv->media_connected;
/* Radio status */
info->param.bss_info.radio_on = pmadapter->radio_on;
/* BSSID */
memcpy(pmadapter, &info->param.bss_info.bssid, pmpriv->curr_addr,
MLAN_MAC_ADDR_LENGTH);
info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
pioctl_req->data_read_written =
sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set Host Sleep configurations
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCES/MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_uap_pm_ioctl_deepsleep(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_pm_cfg *pm = MNULL;
mlan_ds_auto_ds auto_ds;
t_u32 mode;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_RESOURCE;
}
pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
if (pmadapter->is_deep_sleep) {
pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
pm->param.auto_deep_sleep.idletime =
pmadapter->idle_time;
} else
pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
} else {
if (pmadapter->is_deep_sleep &&
pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
PRINTM(MMSG, "uAP already in deep sleep mode\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.
auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
auto_ds.auto_ds = DEEP_SLEEP_ON;
mode = EN_AUTO_PS;
PRINTM(MINFO, "Auto Deep Sleep: on\n");
} else {
mode = DIS_AUTO_PS;
auto_ds.auto_ds = DEEP_SLEEP_OFF;
PRINTM(MINFO, "Auto Deep Sleep: off\n");
}
if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.
auto_deep_sleep.idletime)
auto_ds.idletime =
((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.
auto_deep_sleep.idletime;
else
auto_ds.idletime = pmadapter->idle_time;
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_PS_MODE_ENH,
(t_u16) mode,
BITMAP_AUTO_DS,
(t_void *) pioctl_req, &auto_ds);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
}
LEAVE();
return ret;
}
/**
* @brief Set SNMP MIB for 11D
*
* @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_uap_snmp_mib_11d(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_snmp_mib *snmp = MNULL;
state_11d_t flag;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
PRINTM(MIOCTL,
"11D setting cannot be changed while UAP bss is started.\n");
pioctl_req->data_read_written = 0;
LEAVE();
return MLAN_STATUS_FAILURE;
}
snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
flag = (snmp->param.oid_value) ? ENABLE_11D : DISABLE_11D;
ret = wlan_11d_enable(pmpriv, (t_void *) pioctl_req, flag);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Callback to finish domain_info handling
* Not to be called directly to initiate domain_info setting.
*
* @param pmpriv A pointer to mlan_private structure (cast from t_void*)
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
* @sa wlan_uap_domain_info
*/
static mlan_status
wlan_uap_callback_domain_info(IN t_void * priv)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = (mlan_private *) priv;
wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
mlan_ds_11d_cfg *cfg11d;
t_u8 band;
pmlan_adapter pmadapter = pmpriv->adapter;
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
/* clear callback now that we're here */
puap_state_chan_cb->get_chan_callback = MNULL;
if (!puap_state_chan_cb->pioctl_req_curr) {
PRINTM(MERROR, "pioctl_req_curr is null\n");
LEAVE();
return ret;
}
cfg11d = (mlan_ds_11d_cfg *) puap_state_chan_cb->pioctl_req_curr->pbuf;
band = (puap_state_chan_cb->
band_config & BAND_CONFIG_5GHZ) ? BAND_A : BAND_B;
ret = wlan_11d_handle_uap_domain_info(pmpriv, band,
cfg11d->param.domain_tlv,
puap_state_chan_cb->
pioctl_req_curr);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
else {
puap_state_chan_cb->pioctl_req_curr->status_code =
MLAN_STATUS_FAILURE;
pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
puap_state_chan_cb->pioctl_req_curr,
MLAN_STATUS_FAILURE);
}
puap_state_chan_cb->pioctl_req_curr = MNULL; /* prevent re-use */
LEAVE();
return ret;
}
/**
* @brief Set Domain Info for 11D
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
* @sa wlan_uap_callback_domain_info
*/
static mlan_status
wlan_uap_domain_info(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();
if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
PRINTM(MWARN, "MLAN 11d_cfg IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
PRINTM(MIOCTL,
"Domain_info cannot be changed while UAP bss is started.\n");
pioctl_req->data_read_written = 0;
LEAVE();
return MLAN_STATUS_FAILURE;
}
/* store params, issue command to get UAP channel, whose CMD_RESP will
callback remainder of domain_info handling */
pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
pmpriv->uap_state_chan_cb.get_chan_callback =
wlan_uap_callback_domain_info;
ret = wlan_uap_get_channel(pmpriv);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Callback to finish 11H channel check handling.
* Not to be called directly to initiate channel check.
*
* @param priv A pointer to mlan_private structure (cast from t_void*)
*
* @return MLAN_STATUS_SUCCESS/PENDING --success, otherwise fail
* @sa wlan_uap_11h_channel_check_req
*/
static mlan_status
wlan_uap_callback_11h_channel_check_req(IN t_void * priv)
{
mlan_status ret = MLAN_STATUS_FAILURE;
mlan_private *pmpriv = (mlan_private *) priv;
mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
Band_Config_t *pband_cfg =
(Band_Config_t *) (&puap_state_chan_cb->band_config);
/* keep copy as local variable */
pmlan_ioctl_req pioctl = puap_state_chan_cb->pioctl_req_curr;
ENTER();
/* clear callback now that we're here */
puap_state_chan_cb->get_chan_callback = MNULL;
/* clear early to avoid race condition */
puap_state_chan_cb->pioctl_req_curr = MNULL;
/*
* Check if the region and channel requires a channel availability
* check.
*/
if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
wlan_11h_radar_detect_required(pmpriv, puap_state_chan_cb->channel)
&& !wlan_11h_is_channel_under_nop(pmpriv->adapter,
puap_state_chan_cb->channel)) {
/*
* Radar detection is required for this channel, make sure
* 11h is activated in the firmware
*/
ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
ret = wlan_11h_check_update_radar_det_state(pmpriv);
/* Check for radar on the channel */
ret = wlan_11h_issue_radar_detect(pmpriv,
pioctl,
puap_state_chan_cb->channel,
pband_cfg->chanWidth);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
} else {
/* No command sent with the ioctl, need manually signal
completion */
pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
pioctl, MLAN_STATUS_FAILURE);
}
LEAVE();
return ret;
}
/**
* @brief 802.11h uap start channel check
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
* @sa wlan_uap_callback_11h_channel_check_req
*/
static mlan_status
wlan_uap_11h_channel_check_req(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();
if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
PRINTM(MWARN, "MLAN 11h_cfg IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
/* store params, issue command to get UAP channel, whose CMD_RESP will
callback remainder of 11H channel check handling */
pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
pmpriv->uap_state_chan_cb.get_chan_callback =
wlan_uap_callback_11h_channel_check_req;
ret = wlan_uap_get_channel(pmpriv);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Callback to finish 11H handling
* Not to be called directly to initiate 11H setting.
*
* @param pmpriv A pointer to mlan_private structure (cast from t_void*)
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
* @sa wlan_uap_snmp_mib_11h
*/
static mlan_status
wlan_uap_callback_snmp_mib_11h(IN t_void * priv)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = (mlan_private *) priv;
wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
mlan_ds_snmp_mib *snmp;
t_bool enable_11h;
ENTER();
/* clear callback now that we're here */
puap_state_chan_cb->get_chan_callback = MNULL;
snmp = (mlan_ds_snmp_mib *) puap_state_chan_cb->pioctl_req_curr->pbuf;
enable_11h = (snmp->param.oid_value) ? MTRUE : MFALSE;
if (enable_11h) {
if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
wlan_11h_radar_detect_required(pmpriv,
puap_state_chan_cb->
channel)) {
if (!wlan_11h_is_master_radar_det_active(pmpriv))
wlan_11h_config_master_radar_det(pmpriv, MTRUE);
}
}
ret = wlan_11h_activate(pmpriv,
(t_void *) puap_state_chan_cb->pioctl_req_curr,
enable_11h);
wlan_11h_check_update_radar_det_state(pmpriv);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
puap_state_chan_cb->pioctl_req_curr = MNULL; /* prevent re-use */
LEAVE();
return ret;
}
/**
* @brief Set SNMP MIB for 11H
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
* @sa wlan_uap_callback_snmp_mib_11h
*/
static mlan_status
wlan_uap_snmp_mib_11h(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_snmp_mib *snmp = MNULL;
t_bool enable;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
enable = (snmp->param.oid_value) ? MTRUE : MFALSE;
if (enable) {
/* first enable 11D if it is not enabled */
if (!wlan_11d_is_enabled(pmpriv)) {
ret = wlan_11d_enable(pmpriv, MNULL, ENABLE_11D);
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR,
"Failed to first enable 11D before enabling 11H.\n");
LEAVE();
return ret;
}
}
}
/* store params, issue command to get UAP channel, whose CMD_RESP will
callback remainder of 11H handling (and radar detect if DFS chan) */
pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
pmpriv->uap_state_chan_cb.get_chan_callback =
wlan_uap_callback_snmp_mib_11h;
ret = wlan_uap_get_channel(pmpriv);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief Issue CMD to UAP firmware to get current channel
*
* @param pmpriv A pointer to mlan_private structure
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status
wlan_uap_get_channel(IN pmlan_private pmpriv)
{
MrvlIEtypes_channel_band_t tlv_chan_band;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t)
- sizeof(MrvlIEtypesHeader_t);
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
HostCmd_ACT_GEN_GET, 0, MNULL, &tlv_chan_band);
LEAVE();
return ret;
}
/**
* @brief Issue CMD to UAP firmware to set current channel
*
* @param pmpriv A pointer to mlan_private structure
* @param uap_band_cfg UAP band configuration
* @param channel New channel
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status
wlan_uap_set_channel(IN pmlan_private pmpriv,
IN t_u8 uap_band_cfg, IN t_u8 channel)
{
MrvlIEtypes_channel_band_t tlv_chan_band;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t)
- sizeof(MrvlIEtypesHeader_t);
tlv_chan_band.band_config = uap_band_cfg;
tlv_chan_band.channel = channel;
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
HostCmd_ACT_GEN_SET, 0, MNULL, &tlv_chan_band);
LEAVE();
return ret;
}
/**
* @brief Issue CMD to UAP firmware to get current beacon and dtim periods
*
* @param pmpriv A pointer to mlan_private structure
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status
wlan_uap_get_beacon_dtim(IN pmlan_private pmpriv)
{
t_u8 tlv_buffer[sizeof(MrvlIEtypes_beacon_period_t) +
sizeof(MrvlIEtypes_dtim_period_t)];
MrvlIEtypes_beacon_period_t *ptlv_beacon_pd;
MrvlIEtypes_dtim_period_t *ptlv_dtim_pd;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
memset(pmpriv->adapter, &tlv_buffer, 0, sizeof(tlv_buffer));
ptlv_beacon_pd = (MrvlIEtypes_beacon_period_t *) tlv_buffer;
ptlv_beacon_pd->header.type = TLV_TYPE_UAP_BEACON_PERIOD;
ptlv_beacon_pd->header.len = sizeof(MrvlIEtypes_beacon_period_t)
- sizeof(MrvlIEtypesHeader_t);
ptlv_dtim_pd = (MrvlIEtypes_dtim_period_t *) (tlv_buffer
+
sizeof
(MrvlIEtypes_beacon_period_t));
ptlv_dtim_pd->header.type = TLV_TYPE_UAP_DTIM_PERIOD;
ptlv_dtim_pd->header.len = sizeof(MrvlIEtypes_dtim_period_t)
- sizeof(MrvlIEtypesHeader_t);
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
HostCmd_ACT_GEN_GET, 0, MNULL, tlv_buffer);
LEAVE();
return ret;
}
/**
* @brief MLAN uap ioctl handler
*
* @param adapter 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_ops_uap_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
{
pmlan_adapter pmadapter = (pmlan_adapter) adapter;
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_bss *bss = MNULL;
mlan_ds_get_info *pget_info = MNULL;
mlan_ds_misc_cfg *misc = MNULL;
mlan_ds_sec_cfg *sec = MNULL;
mlan_ds_pm_cfg *pm = MNULL;
mlan_ds_11d_cfg *cfg11d = MNULL;
mlan_ds_snmp_mib *snmp = MNULL;
mlan_ds_11h_cfg *cfg11h = MNULL;
mlan_ds_radio_cfg *radiocfg = MNULL;
mlan_ds_rate *rate = MNULL;
mlan_ds_reg_mem *reg_mem = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
mlan_ds_scan *pscan;
#endif
ENTER();
switch (pioctl_req->req_id) {
case MLAN_IOCTL_BSS:
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR)
status = wlan_uap_bss_ioctl_mac_address(pmadapter,
pioctl_req);
else if (bss->sub_command == MLAN_OID_BSS_STOP)
status = wlan_uap_bss_ioctl_stop(pmadapter, pioctl_req);
else if (bss->sub_command == MLAN_OID_BSS_START)
status = wlan_uap_bss_ioctl_start(pmadapter,
pioctl_req);
else if (bss->sub_command == MLAN_OID_UAP_BSS_CONFIG)
status = wlan_uap_bss_ioctl_config(pmadapter,
pioctl_req);
else if (bss->sub_command == MLAN_OID_UAP_DEAUTH_STA)
status = wlan_uap_bss_ioctl_deauth_sta(pmadapter,
pioctl_req);
else if (bss->sub_command == MLAN_OID_UAP_BSS_RESET)
status = wlan_uap_bss_ioctl_reset(pmadapter,
pioctl_req);
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
else if (bss->sub_command == MLAN_OID_BSS_ROLE)
status = wlan_bss_ioctl_bss_role(pmadapter, pioctl_req);
#endif
#ifdef WIFI_DIRECT_SUPPORT
else if (bss->sub_command == MLAN_OID_WIFI_DIRECT_MODE)
status = wlan_bss_ioctl_wifi_direct_mode(pmadapter,
pioctl_req);
#endif
else if (bss->sub_command == MLAN_OID_BSS_REMOVE)
status = wlan_bss_ioctl_bss_remove(pmadapter,
pioctl_req);
break;
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
case MLAN_IOCTL_SCAN:
pscan = (mlan_ds_scan *) pioctl_req->pbuf;
if ((pscan->sub_command == MLAN_OID_SCAN_NORMAL) &&
(pioctl_req->action == MLAN_ACT_GET)) {
PRINTM(MIOCTL, "Get scan table in uap\n");
pscan->param.scan_resp.pscan_table =
(t_u8 *) pmadapter->pscan_table;
pscan->param.scan_resp.num_in_scan_table =
pmadapter->num_in_scan_table;
pscan->param.scan_resp.age_in_secs =
pmadapter->age_in_secs;
pioctl_req->data_read_written =
sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
pscan->param.scan_resp.pchan_stats =
(t_u8 *) pmadapter->pchan_stats;
pscan->param.scan_resp.num_in_chan_stats =
pmadapter->num_in_chan_stats;
}
break;
#endif
case MLAN_IOCTL_GET_INFO:
pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
if (pget_info->sub_command == MLAN_OID_GET_VER_EXT)
status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
else if (pget_info->sub_command == MLAN_OID_GET_DEBUG_INFO)
status = wlan_get_info_debug_info(pmadapter,
pioctl_req);
else if (pget_info->sub_command == MLAN_OID_GET_STATS)
status = wlan_uap_get_stats(pmadapter, pioctl_req);
else if (pget_info->sub_command == MLAN_OID_UAP_STA_LIST)
status = wlan_uap_get_sta_list(pmadapter, pioctl_req);
else if (pget_info->sub_command == MLAN_OID_GET_BSS_INFO)
status = wlan_uap_get_bss_info(pmadapter, pioctl_req);
else if (pget_info->sub_command == MLAN_OID_GET_FW_INFO) {
pioctl_req->data_read_written =
sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
memcpy(pmadapter, &pget_info->param.fw_info.mac_addr,
pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
pget_info->param.fw_info.fw_ver =
pmadapter->fw_release_number;
pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
pget_info->param.fw_info.hw_dev_mcs_support =
pmadapter->hw_dev_mcs_support;
pget_info->param.fw_info.hw_dot_11n_dev_cap =
pmadapter->hw_dot_11n_dev_cap;
pget_info->param.fw_info.region_code =
pmadapter->region_code;
}
break;
case MLAN_IOCTL_MISC_CFG:
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
if (misc->sub_command == MLAN_OID_MISC_INIT_SHUTDOWN)
status = wlan_misc_ioctl_init_shutdown(pmadapter,
pioctl_req);
if (misc->sub_command == MLAN_OID_MISC_SOFT_RESET)
status = wlan_uap_misc_ioctl_soft_reset(pmadapter,
pioctl_req);
if (misc->sub_command == MLAN_OID_MISC_HOST_CMD)
status = wlan_misc_ioctl_host_cmd(pmadapter,
pioctl_req);
if (misc->sub_command == MLAN_OID_MISC_GEN_IE)
status = wlan_uap_misc_ioctl_gen_ie(pmadapter,
pioctl_req);
if (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)
status = wlan_misc_ioctl_custom_ie_list(pmadapter,
pioctl_req,
MTRUE);
if (misc->sub_command == MLAN_OID_MISC_TX_DATAPAUSE)
status = wlan_uap_misc_ioctl_txdatapause(pmadapter,
pioctl_req);
if (misc->sub_command == MLAN_OID_MISC_RX_MGMT_IND)
status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
#ifdef DEBUG_LEVEL1
if (misc->sub_command == MLAN_OID_MISC_DRVDBG)
status = wlan_set_drvdbg(pmadapter, pioctl_req);
#endif
if (misc->sub_command == MLAN_OID_MISC_TXCONTROL)
status = wlan_misc_ioctl_txcontrol(pmadapter,
pioctl_req);
if (misc->sub_command == MLAN_OID_MISC_MAC_CONTROL)
status = wlan_misc_ioctl_mac_control(pmadapter,
pioctl_req);
#ifdef WIFI_DIRECT_SUPPORT
if (misc->sub_command == MLAN_OID_MISC_WIFI_DIRECT_CONFIG)
status = wlan_misc_p2p_config(pmadapter, pioctl_req);
#endif
break;
case MLAN_IOCTL_PM_CFG:
pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
if (pm->sub_command == MLAN_OID_PM_CFG_PS_MODE)
status = wlan_uap_pm_ioctl_mode(pmadapter, pioctl_req);
if (pm->sub_command == MLAN_OID_PM_CFG_DEEP_SLEEP)
status = wlan_uap_pm_ioctl_deepsleep(pmadapter,
pioctl_req);
if (pm->sub_command == MLAN_OID_PM_CFG_HS_CFG)
status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
if (pm->sub_command == MLAN_OID_PM_HS_WAKEUP_REASON)
status = wlan_get_hs_wakeup_reason(pmadapter,
pioctl_req);
if (pm->sub_command == MLAN_OID_PM_INFO)
status = wlan_get_pm_info(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_SNMP_MIB:
snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11D)
status = wlan_uap_snmp_mib_11d(pmadapter, pioctl_req);
if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11H)
status = wlan_uap_snmp_mib_11h(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_SEC_CFG:
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (sec->sub_command == MLAN_OID_SEC_CFG_ENCRYPT_KEY)
status = wlan_uap_sec_ioctl_set_encrypt_key(pmadapter,
pioctl_req);
if (sec->sub_command == MLAN_OID_SEC_CFG_WAPI_ENABLED)
status = wlan_uap_sec_ioctl_wapi_enable(pmadapter,
pioctl_req);
break;
case MLAN_IOCTL_11N_CFG:
status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_11D_CFG:
cfg11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
if (cfg11d->sub_command == MLAN_OID_11D_DOMAIN_INFO)
status = wlan_uap_domain_info(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_11H_CFG:
cfg11h = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
if (cfg11h->sub_command == MLAN_OID_11H_CHANNEL_CHECK)
status = wlan_uap_11h_channel_check_req(pmadapter,
pioctl_req);
#if defined(DFS_TESTING_SUPPORT)
if (cfg11h->sub_command == MLAN_OID_11H_DFS_TESTING)
status = wlan_11h_ioctl_dfs_testing(pmadapter,
pioctl_req);
#endif
break;
case MLAN_IOCTL_RADIO_CFG:
radiocfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
if (radiocfg->sub_command == MLAN_OID_RADIO_CTRL)
status = wlan_radio_ioctl_radio_ctl(pmadapter,
pioctl_req);
#ifdef WIFI_DIRECT_SUPPORT
if (radiocfg->sub_command == MLAN_OID_REMAIN_CHAN_CFG)
status = wlan_radio_ioctl_remain_chan_cfg(pmadapter,
pioctl_req);
#endif
break;
case MLAN_IOCTL_RATE:
rate = (mlan_ds_rate *) pioctl_req->pbuf;
if (rate->sub_command == MLAN_OID_RATE_CFG)
status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
else if (rate->sub_command == MLAN_OID_GET_DATA_RATE)
status = wlan_rate_ioctl_get_data_rate(pmadapter,
pioctl_req);
break;
case MLAN_IOCTL_REG_MEM:
reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
if (reg_mem->sub_command == MLAN_OID_REG_RW)
status = wlan_reg_mem_ioctl_reg_rw(pmadapter,
pioctl_req);
else if (reg_mem->sub_command == MLAN_OID_EEPROM_RD)
status = wlan_reg_mem_ioctl_read_eeprom(pmadapter,
pioctl_req);
else if (reg_mem->sub_command == MLAN_OID_MEM_RW)
status = wlan_reg_mem_ioctl_mem_rw(pmadapter,
pioctl_req);
break;
case MLAN_IOCTL_WMM_CFG:
status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
break;
default:
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
break;
}
LEAVE();
return status;
}