blob: 749055f3743b3e7b8d5173be9774e705b490e510 [file] [log] [blame]
/** @file mlan_sta_ioctl.c
*
* @brief This file contains the functions for station ioctl.
*
* Copyright (C) 2008-2009, Marvell International Ltd.
* All Rights Reserved
*/
/******************************************************
Change log:
10/21/2008: initial version
******************************************************/
#include "mlan.h"
#include "mlan_join.h"
#include "mlan_util.h"
#include "mlan_fw.h"
#include "mlan_main.h"
#include "mlan_wmm.h"
#include "mlan_11n.h"
#include "mlan_sdio.h"
/********************************************************
Local Variables
********************************************************/
/********************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
/**
* @brief enable adhoc aes key
*
* @param pmpriv A pointer to mlan_private structure
*
* @return N/A
*/
void
wlan_enable_aes_key(pmlan_private pmpriv)
{
mlan_ds_encrypt_key encrypt_key;
if (pmpriv->aes_key.key_param_set.key_len != WPA_AES_KEY_LEN)
return;
memset(&encrypt_key, 0, sizeof(mlan_ds_encrypt_key));
encrypt_key.key_len = WPA_AES_KEY_LEN;
encrypt_key.key_index = 0x40000000;
memcpy(encrypt_key.key_material, pmpriv->aes_key.key_param_set.key,
encrypt_key.key_len);
wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, MNULL,
&encrypt_key);
encrypt_key.key_index &= ~0x40000000;
wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET,
KEY_INFO_ENABLED, MNULL, &encrypt_key);
return;
}
/**
* @brief Get signal information
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_get_info_signal(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (pioctl_req != MNULL) {
pmpriv = pmadapter->priv[pioctl_req->bss_num];
} else {
PRINTM(MERROR, "MLAN IOCTL information is not present\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Check information buffer length of MLAN IOCTL */
if (pioctl_req->buf_len < sizeof(mlan_ds_get_signal)) {
PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_get_signal);
ret = MLAN_STATUS_RESOURCE;
goto exit;
}
/* Signal info can be obtained only if connected */
if (pmpriv->media_connected == MFALSE) {
PRINTM(MINFO, "Can not get signal in disconnected state\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Get statistics information
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_get_info_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (pioctl_req != MNULL) {
pmpriv = pmadapter->priv[pioctl_req->bss_num];
} else {
PRINTM(MERROR, "MLAN IOCTL information is not present\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Check information buffer length of MLAN IOCTL */
if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
ret = MLAN_STATUS_RESOURCE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_GET_LOG,
HostCmd_ACT_GEN_GET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
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, otherwise fail
*/
static mlan_status
wlan_get_info_bss_info(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_get_info *info;
BSSDescriptor_t *pbss_desc;
t_s32 tbl_idx = 0;
ENTER();
/* Get current BSS info */
pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
info = (mlan_ds_get_info *) pioctl_req->pbuf;
/* BSS mode */
info->param.bss_info.bss_mode = pmpriv->bss_mode;
/* SSID */
memcpy(&info->param.bss_info.ssid, &pbss_desc->ssid,
sizeof(mlan_802_11_ssid));
/* BSSID */
memcpy(&info->param.bss_info.bssid, &pbss_desc->mac_address,
MLAN_MAC_ADDR_LENGTH);
/* Channel */
info->param.bss_info.bss_chan = pbss_desc->channel;
/* Region code */
info->param.bss_info.region_code = pmadapter->region_code;
/* Scan table index if connected */
info->param.bss_info.scan_table_idx = 0;
if (pmpriv->media_connected == MTRUE) {
tbl_idx =
wlan_find_ssid_in_list(pmpriv, &pbss_desc->ssid,
pbss_desc->mac_address, pmpriv->bss_mode);
if (tbl_idx >= 0)
info->param.bss_info.scan_table_idx = tbl_idx;
}
/* Connection status */
info->param.bss_info.media_connected = pmpriv->media_connected;
/* Radio status */
info->param.bss_info.radio_on = pmadapter->radio_on;
/* Tx power information */
info->param.bss_info.max_power_level = pmpriv->max_tx_power_level;
info->param.bss_info.min_power_level = pmpriv->min_tx_power_level;
/* AdHoc state */
info->param.bss_info.adhoc_state = pmpriv->adhoc_state;
/* Last beacon NF */
info->param.bss_info.bcn_nf_last = pmpriv->bcn_nf_last;
/* wep status */
if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
info->param.bss_info.wep_status = MTRUE;
else
info->param.bss_info.wep_status = MFALSE;
info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
info->param.bss_info.is_deep_sleep = pmadapter->is_deep_sleep;
pioctl_req->data_read_written =
sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
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_SUCCESS --success, otherwise fail
*/
static 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_num];
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_get_info *info;
ENTER();
info = (mlan_ds_get_info *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_VERSION_EXT,
HostCmd_ACT_GEN_GET,
0,
(t_void *) pioctl_req,
&info->param.ver_ext.version_str_sel);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get information handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_get_info_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_get_info *pget_info = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
ENTER();
pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
switch (pget_info->sub_command) {
case MLAN_OID_GET_STATS:
status = wlan_get_info_stats(pmadapter, pioctl_req);
break;
case MLAN_OID_GET_SIGNAL:
status = wlan_get_info_signal(pmadapter, pioctl_req);
break;
case MLAN_OID_GET_FW_INFO:
pioctl_req->data_read_written =
sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
memcpy(&pget_info->param.fw_info.mac_addr, pmpriv->curr_addr,
MLAN_MAC_ADDR_LENGTH);
break;
case MLAN_OID_GET_BSS_INFO:
status = wlan_get_info_bss_info(pmadapter, pioctl_req);
break;
case MLAN_OID_GET_DEBUG_INFO:
status = wlan_get_info_debug_info(pmadapter, pioctl_req);
break;
case MLAN_OID_GET_VER_EXT:
status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set/Get SNMP MIB handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_snmp_mib_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
t_u16 cmd_oid = 0;
mlan_ds_snmp_mib *mib = MNULL;
t_u32 value = 0;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
ret = MLAN_STATUS_RESOURCE;
goto exit;
}
mib = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
switch (mib->sub_command) {
case MLAN_OID_SNMP_MIB_RTS_THRESHOLD:
value = mib->param.rts_threshold;
cmd_oid = RtsThresh_i;
break;
case MLAN_OID_SNMP_MIB_FRAG_THRESHOLD:
value = mib->param.frag_threshold;
cmd_oid = FragThresh_i;
break;
case MLAN_OID_SNMP_MIB_RETRY_COUNT:
value = mib->param.retry_count;
cmd_oid = ShortRetryLim_i;
break;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_SNMP_MIB,
cmd_action, cmd_oid, (t_void *) pioctl_req, &value);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
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
*/
static 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_num];
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;
pmadapter->radio_on = (t_u16) radio_cfg->param.radio_on_off;
}
} 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, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set/Get Infra/Ad-hoc band configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_radio_ioctl_band_cfg(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
t_u8 infra_band = 0;
t_u8 adhoc_band = 0;
t_u32 adhoc_channel = 0;
mlan_ds_radio_cfg *radio_cfg = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
ENTER();
radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
infra_band = (t_u8) radio_cfg->param.band_cfg.config_bands;
adhoc_band = (t_u8) radio_cfg->param.band_cfg.adhoc_start_band;
adhoc_channel = radio_cfg->param.band_cfg.adhoc_channel;
/* SET Infra band */
if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (wlan_set_regiontable
(pmpriv, (t_u8) pmadapter->region_code, infra_band)) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (wlan_set_universal_table(pmpriv, infra_band)) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmadapter->config_bands = infra_band;
/* SET Ad-hoc Band */
if ((adhoc_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (adhoc_band)
pmadapter->adhoc_start_band = adhoc_band;
pmpriv->adhoc_auto_sel = MFALSE;
/*
* If no adhoc_channel is supplied verify if the existing adhoc channel
* compiles with new adhoc_band
*/
if (!adhoc_channel) {
if (!wlan_find_cfp_by_band_and_channel
(pmadapter, pmadapter->adhoc_start_band,
pmpriv->adhoc_channel)) {
/* Pass back the default channel */
radio_cfg->param.band_cfg.adhoc_channel =
DEFAULT_AD_HOC_CHANNEL;
if ((pmadapter->adhoc_start_band & BAND_A)
|| (pmadapter->adhoc_start_band & BAND_AN)
) {
radio_cfg->param.band_cfg.adhoc_channel =
DEFAULT_AD_HOC_CHANNEL_A;
}
}
} else { /* Retrurn error if adhoc_band and
adhoc_channel combination is invalid */
if (!wlan_find_cfp_by_band_and_channel
(pmadapter, pmadapter->adhoc_start_band,
(t_u16) adhoc_channel)) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmpriv->adhoc_channel = (t_u8) adhoc_channel;
}
if ((adhoc_band & BAND_GN)
|| (adhoc_band & BAND_AN)
) {
pmadapter->adhoc_11n_enabled = MTRUE;
} else {
pmadapter->adhoc_11n_enabled = MFALSE;
}
} else {
radio_cfg->param.band_cfg.config_bands = pmadapter->config_bands; /* Infra
Bands
*/
radio_cfg->param.band_cfg.adhoc_start_band = pmadapter->adhoc_start_band; /* Adhoc
Band
*/
radio_cfg->param.band_cfg.adhoc_channel = pmpriv->adhoc_channel; /* Adhoc
Channel
*/
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @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
*/
static mlan_status
wlan_radio_ioctl_ant_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;
t_u16 antenna_mode;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
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 < RF_ANTENNA_1 ||
radio_cfg->param.antenna >=
(unsigned) (RF_ANTENNA_1 + pmadapter->number_of_antenna)) &&
(radio_cfg->param.antenna != RF_ANTENNA_AUTO ||
pmadapter->number_of_antenna <= 1)) {
PRINTM(MERROR, "Invalid antenna setting\n");
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 */
antenna_mode = (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 *) & antenna_mode);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Radio command handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_radio_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_radio_cfg *radio_cfg = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_radio_cfg)) {
PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_radio_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
switch (radio_cfg->sub_command) {
case MLAN_OID_RADIO_CTRL:
status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
break;
case MLAN_OID_BAND_CFG:
status = wlan_radio_ioctl_band_cfg(pmadapter, pioctl_req);
break;
case MLAN_OID_ANT_CFG:
status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @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_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_mac_address(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
pioctl_req->data_read_written =
MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
memcpy(&bss->param.mac_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
ret = MLAN_STATUS_SUCCESS;
goto exit;
}
memcpy(pmpriv->curr_addr, &bss->param.mac_addr, MLAN_MAC_ADDR_LENGTH);
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_MAC_ADDRESS,
HostCmd_ACT_GEN_SET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set multicast list
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_set_multicast_list(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 old_pkt_filter;
ENTER();
old_pkt_filter = pmpriv->curr_pkt_filter;
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
pioctl_req->data_read_written =
sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) {
PRINTM(MINFO, "Enable Promiscuous mode\n");
pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
} else {
/* Multicast */
pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
if (bss->param.multicast_list.mode == MLAN_MULTICAST_MODE) {
PRINTM(MINFO, "Enabling All Multicast!\n");
pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
} else {
pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
if (bss->param.multicast_list.num_multicast_addr) {
PRINTM(MINFO, "Set multicast list=%d\n",
bss->param.multicast_list.num_multicast_addr);
/* Set multicast addresses to firmware */
if (old_pkt_filter == pmpriv->curr_pkt_filter) {
/* Send request to firmware */
ret =
wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
HostCmd_ACT_GEN_SET, 0,
(t_void *) pioctl_req,
&bss->param.multicast_list);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
} else {
/* Send request to firmware */
ret =
wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
HostCmd_ACT_GEN_SET, 0, MNULL,
&bss->param.multicast_list);
}
}
}
}
PRINTM(MINFO, "old_pkt_filter=0x%lx, curr_pkt_filter=0x%lx\n",
old_pkt_filter, pmpriv->curr_pkt_filter);
if (old_pkt_filter != pmpriv->curr_pkt_filter) {
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET,
0,
(t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
}
exit:
LEAVE();
return ret;
}
/**
* @brief Get channel list
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_get_channel_list(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
chan_freq_power_t *cfp;
t_u32 i, j;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action != MLAN_ACT_GET) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
if ((wlan_11d_get_state(pmpriv) == ENABLE_11D &&
pmpriv->media_connected == MTRUE) &&
((pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ||
(pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
pmpriv->adhoc_state != ADHOC_STARTED))
) {
t_u8 chan_no;
t_u8 band;
parsed_region_chan_11d_t *parsed_region_chan = MNULL;
parsed_region_chan_11d_t region_chan;
BSSDescriptor_t *pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
/* If country IE is present in the associated AP then return the
channel list from country IE else return it from the learning table */
if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
(t_u8) pbss_desc->bss_band,
&region_chan) == MLAN_STATUS_SUCCESS) {
parsed_region_chan = &region_chan;
} else {
parsed_region_chan = &pmadapter->parsed_region_chan;
}
band = parsed_region_chan->band;
PRINTM(MINFO, "band=%d no_of_chan=%d\n", band,
parsed_region_chan->no_of_chan);
for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
&& (i < parsed_region_chan->no_of_chan); i++) {
chan_no = parsed_region_chan->chan_pwr[i].chan;
PRINTM(MINFO, "chan_no=%d\n", chan_no);
bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].channel =
(t_u32) chan_no;
bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
(t_u32) wlan_11d_chan_2_freq(pmadapter, chan_no, band);
bss->param.chanlist.num_of_chan++;
}
} else {
for (j = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
&& (j <
sizeof(pmadapter->region_channel) /
sizeof(pmadapter->region_channel[0])); j++) {
cfp = pmadapter->region_channel[j].pcfp;
for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
&& pmadapter->region_channel[j].valid
&& cfp && (i < pmadapter->region_channel[j].num_cfp); i++) {
bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].
channel = (t_u32) cfp->channel;
bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
(t_u32) cfp->freq;
bss->param.chanlist.num_of_chan++;
cfp++;
}
}
}
PRINTM(MINFO, "num of channel=%d\n", bss->param.chanlist.num_of_chan);
LEAVE();
return ret;
}
/**
* @brief Set/Get BSS channel
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_channel(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
chan_freq_power_t *cfp;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
pmpriv->curr_bss_params.band,
(t_u16) pmpriv->curr_bss_params.
bss_descriptor.channel);
if (cfp) {
bss->param.bss_chan.channel = cfp->channel;
bss->param.bss_chan.freq = cfp->freq;
} else
ret = MLAN_STATUS_FAILURE;
pioctl_req->data_read_written =
sizeof(chan_freq) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
if (!bss->param.bss_chan.channel && !bss->param.bss_chan.freq) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (pmadapter->adhoc_start_band & BAND_AN)
pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
else if (pmadapter->adhoc_start_band & BAND_A)
pmadapter->adhoc_start_band = BAND_G | BAND_B;
if (bss->param.bss_chan.channel) {
cfp =
wlan_find_cfp_by_band_and_channel(pmadapter, 0,
(t_u16) bss->param.bss_chan.
channel);
if (!cfp) {
cfp =
wlan_find_cfp_by_band_and_channel(pmadapter, BAND_A,
(t_u16) bss->param.bss_chan.
channel);
if (cfp) {
if (pmadapter->adhoc_11n_enabled)
pmadapter->adhoc_start_band = BAND_A | BAND_AN;
else
pmadapter->adhoc_start_band = BAND_A;
}
}
} else {
cfp =
wlan_find_cfp_by_band_and_freq(pmadapter, 0,
bss->param.bss_chan.freq);
if (!cfp) {
cfp =
wlan_find_cfp_by_band_and_freq(pmadapter, BAND_A,
bss->param.bss_chan.freq);
if (cfp) {
if (pmadapter->adhoc_11n_enabled)
pmadapter->adhoc_start_band = BAND_A | BAND_AN;
else
pmadapter->adhoc_start_band = BAND_A;
}
}
}
if (!cfp || !cfp->channel) {
PRINTM(MERROR, "Invalid channel/freq\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmpriv->adhoc_channel = (t_u8) cfp->channel;
pmpriv->adhoc_auto_sel = MFALSE;
bss->param.bss_chan.channel = cfp->channel;
bss->param.bss_chan.freq = cfp->freq;
LEAVE();
return ret;
}
/**
* @brief Set/Get BSS 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
*/
static mlan_status
wlan_bss_ioctl_mode(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
bss = (mlan_ds_bss *) pioctl_req->pbuf;
ENTER();
if (pioctl_req->action == MLAN_ACT_GET) {
bss->param.bss_mode = pmpriv->bss_mode;
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
goto exit;
}
if ((pmpriv->bss_mode == bss->param.bss_mode) ||
(bss->param.bss_mode == MLAN_BSS_MODE_AUTO)) {
PRINTM(MINFO, "Already set to required mode! No change!\n");
pmpriv->bss_mode = bss->param.bss_mode;
goto exit;
}
if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
pmadapter->ps_mode = Wlan802_11PowerModeCAM;
}
ret = wlan_disconnect(pmpriv, pioctl_req, MNULL);
pmpriv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
pmpriv->bss_mode = bss->param.bss_mode;
exit:
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_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_start(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
t_s32 i = -1;
ENTER();
if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
/* Infra mode */
ret = wlan_disconnect(pmpriv, MNULL, MNULL);
if (ret)
goto start_ssid_done;
/* Search for the requested SSID in the scan table */
if (bss->param.ssid_bssid.ssid.ssid_len) {
i = wlan_find_ssid_in_list(pmpriv,
&bss->param.ssid_bssid.ssid,
MNULL, MLAN_BSS_MODE_INFRA);
} else {
i = wlan_find_bssid_in_list(pmpriv,
(t_u8 *) & bss->param.ssid_bssid.bssid,
MLAN_BSS_MODE_INFRA);
}
if (i >= 0) {
PRINTM(MINFO, "SSID found in scan list ... associating...\n");
/* Clear any past association response stored for application
retrieval */
pmpriv->assoc_rsp_size = 0;
ret = wlan_associate(pmpriv, pioctl_req,
&pmadapter->pscan_table[i]);
if (ret)
goto start_ssid_done;
} else { /* i >= 0 */
ret = MLAN_STATUS_FAILURE;
goto start_ssid_done;
}
} else {
/* Adhoc mode */
/* If the requested SSID matches current SSID, return */
if (bss->param.ssid_bssid.ssid.ssid_len &&
(!wlan_ssid_cmp
(pmadapter, &pmpriv->curr_bss_params.bss_descriptor.ssid,
&bss->param.ssid_bssid.ssid))) {
ret = MLAN_STATUS_SUCCESS;
goto start_ssid_done;
}
/* Exit Adhoc mode first */
PRINTM(MINFO, "Sending Adhoc Stop\n");
ret = wlan_disconnect(pmpriv, MNULL, MNULL);
if (ret)
goto start_ssid_done;
pmpriv->adhoc_is_link_sensed = MFALSE;
/* Search for the requested network in the scan table */
if (bss->param.ssid_bssid.ssid.ssid_len) {
i = wlan_find_ssid_in_list(pmpriv,
&bss->param.ssid_bssid.ssid,
MNULL, MLAN_BSS_MODE_IBSS);
} else {
i = wlan_find_bssid_in_list(pmpriv,
(t_u8 *) & bss->param.ssid_bssid.bssid,
MLAN_BSS_MODE_IBSS);
}
if (i >= 0) {
PRINTM(MINFO, "Network found in scan list ... joining ...\n");
if (pmpriv->adhoc_aes_enabled)
wlan_enable_aes_key(pmpriv);
ret =
wlan_adhoc_join(pmpriv, pioctl_req, &pmadapter->pscan_table[i]);
if (ret)
goto start_ssid_done;
} else { /* i >= 0 */
PRINTM(MINFO, "Network not found in the list, "
"creating adhoc with ssid = %s\n",
bss->param.ssid_bssid.ssid.ssid);
if (pmpriv->adhoc_aes_enabled)
wlan_enable_aes_key(pmpriv);
ret =
wlan_adhoc_start(pmpriv, pioctl_req,
&bss->param.ssid_bssid.ssid);
if (ret)
goto start_ssid_done;
}
}
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
start_ssid_done:
LEAVE();
return ret;
}
/**
* @brief Stop BSS
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_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_num];
mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
ENTER();
ret = wlan_disconnect(pmpriv, pioctl_req, &bss->param.bssid);
LEAVE();
return ret;
}
/**
* @brief Set/Get IBSS channel
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_ibss_channel(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
if (pmpriv->media_connected == MFALSE) {
bss->param.bss_chan.channel = pmpriv->adhoc_channel;
goto exit;
}
cmd_action = HostCmd_ACT_GEN_GET;
} else {
cmd_action = HostCmd_ACT_GEN_SET;
pmpriv->adhoc_channel = (t_u8) bss->param.bss_chan.channel;
pmpriv->adhoc_auto_sel = MFALSE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_RF_CHANNEL,
cmd_action,
0,
(t_void *) pioctl_req, &bss->param.bss_chan.channel);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set/Get beacon interval
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_beacon_interval(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
bss->param.bcn_interval = pmpriv->beacon_period;
if (pmpriv->media_connected == MTRUE)
bss->param.bcn_interval =
pmpriv->curr_bss_params.bss_descriptor.beacon_period;
} else
pmpriv->beacon_period = (t_u16) bss->param.bcn_interval;
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/Get ATIM window
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_atim_window(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
bss->param.atim_window = pmpriv->atim_window;
if (pmpriv->media_connected == MTRUE)
bss->param.atim_window =
pmpriv->curr_bss_params.bss_descriptor.atim_window;
} else
pmpriv->atim_window = (t_u16) bss->param.atim_window;
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Search for a BSS
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl_find_bss(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bss *bss = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
t_u8 mac[MLAN_MAC_ADDR_LENGTH];
int i = 0;
BSSDescriptor_t *pbss_desc;
ENTER();
bss = (mlan_ds_bss *) pioctl_req->pbuf;
if (memcmp(&bss->param.ssid_bssid.bssid, zero_mac, sizeof(zero_mac))) {
i = wlan_find_bssid_in_list(pmpriv,
(t_u8 *) & bss->param.ssid_bssid.bssid,
pmpriv->bss_mode);
if (i < 0) {
memcpy(mac, &bss->param.ssid_bssid.bssid, sizeof(mac));
PRINTM(MERROR, "Can not find bssid %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
LEAVE();
return MLAN_STATUS_FAILURE;
}
pbss_desc = &pmadapter->pscan_table[i];
memcpy(&bss->param.ssid_bssid.ssid, &pbss_desc->ssid,
sizeof(mlan_802_11_ssid));
} else if (bss->param.ssid_bssid.ssid.ssid_len) {
i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid, MNULL,
pmpriv->bss_mode);
if (i < 0) {
PRINTM(MERROR, "Can not find ssid %s\n",
bss->param.ssid_bssid.ssid.ssid);
LEAVE();
return MLAN_STATUS_FAILURE;
}
pbss_desc = &pmadapter->pscan_table[i];
memcpy((t_u8 *) & bss->param.ssid_bssid.bssid,
(t_u8 *) & pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
} else {
ret = wlan_find_best_network(pmpriv, &bss->param.ssid_bssid);
}
LEAVE();
return ret;
}
/**
* @brief BSS command handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bss_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_bss *bss = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_bss)) {
PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_bss);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
bss = (mlan_ds_bss *) pioctl_req->pbuf;
switch (bss->sub_command) {
case MLAN_OID_BSS_START:
status = wlan_bss_ioctl_start(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_STOP:
status = wlan_bss_ioctl_stop(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_MODE:
status = wlan_bss_ioctl_mode(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_CHANNEL:
status = wlan_bss_ioctl_channel(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_CHANNEL_LIST:
status = wlan_bss_ioctl_get_channel_list(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_MAC_ADDR:
status = wlan_bss_ioctl_mac_address(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_MULTICAST_LIST:
status = wlan_bss_ioctl_set_multicast_list(pmadapter, pioctl_req);
break;
case MLAN_OID_BSS_FIND_BSS:
status = wlan_bss_ioctl_find_bss(pmadapter, pioctl_req);
break;
case MLAN_OID_IBSS_BCN_INTERVAL:
status = wlan_bss_ioctl_beacon_interval(pmadapter, pioctl_req);
break;
case MLAN_OID_IBSS_ATIM_WINDOW:
status = wlan_bss_ioctl_atim_window(pmadapter, pioctl_req);
break;
case MLAN_OID_IBSS_CHANNEL:
status = wlan_bss_ioctl_ibss_channel(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Get supported rates
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_rate_ioctl_get_supported_rate(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_rate *rate = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (pioctl_req->action != MLAN_ACT_GET) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
rate = (mlan_ds_rate *) pioctl_req->pbuf;
wlan_get_active_data_rates(pmpriv, rate->param.rates);
pioctl_req->data_read_written =
MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
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 --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_num];
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 (pmpriv->media_connected != MTRUE) {
switch (pmadapter->config_bands) {
case BAND_B:
/* Return the lowest supported rate for B band */
rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
break;
case BAND_G:
case BAND_G | BAND_GN:
/* Return the lowest supported rate for G band */
rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
break;
case BAND_B | BAND_G:
case BAND_A | BAND_B | BAND_G:
case BAND_A | BAND_B:
case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
case BAND_B | BAND_G | BAND_GN:
/* Return the lowest supported rate for BG band */
rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
break;
case BAND_A:
case BAND_A | BAND_G:
case BAND_A | BAND_G | BAND_AN | BAND_GN:
case BAND_A | BAND_AN:
/* Return the lowest supported rate for A band */
rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
break;
case BAND_GN:
/* Return the lowest supported rate for N band */
rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
break;
default:
PRINTM(MMSG, "Invalid Band 0x%x\n", pmadapter->config_bands);
break;
}
} 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_SUCCESS --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_num];
ENTER();
ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
if (ds_rate->param.rate_cfg.is_rate_auto) {
memset(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(rates, 0, sizeof(rates));
wlan_get_active_data_rates(pmpriv, 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);
ret = MLAN_STATUS_FAILURE;
goto exit;
}
memset(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_SUCCESS --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_num];
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_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_rate_ioctl_set_rate_index(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
int rate_index;
t_u32 i;
mlan_ds_rate *ds_rate = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
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(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(bitmap_rates) - 3; i++)
bitmap_rates[i + 2] = 0xFFFF;
bitmap_rates[9] = 0x3FFF;
} else {
PRINTM(MINFO, "Rate index is %d\n", rate_index);
memset(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;
/* Bitmap of OFDM rates */
if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
rate_index <= MLAN_RATE_INDEX_OFDM7)
bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
/* Bitmap of HT-MCSs allowed for initial rate */
if (rate_index >= MLAN_RATE_INDEX_MCS0 &&
rate_index <= MLAN_RATE_INDEX_MCS32)
bitmap_rates[((rate_index - MLAN_RATE_INDEX_MCS0) / 16) + 2] =
1 << ((rate_index - MLAN_RATE_INDEX_MCS0) % 16);
}
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 --success, otherwise fail
*/
static mlan_status
wlan_rate_ioctl_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_ds_rate *rate = MNULL;
mlan_status status = MLAN_STATUS_SUCCESS;
ENTER();
rate = (mlan_ds_rate *) pioctl_req->pbuf;
if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) {
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_rate_ioctl_get_rate_value(pmadapter, pioctl_req);
else
status = wlan_rate_ioctl_set_rate_value(pmadapter, pioctl_req);
} else {
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_rate_ioctl_get_rate_index(pmadapter, pioctl_req);
else
status = wlan_rate_ioctl_set_rate_index(pmadapter, pioctl_req);
}
LEAVE();
return status;
}
/**
* @brief Get data rates
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static 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_num];
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (pioctl_req->action != MLAN_ACT_GET) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_TX_RATE_QUERY,
HostCmd_ACT_GEN_GET,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Rate command handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_rate_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_rate *rate = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_rate)) {
PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_rate);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
rate = (mlan_ds_rate *) pioctl_req->pbuf;
switch (rate->sub_command) {
case MLAN_OID_RATE_CFG:
status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
break;
case MLAN_OID_GET_DATA_RATE:
status = wlan_rate_ioctl_get_data_rate(pmadapter, pioctl_req);
break;
case MLAN_OID_SUPPORTED_RATES:
status = wlan_rate_ioctl_get_supported_rate(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Get Tx power configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_power_ioctl_get_power(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_TXPWR_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 Tx power configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_power_ioctl_set_power(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_ds_power_cfg *power = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
MrvlTypes_Power_Group_t *pg_tlv = MNULL;
Power_Group_t *pg = MNULL;
pmlan_callbacks pcb = &pmadapter->callbacks;
t_u8 *buf = MNULL;
t_u16 dbm = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
ENTER();
power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
if (!power->param.power_cfg.is_power_auto) {
dbm = (t_u16) power->param.power_cfg.power_level;
if ((dbm < pmpriv->min_tx_power_level) ||
(dbm > pmpriv->max_tx_power_level)) {
PRINTM(MERROR,
"The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
dbm, pmpriv->min_tx_power_level, pmpriv->max_tx_power_level);
ret = MLAN_STATUS_FAILURE;
goto exit;
}
}
ret = pcb->moal_malloc(MRVDRV_SIZE_OF_CMD_BUFFER, &buf);
if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
PRINTM(MMSG, "ALLOC_CMD_BUF: pcmd_buf: out of memory\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
txp_cfg->action = HostCmd_ACT_GEN_SET;
if (!power->param.power_cfg.is_power_auto) {
txp_cfg->mode = 1;
pg_tlv =
(MrvlTypes_Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG));
pg_tlv->type = TLV_TYPE_POWER_GROUP;
pg_tlv->length = 4 * sizeof(Power_Group_t);
pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
sizeof(MrvlTypes_Power_Group_t));
/* Power group for modulation class HR/DSSS */
pg->first_rate_code = 0x00;
pg->last_rate_code = 0x03;
pg->modulation_class = MOD_CLASS_HR_DSSS;
pg->power_step = 0;
pg->power_min = (t_s8) dbm;
pg->power_max = (t_s8) dbm;
pg++;
/* Power group for modulation class OFDM */
pg->first_rate_code = 0x00;
pg->last_rate_code = 0x07;
pg->modulation_class = MOD_CLASS_OFDM;
pg->power_step = 0;
pg->power_min = (t_s8) dbm;
pg->power_max = (t_s8) dbm;
pg++;
/* Power group for modulation class HTBW20 */
pg->first_rate_code = 0x00;
pg->last_rate_code = 0x20;
pg->modulation_class = MOD_CLASS_HT;
pg->power_step = 0;
pg->power_min = (t_s8) dbm;
pg->power_max = (t_s8) dbm;
pg->ht_bandwidth = HT_BW_20;
pg++;
/* Power group for modulation class HTBW40 */
pg->first_rate_code = 0x00;
pg->last_rate_code = 0x20;
pg->modulation_class = MOD_CLASS_HT;
pg->power_step = 0;
pg->power_min = (t_s8) dbm;
pg->power_max = (t_s8) dbm;
pg->ht_bandwidth = HT_BW_40;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_TXPWR_CFG,
HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
if (buf)
pcb->moal_mfree(buf);
exit:
LEAVE();
return ret;
}
/**
* @brief Get modulation class from rate index
*
* @param pmadapter A pointer to mlan_adapter structure
* @param rate_index Rate index
*
* @return 0 fail, otherwise return modulation class
*/
static int
wlan_get_modulation_class(pmlan_adapter pmadapter, int rate_index)
{
ENTER();
if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
rate_index <= MLAN_RATE_INDEX_HRDSSS3) {
return MOD_CLASS_HR_DSSS;
} else if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
rate_index <= MLAN_RATE_INDEX_OFDM7) {
return MOD_CLASS_OFDM;
} else if (rate_index >= MLAN_RATE_INDEX_MCS0 &&
rate_index <= MLAN_RATE_INDEX_MCS127) {
return MOD_CLASS_HT;
}
PRINTM(MERROR, "Invalid rate index = %d supplied!\n", rate_index);
LEAVE();
return 0;
}
/**
* @brief Set extended power configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_power_ioctl_set_power_ext(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_power_cfg *power = MNULL;
pmlan_callbacks pcb = &pmadapter->callbacks;
t_u8 *buf = MNULL;
HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
MrvlTypes_Power_Group_t *pg_tlv = MNULL;
Power_Group_t *pg = MNULL;
int mod_class;
t_u32 data[4];
t_u8 ht_bw;
ENTER();
power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
ret = pcb->moal_malloc(MRVDRV_SIZE_OF_CMD_BUFFER, &buf);
if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
PRINTM(MERROR, "ALLOC_CMD_BUF: pcmd_buf: out of memory\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
txp_cfg->action = HostCmd_ACT_GEN_SET;
memcpy((t_u8 *) & data, (t_u8 *) power->param.power_ext.power_data,
sizeof(data));
switch (power->param.power_ext.len) {
case 1:
if (data[0] == 0xFF)
txp_cfg->mode = 0;
else
ret = MLAN_STATUS_FAILURE;
break;
case 2:
case 4:
ht_bw = (data[0] & TX_RATE_HT_BW40_BIT) ? HT_BW_40 : HT_BW_20;
data[0] &= ~TX_RATE_HT_BW40_BIT;
if (!(mod_class = wlan_get_modulation_class(pmadapter, data[0]))) {
ret = MLAN_STATUS_FAILURE;
break;
}
if (ht_bw && mod_class != MOD_CLASS_HT) {
ret = MLAN_STATUS_FAILURE;
break;
}
txp_cfg->mode = 1;
pg_tlv =
(MrvlTypes_Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG));
pg_tlv->type = TLV_TYPE_POWER_GROUP;
pg_tlv->length = sizeof(Power_Group_t);
pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
sizeof(MrvlTypes_Power_Group_t));
pg->modulation_class = (t_u8) mod_class;
pg->first_rate_code = (t_u8) data[0];
pg->last_rate_code = (t_u8) data[0];
if (mod_class == MOD_CLASS_OFDM) {
pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
} else if (mod_class == MOD_CLASS_HT) {
pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
pg->ht_bandwidth = ht_bw;
}
pg->power_min = (t_s8) data[1];
pg->power_max = (t_s8) data[1];
if (power->param.power_ext.len == 4) {
pg->power_max = (t_s8) data[2];
pg->power_step = (t_s8) data[3];
}
break;
default:
ret = MLAN_STATUS_FAILURE;
break;
}
if (ret == MLAN_STATUS_FAILURE) {
if (buf)
pcb->moal_mfree(buf);
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_TXPWR_CFG,
HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
if (buf)
pcb->moal_mfree(buf);
exit:
LEAVE();
return ret;
}
/**
* @brief Power configuration command handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_power_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_power_cfg *power = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_power_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_power_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
switch (power->sub_command) {
case MLAN_OID_POWER_CFG:
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_power_ioctl_get_power(pmadapter, pioctl_req);
else
status = wlan_power_ioctl_set_power(pmadapter, pioctl_req);
break;
case MLAN_OID_POWER_CFG_EXT:
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_power_ioctl_get_power(pmadapter, pioctl_req);
else
status = wlan_power_ioctl_set_power_ext(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set power save configurations
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
* @param ps_mode Power save mode
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_pm_ioctl_ps_mode(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req, IN t_u16 ps_mode)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
t_u16 sub_cmd;
ENTER();
sub_cmd = (pmadapter->ps_mode == Wlan802_11PowerModePSP) ? EN_PS : DIS_PS;
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_PS_MODE_ENH, sub_cmd,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
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
* @param phs_cfg A pointer to HOST_SLEEP_CFG structure
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_pm_ioctl_hs_cfg(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req,
IN HostCmd_DS_802_11_HS_CFG_ENH * phs_cfg)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
ENTER();
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_HS_CFG_ENH,
HostCmd_ACT_GEN_SET,
0, (t_void *) pioctl_req, phs_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get Inactivity timeout extend
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_pm_ioctl_inactivity_timeout(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_pm_cfg *pmcfg = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
pmcfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
cmd_action = HostCmd_ACT_GEN_GET;
if (pioctl_req->action == MLAN_ACT_SET) {
cmd_action = HostCmd_ACT_GEN_SET;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_INACTIVITY_TIMEOUT_EXT,
cmd_action, 0, (t_void *) pioctl_req,
(t_void *) & pmcfg->param.inactivity_to);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Enable/Disable Auto Deep Sleep
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_set_auto_deep_sleep(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = (pmlan_private) pmadapter->priv[pioctl_req->bss_num];
mlan_ds_auto_ds auto_ds;
t_u32 mode;
ENTER();
if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.auto_ds ==
DEEP_SLEEP_ON) {
auto_ds.auto_ds = DEEP_SLEEP_ON;
PRINTM(MINFO, "Auto Deep Sleep: on\n");
mode = EN_AUTO_DS;
} else {
auto_ds.auto_ds = DEEP_SLEEP_OFF;
PRINTM(MINFO, "AutoAUTO_DEEP_SLEEP Deep Sleep: off\n");
mode = DIS_AUTO_DS;
}
auto_ds.idletime =
((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.idletime;
/* note: the command could be queued and executed later if there is
command in progress. */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_PS_MODE_ENH,
mode, 0, (t_void *) pioctl_req, &auto_ds);
if (ret) {
LEAVE();
return ret;
}
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get sleep period
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_set_get_sleep_pd(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_pm_cfg *pm_cfg = MNULL;
t_u16 cmd_action = 0;
ENTER();
pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
cmd_action = HostCmd_ACT_GEN_GET;
if (pioctl_req->action == MLAN_ACT_SET) {
cmd_action = HostCmd_ACT_GEN_SET;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PERIOD,
cmd_action, 0, (t_void *) pioctl_req,
&pm_cfg->param.sleep_period);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get PS configuration parameter
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_set_get_ps_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_ds_pm_cfg *pm_cfg = MNULL;
ENTER();
pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
pm_cfg->param.ps_cfg.ps_null_interval =
(t_u32) pmadapter->null_pkt_interval;
pm_cfg->param.ps_cfg.multiple_dtim_interval =
(t_u32) pmadapter->multiple_dtim;
pm_cfg->param.ps_cfg.listen_interval =
(t_u32) pmadapter->local_listen_interval;
pm_cfg->param.ps_cfg.adhoc_awake_period =
(t_u32) pmadapter->adhoc_awake_period;
pm_cfg->param.ps_cfg.bcn_miss_timeout =
(t_u32) pmadapter->bcn_miss_time_out;
pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
} else {
if (pm_cfg->param.ps_cfg.ps_null_interval)
pmadapter->null_pkt_interval =
(t_u16) pm_cfg->param.ps_cfg.ps_null_interval;
else
pm_cfg->param.ps_cfg.ps_null_interval =
(t_u32) pmadapter->null_pkt_interval;
if (pm_cfg->param.ps_cfg.multiple_dtim_interval)
pmadapter->multiple_dtim =
(t_u16) pm_cfg->param.ps_cfg.multiple_dtim_interval;
else
pm_cfg->param.ps_cfg.multiple_dtim_interval =
(t_u32) pmadapter->multiple_dtim;
if (pm_cfg->param.ps_cfg.listen_interval)
pmadapter->local_listen_interval =
(t_u16) pm_cfg->param.ps_cfg.listen_interval;
else
pm_cfg->param.ps_cfg.listen_interval =
(t_u32) pmadapter->local_listen_interval;
if (pm_cfg->param.ps_cfg.adhoc_awake_period)
pmadapter->adhoc_awake_period =
(t_u16) pm_cfg->param.ps_cfg.adhoc_awake_period;
else
pm_cfg->param.ps_cfg.adhoc_awake_period =
(t_u32) pmadapter->adhoc_awake_period;
if (pm_cfg->param.ps_cfg.bcn_miss_timeout)
pmadapter->bcn_miss_time_out =
(t_u16) pm_cfg->param.ps_cfg.bcn_miss_timeout;
else
pm_cfg->param.ps_cfg.bcn_miss_timeout =
(t_u32) pmadapter->bcn_miss_time_out;
if (pm_cfg->param.ps_cfg.delay_to_ps != DELAY_TO_PS_UNCHANGED)
pmadapter->delay_to_ps = (t_u16) pm_cfg->param.ps_cfg.delay_to_ps;
else
pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
if (pm_cfg->param.ps_cfg.ps_mode)
pmadapter->enhanced_ps_mode = (t_u16) pm_cfg->param.ps_cfg.ps_mode;
else
pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Get/Set the sleep parameters
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status
wlan_set_get_sleep_params(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_pm_cfg *pm_cfg = MNULL;
t_u16 cmd_action = 0;
ENTER();
pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
cmd_action = HostCmd_ACT_GEN_GET;
if (pioctl_req->action == MLAN_ACT_SET) {
cmd_action = HostCmd_ACT_GEN_SET;
}
/* Send command to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PARAMS,
cmd_action, 0, (t_void *) pioctl_req,
&pm_cfg->param.sleep_params);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Power save command handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_pm_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_pm_cfg *pm = MNULL;
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);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
switch (pm->sub_command) {
case MLAN_OID_PM_CFG_IEEE_PS:
switch (pioctl_req->action) {
case MLAN_ACT_SET:
if (pm->param.ps_mode)
pmadapter->ps_mode = Wlan802_11PowerModePSP;
else
pmadapter->ps_mode = Wlan802_11PowerModeCAM;
status =
wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
pmadapter->ps_mode);
break;
case MLAN_ACT_GET:
if (pmadapter->ps_mode == Wlan802_11PowerModePSP)
pm->param.ps_mode = 1;
else
pm->param.ps_mode = 0;
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
break;
case MLAN_OID_PM_CFG_HS_CFG:
switch (pioctl_req->action) {
case MLAN_ACT_SET:
pmadapter->hs_cfg.params.hs_config.conditions =
pm->param.hs_cfg.conditions;
pmadapter->hs_cfg.params.hs_config.gpio = pm->param.hs_cfg.gpio;
pmadapter->hs_cfg.params.hs_config.gap = pm->param.hs_cfg.gap;
if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) {
status =
wlan_pm_ioctl_hs_cfg(pmadapter, pioctl_req,
&pmadapter->hs_cfg);
}
break;
case MLAN_ACT_GET:
if (pmadapter->is_hs_configured) {
pm->param.hs_cfg.conditions =
pmadapter->hs_cfg.params.hs_config.conditions;
pm->param.hs_cfg.gpio = pmadapter->hs_cfg.params.hs_config.gpio;
pm->param.hs_cfg.gap = pmadapter->hs_cfg.params.hs_config.gap;
}
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
break;
case MLAN_OID_PM_CFG_INACTIVITY_TO:
status = wlan_pm_ioctl_inactivity_timeout(pmadapter, pioctl_req);
break;
case MLAN_OID_PM_CFG_DEEP_SLEEP:
switch (pioctl_req->action) {
case MLAN_ACT_SET:
if (pmadapter->is_deep_sleep &&
pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
PRINTM(MMSG, "Station already in enhanced deep sleep mode\n");
status = MLAN_STATUS_FAILURE;
break;
} else if (!pmadapter->is_deep_sleep &&
pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_OFF) {
PRINTM(MMSG,
"Station already not in enhanced deep sleep mode\n");
status = MLAN_STATUS_FAILURE;
break;
}
status = wlan_set_auto_deep_sleep(pmadapter, pioctl_req);
break;
case MLAN_ACT_GET:
if (pmadapter->is_deep_sleep)
pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
else
pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
break;
case MLAN_OID_PM_CFG_PS_CFG:
status = wlan_set_get_ps_cfg(pmadapter, pioctl_req);
break;
case MLAN_OID_PM_CFG_SLEEP_PD:
status = wlan_set_get_sleep_pd(pmadapter, pioctl_req);
break;
case MLAN_OID_PM_CFG_SLEEP_PARAMS:
status = wlan_set_get_sleep_params(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set/Get WMM 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
*/
static mlan_status
wlan_wmm_ioctl_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_num];
mlan_ds_wmm_cfg *wmm = MNULL;
ENTER();
wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
wmm->param.wmm_enable = (t_u32) pmpriv->wmm_required;
else
pmpriv->wmm_required = (t_u8) wmm->param.wmm_enable;
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/Get WMM QoS configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_qos(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wmm_cfg *wmm = MNULL;
ENTER();
wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
wmm->param.qos_cfg = pmpriv->wmm_qosinfo;
else
pmpriv->wmm_qosinfo = wmm->param.qos_cfg;
pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/get tid multi-port eligibility table
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_tid_elig_tbl(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_wmm_cfg *wmm = MNULL;
t_u32 i;
ENTER();
wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
for (i = 0; i < MAX_NUM_TID; i++)
wmm->param.tid_tbl[i] = pmadapter->tx_eligibility[i];
} else {
for (i = 0; i < MAX_NUM_TID; i++) {
if (wmm->param.tid_tbl[i] >= pmadapter->mp_end_port)
ret = MLAN_STATUS_FAILURE;
}
if (ret == MLAN_STATUS_SUCCESS) {
for (i = 0; i < MAX_NUM_TID; i++) {
if (wmm->param.tid_tbl[i])
pmadapter->tx_eligibility[i] = (t_u8) wmm->param.tid_tbl[i];
}
}
}
pioctl_req->data_read_written =
sizeof(wmm->param.tid_tbl) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Request for add a TSPEC
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_addts_req(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wmm_cfg *cfg = MNULL;
ENTER();
cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_ADDTS_REQ,
0, 0, (t_void *) pioctl_req,
(t_void *) & cfg->param.addts);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Request for delete a TSPEC
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_delts_req(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wmm_cfg *cfg = MNULL;
ENTER();
cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_DELTS_REQ,
0, 0, (t_void *) pioctl_req,
(t_void *) & cfg->param.delts);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get a specified AC Queue's parameters
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_queue_config(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wmm_cfg *cfg = MNULL;
ENTER();
cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_CONFIG,
0, 0, (t_void *) pioctl_req,
(t_void *) & cfg->param.q_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief To get and start/stop queue stats on a WMM AC
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_queue_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_num];
mlan_ds_wmm_cfg *cfg = MNULL;
ENTER();
cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_STATS,
0, 0, (t_void *) pioctl_req,
(t_void *) & cfg->param.q_stats);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get the status of the WMM AC queues
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_queue_status(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wmm_cfg *cfg = MNULL;
mlan_ds_wmm_queue_status *pqstatus = MNULL;
WmmAcStatus_t *pac_status = MNULL;
mlan_wmm_ac_e ac_idx;
ENTER();
cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
pqstatus = (mlan_ds_wmm_queue_status *) & cfg->param.q_status;
for (ac_idx = WMM_AC_BK; ac_idx <= WMM_AC_VO; ac_idx++) {
pac_status = &pmpriv->wmm.ac_status[ac_idx];
/* Firmware status */
pqstatus->ac_status[ac_idx].flow_required = pac_status->flow_required;
pqstatus->ac_status[ac_idx].flow_created = pac_status->flow_created;
pqstatus->ac_status[ac_idx].disabled = pac_status->disabled;
/* ACM bit reflected in firmware status (redundant) */
pqstatus->ac_status[ac_idx].wmm_acm = pac_status->flow_required;
}
LEAVE();
return ret;
}
/**
* @brief Get the status of the WMM Traffic Streams
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_ioctl_ts_status(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wmm_cfg *cfg = MNULL;
ENTER();
cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_TS_STATUS,
0, 0, (t_void *) pioctl_req,
(t_void *) & cfg->param.ts_status);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief WMM configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wmm_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_wmm_cfg *wmm = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_wmm_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_wmm_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
switch (wmm->sub_command) {
case MLAN_OID_WMM_CFG_ENABLE:
status = wlan_wmm_ioctl_enable(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_QOS:
status = wlan_wmm_ioctl_qos(pmadapter, pioctl_req);
break;
case MLAN_OID_TID_ELIG_TBL:
status = wlan_wmm_ioctl_tid_elig_tbl(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_ADDTS:
status = wlan_wmm_ioctl_addts_req(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_DELTS:
status = wlan_wmm_ioctl_delts_req(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_QUEUE_CONFIG:
status = wlan_wmm_ioctl_queue_config(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_QUEUE_STATS:
status = wlan_wmm_ioctl_queue_stats(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_QUEUE_STATUS:
status = wlan_wmm_ioctl_queue_status(pmadapter, pioctl_req);
break;
case MLAN_OID_WMM_CFG_TS_STATUS:
status = wlan_wmm_ioctl_ts_status(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set/Get WPA IE
*
* @param priv A pointer to mlan_private structure
* @param ie_data_ptr A pointer to IE
* @param ie_len Length of the IE
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status
wlan_set_wpa_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
{
ENTER();
if (ie_len) {
if (ie_len > sizeof(priv->wpa_ie)) {
PRINTM(MERROR, "failed to copy WPA IE, too big \n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
priv->wpa_ie_len = (t_u8) ie_len;
PRINTM(MCMND, "Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
priv->wpa_ie[0]);
DBG_HEXDUMP(MCMD_D, "Wpa_ie", priv->wpa_ie, priv->wpa_ie_len);
if (priv->wpa_ie[0] == WPA_IE) {
priv->sec_info.wpa_enabled = MTRUE;
} else if (priv->wpa_ie[0] == RSN_IE) {
priv->sec_info.wpa2_enabled = MTRUE;
} else {
priv->sec_info.wpa_enabled = MFALSE;
priv->sec_info.wpa2_enabled = MFALSE;
}
} else {
memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
priv->wpa_ie_len = 0;
PRINTM(MINFO, "Reset Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
priv->wpa_ie[0]);
priv->sec_info.wpa_enabled = MFALSE;
priv->sec_info.wpa2_enabled = MFALSE;
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Set WAPI IE
*
* @param priv A pointer to mlan_private structure
* @param ie_data_ptr A pointer to IE
* @param ie_len Length of the IE
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status
wlan_set_wapi_ie(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
{
ENTER();
if (ie_len) {
if (ie_len > sizeof(priv->wapi_ie)) {
PRINTM(MINFO, "failed to copy WAPI IE, too big \n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
priv->wapi_ie_len = ie_len;
PRINTM(MCMND, "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->wapi_ie, 0, sizeof(priv->wapi_ie));
priv->wapi_ie_len = 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;
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @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, otherwise fail
*/
static mlan_status
wlan_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_num];
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)
wlan_set_wapi_ie(pmpriv, MNULL, 0);
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set WAPI key
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_ioctl_set_wapi_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_num];
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
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 Set/Get authentication 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
*/
static mlan_status
wlan_sec_ioctl_auth_mode(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
sec->param.auth_mode = pmpriv->sec_info.authentication_mode;
else {
pmpriv->sec_info.authentication_mode = sec->param.auth_mode;
if (pmpriv->sec_info.authentication_mode == MLAN_AUTH_MODE_NETWORKEAP)
wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/Get encryption 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
*/
static mlan_status
wlan_sec_ioctl_encrypt_mode(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
sec->param.encrypt_mode = pmpriv->sec_info.encryption_mode;
else {
pmpriv->sec_info.encryption_mode = sec->param.encrypt_mode;
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/Get WPA 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
*/
static mlan_status
wlan_sec_ioctl_wpa_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_num];
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
if (pmpriv->wpa_ie_len)
sec->param.wpa_enabled = MTRUE;
else
sec->param.wpa_enabled = MFALSE;
} else {
if (sec->param.wpa_enabled == MFALSE)
wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set WEP keys
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_ioctl_set_wep_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_num];
mlan_ds_sec_cfg *sec = MNULL;
mrvl_wep_key_t *pwep_key = MNULL;
int index;
ENTER();
if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
pmpriv->wep_key_curr_index = 0;
pwep_key = &pmpriv->wep_key[pmpriv->wep_key_curr_index];
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (sec->param.encrypt_key.is_current_wep_key == MTRUE)
index = pmpriv->wep_key_curr_index;
else
index = sec->param.encrypt_key.key_index;
if (sec->param.encrypt_key.key_disable == MTRUE) {
if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled &&
pmpriv->media_connected == MTRUE &&
pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
PRINTM(MERROR, "Can not disable key in IBSS connected state\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
pmpriv->sec_info.wep_status = Wlan802_11WEPDisabled;
} else if (!sec->param.encrypt_key.key_len) {
if (pmpriv->sec_info.wep_status != Wlan802_11WEPEnabled &&
pmpriv->media_connected == MTRUE &&
pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
PRINTM(MERROR, "Can not enable key in IBSS connected state\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Copy the required key as the current key */
pwep_key = &pmpriv->wep_key[index];
if (!pwep_key->key_length) {
PRINTM(MERROR, "Key not set,so cannot enable it\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
pmpriv->wep_key_curr_index = (t_u16) index;
pmpriv->sec_info.wep_status = Wlan802_11WEPEnabled;
} else {
pwep_key = &pmpriv->wep_key[index];
/* Cleanup */
memset(pwep_key, 0, sizeof(mrvl_wep_key_t));
/* Copy the key in the driver */
memcpy(pwep_key->key_material, sec->param.encrypt_key.key_material,
sec->param.encrypt_key.key_len);
pwep_key->key_index = index;
pwep_key->key_length = sec->param.encrypt_key.key_len;
if (pmpriv->sec_info.wep_status != Wlan802_11WEPEnabled) {
/*
* The status is set as Key Absent
* so as to make sure we display the
* keys when iwlist mlanX key is used
*/
pmpriv->sec_info.wep_status = Wlan802_11WEPKeyAbsent;
}
pmpriv->wep_key_curr_index = (t_u16) index;
}
if (pwep_key->key_length) {
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
if (ret)
goto exit;
}
if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
else
pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET,
0, (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set WPA key
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_ioctl_set_wpa_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_num];
mlan_ds_sec_cfg *sec = MNULL;
t_u8 remove_key = MFALSE;
HostCmd_DS_802_11_KEY_MATERIAL *pibss_key;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
/* Current driver only supports key length of up to 32 bytes */
if (sec->param.encrypt_key.key_len > MLAN_MAX_KEY_LENGTH) {
PRINTM(MERROR, " Error in key length \n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
/*
* IBSS/WPA-None uses only one key (Group) for both receiving and
* sending unicast and multicast packets.
*/
/* Send the key as PTK to firmware */
sec->param.encrypt_key.key_index = 0x40000000;
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET,
KEY_INFO_ENABLED,
MNULL, &sec->param.encrypt_key);
if (ret)
goto exit;
pibss_key = &pmpriv->aes_key;
memset(pibss_key, 0, sizeof(HostCmd_DS_802_11_KEY_MATERIAL));
/* Copy the key in the driver */
memcpy(pibss_key->key_param_set.key,
sec->param.encrypt_key.key_material,
sec->param.encrypt_key.key_len);
memcpy(&pibss_key->key_param_set.key_len,
&sec->param.encrypt_key.key_len,
sizeof(pibss_key->key_param_set.key_len));
pibss_key->key_param_set.key_type_id = KEY_TYPE_ID_TKIP;
pibss_key->key_param_set.key_info = KEY_INFO_TKIP_ENABLED;
/* Send the key as GTK to firmware */
sec->param.encrypt_key.key_index = ~0x40000000;
}
if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN) {
t_u8 zero_key_material[WPA_AES_KEY_LEN];
memset(zero_key_material, 0, sizeof(zero_key_material));
if (memcmp(sec->param.encrypt_key.key_material, zero_key_material,
WPA_AES_KEY_LEN)) {
PRINTM(MINFO, "Adhoc AES Enabled.\n");
pmpriv->adhoc_aes_enabled = MTRUE;
remove_key = MFALSE;
} else {
PRINTM(MINFO, "Adhoc AES Disabled.\n");
pmpriv->adhoc_aes_enabled = MFALSE;
remove_key = MTRUE;
}
}
if (!sec->param.encrypt_key.key_index)
sec->param.encrypt_key.key_index = 0x40000000;
if (remove_key == MTRUE) {
/* Send request to firmware */
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);
} else {
/* Send request to firmware */
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;
exit:
LEAVE();
return ret;
}
/**
* @brief Get security keys
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_ioctl_get_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_num];
mlan_ds_sec_cfg *sec = MNULL;
int index;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pmpriv->adhoc_aes_enabled == MTRUE &&
(pmpriv->aes_key.key_param_set.key_len == WPA_AES_KEY_LEN)) {
HEXDUMP("Get WPA Key", pmpriv->aes_key.key_param_set.key,
WPA_AES_KEY_LEN);
memcpy(sec->param.encrypt_key.key_material,
pmpriv->aes_key.key_param_set.key, WPA_AES_KEY_LEN);
LEAVE();
return ret;
}
if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
pmpriv->wep_key_curr_index = 0;
if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
|| (pmpriv->sec_info.wep_status == Wlan802_11WEPKeyAbsent)
|| pmpriv->sec_info.ewpa_enabled
|| pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled) {
sec->param.encrypt_key.key_disable = MFALSE;
} else {
sec->param.encrypt_key.key_disable = MTRUE;
}
if (sec->param.encrypt_key.is_current_wep_key == MTRUE) {
if ((pmpriv->wep_key[pmpriv->wep_key_curr_index].key_length) &&
(pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)) {
index = pmpriv->wep_key_curr_index;
sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
memcpy(sec->param.encrypt_key.key_material,
pmpriv->wep_key[index].key_material,
pmpriv->wep_key[index].key_length);
sec->param.encrypt_key.key_len = pmpriv->wep_key[index].key_length;
} else if ((pmpriv->sec_info.wpa_enabled)
|| (pmpriv->sec_info.ewpa_enabled)
|| (pmpriv->sec_info.wpa2_enabled)
) {
/* Return WPA enabled */
sec->param.encrypt_key.key_disable = MFALSE;
memcpy(sec->param.encrypt_key.key_material,
pmpriv->aes_key.key_param_set.key,
pmpriv->aes_key.key_param_set.key_len);
sec->param.encrypt_key.key_len =
pmpriv->aes_key.key_param_set.key_len;
} else {
sec->param.encrypt_key.key_disable = MTRUE;
}
} else {
index = sec->param.encrypt_key.key_index;
if (pmpriv->wep_key[index].key_length) {
sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
memcpy(sec->param.encrypt_key.key_material,
pmpriv->wep_key[index].key_material,
pmpriv->wep_key[index].key_length);
sec->param.encrypt_key.key_len = pmpriv->wep_key[index].key_length;
} else if ((pmpriv->sec_info.wpa_enabled)
|| (pmpriv->sec_info.ewpa_enabled)
|| (pmpriv->sec_info.wpa2_enabled)
) {
/* Return WPA enabled */
sec->param.encrypt_key.key_disable = MFALSE;
} else {
sec->param.encrypt_key.key_disable = MTRUE;
}
}
LEAVE();
return ret;
}
/**
* @brief Set security key(s)
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_ioctl_encrypt_key(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
if (sec->param.encrypt_key.is_wapi_key)
status = wlan_sec_ioctl_set_wapi_key(pmadapter, pioctl_req);
else if (sec->param.encrypt_key.key_len > MAX_WEP_KEY_SIZE)
status = wlan_sec_ioctl_set_wpa_key(pmadapter, pioctl_req);
else
status = wlan_sec_ioctl_set_wep_key(pmadapter, pioctl_req);
} else {
status = wlan_sec_ioctl_get_key(pmadapter, pioctl_req);
}
LEAVE();
return status;
}
/**
* @brief Set/Get WPA passphrase for esupplicant
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_ioctl_passphrase(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_sec_cfg *sec = MNULL;
t_u16 cmd_action = 0;
BSSDescriptor_t *pbss_desc;
int i = 0;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
cmd_action = HostCmd_ACT_GEN_REMOVE;
else
cmd_action = HostCmd_ACT_GEN_SET;
} else {
if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) {
if (sec->param.passphrase.ssid.ssid_len == 0) {
i = wlan_find_bssid_in_list(pmpriv,
(t_u8 *) & sec->param.passphrase.
bssid, MLAN_BSS_MODE_AUTO);
if (i > 0) {
pbss_desc = &pmadapter->pscan_table[i];
memcpy(&sec->param.passphrase.ssid, &pbss_desc->ssid,
sizeof(mlan_802_11_ssid));
memset(&sec->param.passphrase.bssid, 0,
MLAN_MAC_ADDR_LENGTH);
PRINTM(MCMND, "PSK_QUERY: found ssid=%s\n",
sec->param.passphrase.ssid.ssid);
}
} else
memset(&sec->param.passphrase.bssid, 0, MLAN_MAC_ADDR_LENGTH);
}
cmd_action = HostCmd_ACT_GEN_GET;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_SUPPLICANT_PMK,
cmd_action,
0, (t_void *) pioctl_req, &sec->param.passphrase);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get esupplicant 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
*/
static mlan_status
wlan_sec_ioctl_ewpa_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_num];
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
sec->param.ewpa_enabled = pmpriv->sec_info.ewpa_enabled;
} else {
pmpriv->sec_info.ewpa_enabled = (t_u8) sec->param.ewpa_enabled;
PRINTM(MCMND, "Set: ewpa_enabled = %d\n",
(int) pmpriv->sec_info.ewpa_enabled);
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Get esupplicant 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
*/
static mlan_status
wlan_sec_ioctl_esupp_mode(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
ENTER();
if (pmpriv->media_connected != MTRUE) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_SUPPLICANT_PROFILE,
HostCmd_ACT_GEN_GET_CURRENT,
0, (t_void *) pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Security configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_sec_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_sec_cfg *sec = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_sec_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_sec_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
switch (sec->sub_command) {
case MLAN_OID_SEC_CFG_AUTH_MODE:
status = wlan_sec_ioctl_auth_mode(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_ENCRYPT_MODE:
status = wlan_sec_ioctl_encrypt_mode(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_WPA_ENABLED:
status = wlan_sec_ioctl_wpa_enable(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_WAPI_ENABLED:
status = wlan_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_ENCRYPT_KEY:
status = wlan_sec_ioctl_encrypt_key(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_PASSPHRASE:
status = wlan_sec_ioctl_passphrase(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_EWPA_ENABLED:
status = wlan_sec_ioctl_ewpa_enable(pmadapter, pioctl_req);
break;
case MLAN_OID_SEC_CFG_ESUPP_MODE:
status = wlan_sec_ioctl_esupp_mode(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Append/Reset IE buffer.
*
* Pass an opaque block of data, expected to be IEEE IEs, to the driver
* for eventual passthrough to the firmware in an associate/join
* (and potentially start) command. This function is the main body
* for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
*
* Data is appended to an existing buffer and then wrapped in a passthrough
* TLV in the command API to the firmware. The firmware treats the data
* as a transparent passthrough to the transmitted management frame.
*
* @param priv A pointer to mlan_private structure
* @param ie_data_ptr A pointer to iwreq structure
* @param ie_len Length of the IE or IE block passed in ie_data_ptr
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
int
wlan_set_gen_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
IEEEtypes_VendorHeader_t *pvendor_ie;
const t_u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
ENTER();
/* If the passed length is zero, reset the buffer */
if (!ie_len) {
priv->gen_ie_buf_len = 0;
priv->wps.session_enable = MFALSE;
} else if (!ie_data_ptr) {
/* MNULL check */
ret = MLAN_STATUS_FAILURE;
} else {
pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
/* Test to see if it is a WPA IE, if not, then it is a gen IE */
if (((pvendor_ie->element_id == WPA_IE)
&& (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
|| (pvendor_ie->element_id == RSN_IE)
) {
/* IE is a WPA/WPA2 IE so call set_wpa function */
ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
priv->wps.session_enable = MFALSE;
} else if (pvendor_ie->element_id == WAPI_IE) {
/* IE is a WAPI IE so call set_wapi function */
ret = wlan_set_wapi_ie(priv, ie_data_ptr, ie_len);
} else {
/*
* Verify that the passed length is not larger than the available
* space remaining in the buffer
*/
if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
/* Test to see if it is a WPS IE, if so, enable wps session
flag */
pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
if ((pvendor_ie->element_id == WPS_IE)
&& (!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
priv->wps.session_enable = MTRUE;
PRINTM(MINFO, "WPS Session Enabled.\n");
}
/* Append the passed data to the end of the genIeBuffer */
memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
ie_len);
/* Increment the stored buffer length by the size passed */
priv->gen_ie_buf_len += ie_len;
} else {
/* Passed data does not fit in the remaining buffer space */
ret = MLAN_STATUS_FAILURE;
}
}
}
/* Return MLAN_STATUS_SUCCESS, or MLAN_STATUS_FAILURE for error case */
LEAVE();
return ret;
}
/**
* @brief Get IE buffer from driver
*
* Used to pass an opaque block of data, expected to be IEEE IEs,
* back to the application. Currently the data block passed
* back to the application is the saved association response retrieved
* from the firmware.
*
* @param priv A pointer to mlan_private structure
* @param ie_data_ptr A pointer to the IE or IE block
* @param ie_len_ptr In/Out parameter pointer for the buffer length passed
* in ie_data_ptr and the resulting data length copied
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
int
wlan_get_gen_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr,
t_u16 * ie_len_ptr)
{
IEEEtypes_AssocRsp_t *passoc_rsp;
t_u16 copy_size;
ENTER();
if ((priv->media_connected == MFALSE) || (priv->assoc_rsp_size == 0)) {
*ie_len_ptr = 0;
LEAVE();
return MLAN_STATUS_SUCCESS;
}
passoc_rsp = (IEEEtypes_AssocRsp_t *) priv->assoc_rsp_buf;
/*
* Set the amount to copy back to the application as the minimum of the
* available IE data or the buffer provided by the application
*/
copy_size = (t_u16) (priv->assoc_rsp_size - sizeof(passoc_rsp->capability)
- sizeof(passoc_rsp->status_code) -
sizeof(passoc_rsp->a_id));
copy_size = MIN(copy_size, *ie_len_ptr);
/* Copy the IEEE TLVs in the assoc response back to the application */
memcpy(ie_data_ptr, (t_u8 *) passoc_rsp->ie_buffer, copy_size);
/* Returned copy length */
*ie_len_ptr = copy_size;
/* No error on return */
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Set/Get WWS 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
*/
static mlan_status
wlan_misc_ioctl_wws_cfg(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc_cfg = MNULL;
t_u16 cmd_action = 0;
t_u32 enable = 0;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
ret = MLAN_STATUS_RESOURCE;
goto exit;
}
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;
enable = misc_cfg->param.wws_cfg;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_SNMP_MIB,
cmd_action,
WwsMode_i, (t_void *) pioctl_req, &enable);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set/Get 11D 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
*/
static mlan_status
wlan_11d_cfg_ioctl_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_num];
mlan_ds_11d_cfg *pcfg_11d = MNULL;
ENTER();
pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
PRINTM(MINFO, "11D: 11dcfg SET=%d\n", pcfg_11d->param.enable_11d);
/* Compare with current settings */
if (pmadapter->state_11d.user_enable_11d != pcfg_11d->param.enable_11d) {
ret =
wlan_11d_enable(pmpriv, pioctl_req,
(state_11d_t) pcfg_11d->param.enable_11d);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
} else {
PRINTM(MINFO, "11D: same as current setting, do nothing\n");
}
} else {
pcfg_11d->param.enable_11d =
(t_u32) pmadapter->state_11d.user_enable_11d;
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
PRINTM(MINFO, "11D: 11dcfg GET=%d\n", pcfg_11d->param.enable_11d);
}
LEAVE();
return ret;
}
/**
* @brief 11D configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_11d_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_11d_cfg *pcfg_11d = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_11d_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_11d_cfg);
status = MLAN_STATUS_RESOURCE;
goto exit;
}
pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
switch (pcfg_11d->sub_command) {
case MLAN_OID_11D_CFG_ENABLE:
status = wlan_11d_cfg_ioctl_enable(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
exit:
LEAVE();
return status;
}
/**
* @brief WPS configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_wps_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_wps_cfg *pwps = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_wps_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_wps_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
pwps = (mlan_ds_wps_cfg *) pioctl_req->pbuf;
switch (pwps->sub_command) {
case MLAN_OID_WPS_CFG_SESSION:
if (pioctl_req->action == MLAN_ACT_SET) {
if (pwps->param.wps_session == MLAN_WPS_CFG_SESSION_START ||
pwps->param.wps_session == MLAN_WPS_CFG_SESSION_END)
pmpriv->wps.session_enable = (t_u8) pwps->param.wps_session;
else
pmpriv->wps.session_enable = MLAN_WPS_CFG_SESSION_END;
} else {
pwps->param.wps_session = (t_u32) pmpriv->wps.session_enable;
pioctl_req->data_read_written = sizeof(t_u32);
PRINTM(MINFO, "wpscfg GET=%d\n", pwps->param.wps_session);
}
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @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_SUCCESS --success, otherwise fail
*/
static 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_num];
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_PMIC:
cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
break;
case MLAN_REG_CAU:
cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
break;
default:
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_SUCCESS --success, otherwise fail
*/
static 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_num];
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_SUCCESS --success, otherwise fail
*/
static 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_num];
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 register memory access handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_reg_mem_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_reg_mem *reg_mem = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_reg_mem)) {
PRINTM(MWARN, "MLAN REG_MEM IOCTL length is too short\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_reg_mem);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
switch (reg_mem->sub_command) {
case MLAN_OID_REG_RW:
status = wlan_reg_mem_ioctl_reg_rw(pmadapter, pioctl_req);
break;
case MLAN_OID_EEPROM_RD:
status = wlan_reg_mem_ioctl_read_eeprom(pmadapter, pioctl_req);
break;
case MLAN_OID_MEM_RW:
status = wlan_reg_mem_ioctl_mem_rw(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set/Get BCA time share parameters
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bca_cfg_ioctl_bca_ts(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_bca_cfg *bca_cfg = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
bca_cfg = (mlan_ds_bca_cfg *) pioctl_req->pbuf;
cmd_action = HostCmd_ACT_GEN_GET;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE,
cmd_action, 0, (t_void *) pioctl_req,
(t_void *) & bca_cfg->param.bca_ts);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief BCA configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_bca_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_bca_cfg *bca_cfg = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_bca_cfg)) {
PRINTM(MWARN, "MLAN_IOCTL_BCA_CFG IOCTL length is too short\n");
pioctl_req->data_read_written = 0;
pioctl_req->buf_len_needed = sizeof(mlan_ds_bca_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
bca_cfg = (mlan_ds_bca_cfg *) pioctl_req->pbuf;
switch (bca_cfg->sub_command) {
case MLAN_OID_BCA_TS:
status = wlan_bca_cfg_ioctl_bca_ts(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set/Get generic IE
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_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_num];
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
switch (misc->param.gen_ie.type) {
case MLAN_IE_TYPE_GEN_IE:
if (pioctl_req->action == MLAN_ACT_GET) {
misc->param.gen_ie.len = pmpriv->wpa_ie_len;
memcpy(misc->param.gen_ie.ie_data, pmpriv->wpa_ie,
misc->param.gen_ie.len);
} else {
wlan_set_gen_ie_helper(pmpriv, misc->param.gen_ie.ie_data,
(t_u16) misc->param.gen_ie.len);
}
break;
case MLAN_IE_TYPE_ARP_FILTER:
memset(pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
if (misc->param.gen_ie.len > ARP_FILTER_MAX_BUF_SIZE) {
pmadapter->arp_filter_size = 0;
PRINTM(MERROR, "Invalid ARP Filter Size\n");
ret = MLAN_STATUS_FAILURE;
} else {
memcpy(pmadapter->arp_filter, misc->param.gen_ie.ie_data,
misc->param.gen_ie.len);
pmadapter->arp_filter_size = misc->param.gen_ie.len;
HEXDUMP("ArpFilter", pmadapter->arp_filter,
pmadapter->arp_filter_size);
}
break;
default:
PRINTM(MERROR, "Invalid IE type\n");
ret = MLAN_STATUS_FAILURE;
}
pioctl_req->data_read_written =
sizeof(mlan_ds_misc_gen_ie) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/Get region code
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_ioctl_region(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_misc_cfg *misc = MNULL;
int i;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
misc->param.region_code = pmadapter->region_code;
} else {
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
/* Use the region code to search for the index */
if (misc->param.region_code == region_code_index[i]) {
pmadapter->region_code = (t_u16) misc->param.region_code;
break;
}
}
/* It's unidentified region code */
if (i >= MRVDRV_MAX_REGION_CODE) {
PRINTM(MERROR, "Region Code not identified\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
pmadapter->config_bands)) {
ret = MLAN_STATUS_FAILURE;
}
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Perform warm reset
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING
*/
static mlan_status
wlan_misc_ioctl_warm_reset(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
pmlan_callbacks pcb = &pmadapter->callbacks;
HostCmd_DS_VERSION_EXT dummy;
t_s32 i = 0;
t_u8 first_sta = MTRUE;
ENTER();
/** Init all the head nodes and free all the locks here */
for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
pmpriv = pmadapter->priv[i];
if (pmadapter->priv[i]) {
wlan_wmm_cleanup_node(pmpriv);
pcb->moal_free_lock(pmpriv->rx_pkt_lock);
pcb->moal_free_lock(pmpriv->wmm.ra_list_spinlock);
}
}
/* Initialize adapter structure */
wlan_init_adapter(pmadapter);
/* Initialize private structures */
for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
pmpriv = pmadapter->priv[i];
if (pmadapter->priv[i])
wlan_init_priv(pmpriv);
}
pmpriv = pmadapter->priv[pioctl_req->bss_num];
/* Restart the firmware */
wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
/* Issue commands to initialize firmware */
for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
if (pmadapter->priv[i]) {
pmadapter->priv[i]->ops.init_cmd(pmadapter->priv[i], first_sta);
first_sta = MFALSE;
}
}
/* Issue dummy Get command to complete the ioctl */
memset(&dummy, 0, sizeof(HostCmd_DS_VERSION_EXT));
wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, HostCmd_ACT_GEN_GET,
0, (t_void *) pioctl_req, (t_void *) & dummy);
LEAVE();
return MLAN_STATUS_PENDING;
}
#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
/**
* @brief Reconfigure SDIO multiport aggregation parameters
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_ioctl_sdio_mpa_ctrl(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
mlan_ds_misc_sdio_mpa_ctrl *mpa_ctrl = MNULL;
ENTER();
mpa_ctrl = &misc->param.mpa_ctrl;
if (pioctl_req->action == MLAN_ACT_SET) {
if (pmpriv->media_connected == MTRUE) {
PRINTM(MMSG, "SDIO MP-A CTRL: not allowed\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (mpa_ctrl->tx_enable > 1) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (mpa_ctrl->rx_enable > 1) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (mpa_ctrl->tx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (mpa_ctrl->rx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (mpa_ctrl->tx_buf_size || mpa_ctrl->rx_buf_size) {
wlan_free_sdio_mpa_buffers(pmadapter);
if (mpa_ctrl->tx_buf_size > 0)
pmadapter->mpa_tx.buf_size = mpa_ctrl->tx_buf_size;
if (mpa_ctrl->rx_buf_size > 0)
pmadapter->mpa_rx.buf_size = mpa_ctrl->rx_buf_size;
if (wlan_alloc_sdio_mpa_buffers(pmadapter,
pmadapter->mpa_tx.buf_size,
pmadapter->mpa_rx.buf_size) !=
MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
}
if (mpa_ctrl->tx_max_ports > 0)
pmadapter->mpa_tx.pkt_aggr_limit = mpa_ctrl->tx_max_ports;
if (mpa_ctrl->rx_max_ports > 0)
pmadapter->mpa_rx.pkt_aggr_limit = mpa_ctrl->rx_max_ports;
pmadapter->mpa_tx.enabled = mpa_ctrl->tx_enable;
pmadapter->mpa_rx.enabled = mpa_ctrl->rx_enable;
} else {
mpa_ctrl->tx_enable = pmadapter->mpa_tx.enabled;
mpa_ctrl->rx_enable = pmadapter->mpa_rx.enabled;
mpa_ctrl->tx_buf_size = pmadapter->mpa_tx.buf_size;
mpa_ctrl->rx_buf_size = pmadapter->mpa_rx.buf_size;
mpa_ctrl->tx_max_ports = pmadapter->mpa_tx.pkt_aggr_limit;
mpa_ctrl->rx_max_ports = pmadapter->mpa_rx.pkt_aggr_limit;
}
exit:
LEAVE();
return ret;
}
#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
#ifdef MFG_CMD_SUPPORT
/**
* @brief send mfg cmd
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_ioctl_mfg_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_num];
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_MFG_COMMAND,
0,
0,
(t_void *) pioctl_req,
(t_void *) & misc->param.mfgcmd);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#endif /* MFG_CMD_SUPPORT */
/**
* @brief Set/Get LDO configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_ioctl_ldo(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_misc_cfg *misc = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
else
cmd_action = HostCmd_ACT_GEN_SET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_LDO_CONFIG,
cmd_action,
0,
(t_void *) pioctl_req,
(t_void *) & misc->param.ldo_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get system clock configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_ioctl_sysclock(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_misc_cfg *misc = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
else
cmd_action = HostCmd_ACT_GEN_SET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG,
cmd_action,
0,
(t_void *) pioctl_req,
(t_void *) & misc->param.sys_clock);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/** Flag for VSIE */
#define VSIE_FLAG 1
/** Max total length of vendor specific IEs for scan/assoc/ad-hoc */
#define MAX_TOTAL_VSIE_LEN 512
/**
* @brief Get/Add/Remove the vendor specific IE
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_ioctl_vendor_spec_ie(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_ds_misc_cfg *misc = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u32 id, index, max_len;
t_u16 mask_bak;
t_u8 bit, len_bak;
ENTER();
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
id = misc->param.vsie.id;
switch (pioctl_req->action) {
case MLAN_ACT_GET:
misc->param.vsie.mask = (t_u32) pmpriv->vs_ie[id].mask;
memcpy(misc->param.vsie.ie, pmpriv->vs_ie[id].ie,
sizeof(misc->param.vsie.ie));
break;
case MLAN_ACT_SET:
mask_bak = pmpriv->vs_ie[id].mask;
pmpriv->vs_ie[id].mask = (t_u16) misc->param.vsie.mask;
if (!pmpriv->vs_ie[id].mask) {
memset(&pmpriv->vs_ie[id], 0, sizeof(vendor_spec_cfg_ie));
} else {
/* Check if the total length of VS IEs is over limitation */
len_bak = pmpriv->vs_ie[id].ie[1];
pmpriv->vs_ie[id].ie[1] = misc->param.vsie.ie[1];
for (bit = MLAN_VSIE_MASK_SCAN; bit <= MLAN_VSIE_MASK_ADHOC;
bit <<= 1) {
max_len = 0;
for (index = 0; index < MLAN_MAX_VSIE_NUM; index++) {
if (pmpriv->vs_ie[index].mask & bit)
max_len += (pmpriv->vs_ie[index].ie[1] + 2);
}
if (max_len > MAX_TOTAL_VSIE_LEN) {
PRINTM(MERROR,
"Total length of VS IEs for %s (%d) is over limitation (%d)\n",
(bit == MLAN_VSIE_MASK_SCAN) ? "scan" : (bit ==
MLAN_VSIE_MASK_ASSOC)
? "assoc" : "ad-hoc", max_len, MAX_TOTAL_VSIE_LEN);
pmpriv->vs_ie[id].mask = mask_bak;
pmpriv->vs_ie[id].ie[1] = len_bak;
ret = MLAN_STATUS_FAILURE;
break;
}
}
if (!ret) {
pmpriv->vs_ie[id].flag = VSIE_FLAG;
memcpy(pmpriv->vs_ie[id].ie, misc->param.vsie.ie,
sizeof(misc->param.vsie.ie));
pmpriv->vs_ie[id].ie[0] = VS_IE;
}
}
break;
default:
break;
}
LEAVE();
return ret;
}
/**
* @brief Miscellaneous configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_misc_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
if (pioctl_req->buf_len < sizeof(mlan_ds_misc_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_misc_cfg);
LEAVE();
return MLAN_STATUS_RESOURCE;
}
misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
switch (misc->sub_command) {
case MLAN_OID_MISC_GEN_IE:
status = wlan_misc_ioctl_gen_ie(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_REGION:
status = wlan_misc_ioctl_region(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_WARM_RESET:
status = wlan_misc_ioctl_warm_reset(pmadapter, pioctl_req);
break;
#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
case MLAN_OID_MISC_SDIO_MPA_CTRL:
status = wlan_misc_ioctl_sdio_mpa_ctrl(pmadapter, pioctl_req);
break;
#endif
#ifdef MFG_CMD_SUPPORT
case MLAN_OID_MISC_MFG_CMD:
status = wlan_misc_ioctl_mfg_cmd(pmadapter, pioctl_req);
break;
#endif
case MLAN_OID_MISC_HOST_CMD:
status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_LDO:
status = wlan_misc_ioctl_ldo(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_SYS_CLOCK:
status = wlan_misc_ioctl_sysclock(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_WWS:
status = wlan_misc_ioctl_wws_cfg(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_VS_IE:
status = wlan_misc_ioctl_vendor_spec_ie(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_INIT_SHUTDOWN:
status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set/Get scan configuration parameter
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
* @param action Set/Get
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_set_get_scan_cfg(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req, IN t_u32 action)
{
mlan_ds_scan *scan = MNULL;
ENTER();
scan = (mlan_ds_scan *) pioctl_req->pbuf;
if (action == MLAN_ACT_GET) {
scan->param.scan_cfg.scan_type = (t_u32) pmadapter->scan_type + 1;
scan->param.scan_cfg.scan_mode = pmadapter->scan_mode;
scan->param.scan_cfg.scan_probe = (t_u32) pmadapter->scan_probes;
scan->param.scan_cfg.scan_time.specific_scan_time =
(t_u32) pmadapter->specific_scan_time;
scan->param.scan_cfg.scan_time.active_scan_time =
(t_u32) pmadapter->active_scan_time;
scan->param.scan_cfg.scan_time.passive_scan_time =
(t_u32) pmadapter->passive_scan_time;
} else {
if (scan->param.scan_cfg.scan_type)
pmadapter->scan_type = (t_u8) scan->param.scan_cfg.scan_type - 1;
if (scan->param.scan_cfg.scan_mode)
pmadapter->scan_mode = scan->param.scan_cfg.scan_mode;
if (scan->param.scan_cfg.scan_probe)
pmadapter->scan_probes = (t_u16) scan->param.scan_cfg.scan_probe;
if (scan->param.scan_cfg.scan_time.specific_scan_time)
pmadapter->specific_scan_time =
(t_u16) scan->param.scan_cfg.scan_time.specific_scan_time;
if (scan->param.scan_cfg.scan_time.active_scan_time)
pmadapter->active_scan_time =
(t_u16) scan->param.scan_cfg.scan_time.active_scan_time;
if (scan->param.scan_cfg.scan_time.passive_scan_time)
pmadapter->passive_scan_time =
(t_u16) scan->param.scan_cfg.scan_time.passive_scan_time;
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Set/Get scan
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status
wlan_scan_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_num];
mlan_status status = MLAN_STATUS_SUCCESS;
mlan_ds_scan *pscan;
ENTER();
pscan = (mlan_ds_scan *) pioctl_req->pbuf;
if (pmadapter->scan_processing && pioctl_req->action == MLAN_ACT_SET) {
PRINTM(MCMND, "Scan already in process...\n");
LEAVE();
return status;
}
/* Set scan */
if (pioctl_req->action == MLAN_ACT_SET) {
switch (pscan->sub_command) {
case MLAN_OID_SCAN_NORMAL:
status = wlan_scan_networks(pmpriv, pioctl_req, MNULL);
break;
case MLAN_OID_SCAN_SPECIFIC_SSID:
status = wlan_scan_specific_ssid(pmpriv, pioctl_req,
&pscan->param.scan_req.scan_ssid);
break;
case MLAN_OID_SCAN_USER_CONFIG:
status = wlan_scan_networks(pmpriv, pioctl_req,
(wlan_user_scan_cfg *) pscan->param.
user_scan.scan_cfg_buf);
break;
case MLAN_OID_SCAN_CONFIG:
status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_SET);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
if ((status == MLAN_STATUS_SUCCESS) &&
(pscan->sub_command != MLAN_OID_SCAN_CONFIG)) {
PRINTM(MINFO, "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
status = MLAN_STATUS_PENDING;
}
}
/* Get scan */
else {
if (pscan->sub_command == MLAN_OID_SCAN_CONFIG) {
status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_GET);
} else if (pscan->sub_command == MLAN_OID_SCAN_SPECIFIC_SSID) {
pscan->param.scan_resp.num_in_scan_table =
pmadapter->num_in_scan_table;
pscan->param.scan_resp.pscan_table =
(t_u8 *) & pmpriv->curr_bss_params.bss_descriptor;
pioctl_req->data_read_written =
sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
} else {
pscan->param.scan_resp.pscan_table =
(t_u8 *) pmadapter->pscan_table;
pscan->param.scan_resp.num_in_scan_table =
pmadapter->num_in_scan_table;
pioctl_req->data_read_written =
sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
}
}
LEAVE();
return status;
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief MLAN station 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
mlan_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
{
pmlan_adapter pmadapter = (pmlan_adapter) adapter;
mlan_status status = MLAN_STATUS_SUCCESS;
ENTER();
switch (pioctl_req->req_id) {
case MLAN_IOCTL_SCAN:
status = wlan_scan_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_BSS:
status = wlan_bss_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_RADIO_CFG:
status = wlan_radio_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_SNMP_MIB:
status = wlan_snmp_mib_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_GET_INFO:
status = wlan_get_info_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_SEC_CFG:
status = wlan_sec_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_RATE:
status = wlan_rate_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_POWER_CFG:
status = wlan_power_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_PM_CFG:
status = wlan_pm_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_WMM_CFG:
status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_WPS_CFG:
status = wlan_wps_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_11N_CFG:
status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_11D_CFG:
status = wlan_11d_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_REG_MEM:
status = wlan_reg_mem_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_BCA_CFG:
status = wlan_bca_cfg_ioctl(pmadapter, pioctl_req);
break;
case MLAN_IOCTL_MISC_CFG:
status = wlan_misc_cfg_ioctl(pmadapter, pioctl_req);
break;
default:
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}