mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-14 19:15:35 +00:00
13b6fdb0b4
changes: 1. WCSWREL-191: Fixed the error when loading module param from user config for SD8801 2. WCSWREL-186: Fixed the issue of mlanutl failing on kernel higher than L5.15 3. Fixed low throughput issue for WPA3 SAE 4. Added driver change for WLAN throughput improvement on 8997 SoC 5. Updated README to recommend not to use WEP/TKIP for all chipsets 6. WCSWREL-180: Fix P2P test fail on kernel higher than L5.12 7. WCSWREL-156: kernel_write/kernel_read not allowed by drivers for L5.10 kernel GKI buildou 8. Alternative for pm_qos_add_request/pm_qos_remove_request Signed-off-by: Sherry Sun <sherry.sun@nxp.com> Approved-by: Tian Yang <yang.tian@nxp.com>
5678 lines
164 KiB
C
5678 lines
164 KiB
C
/** @file mlan_sta_ioctl.c
|
|
*
|
|
* @brief This file contains the functions for station ioctl.
|
|
*
|
|
*
|
|
* Copyright 2008-2021 NXP
|
|
*
|
|
* This software file (the File) is distributed by NXP
|
|
* under the terms of the GNU General Public License Version 2, June 1991
|
|
* (the License). You may use, redistribute and/or modify the File in
|
|
* accordance with the terms and conditions of the License, a copy of which
|
|
* is available by writing to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
|
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
*
|
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
* this warranty disclaimer.
|
|
*
|
|
*/
|
|
|
|
/******************************************************
|
|
Change log:
|
|
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_11ac.h"
|
|
#include "mlan_11ax.h"
|
|
#include "mlan_11h.h"
|
|
#ifdef DRV_EMBEDDED_SUPPLICANT
|
|
#include "authenticator_api.h"
|
|
#endif
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief Get signal information
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_get_info_signal(pmlan_adapter pmadapter,
|
|
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_index];
|
|
} 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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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");
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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 signal information
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_get_info_signal_ext(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_get_info *info = MNULL;
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req != MNULL) {
|
|
pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
} else {
|
|
PRINTM(MERROR, "MLAN IOCTL information is not present\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
info = (mlan_ds_get_info *)pioctl_req->pbuf;
|
|
|
|
/* Check information buffer length of MLAN IOCTL */
|
|
if (pioctl_req->buf_len < sizeof(mlan_ds_get_info)) {
|
|
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_info);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_RESOURCE;
|
|
goto exit;
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RSSI_INFO_EXT,
|
|
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
|
|
(t_void *)info);
|
|
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_get_info_stats(pmlan_adapter pmadapter,
|
|
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_index];
|
|
} 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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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 sta channel information
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_get_chan_info(pmlan_adapter pmadapter,
|
|
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_index];
|
|
} 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(chan_band_info)) {
|
|
PRINTM(MWARN,
|
|
"MLAN IOCTL information buffer length is too short.\n");
|
|
pioctl_req->data_read_written = 0;
|
|
pioctl_req->buf_len_needed = sizeof(chan_band_info);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_RESOURCE;
|
|
goto exit;
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_STA_CONFIGURE,
|
|
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
|
|
*/
|
|
static mlan_status wlan_get_info_bss_info(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_get_info *info;
|
|
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_ext(pmadapter, &info->param.bss_info.ssid, &pbss_desc->ssid,
|
|
sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
|
|
|
|
/* BSSID */
|
|
memcpy_ext(pmadapter, &info->param.bss_info.bssid,
|
|
&pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
|
|
/* Channel */
|
|
info->param.bss_info.bss_chan = pbss_desc->channel;
|
|
|
|
/* Beacon interval */
|
|
info->param.bss_info.beacon_interval = pbss_desc->beacon_period;
|
|
|
|
/* Band */
|
|
info->param.bss_info.bss_band = (t_u8)pbss_desc->bss_band;
|
|
|
|
/* Region code */
|
|
info->param.bss_info.region_code = pmadapter->region_code;
|
|
|
|
/* Scan table index if connected */
|
|
info->param.bss_info.scan_table_idx = 0;
|
|
info->param.bss_info.scan_block = pmadapter->scan_block;
|
|
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;
|
|
|
|
/* Capability Info */
|
|
info->param.bss_info.capability_info = 0;
|
|
memcpy_ext(pmadapter, &info->param.bss_info.capability_info,
|
|
&pbss_desc->cap_info,
|
|
sizeof(info->param.bss_info.capability_info),
|
|
sizeof(info->param.bss_info.capability_info));
|
|
|
|
memset(pmadapter, &info->param.bss_info.ext_cap, 0, sizeof(ExtCap_t));
|
|
if (pbss_desc->pext_cap) {
|
|
memcpy_ext(pmadapter, &info->param.bss_info.ext_cap,
|
|
(t_u8 *)pbss_desc->pext_cap +
|
|
sizeof(IEEEtypes_Header_t),
|
|
pbss_desc->pext_cap->ieee_hdr.len,
|
|
sizeof(info->param.bss_info.ext_cap));
|
|
}
|
|
|
|
/* Listen Interval */
|
|
info->param.bss_info.listen_interval = pmpriv->listen_interval;
|
|
|
|
/* Association ID */
|
|
info->param.bss_info.assoc_id =
|
|
(t_u16)((IEEEtypes_AssocRsp_t *)pmpriv->assoc_rsp_buf)->a_id;
|
|
|
|
/* AP/Peer supported rates */
|
|
memset(pmadapter, info->param.bss_info.peer_supp_rates, 0,
|
|
sizeof(info->param.bss_info.peer_supp_rates));
|
|
memcpy_ext(pmadapter, info->param.bss_info.peer_supp_rates,
|
|
pbss_desc->supported_rates,
|
|
sizeof(pbss_desc->supported_rates),
|
|
sizeof(info->param.bss_info.peer_supp_rates));
|
|
if (pbss_desc->pmd_ie) {
|
|
info->param.bss_info.mdid = pbss_desc->pmd_ie->mdid;
|
|
info->param.bss_info.ft_cap = pbss_desc->pmd_ie->ft_cap;
|
|
}
|
|
pioctl_req->data_read_written =
|
|
sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
|
|
|
|
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(pmlan_adapter pmadapter,
|
|
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_index];
|
|
|
|
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_SIGNAL_EXT:
|
|
status = wlan_get_info_signal_ext(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;
|
|
pget_info->param.fw_info.hotfix_version =
|
|
pmadapter->fw_hotfix_ver;
|
|
memcpy_ext(pmadapter, &pget_info->param.fw_info.mac_addr,
|
|
pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
|
|
pget_info->param.fw_info.region_code = pmadapter->region_code;
|
|
if (pmadapter->otp_region && pmadapter->otp_region->force_reg)
|
|
pget_info->param.fw_info.force_reg = MTRUE;
|
|
else
|
|
pget_info->param.fw_info.force_reg = MFALSE;
|
|
pget_info->param.fw_info.ecsa_enable = pmadapter->ecsa_enable;
|
|
pget_info->param.fw_info.getlog_enable =
|
|
pmadapter->getlog_enable;
|
|
pget_info->param.fw_info.hw_dev_mcs_support =
|
|
pmadapter->hw_dev_mcs_support;
|
|
pget_info->param.fw_info.hw_dot_11n_dev_cap =
|
|
pmadapter->hw_dot_11n_dev_cap;
|
|
pget_info->param.fw_info.usr_dev_mcs_support =
|
|
pmpriv->usr_dev_mcs_support;
|
|
if (IS_FW_SUPPORT_NO_80MHZ(pmadapter))
|
|
pget_info->param.fw_info.prohibit_80mhz = MTRUE;
|
|
else
|
|
pget_info->param.fw_info.prohibit_80mhz = MFALSE;
|
|
pget_info->param.fw_info.hw_dot_11ac_mcs_support =
|
|
pmadapter->hw_dot_11ac_mcs_support;
|
|
pget_info->param.fw_info.hw_dot_11ac_dev_cap =
|
|
pmadapter->hw_dot_11ac_dev_cap;
|
|
pget_info->param.fw_info.usr_dot_11ac_dev_cap_bg =
|
|
pmpriv->usr_dot_11ac_dev_cap_bg;
|
|
pget_info->param.fw_info.usr_dot_11ac_mcs_support =
|
|
pmpriv->usr_dot_11ac_mcs_support;
|
|
pget_info->param.fw_info.usr_dot_11ac_dev_cap_a =
|
|
pmpriv->usr_dot_11ac_dev_cap_a;
|
|
pget_info->param.fw_info.hw_hecap_len = pmadapter->hw_hecap_len;
|
|
pget_info->param.fw_info.hw_2g_hecap_len =
|
|
pmadapter->hw_2g_hecap_len;
|
|
memcpy_ext(pmadapter, pget_info->param.fw_info.hw_he_cap,
|
|
pmadapter->hw_he_cap, pmadapter->hw_hecap_len,
|
|
sizeof(pget_info->param.fw_info.hw_he_cap));
|
|
memcpy_ext(pmadapter, pget_info->param.fw_info.hw_2g_he_cap,
|
|
pmadapter->hw_2g_he_cap, pmadapter->hw_2g_hecap_len,
|
|
sizeof(pget_info->param.fw_info.hw_2g_he_cap));
|
|
pget_info->param.fw_info.fw_supplicant_support =
|
|
IS_FW_SUPPORT_SUPPLICANT(pmadapter) ? 0x01 : 0x00;
|
|
pget_info->param.fw_info.antinfo = pmadapter->antinfo;
|
|
pget_info->param.fw_info.max_ap_assoc_sta =
|
|
pmadapter->max_sta_conn;
|
|
pget_info->param.fw_info.fw_beacon_prot =
|
|
IS_FW_SUPPORT_BEACON_PROT(pmadapter) ? 0x01 : 0x00;
|
|
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;
|
|
case MLAN_OID_LINK_STATS:
|
|
status = wlan_ioctl_link_statistic(pmpriv, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_snmp_mib_ioctl(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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;
|
|
case MLAN_OID_SNMP_MIB_DTIM_PERIOD:
|
|
value = mib->param.dtim_period;
|
|
cmd_oid = DtimPeriod_i;
|
|
break;
|
|
case MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE:
|
|
value = mib->param.signalext_enable;
|
|
cmd_oid = SignalextEnable_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 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(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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;
|
|
case MLAN_OID_REMAIN_CHAN_CFG:
|
|
status =
|
|
wlan_radio_ioctl_remain_chan_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MIMO_SWITCH:
|
|
status =
|
|
wlan_radio_ioctl_mimo_switch_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_mac_address(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
t_u16 cmd_action;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
} else {
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
memcpy_ext(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
|
|
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_MAC_ADDRESS,
|
|
cmd_action, 0, (t_void *)pioctl_req, MNULL);
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_set_multicast_list(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u16 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) {
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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_ALL_MULTI_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);
|
|
}
|
|
if (ret)
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
PRINTM(MINFO, "old_pkt_filter=0x%x, curr_pkt_filter=0x%x\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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
chan_freq_power_t *cfp;
|
|
t_u32 i, j;
|
|
|
|
ENTER();
|
|
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
if (pioctl_req->action != MLAN_ACT_GET) {
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
if ((wlan_11d_is_enabled(pmpriv) && 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;
|
|
|
|
memset(pmadapter, ®ion_chan, 0,
|
|
sizeof(parsed_region_chan_11d_t));
|
|
|
|
/*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,
|
|
®ion_chan) == MLAN_STATUS_SUCCESS) {
|
|
parsed_region_chan = ®ion_chan;
|
|
} else {
|
|
parsed_region_chan = &pmadapter->parsed_region_chan;
|
|
}
|
|
|
|
PRINTM(MINFO, "no_of_chan=%d\n",
|
|
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;
|
|
band = parsed_region_chan->chan_pwr[i].band;
|
|
PRINTM(MINFO, "band=%d, chan_no=%d\n", band, 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 < MAX_REGION_CHANNEL_NUM);
|
|
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;
|
|
}
|
|
|
|
/** Highest channel used in 2.4GHz band */
|
|
#define MAX_CHANNEL_BAND_B (14)
|
|
|
|
/** Highest frequency used in 2.4GHz band */
|
|
#define MAX_FREQUENCY_BAND_B (2484)
|
|
|
|
/**
|
|
* @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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = MNULL;
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
chan_freq_power_t *cfp = MNULL;
|
|
ENTER();
|
|
|
|
if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
|
|
PRINTM(MERROR, "Request buffer not found!\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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 {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
if (pmadapter->adhoc_start_band & BAND_A)
|
|
pmadapter->adhoc_start_band = BAND_G | BAND_B;
|
|
if (bss->param.bss_chan.channel) {
|
|
if (bss->param.bss_chan.channel <= MAX_CHANNEL_BAND_B)
|
|
cfp = wlan_find_cfp_by_band_and_channel(
|
|
pmadapter, BAND_B,
|
|
(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) {
|
|
pmadapter->adhoc_start_band = BAND_A;
|
|
}
|
|
}
|
|
} else {
|
|
if (bss->param.bss_chan.freq <= MAX_FREQUENCY_BAND_B)
|
|
cfp = wlan_find_cfp_by_band_and_freq(
|
|
pmadapter, BAND_B, 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) {
|
|
pmadapter->adhoc_start_band = BAND_A;
|
|
}
|
|
}
|
|
}
|
|
if (!cfp || !cfp->channel) {
|
|
PRINTM(MERROR, "Invalid channel/freq\n");
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pmpriv->adhoc_channel = (t_u8)cfp->channel;
|
|
pmpriv->intf_state_11h.adhoc_auto_sel_chan = 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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_mode(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
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_AUTO)
|
|
ret = wlan_disconnect(pmpriv, MNULL, MNULL);
|
|
else
|
|
ret = wlan_disconnect(pmpriv, pioctl_req, MNULL);
|
|
|
|
if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO)
|
|
pmpriv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
|
|
pmpriv->bss_mode = bss->param.bss_mode;
|
|
if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
|
|
pmpriv->port_ctrl_mode = MTRUE;
|
|
else
|
|
pmpriv->port_ctrl_mode = MFALSE;
|
|
if (pmpriv->bss_mode != MLAN_BSS_MODE_AUTO) {
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE,
|
|
HostCmd_ACT_GEN_SET, 0,
|
|
(t_void *)pioctl_req, MNULL);
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
}
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_start(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
t_s32 i = -1;
|
|
t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
|
|
|
|
ENTER();
|
|
|
|
/* Before ASSOC REQ, If "port ctrl" mode is enabled,
|
|
* move the port to CLOSED state */
|
|
if (pmpriv->port_ctrl_mode == MTRUE) {
|
|
PRINTM(MINFO, "bss_ioctl_start(): port_state=CLOSED\n");
|
|
pmpriv->prior_port_status = pmpriv->port_open;
|
|
pmpriv->port_open = MFALSE;
|
|
}
|
|
pmadapter->scan_block = MFALSE;
|
|
|
|
if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
|
|
if (!bss->param.ssid_bssid.idx ||
|
|
bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
|
|
/* Search for the requested SSID in the scan table */
|
|
if (bss->param.ssid_bssid.ssid.ssid_len) {
|
|
if (memcmp(pmadapter,
|
|
&bss->param.ssid_bssid.bssid,
|
|
zero_mac, sizeof(zero_mac)))
|
|
i = wlan_find_ssid_in_list(
|
|
pmpriv,
|
|
&bss->param.ssid_bssid.ssid,
|
|
(t_u8 *)&bss->param.ssid_bssid
|
|
.bssid,
|
|
MLAN_BSS_MODE_INFRA);
|
|
else
|
|
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);
|
|
}
|
|
} else {
|
|
/* use bsslist index number to assoicate */
|
|
i = wlan_is_network_compatible(
|
|
pmpriv, bss->param.ssid_bssid.idx - 1,
|
|
pmpriv->bss_mode);
|
|
}
|
|
if (i >= 0) {
|
|
/* block if upper-layer tries to reconnect before new
|
|
* scan */
|
|
if (wlan_11h_get_csa_closed_channel(pmpriv) ==
|
|
(t_u8)pmadapter->pscan_table[i].channel) {
|
|
PRINTM(MINFO,
|
|
"Attempt to reconnect on csa_closed_chan(%d)\n",
|
|
pmadapter->pscan_table[i].channel);
|
|
pioctl_req->status_code =
|
|
MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto start_ssid_done;
|
|
}
|
|
PRINTM(MINFO,
|
|
"SSID found in scan list ... associating...\n");
|
|
pmpriv->curr_bss_params.host_mlme =
|
|
bss->param.ssid_bssid.host_mlme;
|
|
memcpy_ext(pmpriv->adapter,
|
|
&pmpriv->curr_bss_params.prev_bssid,
|
|
&bss->param.ssid_bssid.prev_bssid,
|
|
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
|
|
/* Clear any past association response stored for
|
|
* application retrieval */
|
|
pmpriv->assoc_rsp_size = 0;
|
|
pmpriv->curr_chan_flags =
|
|
bss->param.ssid_bssid.channel_flags;
|
|
if (IS_FW_SUPPORT_NO_80MHZ(pmadapter))
|
|
pmpriv->curr_chan_flags |= CHAN_FLAGS_NO_80MHZ;
|
|
ret = wlan_associate(pmpriv, pioctl_req,
|
|
&pmadapter->pscan_table[i]);
|
|
if (ret)
|
|
goto start_ssid_done;
|
|
} else { /* i >= 0 */
|
|
PRINTM(MERROR,
|
|
"SSID not found in scan list: ssid=%s, " MACSTR
|
|
", idx=%d\n",
|
|
bss->param.ssid_bssid.ssid.ssid,
|
|
MAC2STR(bss->param.ssid_bssid.bssid),
|
|
(int)bss->param.ssid_bssid.idx);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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;
|
|
|
|
if (!bss->param.ssid_bssid.idx ||
|
|
bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
|
|
/* 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);
|
|
}
|
|
} else {
|
|
/* use bsslist index number to assoicate */
|
|
i = wlan_is_network_compatible(
|
|
pmpriv, bss->param.ssid_bssid.idx - 1,
|
|
pmpriv->bss_mode);
|
|
}
|
|
|
|
if (i >= 0) {
|
|
PRINTM(MINFO,
|
|
"Network found in scan list ... joining ...\n");
|
|
pmpriv->curr_chan_flags =
|
|
bss->param.ssid_bssid.channel_flags;
|
|
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);
|
|
pmpriv->curr_chan_flags =
|
|
bss->param.ssid_bssid.channel_flags;
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_stop(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
|
|
ENTER();
|
|
|
|
ret = wlan_disconnect(pmpriv, pioctl_req, &bss->param.deauth_param);
|
|
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_ibss_channel(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u16 cmd_action;
|
|
|
|
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->intf_state_11h.adhoc_auto_sel_chan = 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 Listen Interval
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_listen_interval(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
|
|
ENTER();
|
|
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET)
|
|
bss->param.listen_interval = pmpriv->listen_interval;
|
|
else
|
|
pmpriv->listen_interval = bss->param.listen_interval;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @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
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_beacon_interval(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
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
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_atim_window(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
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 Query embe
|
|
*
|
|
* @param priv A pointer to mlan_private structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS -- success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_query_passphrase(mlan_private *priv,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_adapter *pmadapter = priv->adapter;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_ssid_bssid *ssid_bssid = MNULL;
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
mlan_ds_passphrase *sec_pp;
|
|
int i = 0;
|
|
BSSDescriptor_t *pbss_desc;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
ssid_bssid = &bss->param.ssid_bssid;
|
|
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_ds_sec_cfg),
|
|
MLAN_MEM_DEF, (t_u8 **)&sec);
|
|
if (ret || !sec) {
|
|
PRINTM(MERROR, "Could not allocate sec!\n");
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
memset(pmadapter, sec, 0, sizeof(mlan_ds_sec_cfg));
|
|
sec_pp = (mlan_ds_passphrase *)&sec->param.passphrase;
|
|
sec_pp->psk_type = MLAN_PSK_QUERY;
|
|
if (ssid_bssid->ssid.ssid_len == 0) {
|
|
i = wlan_find_bssid_in_list(priv, (t_u8 *)&ssid_bssid->bssid,
|
|
MLAN_BSS_MODE_AUTO);
|
|
if (i >= 0) {
|
|
pbss_desc = &pmadapter->pscan_table[i];
|
|
memcpy_ext(pmadapter, (t_u8 *)&sec_pp->ssid,
|
|
&pbss_desc->ssid, sizeof(mlan_802_11_ssid),
|
|
sizeof(mlan_802_11_ssid));
|
|
} else
|
|
memcpy_ext(pmadapter, (t_u8 *)&sec_pp->bssid,
|
|
&ssid_bssid->bssid, MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
} else {
|
|
memcpy_ext(pmadapter, (t_u8 *)&sec_pp->ssid, &ssid_bssid->ssid,
|
|
sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(priv, HostCmd_CMD_SUPPLICANT_PMK,
|
|
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
|
|
(t_void *)sec);
|
|
if (sec)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)sec);
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_find_bss(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
#ifdef DRV_EMBEDDED_SUPPLICANT
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_ssid_bssid *ssid_bssid = MNULL;
|
|
#endif
|
|
|
|
ENTER();
|
|
|
|
if (pmpriv->ewpa_query) {
|
|
if (wlan_query_passphrase(pmpriv, pioctl_req) ==
|
|
MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MINFO, "Find BSS ioctl: query passphrase\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_PENDING;
|
|
}
|
|
}
|
|
#ifdef DRV_EMBEDDED_SUPPLICANT
|
|
if (!IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) {
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
ssid_bssid = &bss->param.ssid_bssid;
|
|
supplicantQueryPassphraseAndEnable(pmpriv->psapriv,
|
|
(t_u8 *)ssid_bssid);
|
|
}
|
|
#endif
|
|
|
|
ret = wlan_find_bss(pmpriv, pioctl_req);
|
|
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_bss_ioctl_find_bssid(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
int i = 0;
|
|
|
|
ENTER();
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
i = wlan_find_bssid_in_list(pmpriv, (t_u8 *)&bss->param.bssid,
|
|
MLAN_BSS_MODE_AUTO);
|
|
if (i < 0) {
|
|
PRINTM(MCMND, "Can not find bssid " MACSTR "\n",
|
|
MAC2STR((t_u8 *)&bss->param.bssid));
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
PRINTM(MCMND, "Find bssid " MACSTR "\n",
|
|
MAC2STR((t_u8 *)&bss->param.bssid));
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if BSS channel is valid for Station's region
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status
|
|
wlan_bss_ioctl_bss_11d_check_channel(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_bss *bss = MNULL;
|
|
mlan_ssid_bssid *ssid_bssid = MNULL;
|
|
|
|
ENTER();
|
|
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
ssid_bssid = &bss->param.ssid_bssid;
|
|
|
|
PRINTM(MINFO, "ssid: %s idx:%d\n", ssid_bssid->ssid.ssid,
|
|
ssid_bssid->idx);
|
|
PRINTM(MINFO, "band:%d channel:%d\n", (t_u8)ssid_bssid->bss_band,
|
|
(t_u32)ssid_bssid->channel);
|
|
|
|
/* check if this channel is supported in the region */
|
|
if (!wlan_find_cfp_by_band_and_channel(pmadapter,
|
|
(t_u8)ssid_bssid->bss_band,
|
|
(t_u32)ssid_bssid->channel)) {
|
|
PRINTM(MERROR, "Unsupported Channel for region 0x%x\n",
|
|
pmadapter->region_code);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
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(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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_BSS_FIND_BSSID:
|
|
status = wlan_bss_ioctl_find_bssid(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;
|
|
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
|
|
case MLAN_OID_BSS_ROLE:
|
|
util_enqueue_list_tail(pmadapter->pmoal_handle,
|
|
&pmadapter->ioctl_pending_q,
|
|
(pmlan_linked_list)pioctl_req,
|
|
pmadapter->callbacks.moal_spin_lock,
|
|
pmadapter->callbacks.moal_spin_unlock);
|
|
pmadapter->pending_ioctl = MTRUE;
|
|
status = MLAN_STATUS_PENDING;
|
|
break;
|
|
#endif
|
|
#ifdef WIFI_DIRECT_SUPPORT
|
|
case MLAN_OID_WIFI_DIRECT_MODE:
|
|
status = wlan_bss_ioctl_wifi_direct_mode(pmadapter, pioctl_req);
|
|
break;
|
|
#endif
|
|
case MLAN_OID_BSS_LISTEN_INTERVAL:
|
|
status = wlan_bss_ioctl_listen_interval(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_BSS_REMOVE:
|
|
status = wlan_bss_ioctl_bss_remove(pmadapter, pioctl_req);
|
|
break;
|
|
|
|
case MLAN_OID_BSS_11D_CHECK_CHANNEL:
|
|
status = wlan_bss_ioctl_bss_11d_check_channel(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_BSS_CHAN_INFO:
|
|
status = wlan_bss_ioctl_get_chan_info(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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_rate *rate = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
if (pioctl_req->action != MLAN_ACT_GET) {
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
rate = (mlan_ds_rate *)pioctl_req->pbuf;
|
|
if (rate->param.rate_band_cfg.config_bands &&
|
|
rate->param.rate_band_cfg.bss_mode)
|
|
wlan_get_active_data_rates(
|
|
pmpriv, rate->param.rate_band_cfg.bss_mode,
|
|
rate->param.rate_band_cfg.config_bands,
|
|
rate->param.rates);
|
|
else
|
|
wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
|
|
(pmpriv->bss_mode ==
|
|
MLAN_BSS_MODE_INFRA) ?
|
|
pmpriv->config_bands :
|
|
pmadapter->adhoc_start_band,
|
|
rate->param.rates);
|
|
pioctl_req->data_read_written =
|
|
MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_rate_ioctl(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
status = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief Get Tx power configuration
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param cmd_no Firmware command number used to retrieve power values
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_power_ioctl_get_power(pmlan_adapter pmadapter,
|
|
t_u16 cmd_no,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
|
|
ENTER();
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, cmd_no, 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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_power_ioctl_set_power(pmlan_adapter pmadapter,
|
|
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_s8 dbm = 0;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
|
|
ENTER();
|
|
|
|
power = (mlan_ds_power_cfg *)pioctl_req->pbuf;
|
|
if (!power->param.power_cfg.is_power_auto) {
|
|
dbm = (t_s8)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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
MRVDRV_SIZE_OF_CMD_BUFFER, MLAN_MEM_DEF, &buf);
|
|
if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
|
|
PRINTM(MERROR,
|
|
"ALLOC_CMD_BUF: Failed to allocate command buffer\n");
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
memset(pmadapter, 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(pmadapter->pmoal_handle, buf);
|
|
|
|
exit:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_power_ioctl_set_power_ext(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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;
|
|
mlan_power_group *pwr_grp = MNULL;
|
|
|
|
ENTER();
|
|
|
|
power = (mlan_ds_power_cfg *)pioctl_req->pbuf;
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
MRVDRV_SIZE_OF_CMD_BUFFER, MLAN_MEM_DEF, &buf);
|
|
if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
|
|
PRINTM(MERROR,
|
|
"ALLOC_CMD_BUF: Failed to allocate command buffer\n");
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
txp_cfg = (HostCmd_DS_TXPWR_CFG *)buf;
|
|
txp_cfg->action = HostCmd_ACT_GEN_SET;
|
|
pwr_grp = &power->param.power_ext.power_group[0];
|
|
if (pwr_grp->rate_format == TX_PWR_CFG_AUTO_CTRL_OFF)
|
|
txp_cfg->mode = 0;
|
|
else {
|
|
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->ht_bandwidth = pwr_grp->bandwidth;
|
|
pg->power_min = (t_s8)pwr_grp->power_min;
|
|
pg->power_max = (t_s8)pwr_grp->power_max;
|
|
pg->power_step = (t_s8)pwr_grp->power_step;
|
|
|
|
if (pwr_grp->rate_format == MLAN_RATE_FORMAT_LG) {
|
|
if (pwr_grp->first_rate_ind <=
|
|
MLAN_RATE_INDEX_HRDSSS3) {
|
|
pg->modulation_class = MOD_CLASS_HR_DSSS;
|
|
} else {
|
|
pg->modulation_class = MOD_CLASS_OFDM;
|
|
pwr_grp->first_rate_ind -=
|
|
MLAN_RATE_INDEX_OFDM0;
|
|
pwr_grp->last_rate_ind -= MLAN_RATE_INDEX_OFDM0;
|
|
}
|
|
pg->first_rate_code = (t_u8)pwr_grp->first_rate_ind;
|
|
pg->last_rate_code = (t_u8)pwr_grp->last_rate_ind;
|
|
} else if (pwr_grp->rate_format == MLAN_RATE_FORMAT_HT) {
|
|
pg->modulation_class = MOD_CLASS_HT;
|
|
pg->first_rate_code = (t_u8)pwr_grp->first_rate_ind;
|
|
pg->last_rate_code = (t_u8)pwr_grp->last_rate_ind;
|
|
} else if (pwr_grp->rate_format == MLAN_RATE_FORMAT_VHT) {
|
|
pg->modulation_class = MOD_CLASS_VHT;
|
|
pg->first_rate_code =
|
|
(t_u8)((pwr_grp->first_rate_ind & 0xF) |
|
|
((pwr_grp->nss - 1) << 4));
|
|
pg->last_rate_code =
|
|
(t_u8)((pwr_grp->last_rate_ind & 0xF) |
|
|
((pwr_grp->nss - 1) << 4));
|
|
} else {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
if (ret == MLAN_STATUS_FAILURE) {
|
|
if (buf)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, 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(pmadapter->pmoal_handle, 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(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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, HostCmd_CMD_TXPWR_CFG, 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, HostCmd_CMD_TXPWR_CFG, pioctl_req);
|
|
else
|
|
status = wlan_power_ioctl_set_power_ext(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_POWER_LOW_POWER_MODE:
|
|
status = wlan_power_ioctl_set_get_lpm(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_pm_ioctl_ps_mode(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req,
|
|
t_u16 ps_mode)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
t_u16 sub_cmd;
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
sub_cmd = (pmadapter->ps_mode == Wlan802_11PowerModePSP) ?
|
|
EN_AUTO_PS :
|
|
DIS_AUTO_PS;
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
|
|
sub_cmd, BITMAP_STA_PS,
|
|
(t_void *)pioctl_req, MNULL);
|
|
if ((ret == MLAN_STATUS_SUCCESS) && (sub_cmd == DIS_AUTO_PS)) {
|
|
ret = wlan_prepare_cmd(pmpriv,
|
|
HostCmd_CMD_802_11_PS_MODE_ENH,
|
|
GET_PS, 0, MNULL, MNULL);
|
|
}
|
|
} else {
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
|
|
GET_PS, 0, (t_void *)pioctl_req, MNULL);
|
|
}
|
|
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_pm_ioctl_inactivity_timeout(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_set_auto_deep_sleep(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_private pmpriv =
|
|
(pmlan_private)pmadapter->priv[pioctl_req->bss_index];
|
|
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_PS;
|
|
} else {
|
|
auto_ds.auto_ds = DEEP_SLEEP_OFF;
|
|
PRINTM(MINFO, "Auto Deep Sleep: off\n");
|
|
mode = DIS_AUTO_PS;
|
|
}
|
|
if (((mlan_ds_pm_cfg *)pioctl_req->pbuf)->param.auto_deep_sleep.idletime)
|
|
auto_ds.idletime = ((mlan_ds_pm_cfg *)pioctl_req->pbuf)
|
|
->param.auto_deep_sleep.idletime;
|
|
else
|
|
auto_ds.idletime = pmadapter->idle_time;
|
|
/* 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,
|
|
(t_u16)mode, BITMAP_AUTO_DS,
|
|
(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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_set_get_sleep_pd(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_pm_cfg *pm_cfg = MNULL;
|
|
t_u16 cmd_action = 0, sleep_pd = 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;
|
|
sleep_pd = (t_u16)pm_cfg->param.sleep_period;
|
|
}
|
|
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PERIOD,
|
|
cmd_action, 0, (t_void *)pioctl_req, &sleep_pd);
|
|
|
|
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
|
|
*/
|
|
static mlan_status wlan_set_get_ps_cfg(pmlan_adapter pmadapter,
|
|
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.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 (((t_s32)pm_cfg->param.ps_cfg.listen_interval) ==
|
|
MRVDRV_LISTEN_INTERVAL_DISABLE)
|
|
pmadapter->local_listen_interval = 0;
|
|
else 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.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 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
|
|
*/
|
|
static mlan_status wlan_set_get_bcn_timeout(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_pm_cfg *pm_cfg = MNULL;
|
|
|
|
ENTER();
|
|
|
|
pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
|
|
|
|
/* Send command to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
|
|
EN_AUTO_PS, BITMAP_BCN_TMO, (t_void *)pioctl_req,
|
|
&pm_cfg->param.bcn_timeout);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_pm_cfg *pm_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 config management frame wakeup filter
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
mlan_status wlan_config_mgmt_filter(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_pm_cfg *pm_cfg = MNULL;
|
|
int i = 0;
|
|
|
|
ENTER();
|
|
|
|
memset(pmadapter, pmadapter->mgmt_filter, 0,
|
|
sizeof(mlan_mgmt_frame_wakeup) * MAX_MGMT_FRAME_FILTER);
|
|
pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
for (i = 0; i < MAX_MGMT_FRAME_FILTER; i++)
|
|
if (!pm_cfg->param.mgmt_filter[i].type)
|
|
break;
|
|
memcpy_ext(pmadapter, (t_u8 *)pmadapter->mgmt_filter,
|
|
(t_u8 *)pm_cfg->param.mgmt_filter,
|
|
(i + 1) * sizeof(mlan_mgmt_frame_wakeup),
|
|
sizeof(pmadapter->mgmt_filter));
|
|
} else if (pioctl_req->action == MLAN_ACT_GET)
|
|
PRINTM(MERROR, "Get not support\n");
|
|
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(pmlan_adapter pmadapter,
|
|
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:
|
|
/**Block ieee power save disable command when bt coex
|
|
* enable*/
|
|
if (pmadapter->coex_scan && !pm->param.ps_mode)
|
|
break;
|
|
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:
|
|
status = wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
|
|
pmadapter->ps_mode);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
status = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
break;
|
|
case MLAN_OID_PM_CFG_HS_CFG:
|
|
status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
|
|
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;
|
|
pm->param.auto_deep_sleep.idletime =
|
|
pmadapter->idle_time;
|
|
} else
|
|
pm->param.auto_deep_sleep.auto_ds =
|
|
DEEP_SLEEP_OFF;
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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;
|
|
case MLAN_OID_PM_INFO:
|
|
status = wlan_get_pm_info(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_PM_HS_WAKEUP_REASON:
|
|
status = wlan_get_hs_wakeup_reason(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_PM_MGMT_FILTER:
|
|
status = wlan_config_mgmt_filter(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_PM_CFG_BCN_TIMEOUT:
|
|
status = wlan_set_get_bcn_timeout(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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
|
|
*/
|
|
static 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 is too big\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
memcpy_ext(priv->adapter, priv->wpa_ie, ie_data_ptr, ie_len,
|
|
sizeof(priv->wpa_ie));
|
|
priv->wpa_ie_len = (t_u8)ie_len;
|
|
PRINTM(MIOCTL, "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->adapter, 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 OSEN 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
|
|
*/
|
|
static mlan_status wlan_set_osen_ie(mlan_private *priv, t_u8 *ie_data_ptr,
|
|
t_u16 ie_len)
|
|
{
|
|
ENTER();
|
|
if (ie_len) {
|
|
if (ie_len > sizeof(priv->osen_ie)) {
|
|
PRINTM(MWARN, "failed to copy, WAPI IE is too big\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
memcpy_ext(priv->adapter, priv->osen_ie, ie_data_ptr, ie_len,
|
|
sizeof(priv->osen_ie));
|
|
priv->osen_ie_len = (t_u8)ie_len;
|
|
PRINTM(MIOCTL, "Set osen_ie_len=%d IE=%#x\n", priv->osen_ie_len,
|
|
priv->osen_ie[0]);
|
|
DBG_HEXDUMP(MCMD_D, "osen_ie", priv->osen_ie,
|
|
priv->osen_ie_len);
|
|
priv->sec_info.osen_enabled = MTRUE;
|
|
} else {
|
|
memset(priv->adapter, priv->osen_ie, 0, sizeof(priv->osen_ie));
|
|
priv->osen_ie_len = (t_u8)ie_len;
|
|
PRINTM(MINFO, "Reset osen_ie_len=%d IE=%#x\n",
|
|
priv->osen_ie_len, priv->osen_ie[0]);
|
|
priv->sec_info.osen_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
|
|
*/
|
|
static 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(MWARN, "failed to copy, WAPI IE is too big\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
memcpy_ext(priv->adapter, priv->wapi_ie, ie_data_ptr, ie_len,
|
|
sizeof(priv->wapi_ie));
|
|
priv->wapi_ie_len = (t_u8)ie_len;
|
|
PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
|
|
priv->wapi_ie[0]);
|
|
DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie,
|
|
priv->wapi_ie_len);
|
|
if (priv->wapi_ie[0] == WAPI_IE)
|
|
priv->sec_info.wapi_enabled = MTRUE;
|
|
} else {
|
|
memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
|
|
priv->wapi_ie_len = (t_u8)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
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_wapi_enable(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
ENTER();
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
if (pmpriv->wapi_ie_len)
|
|
sec->param.wapi_enabled = MTRUE;
|
|
else
|
|
sec->param.wapi_enabled = MFALSE;
|
|
} else {
|
|
if (sec->param.wapi_enabled == MFALSE)
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_set_wapi_key(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
ENTER();
|
|
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
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 Port Control 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_port_ctrl_enable(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
|
|
ENTER();
|
|
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
if (pmpriv->port_ctrl_mode)
|
|
sec->param.port_ctrl_enabled = MTRUE;
|
|
else
|
|
sec->param.port_ctrl_enabled = MFALSE;
|
|
} else {
|
|
if (sec->param.port_ctrl_enabled) {
|
|
pmpriv->port_ctrl_mode = MTRUE;
|
|
pmpriv->port_open = MFALSE;
|
|
} else {
|
|
if (pmpriv->port_ctrl_mode == MTRUE) {
|
|
pmpriv->port_ctrl_mode = MFALSE;
|
|
/* Cleanup the bypass TX queue */
|
|
wlan_cleanup_bypass_txq(pmpriv);
|
|
}
|
|
}
|
|
}
|
|
PRINTM(MINFO, "port_ctrl: port_ctrl_mode=%d port_open=%d\n",
|
|
pmpriv->port_ctrl_mode, pmpriv->port_open);
|
|
|
|
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
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_auth_mode(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
ENTER();
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET)
|
|
sec->param.auth_mode = pmpriv->sec_info.authentication_mode;
|
|
else
|
|
pmpriv->sec_info.authentication_mode = sec->param.auth_mode;
|
|
|
|
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
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_encrypt_mode(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
ENTER();
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET)
|
|
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 Get Random charactor
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return random charactor
|
|
*/
|
|
static t_u8 wlan_get_random_charactor(pmlan_adapter pmadapter)
|
|
{
|
|
t_u32 sec, usec;
|
|
t_u8 ch = 0;
|
|
|
|
ENTER();
|
|
|
|
pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
|
|
&usec);
|
|
sec = (sec & 0xFFFF) + (sec >> 16);
|
|
usec = (usec & 0xFFFF) + (usec >> 16);
|
|
ch = (((sec << 16) + usec) % 26) + 'a';
|
|
LEAVE();
|
|
return ch;
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_wpa_enable(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
ENTER();
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
if (pmpriv->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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_set_wep_key(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
mrvl_wep_key_t *pwep_key = MNULL;
|
|
int index;
|
|
int i = 0;
|
|
|
|
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.key_index == MLAN_KEY_INDEX_DEFAULT) {
|
|
index = pmpriv->wep_key_curr_index;
|
|
sec->param.encrypt_key.key_index = index;
|
|
} else {
|
|
if (sec->param.encrypt_key.key_index >= MRVL_NUM_WEP_KEY) {
|
|
if ((sec->param.encrypt_key.key_remove == MTRUE) &&
|
|
(sec->param.encrypt_key.key_index <= 5)) {
|
|
/* call firmware remove key */
|
|
ret = wlan_prepare_cmd(
|
|
pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
|
|
HostCmd_ACT_GEN_SET, 0,
|
|
(t_void *)pioctl_req,
|
|
&sec->param.encrypt_key);
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
goto exit;
|
|
}
|
|
PRINTM(MERROR, "Key_index is invalid\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
index = sec->param.encrypt_key.key_index;
|
|
}
|
|
|
|
if ((sec->param.encrypt_key.key_disable == MTRUE) ||
|
|
(sec->param.encrypt_key.key_remove == MTRUE)) {
|
|
pmpriv->sec_info.wep_status = Wlan802_11WEPDisabled;
|
|
/* remove key */
|
|
if (sec->param.encrypt_key.key_remove == MTRUE) {
|
|
memset(pmadapter, &pmpriv->wep_key[index], 0,
|
|
sizeof(mrvl_wep_key_t));
|
|
/* call firmware remove key */
|
|
ret = wlan_prepare_cmd(pmpriv,
|
|
HostCmd_CMD_802_11_KEY_MATERIAL,
|
|
HostCmd_ACT_GEN_SET, 0, MNULL,
|
|
&sec->param.encrypt_key);
|
|
if (ret)
|
|
goto exit;
|
|
}
|
|
} else {
|
|
if (sec->param.encrypt_key.key_len) {
|
|
if ((sec->param.encrypt_key.key_len !=
|
|
WEP_104_BIT_LEN) &&
|
|
(sec->param.encrypt_key.key_len !=
|
|
WEP_40_BIT_LEN)) {
|
|
PRINTM(MERROR, "Invalid wep key len=%d\n",
|
|
sec->param.encrypt_key.key_len);
|
|
/* We will use random key to clear the key
|
|
* buffer in FW */
|
|
if (sec->param.encrypt_key.key_len <
|
|
WEP_40_BIT_LEN)
|
|
sec->param.encrypt_key.key_len =
|
|
WEP_40_BIT_LEN;
|
|
else
|
|
sec->param.encrypt_key.key_len =
|
|
WEP_104_BIT_LEN;
|
|
for (i = 0;
|
|
i < (int)sec->param.encrypt_key.key_len;
|
|
i++)
|
|
sec->param.encrypt_key.key_material[i] =
|
|
wlan_get_random_charactor(
|
|
pmadapter);
|
|
}
|
|
pwep_key = &pmpriv->wep_key[index];
|
|
/* Cleanup */
|
|
memset(pmadapter, pwep_key, 0, sizeof(mrvl_wep_key_t));
|
|
/* Copy the key in the driver */
|
|
|
|
memcpy_ext(pmadapter, pwep_key->key_material,
|
|
sec->param.encrypt_key.key_material,
|
|
sec->param.encrypt_key.key_len,
|
|
MRVL_KEY_BUFFER_SIZE_IN_BYTE);
|
|
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;
|
|
}
|
|
}
|
|
if (sec->param.encrypt_key.is_current_wep_key == MTRUE) {
|
|
/* Copy the required key as the current key */
|
|
pwep_key = &pmpriv->wep_key[index];
|
|
if (!pwep_key->key_length) {
|
|
if (pmpriv->sec_info.wpa_enabled ||
|
|
pmpriv->sec_info.wpa2_enabled ||
|
|
pmpriv->sec_info.wapi_enabled) {
|
|
ret = MLAN_STATUS_SUCCESS;
|
|
goto exit;
|
|
}
|
|
PRINTM(MERROR,
|
|
"Key %d not set,so cannot enable it\n",
|
|
index);
|
|
pioctl_req->status_code =
|
|
MLAN_ERROR_CMD_RESP_FAIL;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
pmpriv->wep_key_curr_index = (t_u16)index;
|
|
pmpriv->sec_info.wep_status = Wlan802_11WEPEnabled;
|
|
}
|
|
if (sec->param.encrypt_key.key_flags && pwep_key->key_length) {
|
|
pmpriv->wep_key_curr_index = (t_u16)index;
|
|
// Only do this if the key is an xmit key. If the key
|
|
// is a group key, we might be in wpa/wep mixed mode in
|
|
// which case we don't want to set wep_status =
|
|
// Wlan802_11WEPEnabled because that enables WEP at the
|
|
// MAC controller level and WPA stops working properly.
|
|
if (sec->param.encrypt_key.key_flags &
|
|
KEY_FLAG_SET_TX_KEY) {
|
|
pmpriv->sec_info.wep_status =
|
|
Wlan802_11WEPEnabled;
|
|
}
|
|
}
|
|
}
|
|
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 */
|
|
if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled &&
|
|
pwep_key->key_length) {
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
|
|
HostCmd_ACT_GEN_SET, 0, MNULL,
|
|
&pmpriv->curr_pkt_filter);
|
|
if (ret)
|
|
goto exit;
|
|
if (!sec->param.encrypt_key.key_len) {
|
|
sec->param.encrypt_key.key_index = pwep_key->key_index;
|
|
sec->param.encrypt_key.key_len = pwep_key->key_length;
|
|
memcpy_ext(pmadapter,
|
|
sec->param.encrypt_key.key_material,
|
|
pwep_key->key_material,
|
|
sec->param.encrypt_key.key_len,
|
|
MLAN_MAX_KEY_LENGTH);
|
|
}
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
|
|
HostCmd_ACT_GEN_SET, 0,
|
|
(t_void *)pioctl_req,
|
|
&sec->param.encrypt_key);
|
|
} else {
|
|
if (pwep_key->key_length) {
|
|
if (!sec->param.encrypt_key.key_len) {
|
|
sec->param.encrypt_key.key_index =
|
|
pwep_key->key_index;
|
|
sec->param.encrypt_key.key_len =
|
|
pwep_key->key_length;
|
|
memcpy_ext(pmadapter,
|
|
sec->param.encrypt_key.key_material,
|
|
pwep_key->key_material,
|
|
sec->param.encrypt_key.key_len,
|
|
MLAN_MAX_KEY_LENGTH);
|
|
}
|
|
ret = wlan_prepare_cmd(pmpriv,
|
|
HostCmd_CMD_802_11_KEY_MATERIAL,
|
|
HostCmd_ACT_GEN_SET, 0, MNULL,
|
|
&sec->param.encrypt_key);
|
|
if (ret)
|
|
goto exit;
|
|
}
|
|
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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_set_wpa_key(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
|
|
ENTER();
|
|
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
/* Current driver only supports key length of up to 32 bytes */
|
|
if (sec->param.encrypt_key.key_len > MLAN_MAX_KEY_LENGTH) {
|
|
PRINTM(MERROR, "Key length is incorrect\n");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
|
|
HostCmd_ACT_GEN_SET, 0, (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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
int index;
|
|
ENTER();
|
|
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
|
|
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.key_index == MLAN_KEY_INDEX_DEFAULT) {
|
|
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_ext(pmadapter,
|
|
sec->param.encrypt_key.key_material,
|
|
pmpriv->wep_key[index].key_material,
|
|
pmpriv->wep_key[index].key_length,
|
|
MLAN_MAX_KEY_LENGTH);
|
|
sec->param.encrypt_key.key_len =
|
|
MIN(MLAN_MAX_KEY_LENGTH,
|
|
pmpriv->wep_key[index].key_length);
|
|
} else if ((pmpriv->sec_info.wpa_enabled) ||
|
|
(pmpriv->sec_info.ewpa_enabled) ||
|
|
(pmpriv->sec_info.wpa2_enabled) ||
|
|
(pmpriv->sec_info.wapi_enabled)) {
|
|
/* Return WPA enabled */
|
|
sec->param.encrypt_key.key_disable = MFALSE;
|
|
memcpy_ext(pmadapter,
|
|
sec->param.encrypt_key.key_material,
|
|
pmpriv->aes_key.key_material,
|
|
pmpriv->aes_key.key_len,
|
|
MLAN_MAX_KEY_LENGTH);
|
|
sec->param.encrypt_key.key_len = MIN(
|
|
MLAN_MAX_KEY_LENGTH, pmpriv->aes_key.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_ext(pmadapter,
|
|
sec->param.encrypt_key.key_material,
|
|
pmpriv->wep_key[index].key_material,
|
|
pmpriv->wep_key[index].key_length,
|
|
MLAN_MAX_KEY_LENGTH);
|
|
sec->param.encrypt_key.key_len =
|
|
MIN(MLAN_MAX_KEY_LENGTH,
|
|
pmpriv->wep_key[index].key_length);
|
|
} else if ((pmpriv->sec_info.wpa_enabled) ||
|
|
(pmpriv->sec_info.ewpa_enabled) ||
|
|
(pmpriv->sec_info.wpa2_enabled) ||
|
|
(pmpriv->sec_info.wapi_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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_encrypt_key(pmlan_adapter pmadapter,
|
|
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 Query Encrpyt key
|
|
*
|
|
* @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_sec_ioctl_query_key(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
|
|
ENTER();
|
|
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
/* Current driver only supports get PTK/GTK */
|
|
if (pmpriv->port_open &&
|
|
(pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled ||
|
|
pmpriv->sec_info.wapi_enabled)) {
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
|
|
HostCmd_ACT_GEN_GET, 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 esupplicant status
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS --success
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_ewpa_enable(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
ENTER();
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
sec->param.ewpa_enabled = pmpriv->sec_info.ewpa_enabled;
|
|
} else {
|
|
pmpriv->sec_info.ewpa_enabled = (t_u8)sec->param.ewpa_enabled;
|
|
PRINTM(MINFO, "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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_sec_ioctl_esupp_mode(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
t_u16 cmd_action = 0;
|
|
mlan_ds_sec_cfg *sec = MNULL;
|
|
|
|
ENTER();
|
|
|
|
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
if (pmpriv->media_connected == MTRUE) {
|
|
PRINTM(MERROR,
|
|
"Cannot set esupplicant mode configuration while connected.\n");
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
if (!sec->param.esupp_mode.rsn_mode ||
|
|
(sec->param.esupp_mode.rsn_mode & RSN_TYPE_VALID_BITS) !=
|
|
sec->param.esupp_mode.rsn_mode) {
|
|
PRINTM(MERROR, "Invalid RSN mode\n");
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
if (!sec->param.esupp_mode.act_paircipher ||
|
|
(sec->param.esupp_mode.act_paircipher &
|
|
EMBED_CIPHER_VALID_BITS) !=
|
|
sec->param.esupp_mode.act_paircipher) {
|
|
PRINTM(MERROR, "Invalid pairwise cipher\n");
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
if (!sec->param.esupp_mode.act_groupcipher ||
|
|
(sec->param.esupp_mode.act_groupcipher &
|
|
EMBED_CIPHER_VALID_BITS) !=
|
|
sec->param.esupp_mode.act_groupcipher) {
|
|
PRINTM(MERROR, "Invalid group cipher\n");
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
cmd_action = HostCmd_ACT_GEN_GET_CURRENT;
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
if (sec) {
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PROFILE,
|
|
cmd_action, 0, (t_void *)pioctl_req,
|
|
&sec->param.esupp_mode);
|
|
} else {
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PROFILE,
|
|
cmd_action, 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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_sec_cfg_ioctl(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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_PORT_CTRL_ENABLED:
|
|
status = wlan_sec_ioctl_port_ctrl_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_QUERY_KEY:
|
|
status = wlan_sec_ioctl_query_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:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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
|
|
*/
|
|
static 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};
|
|
const t_u8 osen_oui[] = {0x50, 0x6f, 0x9a, 0x12};
|
|
t_u8 i = 0, temp[12] = {0};
|
|
|
|
ENTER();
|
|
|
|
/* If the passed length is zero, reset the buffer */
|
|
if (!ie_len) {
|
|
priv->gen_ie_buf_len = 0;
|
|
priv->wps.session_enable = MFALSE;
|
|
wlan_set_wpa_ie_helper(priv, MNULL, 0);
|
|
wlan_set_wapi_ie(priv, MNULL, 0);
|
|
wlan_set_osen_ie(priv, MNULL, 0);
|
|
} else if (!ie_data_ptr) {
|
|
/* MNULL check */
|
|
ret = MLAN_STATUS_FAILURE;
|
|
} else {
|
|
pvendor_ie = (IEEEtypes_VendorHeader_t *)ie_data_ptr;
|
|
if (pvendor_ie->element_id == EXT_CAPABILITY) {
|
|
memcpy_ext(priv->adapter, temp, &priv->ext_cap,
|
|
sizeof(priv->ext_cap), sizeof(temp));
|
|
for (i = 0;
|
|
i < MIN(sizeof(priv->ext_cap), pvendor_ie->len);
|
|
i++)
|
|
temp[i] |= ie_data_ptr[2 + i];
|
|
memcpy_ext(priv->adapter, &priv->ext_cap, temp,
|
|
sizeof(temp), sizeof(priv->ext_cap));
|
|
} else
|
|
/* 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(priv->adapter, 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 if ((pvendor_ie->element_id == VENDOR_SPECIFIC_221) &&
|
|
(!memcmp(priv->adapter, pvendor_ie->oui, osen_oui,
|
|
sizeof(osen_oui)))) {
|
|
/* IE is a OSEN IE so call set_osen function */
|
|
ret = wlan_set_osen_ie(priv, ie_data_ptr, ie_len);
|
|
|
|
} else if ((pvendor_ie->element_id == WPS_IE) &&
|
|
(priv->wps.session_enable == MFALSE) &&
|
|
(!memcmp(priv->adapter, pvendor_ie->oui, wps_oui,
|
|
sizeof(wps_oui)))) {
|
|
/*
|
|
* Discard first two byte (Element ID and Length)
|
|
* because they are not needed in the case of setting
|
|
* WPS_IE
|
|
*/
|
|
if (pvendor_ie->len > 4) {
|
|
memcpy_ext(priv->adapter,
|
|
(t_u8 *)&priv->wps.wps_ie,
|
|
ie_data_ptr, ie_len,
|
|
sizeof(IEEEtypes_VendorSpecific_t));
|
|
HEXDUMP("wps_ie", (t_u8 *)&priv->wps.wps_ie,
|
|
priv->wps.wps_ie.vend_hdr.len + 2);
|
|
} else {
|
|
/* Only wps oui exist, reset driver wps buffer
|
|
*/
|
|
memset(priv->adapter, (t_u8 *)&priv->wps.wps_ie,
|
|
0x00, sizeof(priv->wps.wps_ie));
|
|
PRINTM(MINFO, "wps_ie cleared\n");
|
|
}
|
|
} 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(priv->adapter, 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_ext(priv->adapter,
|
|
priv->gen_ie_buf +
|
|
priv->gen_ie_buf_len,
|
|
ie_data_ptr, ie_len,
|
|
MRVDRV_GENIE_BUF_SIZE -
|
|
priv->gen_ie_buf_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 Set/Get WWS mode
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_misc_ioctl_wws_cfg(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_11d_cfg_ioctl_enable(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_11d_cfg *pcfg_11d = MNULL;
|
|
|
|
ENTER();
|
|
|
|
pcfg_11d = (mlan_ds_11d_cfg *)pioctl_req->pbuf;
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
if (pmpriv->media_connected == MTRUE) {
|
|
PRINTM(MIOCTL,
|
|
"11D setting cannot be changed while interface is active.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
PRINTM(MINFO, "11D: 11dcfg SET=%d\n",
|
|
pcfg_11d->param.enable_11d);
|
|
|
|
/* Compare with current settings */
|
|
if (pmpriv->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)pmpriv->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);
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Clear 11D chan table
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS --success
|
|
*/
|
|
static mlan_status wlan_11d_clr_chan_table(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
PRINTM(MINFO, "11D: 11dclrtbl SET\n");
|
|
|
|
if (wlan_11d_clear_parsedtable(pmpriv) == MLAN_STATUS_SUCCESS)
|
|
PRINTM(MINFO,
|
|
"11D: cleared parsed_region_chan (now no_of_chan=%d)\n",
|
|
pmadapter->parsed_region_chan.no_of_chan);
|
|
}
|
|
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_11d_cfg_ioctl(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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;
|
|
case MLAN_OID_11D_CLR_CHAN_TABLE:
|
|
status = wlan_11d_clr_chan_table(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_11D_DOMAIN_INFO_EXT:
|
|
status = wlan_11d_cfg_domain_info(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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)
|
|
pmpriv->wps.session_enable = MTRUE;
|
|
else
|
|
pmpriv->wps.session_enable = MFALSE;
|
|
} 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:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
status = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_reg_mem_ioctl(pmlan_adapter pmadapter,
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
status = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief 802.11h ad-hoc start channel check
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_11h_channel_check_req(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = MNULL;
|
|
mlan_status ret = MLAN_STATUS_FAILURE;
|
|
t_u8 chan_width = CHAN_BW_20MHZ;
|
|
Band_Config_t bandcfg;
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req != MNULL) {
|
|
pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
} else {
|
|
PRINTM(MERROR, "MLAN IOCTL information is not present\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
memset(pmadapter, &bandcfg, 0, sizeof(Band_Config_t));
|
|
pmpriv->adhoc_state = ADHOC_STARTING;
|
|
|
|
if ((pmadapter->adhoc_start_band & BAND_A)) {
|
|
if (pmpriv->intf_state_11h.adhoc_auto_sel_chan)
|
|
pmpriv->adhoc_channel =
|
|
wlan_11h_get_adhoc_start_channel(pmpriv);
|
|
|
|
/*
|
|
* Check if the region and channel requires a channel
|
|
* availability check.
|
|
*/
|
|
if (wlan_11h_radar_detect_required(pmpriv,
|
|
pmpriv->adhoc_channel) &&
|
|
!wlan_11h_is_channel_under_nop(pmadapter,
|
|
pmpriv->adhoc_channel)) {
|
|
/*
|
|
* Radar detection is required for this channel, make
|
|
* sure 11h is activated in the firmware
|
|
*/
|
|
ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
|
|
ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
|
|
ret = wlan_11h_check_update_radar_det_state(pmpriv);
|
|
|
|
/* Check for radar on the channel */
|
|
if ((pmadapter->chan_bandwidth ==
|
|
CHANNEL_BW_40MHZ_ABOVE) ||
|
|
(pmadapter->chan_bandwidth ==
|
|
CHANNEL_BW_40MHZ_BELOW)) {
|
|
chan_width = CHAN_BW_40MHZ;
|
|
if (pmadapter->chanrpt_param_bandcfg) {
|
|
bandcfg.chan2Offset =
|
|
pmadapter->chan_bandwidth;
|
|
}
|
|
} else if (pmadapter->chan_bandwidth ==
|
|
CHANNEL_BW_80MHZ)
|
|
chan_width = CHAN_BW_80MHZ;
|
|
if (pmadapter->chanrpt_param_bandcfg) {
|
|
bandcfg.chanWidth = chan_width;
|
|
bandcfg.chanBand = BAND_5GHZ;
|
|
} else {
|
|
*((t_u8 *)&bandcfg) = chan_width;
|
|
}
|
|
|
|
ret = wlan_11h_issue_radar_detect(pmpriv, pioctl_req,
|
|
pmpriv->adhoc_channel,
|
|
bandcfg);
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief 802.11h set/get local power constraint
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
static mlan_status
|
|
wlan_11h_ioctl_local_power_constraint(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_ds_11h_cfg *ds_11hcfg = MNULL;
|
|
t_s8 *plocalpower = &pmadapter->state_11h.usr_def_power_constraint;
|
|
|
|
ENTER();
|
|
|
|
ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
|
|
|
|
if (pioctl_req->action == MLAN_ACT_GET)
|
|
ds_11hcfg->param.usr_local_power_constraint = *plocalpower;
|
|
else
|
|
*plocalpower = ds_11hcfg->param.usr_local_power_constraint;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief 11h configuration handler
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_11h_cfg_ioctl(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_11h_cfg *ds_11hcfg = MNULL;
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
|
|
PRINTM(MWARN, "MLAN 11H IOCTL length is too short.\n");
|
|
pioctl_req->data_read_written = 0;
|
|
pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_RESOURCE;
|
|
}
|
|
ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
|
|
|
|
switch (ds_11hcfg->sub_command) {
|
|
case MLAN_OID_11H_CHANNEL_CHECK:
|
|
status = wlan_11h_channel_check_req(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_11H_LOCAL_POWER_CONSTRAINT:
|
|
status = wlan_11h_ioctl_local_power_constraint(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_11H_DFS_TESTING:
|
|
status = wlan_11h_ioctl_dfs_testing(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_11H_DFS_W53_CFG:
|
|
status = wlan_11h_ioctl_dfs_w53_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_cfg *misc = MNULL;
|
|
|
|
ENTER();
|
|
|
|
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
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_ext(pmadapter, misc->param.gen_ie.ie_data,
|
|
pmpriv->wpa_ie, misc->param.gen_ie.len,
|
|
MAX_IE_SIZE);
|
|
} 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, 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");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
} else if (misc->param.gen_ie.len <=
|
|
sizeof(MrvlIEtypesHeader_t)) {
|
|
pmadapter->arp_filter_size = 0;
|
|
PRINTM(MINFO, "Clear ARP filter\n");
|
|
} else {
|
|
memcpy_ext(pmadapter, pmadapter->arp_filter,
|
|
misc->param.gen_ie.ie_data,
|
|
misc->param.gen_ie.len,
|
|
ARP_FILTER_MAX_BUF_SIZE);
|
|
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");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
pioctl_req->data_read_written =
|
|
sizeof(mlan_ds_misc_gen_ie) + 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 --success, MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_misc_ioctl_warm_reset(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
pmlan_buffer pmbuf;
|
|
t_s32 i = 0;
|
|
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
|
|
ENTER();
|
|
mlan_block_rx_process(pmadapter, MTRUE);
|
|
|
|
/* Cancel all pending commands and complete ioctls */
|
|
if (misc->param.fw_reload)
|
|
wlan_cancel_all_pending_cmd(pmadapter, MTRUE);
|
|
|
|
/** Init all the head nodes and free all the locks here */
|
|
for (i = 0; i < pmadapter->priv_num; i++)
|
|
wlan_free_priv(pmadapter->priv[i]);
|
|
|
|
while ((pmbuf = (pmlan_buffer)util_dequeue_list(
|
|
pmadapter->pmoal_handle, &pmadapter->rx_data_queue,
|
|
pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
|
|
pmadapter->ops.data_complete(pmadapter, pmbuf,
|
|
MLAN_STATUS_FAILURE);
|
|
}
|
|
pmadapter->rx_pkts_queued = 0;
|
|
|
|
/* Initialize adapter structure */
|
|
wlan_init_adapter(pmadapter);
|
|
pmadapter->hw_status = WlanHardwareStatusInitializing;
|
|
|
|
/* Initialize private structures */
|
|
for (i = 0; i < pmadapter->priv_num; i++) {
|
|
if (pmadapter->priv[i])
|
|
wlan_init_priv(pmadapter->priv[i]);
|
|
}
|
|
mlan_block_rx_process(pmadapter, MFALSE);
|
|
|
|
if (misc->param.fw_reload != MTRUE) {
|
|
/* Restart the firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
|
|
HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
|
|
/* Issue firmware initialize commands for first BSS,
|
|
* for other interfaces it will be called after getting
|
|
* the last init command response of previous interface
|
|
*/
|
|
pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
|
|
if (!pmpriv) {
|
|
ret = MLAN_STATUS_FAILURE;
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
ret = wlan_adapter_get_hw_spec(pmpriv->adapter);
|
|
if (ret == MLAN_STATUS_FAILURE) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
ret = pmpriv->ops.init_cmd(pmpriv, MTRUE);
|
|
if (ret == MLAN_STATUS_FAILURE) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
if (ret == MLAN_STATUS_PENDING)
|
|
pmadapter->pwarm_reset_ioctl_req = pioctl_req;
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
#ifdef SDIO
|
|
/**
|
|
* @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(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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 MPA CTRL: not allowed in connected state\n");
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
if (mpa_ctrl->tx_enable > 1) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
if (mpa_ctrl->rx_enable > 1) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
if (mpa_ctrl->tx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
if (mpa_ctrl->rx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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->pcard_sd->mpa_tx.buf_size =
|
|
mpa_ctrl->tx_buf_size;
|
|
|
|
if (mpa_ctrl->rx_buf_size > 0)
|
|
pmadapter->pcard_sd->mpa_rx.buf_size =
|
|
mpa_ctrl->rx_buf_size;
|
|
|
|
if (wlan_alloc_sdio_mpa_buffers(
|
|
pmadapter,
|
|
pmadapter->pcard_sd->mpa_tx.buf_size,
|
|
pmadapter->pcard_sd->mpa_rx.buf_size) !=
|
|
MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR,
|
|
"Failed to allocate sdio mp-a buffers\n");
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (mpa_ctrl->tx_max_ports > 0)
|
|
pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit =
|
|
mpa_ctrl->tx_max_ports;
|
|
if (mpa_ctrl->rx_max_ports > 0)
|
|
pmadapter->pcard_sd->mpa_rx.pkt_aggr_limit =
|
|
mpa_ctrl->rx_max_ports;
|
|
|
|
pmadapter->pcard_sd->mpa_tx.enabled = (t_u8)mpa_ctrl->tx_enable;
|
|
pmadapter->pcard_sd->mpa_rx.enabled = (t_u8)mpa_ctrl->rx_enable;
|
|
|
|
} else {
|
|
mpa_ctrl->tx_enable =
|
|
(t_u16)pmadapter->pcard_sd->mpa_tx.enabled;
|
|
mpa_ctrl->rx_enable =
|
|
(t_u16)pmadapter->pcard_sd->mpa_rx.enabled;
|
|
mpa_ctrl->tx_buf_size =
|
|
(t_u16)pmadapter->pcard_sd->mpa_tx.buf_size;
|
|
mpa_ctrl->rx_buf_size =
|
|
(t_u16)pmadapter->pcard_sd->mpa_rx.buf_size;
|
|
mpa_ctrl->tx_max_ports =
|
|
(t_u16)pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit;
|
|
mpa_ctrl->rx_max_ports =
|
|
(t_u16)pmadapter->pcard_sd->mpa_rx.pkt_aggr_limit;
|
|
}
|
|
|
|
exit:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @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_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_misc_ioctl_sysclock(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the associate response
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS --success
|
|
*/
|
|
static mlan_status wlan_misc_ioctl_get_assoc_rsp(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_ds_misc_cfg *misc = MNULL;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
if ((pioctl_req->action == MLAN_ACT_GET) && pmpriv->assoc_rsp_size) {
|
|
memcpy_ext(pmadapter, misc->param.assoc_resp.assoc_resp_buf,
|
|
pmpriv->assoc_rsp_buf, pmpriv->assoc_rsp_size,
|
|
ASSOC_RSP_BUF_SIZE);
|
|
misc->param.assoc_resp.assoc_resp_len =
|
|
MIN(ASSOC_RSP_BUF_SIZE, pmpriv->assoc_rsp_size);
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Send function softreset command to firmware
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_misc_ioctl_soft_reset(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
/* Send command to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SOFT_RESET,
|
|
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
|
|
MNULL);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the thermal reading
|
|
*
|
|
* @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_misc_ioctl_thermal(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u16 cmd_action = 0;
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req->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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_RESOURCE;
|
|
}
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
PRINTM(MERROR, "Thermal reading setting is not allowed!\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
} else {
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
}
|
|
|
|
/* Send command to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB, cmd_action,
|
|
Thermal_i, (t_void *)pioctl_req, MNULL);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get/Set subscribe event
|
|
*
|
|
* @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_misc_ioctl_subscribe_evt(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_misc_cfg *misc = MNULL;
|
|
t_u16 cmd_action = 0;
|
|
|
|
ENTER();
|
|
|
|
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_SET)
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
else
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
|
|
/* Send command to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
|
|
cmd_action, 0, (t_void *)pioctl_req,
|
|
&misc->param.subscribe_event);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Set ARP filter based on IP address
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
* @param ipv4_addr ipv4 Address
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
static mlan_status wlan_ipaddr_arp_filter(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req,
|
|
t_u32 ipv4_addr)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u8 *buf;
|
|
arpfilter_header *arpfilter = MNULL;
|
|
filter_entry *entry = MNULL;
|
|
t_u32 len;
|
|
|
|
ENTER();
|
|
|
|
pcb->moal_malloc(pmadapter->pmoal_handle, MRVDRV_SIZE_OF_CMD_BUFFER,
|
|
MLAN_MEM_DEF, &buf);
|
|
if (!buf) {
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Construct the ARP filter TLV */
|
|
arpfilter = (arpfilter_header *)buf;
|
|
arpfilter->type = wlan_cpu_to_le16(TLV_TYPE_ARP_FILTER);
|
|
|
|
if (ipv4_addr) {
|
|
arpfilter->len = wlan_cpu_to_le16(sizeof(filter_entry) * 3);
|
|
entry = (filter_entry *)(buf + sizeof(arpfilter_header));
|
|
entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_BROADCAST);
|
|
entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ARP);
|
|
entry->ipv4_addr = wlan_cpu_to_le32(ipv4_addr);
|
|
entry++;
|
|
entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_UNICAST);
|
|
entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ANY);
|
|
entry->ipv4_addr = wlan_cpu_to_le32(IPV4_ADDR_ANY);
|
|
entry++;
|
|
entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_MULTICAST);
|
|
entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ANY);
|
|
entry->ipv4_addr = wlan_cpu_to_le32(IPV4_ADDR_ANY);
|
|
} else
|
|
arpfilter->len = 0;
|
|
|
|
/* Update the total length */
|
|
len = sizeof(arpfilter_header) + wlan_le16_to_cpu(arpfilter->len);
|
|
|
|
memset(pmadapter, pmadapter->arp_filter, 0,
|
|
sizeof(pmadapter->arp_filter));
|
|
if (len > ARP_FILTER_MAX_BUF_SIZE) {
|
|
pmadapter->arp_filter_size = 0;
|
|
PRINTM(MERROR, "Invalid ARP Filter Size\n");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
} else if (len <= sizeof(MrvlIEtypesHeader_t)) {
|
|
pmadapter->arp_filter_size = 0;
|
|
PRINTM(MINFO, "Clear ARP filter\n");
|
|
} else {
|
|
memcpy_ext(pmadapter, pmadapter->arp_filter, buf, len,
|
|
ARP_FILTER_MAX_BUF_SIZE);
|
|
pmadapter->arp_filter_size = len;
|
|
HEXDUMP("ArpFilter", pmadapter->arp_filter,
|
|
pmadapter->arp_filter_size);
|
|
}
|
|
|
|
done:
|
|
if (buf)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, buf);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief MEF 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_misc_ioctl_mef_cfg(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_mef_cfg *mef_cfg =
|
|
&((mlan_ds_misc_cfg *)pioctl_req->pbuf)->param.mef_cfg;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
HostCmd_DS_GEN *hostcmd_hdr;
|
|
HostCmd_DS_MEF_CFG *mefcmd;
|
|
mlan_ds_misc_cmd *hostcmd = MNULL;
|
|
t_u32 buf_len = 0;
|
|
t_u8 *buf, *filter;
|
|
t_u8 fltr_buf[] = {0x02, 0x00, 0x2f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
0x01, 0x00, 0x5e, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x41, 0x06, 0x00, 0x00, 0x00, 0x01, 0xff, 0x01,
|
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x45, 0x01,
|
|
0x00, 0x00, 0x00, 0x01, 0x33, 0x33, 0x02, 0x02, 0x00,
|
|
0x00, 0x00, 0x00, 0x01, 0x41, 0x45};
|
|
|
|
ENTER();
|
|
|
|
/* GET operation */
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
/* TODO: need to store for get operation */
|
|
goto done;
|
|
}
|
|
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF,
|
|
(t_u8 **)&hostcmd);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
|
|
PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
|
|
buf = hostcmd->cmd;
|
|
|
|
/* Prepare hostcmd buffer */
|
|
hostcmd_hdr = (HostCmd_DS_GEN *)(buf);
|
|
hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
|
|
mefcmd = (HostCmd_DS_MEF_CFG *)(buf + S_DS_GEN);
|
|
buf_len = S_DS_GEN;
|
|
|
|
switch (mef_cfg->sub_id) {
|
|
case MEF_CFG_DISABLE:
|
|
PRINTM(MINFO, "Disable MEF\n");
|
|
mefcmd->criteria = wlan_cpu_to_le32(0);
|
|
mefcmd->nentries = wlan_cpu_to_le16(0);
|
|
buf_len += sizeof(HostCmd_DS_MEF_CFG);
|
|
break;
|
|
case MEF_CFG_RX_FILTER_ENABLE:
|
|
PRINTM(MINFO, "Enable Rx filter\n");
|
|
mefcmd->criteria = wlan_cpu_to_le32((MBIT(3) | MBIT(0)));
|
|
mefcmd->nentries = wlan_cpu_to_le16(1);
|
|
buf_len += sizeof(HostCmd_DS_MEF_CFG);
|
|
filter = buf + buf_len;
|
|
memcpy_ext(pmpriv->adapter, filter, fltr_buf, sizeof(fltr_buf),
|
|
MRVDRV_SIZE_OF_CMD_BUFFER - buf_len);
|
|
buf_len += sizeof(fltr_buf);
|
|
break;
|
|
case MEF_CFG_AUTO_ARP_RESP:
|
|
PRINTM(MINFO, "Enable auto ARP response\n");
|
|
/* TODO */
|
|
break;
|
|
case MEF_CFG_HOSTCMD:
|
|
PRINTM(MINFO, "MEF hostcmd from MOAL\n");
|
|
filter = buf + buf_len;
|
|
memcpy_ext(pmpriv->adapter, filter, mef_cfg->param.cmd_buf.cmd,
|
|
mef_cfg->param.cmd_buf.len,
|
|
MRVDRV_SIZE_OF_CMD_BUFFER - buf_len);
|
|
buf_len += mef_cfg->param.cmd_buf.len;
|
|
break;
|
|
default:
|
|
PRINTM(MERROR, "Invalid sub ID parameter\n");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
break;
|
|
}
|
|
hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
|
|
hostcmd->len = buf_len;
|
|
|
|
/* Send command to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)pioctl_req,
|
|
(t_void *)hostcmd);
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
done:
|
|
if (hostcmd)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief ipaddr 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_misc_ioctl_ipaddr_cfg(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 ipv4_addr[MAX_IPADDR] = {0};
|
|
int i = 0;
|
|
|
|
ENTER();
|
|
|
|
/* GET operation */
|
|
if (pioctl_req->action == MLAN_ACT_GET) {
|
|
memcpy_ext(pmadapter, misc->param.ipaddr_cfg.ip_addr,
|
|
pmpriv->ip_addr, IPADDR_LEN, IPADDR_LEN);
|
|
misc->param.ipaddr_cfg.op_code = pmpriv->op_code;
|
|
goto done;
|
|
}
|
|
/* only one IP is supported in current firmware */
|
|
for (i = 0; i < (int)misc->param.ipaddr_cfg.ip_addr_num; i++) {
|
|
memcpy_ext(pmadapter, &ipv4_addr[i],
|
|
misc->param.ipaddr_cfg.ip_addr[i], sizeof(t_u32),
|
|
sizeof(t_u32));
|
|
}
|
|
|
|
if (misc->param.ipaddr_cfg.op_code != MLAN_IPADDR_OP_IP_REMOVE &&
|
|
!misc->param.ipaddr_cfg.ip_addr_num) {
|
|
PRINTM(MERROR, "Invalid IPv4 address\n");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (misc->param.ipaddr_cfg.op_code & MLAN_IPADDR_OP_ARP_FILTER)
|
|
ret = wlan_ipaddr_arp_filter(pmadapter, pioctl_req,
|
|
ipv4_addr[0]);
|
|
else if (pmpriv->op_code & MLAN_IPADDR_OP_ARP_FILTER)
|
|
ret = wlan_ipaddr_arp_filter(pmadapter, pioctl_req, 0);
|
|
if (ret == MLAN_STATUS_FAILURE)
|
|
goto done;
|
|
|
|
/* Save the values in MLAN */
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
pmpriv->op_code = misc->param.ipaddr_cfg.op_code;
|
|
memcpy_ext(pmadapter, pmpriv->ip_addr,
|
|
misc->param.ipaddr_cfg.ip_addr, IPADDR_LEN,
|
|
IPADDR_LEN);
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief CFP code 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_misc_ioctl_cfp_code_cfg(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
mlan_ds_misc_cfp_code *cfp_code = MNULL;
|
|
t_u32 region_bg = 0;
|
|
t_u32 region_a = 0;
|
|
int i;
|
|
|
|
ENTER();
|
|
|
|
cfp_code = &misc->param.cfp_code;
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
|
|
PRINTM(MERROR,
|
|
"ForceRegionRule is set in the on-chip OTP"
|
|
"memory\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Save the values in MLAN */
|
|
if (!cfp_code->cfp_code_bg)
|
|
cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
|
|
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
|
|
/* Use the region code to search for the index */
|
|
if (cfp_code->cfp_code_bg == region_code_index[i]) {
|
|
region_bg = cfp_code->cfp_code_bg;
|
|
break;
|
|
}
|
|
}
|
|
if (!cfp_code->cfp_code_a)
|
|
cfp_code->cfp_code_a = pmadapter->cfp_code_a;
|
|
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
|
|
/* Use the region code to search for the index */
|
|
if (cfp_code->cfp_code_a == region_code_index[i]) {
|
|
region_a = cfp_code->cfp_code_a;
|
|
break;
|
|
}
|
|
}
|
|
if (!region_a) {
|
|
for (i = 0; i < MRVDRV_MAX_CFP_CODE_A; i++) {
|
|
/* Use the CFP code to search for the index */
|
|
if (cfp_code->cfp_code_a == cfp_code_index_a[i])
|
|
break;
|
|
}
|
|
if (i >= MRVDRV_MAX_CFP_CODE_A) {
|
|
PRINTM(MERROR,
|
|
"CFP Code not identified for A\n");
|
|
pioctl_req->status_code =
|
|
MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
pmadapter->cfp_code_bg = (t_u8)cfp_code->cfp_code_bg;
|
|
pmadapter->cfp_code_a = (t_u8)cfp_code->cfp_code_a;
|
|
if (region_bg && region_a && (region_bg == region_a))
|
|
pmadapter->region_code = pmadapter->cfp_code_a;
|
|
else
|
|
pmadapter->region_code = 0;
|
|
if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
|
|
pmadapter->config_bands |
|
|
pmadapter->adhoc_start_band)) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
} else {
|
|
/* GET operation */
|
|
cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
|
|
cfp_code->cfp_code_a = pmadapter->cfp_code_a;
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function sets up country code and downloads CMD to FW
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req Pointer to the IOCTL request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_misc_ioctl_country_code(pmlan_adapter pmadapter,
|
|
mlan_ioctl_req *pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_country_code *country_code = MNULL;
|
|
mlan_ds_misc_cfg *cfg_misc = MNULL;
|
|
t_u8 cfp_bg = 0, cfp_a = 0;
|
|
|
|
ENTER();
|
|
|
|
cfg_misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
country_code = &cfg_misc->param.country_code;
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
|
|
PRINTM(MERROR,
|
|
"ForceRegionRule is set in the on-chip OTP"
|
|
"memory\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Update region code and table based on country code */
|
|
if (wlan_misc_country_2_cfp_table_code(
|
|
pmadapter, country_code->country_code, &cfp_bg,
|
|
&cfp_a)) {
|
|
PRINTM(MERROR, "Country code not found!\n");
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
pmadapter->cfp_code_bg = cfp_bg;
|
|
pmadapter->cfp_code_a = cfp_a;
|
|
if (cfp_a)
|
|
pmadapter->region_code = cfp_a;
|
|
else if (cfp_bg)
|
|
pmadapter->region_code = cfp_bg;
|
|
else
|
|
pmadapter->region_code = 0;
|
|
if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
|
|
pmadapter->config_bands |
|
|
pmadapter->adhoc_start_band)) {
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
memcpy_ext(pmadapter, pmadapter->country_code,
|
|
country_code->country_code, COUNTRY_CODE_LEN,
|
|
COUNTRY_CODE_LEN);
|
|
} else {
|
|
/* GET operation */
|
|
memcpy_ext(pmadapter, country_code->country_code,
|
|
pmadapter->country_code, COUNTRY_CODE_LEN,
|
|
COUNTRY_CODE_LEN);
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Configure MFPC and MFPR for management frame protection
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req Pointer to the IOCTL request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_misc_pmfcfg(pmlan_adapter pmadapter,
|
|
mlan_ioctl_req *pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_misc_cfg *cfg_misc = MNULL;
|
|
mlan_ds_misc_pmfcfg *pmfcfg;
|
|
|
|
cfg_misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
pmfcfg = &cfg_misc->param.pmfcfg;
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET) {
|
|
pmpriv->pmfcfg.mfpc = pmfcfg->mfpc;
|
|
pmpriv->pmfcfg.mfpr = pmfcfg->mfpr;
|
|
} else {
|
|
/* GET operation */
|
|
pmfcfg->mfpc = pmpriv->pmfcfg.mfpc;
|
|
pmfcfg->mfpr = pmpriv->pmfcfg.mfpr;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief HW ARB Cfg
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
mlan_status wlan_misc_ioctl_arb_cfg(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u16 cmd_action = 0;
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET)
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
else
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_ARB_CONFIG, cmd_action, 0,
|
|
(t_void *)pioctl_req, &(pmisc->param.arb_cfg));
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Save tp accounting command configurations.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_PENDING --success, otherwise fail
|
|
*/
|
|
mlan_status wlan_misc_ioctl_tp_state(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
pmadapter->tp_state_on = pmisc->param.tp_state.on;
|
|
pmadapter->tp_state_drop_point = pmisc->param.tp_state.drop_point;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
static mlan_status wlan_misc_ioctl_get_sensor_temp(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u16 cmd_action = 0;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
|
|
ENTER();
|
|
|
|
if (pioctl_req->action == MLAN_ACT_GET)
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
else {
|
|
PRINTM(MERROR, " sensor temp only support get operation \n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_DS_GET_SENSOR_TEMP, cmd_action,
|
|
0, (t_void *)pioctl_req, MNULL);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief IPv6 Router Advertisement offload configuration
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req Pointer to the IOCTL request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_misc_ioctl_ipv6_ra_offload(pmlan_adapter pmadapter,
|
|
mlan_ioctl_req *pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_cfg *misc = MNULL;
|
|
t_u16 cmd_action = 0;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_SET)
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
else if (pioctl_req->action == MLAN_ACT_GET)
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_IPV6_RA_OFFLOAD_CFG,
|
|
cmd_action, 0, (t_void *)pioctl_req,
|
|
&misc->param.ipv6_ra_offload);
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Gtk Rekey Offload
|
|
*
|
|
* @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_gtk_rekey_offload(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_misc_cfg *misc_cfg = MNULL;
|
|
t_u16 cmd_action = 0;
|
|
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
|
|
ENTER();
|
|
misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
if (pioctl_req->action == MLAN_ACT_SET)
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
else if (pioctl_req->action == MLAN_ACT_CLEAR)
|
|
cmd_action = HostCmd_ACT_GEN_REMOVE;
|
|
else
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
|
|
if (!pmpriv->wpa_is_gtk_set) {
|
|
/* Store the gtk rekey data if it has already set gtk */
|
|
memcpy_ext(pmadapter, &pmpriv->gtk_rekey,
|
|
&misc_cfg->param.gtk_rekey,
|
|
sizeof(mlan_ds_misc_gtk_rekey_data),
|
|
sizeof(mlan_ds_misc_gtk_rekey_data));
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
/* Send request to firmware if it hasn't set gtk yet */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG,
|
|
cmd_action, 0, (t_void *)pioctl_req,
|
|
&misc_cfg->param.gtk_rekey);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief cloud keep alive
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pioctl_req Pointer to the IOCTL request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_misc_cloud_keep_alive(pmlan_adapter pmadapter,
|
|
mlan_ioctl_req *pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_ds_misc_cfg *misc = MNULL;
|
|
t_u16 cmd_action = 0;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
|
|
|
|
if (pioctl_req->action == MLAN_ACT_SET)
|
|
cmd_action = HostCmd_ACT_GEN_SET;
|
|
else if (pioctl_req->action == MLAN_ACT_GET) {
|
|
cmd_action = HostCmd_ACT_GEN_GET;
|
|
} else if (pioctl_req->action == MLAN_ACT_RESET) {
|
|
cmd_action = HostCmd_ACT_GEN_RESET;
|
|
} else {
|
|
cmd_action = HostCmd_ACT_GEN_REMOVE;
|
|
}
|
|
|
|
/* Send request to firmware */
|
|
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AUTO_TX, cmd_action,
|
|
OID_CLOUD_KEEP_ALIVE, (t_void *)pioctl_req,
|
|
&misc->param.keep_alive);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
ret = MLAN_STATUS_PENDING;
|
|
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_misc_cfg_ioctl(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_misc_cfg *misc = MNULL;
|
|
|
|
ENTER();
|
|
|
|
if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
|
|
PRINTM(MERROR, "Request buffer not found!\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
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);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
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:
|
|
PRINTM(MCMND, "Request WARM RESET\n");
|
|
util_enqueue_list_tail(pmadapter->pmoal_handle,
|
|
&pmadapter->ioctl_pending_q,
|
|
(pmlan_linked_list)pioctl_req,
|
|
pmadapter->callbacks.moal_spin_lock,
|
|
pmadapter->callbacks.moal_spin_unlock);
|
|
pmadapter->pending_ioctl = MTRUE;
|
|
status = MLAN_STATUS_PENDING;
|
|
break;
|
|
#ifdef SDIO
|
|
case MLAN_OID_MISC_SDIO_MPA_CTRL:
|
|
status = wlan_misc_ioctl_sdio_mpa_ctrl(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_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_ASSOC_RSP:
|
|
status = wlan_misc_ioctl_get_assoc_rsp(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_INIT_SHUTDOWN:
|
|
status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_SOFT_RESET:
|
|
status = wlan_misc_ioctl_soft_reset(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_CUSTOM_IE:
|
|
status = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req,
|
|
MTRUE);
|
|
break;
|
|
case MLAN_OID_MISC_TDLS_CONFIG:
|
|
status = wlan_misc_ioctl_tdls_config(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_TDLS_OPER:
|
|
status = wlan_misc_ioctl_tdls_oper(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_TDLS_IES:
|
|
status = wlan_misc_ioctl_tdls_get_ies(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_TDLS_CS_CHANNEL:
|
|
status = wlan_misc_ioctl_tdls_cs_channel(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_TDLS_IDLE_TIME:
|
|
status = wlan_misc_ioctl_tdls_idle_time(pmadapter, pioctl_req);
|
|
break;
|
|
|
|
case MLAN_OID_MISC_MAC_CONTROL:
|
|
status = wlan_misc_ioctl_mac_control(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_MEF_CFG:
|
|
status = wlan_misc_ioctl_mef_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_RX_MGMT_IND:
|
|
status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
|
|
break;
|
|
#ifdef DEBUG_LEVEL1
|
|
case MLAN_OID_MISC_DRVDBG:
|
|
status = wlan_set_drvdbg(pmadapter, pioctl_req);
|
|
break;
|
|
#endif
|
|
case MLAN_OID_MISC_IP_ADDR:
|
|
status = wlan_misc_ioctl_ipaddr_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_CFP_CODE:
|
|
status = wlan_misc_ioctl_cfp_code_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_COUNTRY_CODE:
|
|
status = wlan_misc_ioctl_country_code(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_THERMAL:
|
|
status = wlan_misc_ioctl_thermal(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_SUBSCRIBE_EVENT:
|
|
status = wlan_misc_ioctl_subscribe_evt(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_HOTSPOT_CFG:
|
|
status = wlan_misc_hotspot_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_OTP_USER_DATA:
|
|
status = wlan_misc_otp_user_data(pmadapter, pioctl_req);
|
|
break;
|
|
#ifdef USB
|
|
case MLAN_OID_MISC_USB_AGGR_CTRL:
|
|
status = wlan_misc_ioctl_usb_aggr_ctrl(pmadapter, pioctl_req);
|
|
break;
|
|
#endif
|
|
case MLAN_OID_MISC_AGGR_CTRL:
|
|
status = wlan_misc_ioctl_aggr_ctrl(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_TXCONTROL:
|
|
status = wlan_misc_ioctl_txcontrol(pmadapter, pioctl_req);
|
|
break;
|
|
#ifdef STA_SUPPORT
|
|
case MLAN_OID_MISC_EXT_CAP_CFG:
|
|
status = wlan_misc_ext_capa_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
#endif
|
|
case MLAN_OID_MISC_PMFCFG:
|
|
status = wlan_misc_pmfcfg(pmadapter, pioctl_req);
|
|
break;
|
|
#ifdef RX_PACKET_COALESCE
|
|
case MLAN_OID_MISC_RX_PACKET_COALESCE:
|
|
status = wlan_misc_ioctl_rx_pkt_coalesce_config(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
#endif
|
|
case MLAN_OID_MISC_LOW_PWR_MODE:
|
|
status = wlan_misc_ioctl_low_pwr_mode(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_PMIC_CFG:
|
|
status = wlan_misc_ioctl_pmic_configure(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_CWMODE_CTRL:
|
|
status = wlan_misc_ioctl_cwmode_ctrl(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_MEF_FLT_CFG:
|
|
status = wlan_misc_ioctl_mef_flt_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_DFS_REAPTER_MODE:
|
|
status =
|
|
wlan_misc_ioctl_dfs_repeater_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_COALESCE_CFG:
|
|
status = wlan_misc_ioctl_coalesce_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_SENSOR_TEMP:
|
|
status = wlan_misc_ioctl_get_sensor_temp(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_OPER_CLASS:
|
|
status = wlan_misc_ioctl_oper_class(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_OPER_CLASS_CHECK:
|
|
status = wlan_misc_ioctl_operclass_validation(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_IPV6_RA_OFFLOAD:
|
|
status = wlan_misc_ioctl_ipv6_ra_offload(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GTK_REKEY_OFFLOAD:
|
|
status = wlan_misc_ioctl_gtk_rekey_offload(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_IND_RST_CFG:
|
|
status = wlan_misc_ioctl_ind_rst_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_TSF:
|
|
status = wlan_misc_ioctl_get_tsf(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_CHAN_REGION_CFG:
|
|
status = wlan_misc_chan_reg_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_CLOUD_KEEP_ALIVE:
|
|
status = wlan_misc_cloud_keep_alive(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_DYN_BW:
|
|
status = wlan_misc_ioctl_dyn_bw(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_FW_DUMP_EVENT:
|
|
status = wlan_misc_ioctl_fw_dump_event(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_PER_PKT_CFG:
|
|
status = wlan_misc_per_pkt_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_ROBUSTCOEX:
|
|
status = wlan_misc_robustcoex(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_DMCS_CONFIG:
|
|
status = wlan_misc_dmcs_config(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_TX_RX_HISTOGRAM:
|
|
status = wlan_get_tx_rx_histogram(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_BOOT_SLEEP:
|
|
status = wlan_misc_bootsleep(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_CFP_INFO:
|
|
status = wlan_get_cfpinfo(pmadapter, pioctl_req);
|
|
break;
|
|
#if defined(PCIE)
|
|
case MLAN_OID_MISC_SSU:
|
|
if (pmadapter->ssu_buf)
|
|
status = MLAN_STATUS_FAILURE;
|
|
else
|
|
status = wlan_misc_ssu(pmadapter, pioctl_req);
|
|
break;
|
|
#endif
|
|
case MLAN_OID_MISC_HAL_PHY_CFG:
|
|
status = wlan_misc_hal_phy_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GPIO_TSF_LATCH:
|
|
status = wlan_misc_gpio_tsf_latch_config(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_TSF_INFO:
|
|
status = wlan_misc_get_tsf_info(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_RX_ABORT_CFG:
|
|
status = wlan_misc_ioctl_rxabortcfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_RX_ABORT_CFG_EXT:
|
|
status = wlan_misc_ioctl_rxabortcfg_ext(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_TX_AMPDU_PROT_MODE:
|
|
status = wlan_misc_ioctl_tx_ampdu_prot_mode(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG:
|
|
status = wlan_misc_ioctl_dot11mc_unassoc_ftm_cfg(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_RATE_ADAPT_CFG:
|
|
status = wlan_misc_ioctl_rate_adapt_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_CCK_DESENSE_CFG:
|
|
status = wlan_misc_ioctl_cck_desense_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_REGIONPWR_CFG:
|
|
status = wlan_get_rgchnpwr_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_GET_CHAN_TRPC_CFG:
|
|
status = wlan_get_chan_trpc_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_RF_TEST_GENERIC:
|
|
case MLAN_OID_MISC_RF_TEST_TX_CONT:
|
|
case MLAN_OID_MISC_RF_TEST_TX_FRAME:
|
|
case MLAN_OID_MISC_RF_TEST_HE_POWER:
|
|
status = wlan_misc_ioctl_rf_test_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_ARB_CONFIG:
|
|
status = wlan_misc_ioctl_arb_cfg(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_RANGE_EXT:
|
|
status = wlan_misc_ioctl_range_ext(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_OID_MISC_TP_STATE:
|
|
status = wlan_misc_ioctl_tp_state(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
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
|
|
*/
|
|
static mlan_status wlan_set_get_scan_cfg(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req,
|
|
t_u32 action)
|
|
{
|
|
mlan_ds_scan *scan = MNULL;
|
|
|
|
ENTER();
|
|
|
|
scan = (mlan_ds_scan *)pioctl_req->pbuf;
|
|
if (action == MLAN_ACT_SET) {
|
|
if (scan->param.scan_cfg.scan_type)
|
|
pmadapter->scan_type =
|
|
(t_u8)scan->param.scan_cfg.scan_type;
|
|
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;
|
|
if (scan->param.scan_cfg.passive_to_active_scan)
|
|
pmadapter->passive_to_active_scan =
|
|
scan->param.scan_cfg.passive_to_active_scan;
|
|
if (scan->param.scan_cfg.ext_scan)
|
|
pmadapter->ext_scan = scan->param.scan_cfg.ext_scan - 1;
|
|
pmadapter->scan_chan_gap = scan->param.scan_cfg.scan_chan_gap;
|
|
}
|
|
scan->param.scan_cfg.scan_type = (t_u32)pmadapter->scan_type;
|
|
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;
|
|
scan->param.scan_cfg.passive_to_active_scan =
|
|
pmadapter->passive_to_active_scan;
|
|
scan->param.scan_cfg.ext_scan = pmadapter->ext_scan + 1;
|
|
scan->param.scan_cfg.scan_chan_gap = pmadapter->scan_chan_gap;
|
|
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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
static mlan_status wlan_scan_ioctl(pmlan_adapter pmadapter,
|
|
pmlan_ioctl_req pioctl_req)
|
|
{
|
|
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
mlan_ds_scan *pscan;
|
|
|
|
ENTER();
|
|
|
|
pscan = (mlan_ds_scan *)pioctl_req->pbuf;
|
|
if (pscan->sub_command == MLAN_OID_SCAN_CONFIG ||
|
|
pscan->sub_command == MLAN_OID_SCAN_BGSCAN_CONFIG)
|
|
goto start_config;
|
|
if (pmadapter->scan_processing && pioctl_req->action == MLAN_ACT_SET &&
|
|
pscan->sub_command != MLAN_OID_SCAN_CANCEL) {
|
|
PRINTM(MINFO, "Scan already in process...\n");
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
if (pmadapter->scan_block && pioctl_req->action == MLAN_ACT_SET) {
|
|
PRINTM(MERROR, "Scan is blocked during association...\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
start_config:
|
|
/* 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;
|
|
case MLAN_OID_SCAN_CANCEL:
|
|
status = wlan_cancel_pending_scan_cmd(pmadapter,
|
|
pioctl_req);
|
|
break;
|
|
case MLAN_OID_SCAN_TABLE_FLUSH:
|
|
status = wlan_flush_scan_table(pmadapter);
|
|
break;
|
|
case MLAN_OID_SCAN_BGSCAN_CONFIG:
|
|
/* Send request to firmware */
|
|
status = wlan_prepare_cmd(
|
|
pmpriv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
|
|
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
|
|
pscan->param.user_scan.scan_cfg_buf);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
status = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if ((status == MLAN_STATUS_SUCCESS) &&
|
|
(pscan->sub_command != MLAN_OID_SCAN_TABLE_FLUSH) &&
|
|
(pscan->sub_command != MLAN_OID_SCAN_CANCEL) &&
|
|
(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_GET_CURRENT_BSS) {
|
|
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 {
|
|
if (pmadapter->bgscan_reported) {
|
|
pmadapter->bgscan_reported = MFALSE;
|
|
/* Clear the previous scan result */
|
|
memset(pmadapter, pmadapter->pscan_table, 0x00,
|
|
sizeof(BSSDescriptor_t) *
|
|
MRVDRV_MAX_BSSID_LIST);
|
|
pmadapter->num_in_scan_table = 0;
|
|
pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
|
|
status = wlan_prepare_cmd(
|
|
pmpriv,
|
|
HostCmd_CMD_802_11_BG_SCAN_QUERY,
|
|
HostCmd_ACT_GEN_GET, 0,
|
|
(t_void *)pioctl_req, MNULL);
|
|
if (status == MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MINFO,
|
|
"wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
|
|
status = MLAN_STATUS_PENDING;
|
|
}
|
|
} 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;
|
|
pscan->param.scan_resp.age_in_secs =
|
|
pmadapter->age_in_secs;
|
|
pioctl_req->data_read_written =
|
|
sizeof(mlan_scan_resp) +
|
|
MLAN_SUB_COMMAND_SIZE;
|
|
pscan->param.scan_resp.pchan_stats =
|
|
(t_u8 *)pmadapter->pchan_stats;
|
|
pscan->param.scan_resp.num_in_chan_stats =
|
|
pmadapter->num_in_chan_stats;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief Set ewpa mode
|
|
*
|
|
* @param priv A pointer to mlan_private structure
|
|
* @param psec_pp A pointer to mlan_ds_passphrase structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_set_ewpa_mode(mlan_private *priv, mlan_ds_passphrase *psec_pp)
|
|
{
|
|
ENTER();
|
|
|
|
if ((psec_pp->psk_type == MLAN_PSK_PASSPHRASE &&
|
|
psec_pp->psk.passphrase.passphrase_len > 0) ||
|
|
(psec_pp->psk_type == MLAN_PSK_PMK))
|
|
priv->sec_info.ewpa_enabled = MTRUE;
|
|
else
|
|
priv->sec_info.ewpa_enabled = MFALSE;
|
|
|
|
PRINTM(MINFO, "Set ewpa mode = %d\n", priv->sec_info.ewpa_enabled);
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Search for a BSS
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pioctl_req A pointer to ioctl request buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS --success, otherwise
|
|
* fail
|
|
*/
|
|
mlan_status wlan_find_bss(mlan_private *pmpriv, pmlan_ioctl_req pioctl_req)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
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 = MNULL;
|
|
|
|
ENTER();
|
|
|
|
bss = (mlan_ds_bss *)pioctl_req->pbuf;
|
|
|
|
if (memcmp(pmadapter, &bss->param.ssid_bssid.bssid, zero_mac,
|
|
sizeof(zero_mac))) {
|
|
if (bss->param.ssid_bssid.ssid.ssid_len) /* ssid & bssid */
|
|
i = wlan_find_ssid_in_list(
|
|
pmpriv, &bss->param.ssid_bssid.ssid,
|
|
(t_u8 *)&bss->param.ssid_bssid.bssid,
|
|
pmpriv->bss_mode);
|
|
else
|
|
i = wlan_find_bssid_in_list(
|
|
pmpriv, (t_u8 *)&bss->param.ssid_bssid.bssid,
|
|
pmpriv->bss_mode);
|
|
if (i < 0) {
|
|
memcpy_ext(pmadapter, mac, &bss->param.ssid_bssid.bssid,
|
|
sizeof(mac), MLAN_MAC_ADDR_LENGTH);
|
|
PRINTM(MIOCTL, "Can not find bssid " MACSTR "\n",
|
|
MAC2STR(mac));
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pbss_desc = &pmadapter->pscan_table[i];
|
|
memcpy_ext(pmadapter, &bss->param.ssid_bssid.ssid,
|
|
&pbss_desc->ssid, sizeof(mlan_802_11_ssid),
|
|
sizeof(mlan_802_11_ssid));
|
|
bss->param.ssid_bssid.rssi = pbss_desc->rssi;
|
|
bss->param.ssid_bssid.channel = (t_u16)pbss_desc->channel;
|
|
|
|
bss->param.ssid_bssid.bss_band = pbss_desc->bss_band;
|
|
/* index in bss list,start from 1 */
|
|
bss->param.ssid_bssid.idx = i + 1;
|
|
} 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(MIOCTL, "Can not find ssid %s\n",
|
|
bss->param.ssid_bssid.ssid.ssid);
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pbss_desc = &pmadapter->pscan_table[i];
|
|
memcpy_ext(pmadapter, (t_u8 *)&bss->param.ssid_bssid.bssid,
|
|
(t_u8 *)&pbss_desc->mac_address,
|
|
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
|
|
bss->param.ssid_bssid.rssi = pbss_desc->rssi;
|
|
bss->param.ssid_bssid.channel = (t_u16)pbss_desc->channel;
|
|
|
|
bss->param.ssid_bssid.bss_band = pbss_desc->bss_band;
|
|
/* index in bss list, start from 1 */
|
|
bss->param.ssid_bssid.idx = i + 1;
|
|
} else {
|
|
ret = wlan_find_best_network(pmpriv, &bss->param.ssid_bssid);
|
|
}
|
|
|
|
if (pbss_desc) {
|
|
/**if rsn do not have ft akm, don't set ft cap and ft md*/
|
|
if (pbss_desc->pmd_ie &&
|
|
wlan_ft_akm_is_used(pmpriv, (t_u8 *)pbss_desc->prsn_ie)) {
|
|
bss->param.ssid_bssid.ft_md = pbss_desc->pmd_ie->mdid;
|
|
bss->param.ssid_bssid.ft_cap =
|
|
pbss_desc->pmd_ie->ft_cap;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @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/MLAN_STATUS_PENDING --success,
|
|
* otherwise fail
|
|
*/
|
|
mlan_status wlan_ops_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_MISC_CFG:
|
|
status = wlan_misc_cfg_ioctl(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_IOCTL_11H_CFG:
|
|
status = wlan_11h_cfg_ioctl(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_IOCTL_11AC_CFG:
|
|
status = wlan_11ac_cfg_ioctl(pmadapter, pioctl_req);
|
|
break;
|
|
case MLAN_IOCTL_11AX_CFG:
|
|
status = wlan_11ax_cfg_ioctl(pmadapter, pioctl_req);
|
|
break;
|
|
default:
|
|
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
|
|
status = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
LEAVE();
|
|
return status;
|
|
}
|