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;