mwifiex/mxm_wifiex/wlan_src/mlan/mlan_misc.c
Sherry Sun 4310e0ca2f mxm_wifiex: update to mxm5x17344.p1 release
Driver Bug Fixes:
-----------------
1. WCSWREL-352: Fixed WiFi driver kernel panic with "use after free" print
2. WCSWREL-353: Fixed WiFi driver panic when switch AP to another AP
3. WCSWREL-337: merge the L5.18 build errors and warnings fix patches into next wifi release
4. WSW-16518: Fixed STA going to unresponsive state during basic UAPSD operation
5. WSW-19350: Observed "unexpected kernel BRK exception" in STA 2G VHT with BT HID traffic running simultaneously
6. WSW-19640: cannot enable the "20/40 BSS Coexistence Management" support

Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
2022-08-05 17:16:29 +00:00

6950 lines
197 KiB
C

/**
* @file mlan_misc.c
*
* @brief This file include Miscellaneous functions for MLAN module
*
*
* Copyright 2009-2022 NXP
*
* NXP CONFIDENTIAL
* The source code contained or described herein and all documents related to
* the source code (Materials) are owned by NXP, its
* suppliers and/or its licensors. Title to the Materials remains with NXP,
* its suppliers and/or its licensors. The Materials contain
* trade secrets and proprietary and confidential information of NXP, its
* suppliers and/or its licensors. The Materials are protected by worldwide
* copyright and trade secret laws and treaty provisions. No part of the
* Materials may be used, copied, reproduced, modified, published, uploaded,
* posted, transmitted, distributed, or disclosed in any way without NXP's
* prior express written permission.
*
* No license under any patent, copyright, trade secret or other intellectual
* property right is granted to or conferred upon you by disclosure or delivery
* of the Materials, either expressly, by implication, inducement, estoppel or
* otherwise. Any license under such intellectual property rights must be
* express and approved by NXP in writing.
*
* Alternatively, this software may be distributed under the terms of GPL v2.
* SPDX-License-Identifier: GPL-2.0
*
*
*/
/*************************************************************
Change Log:
05/11/2009: initial version
************************************************************/
#include "mlan.h"
#ifdef STA_SUPPORT
#include "mlan_join.h"
#endif /* STA_SUPPORT */
#include "mlan_util.h"
#include "mlan_fw.h"
#include "mlan_main.h"
#include "mlan_wmm.h"
#include "mlan_11n.h"
#include "mlan_11ac.h"
#include "mlan_11ax.h"
#ifdef UAP_SUPPORT
#include "mlan_uap.h"
#endif
#ifdef DRV_EMBEDDED_AUTHENTICATOR
#include "authenticator_api.h"
#endif
/********************************************************
Local Variables
********************************************************/
/********************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
#if defined(PCIE) || defined(SDIO)
/**
* @brief Check pending irq
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MTRUE/MFALSE;
*/
static t_u8 wlan_pending_interrupt(pmlan_adapter pmadapter)
{
if (!IS_USB(pmadapter->card_type) && pmadapter->ireg)
return MTRUE;
return MFALSE;
}
#endif
/** Custom IE auto index and mask */
#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
/** Custom IE mask for delete operation */
#define MLAN_CUSTOM_IE_DELETE_MASK 0
/** Custom IE mask for create new index */
#define MLAN_CUSTOM_IE_NEW_MASK 0x8000
/** Custom IE header size */
#define MLAN_CUSTOM_IE_HDR_SIZE (sizeof(custom_ie) - MAX_IE_SIZE)
/**
* @brief Check if current custom IE index is used on other interfaces.
*
* @param pmpriv A pointer to mlan_private structure
* @param idx index to check for in use
*
* @return MLAN_STATUS_SUCCESS --unused, otherwise used.
*/
static mlan_status wlan_is_custom_ie_index_unused(pmlan_private pmpriv,
t_u16 idx)
{
t_u8 i = 0;
pmlan_adapter pmadapter = pmpriv->adapter;
pmlan_private priv;
ENTER();
for (i = 0; i < pmadapter->priv_num; i++) {
priv = pmadapter->priv[i];
/* Check for other interfaces only */
if (priv && priv->bss_index != pmpriv->bss_index) {
if (priv->mgmt_ie[idx].mgmt_subtype_mask &&
priv->mgmt_ie[idx].ie_length) {
/* used entry found */
LEAVE();
return MLAN_STATUS_FAILURE;
}
}
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Get the custom IE index
*
* @param pmpriv A pointer to mlan_private structure
* @param pioctl_req A pointer to ioctl request buffer
* @param mask mask value for which the index to be returned
* @param ie_data a pointer to custom_ie structure
* @param idx will hold the computed index
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status wlan_custom_ioctl_get_autoidx(pmlan_private pmpriv,
pmlan_ioctl_req pioctl_req,
t_u16 mask, custom_ie *ie_data,
t_u16 *idx)
{
t_u16 index = 0, insert = MFALSE;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
/* Determine the index where the IE needs to be inserted */
while (!insert) {
while (index < MIN(pmpriv->adapter->max_mgmt_ie_index,
MAX_MGMT_IE_INDEX)) {
if (pmpriv->mgmt_ie[index].mgmt_subtype_mask ==
MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
index++;
continue;
}
if (pmpriv->mgmt_ie[index].mgmt_subtype_mask == mask) {
/* Duplicate IE should be avoided */
if (pmpriv->mgmt_ie[index].ie_length) {
if (!memcmp(pmpriv->adapter,
pmpriv->mgmt_ie[index]
.ie_buffer,
ie_data->ie_buffer,
pmpriv->mgmt_ie[index]
.ie_length)) {
PRINTM(MINFO,
"IE with the same mask exists at index %d mask=0x%x\n",
index, mask);
*idx = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
goto done;
}
}
/* Check if enough space is available */
if (pmpriv->mgmt_ie[index].ie_length +
ie_data->ie_length >
MAX_IE_SIZE) {
index++;
continue;
}
insert = MTRUE;
break;
}
index++;
}
if (!insert) {
for (index = 0;
index < MIN(pmpriv->adapter->max_mgmt_ie_index,
MAX_MGMT_IE_INDEX);
index++) {
if (pmpriv->mgmt_ie[index].ie_length == 0) {
/*
* Check if this index is in use
* by other interface If yes,
* move ahead to next index
*/
if (MLAN_STATUS_SUCCESS ==
wlan_is_custom_ie_index_unused(
pmpriv, index)) {
insert = MTRUE;
break;
} else {
PRINTM(MINFO,
"Skipping IE index %d in use.\n",
index);
}
}
}
}
if (index == pmpriv->adapter->max_mgmt_ie_index && !insert) {
PRINTM(MERROR, "Failed to Set the IE buffer\n");
if (pioctl_req)
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
ret = MLAN_STATUS_FAILURE;
goto done;
}
}
*idx = index;
done:
LEAVE();
return ret;
}
/**
* @brief Delete custom IE
*
* @param pmpriv A pointer to mlan_private structure
* @param pioctl_req A pointer to ioctl request buffer
* @param ie_data a pointer to custom_ie structure
* @param idx index supplied
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
static mlan_status wlan_custom_ioctl_auto_delete(pmlan_private pmpriv,
pmlan_ioctl_req pioctl_req,
custom_ie *ie_data, t_u16 idx)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_adapter pmadapter = pmpriv->adapter;
t_u16 index = 0, insert = MFALSE, del_len;
t_u8 del_ie[MAX_IE_SIZE], ie[MAX_IE_SIZE];
t_s32 cnt, tmp_len = 0;
t_u8 *tmp_ie;
ENTER();
memset(pmpriv->adapter, del_ie, 0, MAX_IE_SIZE);
memcpy_ext(pmpriv->adapter, del_ie, ie_data->ie_buffer,
ie_data->ie_length, MAX_IE_SIZE);
del_len = MIN(MAX_IE_SIZE - 1, ie_data->ie_length);
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx)
ie_data->ie_index = 0;
for (index = 0;
index < MIN(pmadapter->max_mgmt_ie_index, MAX_MGMT_IE_INDEX);
index++) {
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx &&
idx < MAX_MGMT_IE_INDEX)
index = idx;
tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
tmp_len = pmpriv->mgmt_ie[index].ie_length;
cnt = 0;
while (tmp_len) {
if (!memcmp(pmpriv->adapter, tmp_ie, del_ie, del_len)) {
memcpy_ext(pmpriv->adapter, ie,
pmpriv->mgmt_ie[index].ie_buffer,
cnt, MAX_IE_SIZE);
if (pmpriv->mgmt_ie[index].ie_length >
(cnt + del_len))
memcpy_ext(
pmpriv->adapter, &ie[cnt],
&pmpriv->mgmt_ie[index].ie_buffer
[MIN((MAX_IE_SIZE - 1),
(cnt + del_len))],
(pmpriv->mgmt_ie[index]
.ie_length -
(cnt + del_len)),
MAX_IE_SIZE - cnt);
memset(pmpriv->adapter,
&pmpriv->mgmt_ie[index].ie_buffer, 0,
sizeof(pmpriv->mgmt_ie[index].ie_buffer));
memcpy_ext(pmpriv->adapter,
&pmpriv->mgmt_ie[index].ie_buffer,
ie,
pmpriv->mgmt_ie[index].ie_length -
del_len,
MAX_IE_SIZE);
pmpriv->mgmt_ie[index].ie_length -= del_len;
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx)
/* set a bit to indicate caller about
* update */
ie_data->ie_index |=
(((t_u16)1) << index);
insert = MTRUE;
tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
tmp_len = pmpriv->mgmt_ie[index].ie_length;
cnt = 0;
continue;
}
tmp_ie++;
tmp_len--;
cnt++;
}
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx)
break;
}
if (index == pmadapter->max_mgmt_ie_index && !insert) {
PRINTM(MERROR, "Failed to Clear IE buffer\n");
if (pioctl_req)
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
ret = MLAN_STATUS_FAILURE;
}
LEAVE();
return ret;
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief send host cmd
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_host_cmd(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;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)pioctl_req,
(t_void *)&misc->param.hostcmd);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Send function init/shutdown command to firmware
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_init_shutdown(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_cfg = MNULL;
t_u16 cmd;
ENTER();
misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_INIT)
cmd = HostCmd_CMD_FUNC_INIT;
else if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_SHUTDOWN)
cmd = HostCmd_CMD_FUNC_SHUTDOWN;
else {
PRINTM(MERROR, "Unsupported parameter\n");
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send command to firmware */
ret = wlan_prepare_cmd(pmpriv, cmd, HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Get debug information
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success
*/
mlan_status wlan_get_info_debug_info(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;
mlan_debug_info *debug_info = MNULL;
t_u32 i;
t_u8 *ptid;
ENTER();
info = (mlan_ds_get_info *)pioctl_req->pbuf;
debug_info = (mlan_debug_info *)info->param.debug_info;
if (pioctl_req->action == MLAN_ACT_GET) {
ptid = ac_to_tid[WMM_AC_BK];
debug_info->wmm_ac_bk = pmpriv->wmm.packets_out[ptid[0]] +
pmpriv->wmm.packets_out[ptid[1]];
ptid = ac_to_tid[WMM_AC_BE];
debug_info->wmm_ac_be = pmpriv->wmm.packets_out[ptid[0]] +
pmpriv->wmm.packets_out[ptid[1]];
ptid = ac_to_tid[WMM_AC_VI];
debug_info->wmm_ac_vi = pmpriv->wmm.packets_out[ptid[0]] +
pmpriv->wmm.packets_out[ptid[1]];
ptid = ac_to_tid[WMM_AC_VO];
debug_info->wmm_ac_vo = pmpriv->wmm.packets_out[ptid[0]] +
pmpriv->wmm.packets_out[ptid[1]];
debug_info->max_tx_buf_size = (t_u32)pmadapter->max_tx_buf_size;
debug_info->tx_buf_size = (t_u32)pmadapter->tx_buf_size;
debug_info->curr_tx_buf_size =
(t_u32)pmadapter->curr_tx_buf_size;
debug_info->rx_tbl_num =
wlan_get_rxreorder_tbl(pmpriv, debug_info->rx_tbl);
debug_info->tx_tbl_num =
wlan_get_txbastream_tbl(pmpriv, debug_info->tx_tbl);
debug_info->ralist_num =
wlan_get_ralist_info(pmpriv, debug_info->ralist);
debug_info->tdls_peer_num =
wlan_get_tdls_list(pmpriv, debug_info->tdls_peer_list);
debug_info->ps_mode = pmadapter->ps_mode;
debug_info->ps_state = pmadapter->ps_state;
#ifdef STA_SUPPORT
debug_info->is_deep_sleep = pmadapter->is_deep_sleep;
#endif /* STA_SUPPORT */
debug_info->pm_wakeup_card_req = pmadapter->pm_wakeup_card_req;
debug_info->pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try;
debug_info->pm_wakeup_in_secs = pmadapter->pm_wakeup_in_secs;
debug_info->pm_wakeup_timeout = pmadapter->pm_wakeup_timeout;
debug_info->is_hs_configured = pmadapter->is_hs_configured;
debug_info->hs_activated = pmadapter->hs_activated;
debug_info->pps_uapsd_mode = pmadapter->pps_uapsd_mode;
debug_info->sleep_pd = pmadapter->sleep_period.period;
debug_info->qos_cfg = pmpriv->wmm_qosinfo;
debug_info->tx_lock_flag = pmadapter->tx_lock_flag;
debug_info->port_open = pmpriv->port_open;
debug_info->bypass_pkt_count = pmadapter->bypass_pkt_count;
debug_info->scan_processing = pmadapter->scan_processing;
debug_info->scan_state = pmadapter->scan_state;
debug_info->mlan_processing = pmadapter->mlan_processing;
debug_info->main_lock_flag = pmadapter->main_lock_flag;
debug_info->main_process_cnt = pmadapter->main_process_cnt;
debug_info->delay_task_flag = pmadapter->delay_task_flag;
debug_info->num_cmd_host_to_card_failure =
pmadapter->dbg.num_cmd_host_to_card_failure;
debug_info->num_cmd_sleep_cfm_host_to_card_failure =
pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
debug_info->num_tx_host_to_card_failure =
pmadapter->dbg.num_tx_host_to_card_failure;
debug_info->num_alloc_buffer_failure =
pmadapter->dbg.num_alloc_buffer_failure;
debug_info->num_pkt_dropped = pmadapter->dbg.num_pkt_dropped;
debug_info->num_event_deauth = pmadapter->dbg.num_event_deauth;
debug_info->num_event_disassoc =
pmadapter->dbg.num_event_disassoc;
debug_info->num_event_link_lost =
pmadapter->dbg.num_event_link_lost;
debug_info->num_cmd_deauth = pmadapter->dbg.num_cmd_deauth;
debug_info->num_cmd_assoc_success =
pmadapter->dbg.num_cmd_assoc_success;
debug_info->num_cmd_assoc_failure =
pmadapter->dbg.num_cmd_assoc_failure;
debug_info->num_cmd_timeout = pmadapter->num_cmd_timeout;
debug_info->timeout_cmd_id = pmadapter->dbg.timeout_cmd_id;
debug_info->timeout_cmd_act = pmadapter->dbg.timeout_cmd_act;
memcpy_ext(pmadapter, debug_info->last_cmd_id,
pmadapter->dbg.last_cmd_id,
sizeof(pmadapter->dbg.last_cmd_id),
sizeof(debug_info->last_cmd_id));
memcpy_ext(pmadapter, debug_info->last_cmd_act,
pmadapter->dbg.last_cmd_act,
sizeof(pmadapter->dbg.last_cmd_act),
sizeof(debug_info->last_cmd_act));
debug_info->last_cmd_index = pmadapter->dbg.last_cmd_index;
memcpy_ext(pmadapter, debug_info->last_cmd_resp_id,
pmadapter->dbg.last_cmd_resp_id,
sizeof(pmadapter->dbg.last_cmd_resp_id),
sizeof(debug_info->last_cmd_resp_id));
debug_info->last_cmd_resp_index =
pmadapter->dbg.last_cmd_resp_index;
memcpy_ext(pmadapter, debug_info->last_event,
pmadapter->dbg.last_event,
sizeof(pmadapter->dbg.last_event),
sizeof(debug_info->last_event));
debug_info->last_event_index = pmadapter->dbg.last_event_index;
debug_info->num_no_cmd_node = pmadapter->dbg.num_no_cmd_node;
debug_info->pending_cmd =
(pmadapter->curr_cmd) ?
pmadapter->dbg.last_cmd_id
[pmadapter->dbg.last_cmd_index] :
0;
debug_info->dnld_cmd_in_secs = pmadapter->dnld_cmd_in_secs;
#ifdef SDIO
if (IS_SD(pmadapter->card_type)) {
debug_info->num_cmdevt_card_to_host_failure =
pmadapter->dbg.num_cmdevt_card_to_host_failure;
debug_info->num_rx_card_to_host_failure =
pmadapter->dbg.num_rx_card_to_host_failure;
debug_info->num_int_read_failure =
pmadapter->dbg.num_int_read_failure;
debug_info->last_int_status =
pmadapter->dbg.last_int_status;
debug_info->mp_rd_bitmap =
pmadapter->pcard_sd->mp_rd_bitmap;
debug_info->mp_wr_bitmap =
pmadapter->pcard_sd->mp_wr_bitmap;
debug_info->curr_rd_port =
pmadapter->pcard_sd->curr_rd_port;
debug_info->curr_wr_port =
pmadapter->pcard_sd->curr_wr_port;
debug_info->mp_invalid_update =
pmadapter->pcard_sd->mp_invalid_update;
debug_info->num_of_irq =
pmadapter->pcard_sd->num_of_irq;
memcpy_ext(pmadapter, debug_info->mp_update,
pmadapter->pcard_sd->mp_update,
sizeof(pmadapter->pcard_sd->mp_update),
sizeof(debug_info->mp_update));
memcpy_ext(pmadapter, debug_info->mpa_tx_count,
pmadapter->pcard_sd->mpa_tx_count,
sizeof(pmadapter->pcard_sd->mpa_tx_count),
sizeof(debug_info->mpa_tx_count));
debug_info->mpa_sent_last_pkt =
pmadapter->pcard_sd->mpa_sent_last_pkt;
debug_info->mpa_sent_no_ports =
pmadapter->pcard_sd->mpa_sent_no_ports;
debug_info->last_recv_wr_bitmap =
pmadapter->pcard_sd->last_recv_wr_bitmap;
debug_info->last_recv_rd_bitmap =
pmadapter->pcard_sd->last_recv_rd_bitmap;
debug_info->mp_data_port_mask =
pmadapter->pcard_sd->mp_data_port_mask;
debug_info->last_mp_index =
pmadapter->pcard_sd->last_mp_index;
memcpy_ext(
pmadapter, debug_info->last_mp_wr_bitmap,
pmadapter->pcard_sd->last_mp_wr_bitmap,
sizeof(pmadapter->pcard_sd->last_mp_wr_bitmap),
sizeof(debug_info->last_mp_wr_bitmap));
memcpy_ext(
pmadapter, debug_info->last_mp_wr_ports,
pmadapter->pcard_sd->last_mp_wr_ports,
sizeof(pmadapter->pcard_sd->last_mp_wr_ports),
sizeof(debug_info->last_mp_wr_ports));
memcpy_ext(pmadapter, debug_info->last_mp_wr_len,
pmadapter->pcard_sd->last_mp_wr_len,
sizeof(pmadapter->pcard_sd->last_mp_wr_len),
sizeof(debug_info->last_mp_wr_len));
memcpy_ext(pmadapter, debug_info->last_mp_wr_info,
pmadapter->pcard_sd->last_mp_wr_info,
sizeof(pmadapter->pcard_sd->last_mp_wr_info),
sizeof(debug_info->last_mp_wr_info));
memcpy_ext(
pmadapter, debug_info->last_curr_wr_port,
pmadapter->pcard_sd->last_curr_wr_port,
sizeof(pmadapter->pcard_sd->last_curr_wr_port),
sizeof(debug_info->last_curr_wr_port));
debug_info->mpa_buf = pmadapter->pcard_sd->mpa_buf;
debug_info->mpa_buf_size =
pmadapter->pcard_sd->mpa_buf_size;
debug_info->sdio_rx_aggr =
pmadapter->pcard_sd->sdio_rx_aggr_enable;
memcpy_ext(pmadapter, debug_info->mpa_rx_count,
pmadapter->pcard_sd->mpa_rx_count,
sizeof(pmadapter->pcard_sd->mpa_rx_count),
sizeof(debug_info->mpa_rx_count));
debug_info->mp_aggr_pkt_limit =
pmadapter->pcard_sd->mp_aggr_pkt_limit;
}
#endif
#ifdef PCIE
if (IS_PCIE(pmadapter->card_type)) {
debug_info->txbd_rdptr =
pmadapter->pcard_pcie->txbd_rdptr;
debug_info->txbd_wrptr =
pmadapter->pcard_pcie->txbd_wrptr;
debug_info->rxbd_rdptr =
pmadapter->pcard_pcie->rxbd_rdptr;
debug_info->rxbd_wrptr =
pmadapter->pcard_pcie->rxbd_wrptr;
debug_info->eventbd_rdptr =
pmadapter->pcard_pcie->evtbd_rdptr;
debug_info->eventbd_wrptr =
pmadapter->pcard_pcie->evtbd_wrptr;
debug_info->txbd_ring_vbase =
pmadapter->pcard_pcie->txbd_ring_vbase;
debug_info->txbd_ring_size =
pmadapter->pcard_pcie->txbd_ring_size;
debug_info->rxbd_ring_vbase =
pmadapter->pcard_pcie->rxbd_ring_vbase;
debug_info->rxbd_ring_size =
pmadapter->pcard_pcie->rxbd_ring_size;
debug_info->evtbd_ring_vbase =
pmadapter->pcard_pcie->evtbd_ring_vbase;
debug_info->evtbd_ring_size =
pmadapter->pcard_pcie->evtbd_ring_size;
debug_info->txrx_bd_size =
pmadapter->pcard_pcie->txrx_bd_size;
}
#endif
debug_info->data_sent = pmadapter->data_sent;
debug_info->data_sent_cnt = pmadapter->data_sent_cnt;
debug_info->cmd_sent = pmadapter->cmd_sent;
debug_info->cmd_resp_received = pmadapter->cmd_resp_received;
debug_info->tx_pkts_queued =
util_scalar_read(pmadapter->pmoal_handle,
&pmpriv->wmm.tx_pkts_queued, MNULL,
MNULL);
#ifdef UAP_SUPPORT
debug_info->num_bridge_pkts =
util_scalar_read(pmadapter->pmoal_handle,
&pmadapter->pending_bridge_pkts,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
debug_info->num_drop_pkts = pmpriv->num_drop_pkts;
#endif
debug_info->fw_hang_report = pmadapter->fw_hang_report;
debug_info->mlan_processing = pmadapter->mlan_processing;
debug_info->mlan_rx_processing = pmadapter->mlan_rx_processing;
debug_info->rx_pkts_queued = pmadapter->rx_pkts_queued;
debug_info->mlan_adapter = pmadapter;
debug_info->mlan_adapter_size = sizeof(mlan_adapter);
debug_info->mlan_priv_num = pmadapter->priv_num;
for (i = 0; i < pmadapter->priv_num; i++) {
debug_info->mlan_priv[i] = pmadapter->priv[i];
debug_info->mlan_priv_size[i] = sizeof(mlan_private);
}
}
pioctl_req->data_read_written =
sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Set/Get the MAC control configuration.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING -- success, otherwise fail
*/
mlan_status wlan_misc_ioctl_mac_control(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_u16 cmd_action = 0;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
misc->param.mac_ctrl = pmpriv->curr_pkt_filter;
} else {
pmpriv->curr_pkt_filter = misc->param.mac_ctrl;
cmd_action = HostCmd_ACT_GEN_SET;
/* Send command to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
cmd_action, 0, (t_void *)pioctl_req,
&misc->param.mac_ctrl);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
}
LEAVE();
return ret;
}
/**
* @brief This timer function handles wakeup card timeout.
*
* @param function_context A pointer to function_context
* @return N/A
*/
t_void wlan_wakeup_card_timeout_func(void *function_context)
{
pmlan_adapter pmadapter = (pmlan_adapter)function_context;
mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
ENTER();
PRINTM(MERROR, "%s: ps_state=%d\n", __FUNCTION__, pmadapter->ps_state);
if (pmadapter->ps_state != PS_STATE_AWAKE) {
PRINTM_NETINTF(MERROR, pmpriv);
PRINTM(MERROR, "Wakeup card timeout!\n");
pmadapter->pm_wakeup_timeout++;
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
}
pmadapter->wakeup_fw_timer_is_set = MFALSE;
LEAVE();
}
/**
* @brief Set/Get HS configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_pm_cfg *pm = MNULL;
mlan_status status = MLAN_STATUS_SUCCESS;
t_u32 prev_cond = 0;
ENTER();
pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
switch (pioctl_req->action) {
case MLAN_ACT_SET:
#ifdef STA_SUPPORT
if (pmadapter->pps_uapsd_mode) {
PRINTM(MINFO,
"Host Sleep IOCTL is blocked in UAPSD/PPS mode\n");
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
status = MLAN_STATUS_FAILURE;
break;
}
#endif /* STA_SUPPORT */
if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) {
if (pm->param.hs_cfg.conditions ==
HOST_SLEEP_CFG_CANCEL) {
if (pmadapter->is_hs_configured == MFALSE) {
/* Already cancelled */
break;
}
/* Save previous condition */
prev_cond = pmadapter->hs_cfg.conditions;
pmadapter->hs_cfg.conditions =
pm->param.hs_cfg.conditions;
} else if (pmadapter->hs_cfg.conditions ==
HOST_SLEEP_CFG_CANCEL) {
/* Return failure if no parameters for HS enable
*/
pioctl_req->status_code =
MLAN_ERROR_INVALID_PARAMETER;
status = MLAN_STATUS_FAILURE;
break;
}
status = wlan_prepare_cmd(
pmpriv, HostCmd_CMD_802_11_HS_CFG_ENH,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
(t_void *)(&pmadapter->hs_cfg));
if (status == MLAN_STATUS_SUCCESS)
status = MLAN_STATUS_PENDING;
if (pm->param.hs_cfg.conditions ==
HOST_SLEEP_CFG_CANCEL) {
/* Restore previous condition */
pmadapter->hs_cfg.conditions = prev_cond;
}
} else {
pmadapter->hs_cfg.conditions =
pm->param.hs_cfg.conditions;
pmadapter->hs_cfg.gpio = (t_u8)pm->param.hs_cfg.gpio;
pmadapter->hs_cfg.gap = (t_u8)pm->param.hs_cfg.gap;
pmadapter->param_type_ind =
(t_u8)pm->param.hs_cfg.param_type_ind;
pmadapter->ind_gpio = (t_u8)pm->param.hs_cfg.ind_gpio;
pmadapter->level = (t_u8)pm->param.hs_cfg.level;
pmadapter->param_type_ext =
(t_u8)pm->param.hs_cfg.param_type_ext;
pmadapter->event_force_ignore =
pm->param.hs_cfg.event_force_ignore;
pmadapter->event_use_ext_gap =
pm->param.hs_cfg.event_use_ext_gap;
pmadapter->ext_gap = pm->param.hs_cfg.ext_gap;
pmadapter->gpio_wave = pm->param.hs_cfg.gpio_wave;
pmadapter->hs_wake_interval =
pm->param.hs_cfg.hs_wake_interval;
pmadapter->min_wake_holdoff =
pm->param.hs_cfg.min_wake_holdoff;
}
break;
case MLAN_ACT_GET:
pm->param.hs_cfg.conditions = pmadapter->hs_cfg.conditions;
pm->param.hs_cfg.gpio = pmadapter->hs_cfg.gpio;
pm->param.hs_cfg.gap = pmadapter->hs_cfg.gap;
pm->param.hs_cfg.param_type_ind = pmadapter->param_type_ind;
pm->param.hs_cfg.ind_gpio = pmadapter->ind_gpio;
pm->param.hs_cfg.level = pmadapter->level;
pm->param.hs_cfg.param_type_ext = pmadapter->param_type_ext;
pm->param.hs_cfg.event_force_ignore =
pmadapter->event_force_ignore;
pm->param.hs_cfg.event_use_ext_gap =
pmadapter->event_use_ext_gap;
pm->param.hs_cfg.ext_gap = pmadapter->ext_gap;
pm->param.hs_cfg.gpio_wave = pmadapter->gpio_wave;
pm->param.hs_cfg.hs_wake_interval = pmadapter->hs_wake_interval;
pm->param.hs_cfg.min_wake_holdoff = pmadapter->min_wake_holdoff;
break;
default:
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
status = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return status;
}
/**
* @brief Set Robustcoex gpiocfg
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
mlan_status wlan_misc_robustcoex(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;
mlan_ds_misc_cfg *robust_coex_cfg =
(mlan_ds_misc_cfg *)pioctl_req->pbuf;
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_802_11_ROBUSTCOEX,
cmd_action, 0, (t_void *)pioctl_req,
&robust_coex_cfg->param.robustcoexparams);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/get DMCS config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_dmcs_config(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;
mlan_ds_misc_cfg *dmcs_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
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_DMCS_CONFIG, cmd_action, 0,
(t_void *)pioctl_req,
&dmcs_cfg->param.dmcs_policy);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#if defined(PCIE)
/**
* @brief Enable SSU support
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
mlan_status wlan_misc_ssu(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 = HostCmd_ACT_GEN_GET;
mlan_ds_misc_cfg *ssu_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
ENTER();
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else if (pioctl_req->action == MLAN_ACT_DEFAULT)
cmd_action = HostCmd_ACT_GEN_SET_DEFAULT;
else if (pioctl_req->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SSU, cmd_action, 0,
(t_void *)pioctl_req,
&ssu_cfg->param.ssu_params);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#endif
/**
* @brief Set the hal/phy cfg params.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
mlan_status wlan_misc_hal_phy_cfg(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 *hal_phy_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
t_u16 cmd_act;
ENTER();
cmd_act = HostCmd_ACT_GEN_SET;
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_HAL_PHY_CFG, cmd_act, 0,
(t_void *)pioctl_req,
&hal_phy_cfg->param.hal_phy_cfg_params);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Enable/disable CSI support
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
mlan_status wlan_misc_csi(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 *csi_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
t_u16 cmd_act;
ENTER();
if (csi_cfg->param.csi_params.csi_enable == 1) {
if (pmadapter->csi_enabled) {
PRINTM(MERROR,
"Enable CSI: CSI was already enabled.\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
cmd_act = CSI_CMD_ENABLE;
} else {
if (!pmadapter->csi_enabled) {
PRINTM(MERROR,
"Disable CSI: CSI was already disabled.\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
cmd_act = CSI_CMD_DISABLE;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CSI, cmd_act, 0,
(t_void *)pioctl_req,
&csi_cfg->param.csi_params);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
done:
LEAVE();
return ret;
}
/**
* @brief This function allocates a mlan_buffer.
*
* @param pmadapter Pointer to mlan_adapter
* @param data_len Data length
* @param head_room head_room reserved in mlan_buffer
* @param malloc_flag flag to user moal_malloc
* @return mlan_buffer pointer or MNULL
*/
pmlan_buffer wlan_alloc_mlan_buffer(mlan_adapter *pmadapter, t_u32 data_len,
t_u32 head_room, t_u32 malloc_flag)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_buffer pmbuf = MNULL;
t_u32 buf_size = 0;
t_u8 *tmp_buf = MNULL;
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
#ifdef SDIO
/* make sure that the data length is at least SDIO block size */
if (IS_SD(pmadapter->card_type))
data_len = (data_len + MLAN_SDIO_BLOCK_SIZE - 1) /
MLAN_SDIO_BLOCK_SIZE * MLAN_SDIO_BLOCK_SIZE;
#endif
/* head_room is not implemented for malloc mlan buffer */
switch (malloc_flag) {
case MOAL_MALLOC_BUFFER:
buf_size = sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT;
ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
MLAN_MEM_DEF | MLAN_MEM_DMA,
(t_u8 **)&pmbuf);
if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
pmbuf = MNULL;
goto exit;
}
memset(pmadapter, pmbuf, 0, sizeof(mlan_buffer));
pmbuf->pdesc = MNULL;
/* Align address */
pmbuf->pbuf = (t_u8 *)ALIGN_ADDR(
(t_u8 *)pmbuf + sizeof(mlan_buffer), DMA_ALIGNMENT);
pmbuf->data_offset = 0;
pmbuf->data_len = data_len;
pmbuf->flags |= MLAN_BUF_FLAG_MALLOC_BUF;
break;
case MOAL_ALLOC_MLAN_BUFFER:
/* use moal_alloc_mlan_buffer, head_room supported */
ret = pcb->moal_alloc_mlan_buffer(
pmadapter->pmoal_handle,
data_len + DMA_ALIGNMENT + head_room, &pmbuf);
if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
goto exit;
}
pmbuf->data_offset = head_room;
tmp_buf = (t_u8 *)ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset,
DMA_ALIGNMENT);
pmbuf->data_offset +=
(t_u32)(tmp_buf - (pmbuf->pbuf + pmbuf->data_offset));
pmbuf->data_len = data_len;
pmbuf->flags = 0;
break;
}
exit:
LEAVE();
return pmbuf;
}
/**
* @brief This function frees a mlan_buffer.
*
* @param pmadapter Pointer to mlan_adapter
* @param pmbuf Pointer to mlan_buffer
*
* @return N/A
*/
t_void wlan_free_mlan_buffer(mlan_adapter *pmadapter, pmlan_buffer pmbuf)
{
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
if (pcb && pmbuf) {
if (pmbuf->flags & MLAN_BUF_FLAG_BRIDGE_BUF)
util_scalar_decrement(
pmadapter->pmoal_handle,
&pmadapter->pending_bridge_pkts,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
if (pmbuf->flags & MLAN_BUF_FLAG_MALLOC_BUF)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmbuf);
else
pcb->moal_free_mlan_buffer(pmadapter->pmoal_handle,
pmbuf);
}
LEAVE();
return;
}
/**
* @brief Delay function implementation
*
* @param pmadapter A pointer to mlan_adapter structure
* @param delay Delay value
* @param u Units of delay (sec, msec or usec)
*
* @return N/A
*/
t_void wlan_delay_func(mlan_adapter *pmadapter, t_u32 delay, t_delay_unit u)
{
t_u32 now_tv_sec, now_tv_usec;
t_u32 upto_tv_sec, upto_tv_usec;
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
if (pcb->moal_udelay) {
if (u == SEC)
delay *= 1000000;
else if (u == MSEC)
delay *= 1000;
pcb->moal_udelay(pmadapter->pmoal_handle, delay);
} else {
pcb->moal_get_system_time(pmadapter->pmoal_handle, &upto_tv_sec,
&upto_tv_usec);
switch (u) {
case SEC:
upto_tv_sec += delay;
break;
case MSEC:
delay *= 1000;
/* fall through */
case USEC:
upto_tv_sec += (delay / 1000000);
upto_tv_usec += (delay % 1000000);
break;
}
do {
pcb->moal_get_system_time(pmadapter->pmoal_handle,
&now_tv_sec, &now_tv_usec);
if (now_tv_sec > upto_tv_sec) {
LEAVE();
return;
}
if ((now_tv_sec == upto_tv_sec) &&
(now_tv_usec >= upto_tv_usec)) {
LEAVE();
return;
}
} while (MTRUE);
}
LEAVE();
return;
}
/**
* @brief BSS remove
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE
*/
mlan_status wlan_bss_ioctl_bss_remove(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
ENTER();
wlan_cancel_bss_pending_cmd(pmadapter, pioctl_req->bss_index);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
/**
* @brief Set/Get BSS role
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE
*/
mlan_status wlan_bss_ioctl_bss_role(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;
HostCmd_DS_VERSION_EXT dummy;
#ifdef USB
pmlan_callbacks pcb = &pmadapter->callbacks;
pmlan_buffer pmbuf;
#endif
#if defined(WIFI_DIRECT_SUPPORT)
t_u8 bss_mode;
#endif
t_u8 i, global_band = 0;
int j;
ENTER();
bss = (mlan_ds_bss *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
bss->param.bss_role = GET_BSS_ROLE(pmpriv);
} else {
if (GET_BSS_ROLE(pmpriv) == bss->param.bss_role) {
PRINTM(MIOCTL, "BSS ie already in the desired role!\n");
goto done;
}
mlan_block_rx_process(pmadapter, MTRUE);
/** Switch BSS role */
wlan_free_priv(pmpriv);
#ifdef USB
if (IS_USB(pmadapter->card_type)) {
while ((pmbuf = (pmlan_buffer)util_dequeue_list(
pmadapter->pmoal_handle,
&pmadapter->rx_data_queue,
pcb->moal_spin_lock,
pcb->moal_spin_unlock))) {
pcb->moal_recv_complete(pmadapter->pmoal_handle,
pmbuf,
pmadapter->rx_data_ep,
MLAN_STATUS_FAILURE);
}
}
#endif
pmpriv->bss_role = bss->param.bss_role;
if (pmpriv->bss_type == MLAN_BSS_TYPE_UAP)
pmpriv->bss_type = MLAN_BSS_TYPE_STA;
else if (pmpriv->bss_type == MLAN_BSS_TYPE_STA)
pmpriv->bss_type = MLAN_BSS_TYPE_UAP;
/* Initialize private structures */
wlan_init_priv(pmpriv);
mlan_block_rx_process(pmadapter, MFALSE);
/* Initialize function table */
for (j = 0; mlan_ops[j]; j++) {
if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmpriv)) {
memcpy_ext(pmadapter, &pmpriv->ops, mlan_ops[j],
sizeof(mlan_operations),
sizeof(mlan_operations));
}
}
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i] &&
GET_BSS_ROLE(pmadapter->priv[i]) ==
MLAN_BSS_ROLE_STA)
global_band |= pmadapter->priv[i]->config_bands;
}
if (global_band != pmadapter->config_bands) {
if (wlan_set_regiontable(
pmpriv, (t_u8)pmadapter->region_code,
global_band |
pmadapter->adhoc_start_band)) {
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (wlan_11d_set_universaltable(
pmpriv,
global_band |
pmadapter->adhoc_start_band)) {
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmadapter->config_bands = global_band;
}
/* Issue commands to initialize firmware */
#if defined(WIFI_DIRECT_SUPPORT)
if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
bss_mode = BSS_MODE_WIFIDIRECT_CLIENT;
else
bss_mode = BSS_MODE_WIFIDIRECT_GO;
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE,
HostCmd_ACT_GEN_SET, 0, MNULL,
&bss_mode);
if (ret)
goto done;
#endif
ret = pmpriv->ops.init_cmd(pmpriv, MFALSE);
if (ret == MLAN_STATUS_FAILURE)
goto done;
/* Issue dummy Get command to complete the ioctl */
memset(pmadapter, &dummy, 0, sizeof(HostCmd_DS_VERSION_EXT));
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT,
HostCmd_ACT_GEN_GET, 0,
(t_void *)pioctl_req, (t_void *)&dummy);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
}
done:
LEAVE();
return ret;
}
#endif
/**
* @brief Set the custom IE
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
* @param send_ioctl Flag to indicate if ioctl should be sent with cmd
* (MTRUE if from moal/user, MFALSE if internal)
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_custom_ie_list(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req,
t_bool send_ioctl)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
custom_ie *ie_data = MNULL;
t_u16 cmd_action = 0, index, mask, i, len, app_data_len;
t_s32 ioctl_len;
t_u8 *tmp_ie;
ENTER();
if ((misc->param.cust_ie.len == 0) ||
(misc->param.cust_ie.len == sizeof(t_u16))) {
pioctl_req->action = MLAN_ACT_GET;
/* Get the IE */
cmd_action = HostCmd_ACT_GEN_GET;
} else {
/* ioctl_len : ioctl length from application, start with
* misc->param.cust_ie.len and reach upto 0 */
ioctl_len = misc->param.cust_ie.len;
/* app_data_len : length from application, start with 0
* and reach upto ioctl_len */
app_data_len = sizeof(MrvlIEtypesHeader_t);
misc->param.cust_ie.len = 0;
while (ioctl_len > 0) {
ie_data = (custom_ie *)(((t_u8 *)&misc->param.cust_ie) +
app_data_len);
ioctl_len -=
(ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
app_data_len +=
(ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
index = ie_data->ie_index;
mask = ie_data->mgmt_subtype_mask;
/* Need to be Autohandled */
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) {
/* Automatic Deletion */
if (mask == MLAN_CUSTOM_IE_DELETE_MASK) {
ret = wlan_custom_ioctl_auto_delete(
pmpriv, pioctl_req, ie_data,
index);
/* if IE to delete is not found, return
* error */
if (ret == MLAN_STATUS_FAILURE)
goto done;
index = ie_data->ie_index;
memset(pmadapter, ie_data, 0,
sizeof(custom_ie) *
MAX_MGMT_IE_INDEX_TO_FW);
len = 0;
for (i = 0;
i < pmadapter->max_mgmt_ie_index;
i++) {
/* Check if index is updated
* before sending to FW */
if (index & ((t_u16)1) << i) {
memcpy_ext(
pmadapter,
(t_u8 *)ie_data +
len,
&i,
sizeof(ie_data->ie_index),
sizeof(ie_data->ie_index));
len += sizeof(
ie_data->ie_index);
memcpy_ext(
pmadapter,
(t_u8 *)ie_data +
len,
&pmpriv->mgmt_ie[i]
.mgmt_subtype_mask,
sizeof(ie_data->mgmt_subtype_mask),
sizeof(ie_data->mgmt_subtype_mask));
len += sizeof(
ie_data->mgmt_subtype_mask);
memcpy_ext(
pmadapter,
(t_u8 *)ie_data +
len,
&pmpriv->mgmt_ie[i]
.ie_length,
sizeof(ie_data->ie_length),
sizeof(ie_data->ie_length));
len += sizeof(
ie_data->ie_length);
if (pmpriv->mgmt_ie[i]
.ie_length) {
memcpy_ext(
pmadapter,
(t_u8 *)ie_data +
len,
&pmpriv->mgmt_ie[i]
.ie_buffer,
pmpriv->mgmt_ie[i]
.ie_length,
pmpriv->mgmt_ie[i]
.ie_length);
len += pmpriv->mgmt_ie[i]
.ie_length;
}
}
}
misc->param.cust_ie.len += len;
pioctl_req->action = MLAN_ACT_SET;
cmd_action = HostCmd_ACT_GEN_SET;
} else { /* Automatic Addition */
if (MLAN_STATUS_FAILURE ==
wlan_custom_ioctl_get_autoidx(
pmpriv, pioctl_req, mask,
ie_data, &index)) {
PRINTM(MERROR,
"Failed to Set the IE buffer\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
mask &= ~MLAN_CUSTOM_IE_NEW_MASK;
if (MLAN_CUSTOM_IE_AUTO_IDX_MASK ==
index ||
index >= MAX_MGMT_IE_INDEX) {
ret = MLAN_STATUS_SUCCESS;
goto done;
}
tmp_ie = (t_u8 *)&pmpriv->mgmt_ie[index]
.ie_buffer;
memcpy_ext(
pmadapter,
tmp_ie + pmpriv->mgmt_ie[index]
.ie_length,
&ie_data->ie_buffer,
ie_data->ie_length,
ie_data->ie_length);
pmpriv->mgmt_ie[index].ie_length +=
ie_data->ie_length;
pmpriv->mgmt_ie[index].ie_index = index;
pmpriv->mgmt_ie[index]
.mgmt_subtype_mask = mask;
pioctl_req->action = MLAN_ACT_SET;
cmd_action = HostCmd_ACT_GEN_SET;
ie_data->ie_index = index;
ie_data->ie_length =
pmpriv->mgmt_ie[index].ie_length;
memcpy_ext(
pmadapter, &ie_data->ie_buffer,
&pmpriv->mgmt_ie[index]
.ie_buffer,
pmpriv->mgmt_ie[index].ie_length,
MAX_IE_SIZE);
misc->param.cust_ie.len +=
pmpriv->mgmt_ie[index]
.ie_length +
MLAN_CUSTOM_IE_HDR_SIZE;
}
} else {
if (index >= pmadapter->max_mgmt_ie_index ||
index >= MAX_MGMT_IE_INDEX) {
PRINTM(MERROR,
"Invalid custom IE index %d\n",
index);
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Set/Clear the IE and save it */
if (ie_data->mgmt_subtype_mask ==
MLAN_CUSTOM_IE_DELETE_MASK &&
ie_data->ie_length) {
PRINTM(MINFO, "Clear the IE buffer\n");
ret = wlan_custom_ioctl_auto_delete(
pmpriv, pioctl_req, ie_data,
index);
/* if IE to delete is not found, return
* error */
if (ret == MLAN_STATUS_FAILURE)
goto done;
memset(pmadapter, ie_data, 0,
sizeof(custom_ie) *
MAX_MGMT_IE_INDEX_TO_FW);
memcpy_ext(
pmadapter, (t_u8 *)ie_data,
&pmpriv->mgmt_ie[index],
pmpriv->mgmt_ie[index].ie_length +
MLAN_CUSTOM_IE_HDR_SIZE,
pmpriv->mgmt_ie[index].ie_length +
MLAN_CUSTOM_IE_HDR_SIZE);
} else {
/*
* Check if this index is being used on
* any other interfaces. If yes, then
* the request needs to be rejected.
*/
ret = wlan_is_custom_ie_index_unused(
pmpriv, index);
if (ret == MLAN_STATUS_FAILURE) {
PRINTM(MERROR,
"IE index is used by other interface.\n");
PRINTM(MERROR,
"Set or delete on index %d is not allowed.\n",
index);
pioctl_req->status_code =
MLAN_ERROR_IOCTL_FAIL;
goto done;
}
PRINTM(MINFO, "Set the IE buffer\n");
if (ie_data->mgmt_subtype_mask ==
MLAN_CUSTOM_IE_DELETE_MASK)
ie_data->ie_length = 0;
else {
if ((pmpriv->mgmt_ie[index]
.mgmt_subtype_mask ==
ie_data->mgmt_subtype_mask) &&
(pmpriv->mgmt_ie[index]
.ie_length ==
ie_data->ie_length) &&
!memcmp(pmpriv->adapter,
pmpriv->mgmt_ie[index]
.ie_buffer,
ie_data->ie_buffer,
ie_data->ie_length)) {
PRINTM(MIOCTL,
"same custom ie already configured!\n");
if (ioctl_len <= 0 &&
misc->param.cust_ie
.len ==
0) {
goto done;
} else {
/* remove
* matching IE
* from app
* buffer */
app_data_len -=
ie_data->ie_length +
MLAN_CUSTOM_IE_HDR_SIZE;
memmove(pmadapter,
(t_u8 *)ie_data,
ie_data->ie_buffer +
ie_data->ie_length,
ioctl_len);
continue;
}
}
}
memset(pmadapter,
&pmpriv->mgmt_ie[index], 0,
sizeof(custom_ie));
memcpy_ext(pmadapter,
&pmpriv->mgmt_ie[index],
ie_data, sizeof(custom_ie),
sizeof(custom_ie));
}
misc->param.cust_ie.len +=
pmpriv->mgmt_ie[index].ie_length +
MLAN_CUSTOM_IE_HDR_SIZE;
pioctl_req->action = MLAN_ACT_SET;
cmd_action = HostCmd_ACT_GEN_SET;
}
}
}
/* Send command to firmware */
if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
ret = wlan_prepare_cmd(
pmpriv, HostCmd_CMD_MGMT_IE_LIST, cmd_action, 0,
(send_ioctl) ? (t_void *)pioctl_req : MNULL,
&misc->param.cust_ie);
}
#ifdef UAP_SUPPORT
else if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
ret = wlan_prepare_cmd(
pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action, 0,
(send_ioctl) ? (t_void *)pioctl_req : MNULL,
(send_ioctl) ? MNULL : &misc->param.cust_ie);
}
#endif
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
done:
LEAVE();
return ret;
}
/**
* @brief Read/write adapter register
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_reg_mem_ioctl_reg_rw(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_reg_mem *reg_mem = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0, cmd_no;
ENTER();
reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
else
cmd_action = HostCmd_ACT_GEN_SET;
switch (reg_mem->param.reg_rw.type) {
case MLAN_REG_MAC:
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(USB9097) || defined(SDNW62X) || \
defined(PCIENW62X) || defined(USBNW62X) || defined(SD9097)
case MLAN_REG_MAC2:
#endif
cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
break;
case MLAN_REG_BBP:
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(USB9097) || defined(SDNW62X) || \
defined(PCIENW62X) || defined(USBNW62X) || defined(SD9097)
case MLAN_REG_BBP2:
#endif
cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
break;
case MLAN_REG_RF:
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(USB9097) || defined(SDNW62X) || \
defined(PCIENW62X) || defined(USBNW62X) || defined(SD9097)
case MLAN_REG_RF2:
#endif
cmd_no = HostCmd_CMD_RF_REG_ACCESS;
break;
case MLAN_REG_CAU:
cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
break;
case MLAN_REG_PSU:
cmd_no = HostCmd_CMD_TARGET_ACCESS;
break;
case MLAN_REG_BCA:
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(USB9097) || defined(SDNW62X) || \
defined(PCIENW62X) || defined(USBNW62X) || defined(SD9097)
case MLAN_REG_BCA2:
#endif
cmd_no = HostCmd_CMD_BCA_REG_ACCESS;
break;
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(USB9097) || defined(SDNW62X) || \
defined(PCIENW62X) || defined(USBNW62X) || defined(SD9097) || \
defined(SD9177)
case MLAN_REG_CIU:
cmd_no = HostCmd_CMD_REG_ACCESS;
break;
#endif
default:
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, cmd_no, cmd_action, 0,
(t_void *)pioctl_req,
(t_void *)&reg_mem->param.reg_rw);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Read the EEPROM contents of the card
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_reg_mem_ioctl_read_eeprom(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_reg_mem *reg_mem = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_EEPROM_ACCESS,
cmd_action, 0, (t_void *)pioctl_req,
(t_void *)&reg_mem->param.rd_eeprom);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Read/write memory of device
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_reg_mem_ioctl_mem_rw(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_reg_mem *reg_mem = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
else
cmd_action = HostCmd_ACT_GEN_SET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
(t_void *)pioctl_req,
(t_void *)&reg_mem->param.mem_rw);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief This function will check if station list is empty
*
* @param priv A pointer to mlan_private
*
* @return MFALSE/MTRUE
*/
t_u8 wlan_is_station_list_empty(mlan_private *priv)
{
ENTER();
if (!(util_peek_list(priv->adapter->pmoal_handle, &priv->sta_list,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.moal_spin_unlock))) {
LEAVE();
return MTRUE;
}
LEAVE();
return MFALSE;
}
/**
* @brief This function will return the pointer to station entry in station
* list table which matches the give mac address
*
* @param priv A pointer to mlan_private
* @param mac mac address to find in station list table
*
* @return A pointer to structure sta_node
*/
sta_node *wlan_get_station_entry(mlan_private *priv, t_u8 *mac)
{
sta_node *sta_ptr;
ENTER();
if (!mac) {
LEAVE();
return MNULL;
}
sta_ptr = (sta_node *)util_peek_list(priv->adapter->pmoal_handle,
&priv->sta_list, MNULL, MNULL);
while (sta_ptr && (sta_ptr != (sta_node *)&priv->sta_list)) {
if (!memcmp(priv->adapter, sta_ptr->mac_addr, mac,
MLAN_MAC_ADDR_LENGTH)) {
LEAVE();
return sta_ptr;
}
sta_ptr = sta_ptr->pnext;
}
LEAVE();
return MNULL;
}
/**
* @brief This function will add a pointer to station entry in station list
* table with the give mac address, if it does not exist already
*
* @param priv A pointer to mlan_private
* @param mac mac address to find in station list table
*
* @return A pointer to structure sta_node
*/
sta_node *wlan_add_station_entry(mlan_private *priv, t_u8 *mac)
{
sta_node *sta_ptr = MNULL;
ENTER();
sta_ptr = wlan_get_station_entry(priv, mac);
if (sta_ptr)
goto done;
if (priv->adapter->callbacks.moal_malloc(priv->adapter->pmoal_handle,
sizeof(sta_node), MLAN_MEM_DEF,
(t_u8 **)&sta_ptr)) {
PRINTM(MERROR, "Failed to allocate memory for station node\n");
LEAVE();
return MNULL;
}
memset(priv->adapter, sta_ptr, 0, sizeof(sta_node));
memcpy_ext(priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->sta_list,
(pmlan_linked_list)sta_ptr,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.moal_spin_unlock);
#ifdef DRV_EMBEDDED_AUTHENTICATOR
if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
IsAuthenticatorEnabled(priv->psapriv))
authenticator_init_client(priv->psapriv,
&sta_ptr->cm_connectioninfo, mac);
#endif
done:
LEAVE();
return sta_ptr;
}
/**
* @brief This function will delete a station entry from station list
*
*
* @param priv A pointer to mlan_private
* @param mac station's mac address
*
* @return N/A
*/
t_void wlan_delete_station_entry(mlan_private *priv, t_u8 *mac)
{
sta_node *sta_ptr = MNULL;
ENTER();
sta_ptr = wlan_get_station_entry(priv, mac);
if (sta_ptr) {
#ifdef DRV_EMBEDDED_AUTHENTICATOR
if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
IsAuthenticatorEnabled(priv->psapriv))
authenticator_free_client(priv->psapriv,
sta_ptr->cm_connectioninfo);
#endif
util_unlink_list(priv->adapter->pmoal_handle, &priv->sta_list,
(pmlan_linked_list)sta_ptr,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.moal_spin_unlock);
priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
(t_u8 *)sta_ptr);
}
LEAVE();
return;
}
/**
* @brief Clean up wapi station list
*
* @param priv Pointer to the mlan_private driver data struct
*
* @return N/A
*/
t_void wlan_delete_station_list(pmlan_private priv)
{
sta_node *sta_ptr;
ENTER();
while ((sta_ptr = (sta_node *)util_dequeue_list(
priv->adapter->pmoal_handle, &priv->sta_list,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.moal_spin_unlock))) {
#ifdef DRV_EMBEDDED_AUTHENTICATOR
if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
IsAuthenticatorEnabled(priv->psapriv))
authenticator_free_client(priv->psapriv,
sta_ptr->cm_connectioninfo);
#endif
priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
(t_u8 *)sta_ptr);
}
LEAVE();
return;
}
/**
* @brief Get tdls peer list
*
* @param priv A pointer to mlan_private structure
* @param buf A pointer to tdls_peer_info buf
* @return number of tdls peer
*/
int wlan_get_tdls_list(mlan_private *priv, tdls_peer_info *buf)
{
tdls_peer_info *peer_info = buf;
sta_node *sta_ptr = MNULL;
int count = 0;
IEEEtypes_Header_t *ieee_hdr;
ENTER();
if (priv->bss_type != MLAN_BSS_TYPE_STA) {
LEAVE();
return count;
}
sta_ptr = (sta_node *)util_peek_list(
priv->adapter->pmoal_handle, &priv->sta_list,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.moal_spin_unlock);
if (!sta_ptr) {
LEAVE();
return count;
}
while (sta_ptr != (sta_node *)&priv->sta_list) {
if (sta_ptr->status == TDLS_SETUP_COMPLETE) {
peer_info->snr = sta_ptr->snr;
peer_info->nf = sta_ptr->nf;
memcpy_ext(priv->adapter, peer_info->mac_addr,
sta_ptr->mac_addr, MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
memcpy_ext(priv->adapter, peer_info->ht_cap,
&sta_ptr->HTcap, sizeof(IEEEtypes_HTCap_t),
sizeof(peer_info->ht_cap));
memcpy_ext(priv->adapter, peer_info->ext_cap,
&sta_ptr->ExtCap, sizeof(IEEEtypes_ExtCap_t),
sizeof(peer_info->ext_cap));
memcpy_ext(priv->adapter, peer_info->vht_cap,
&sta_ptr->vht_cap,
sizeof(IEEEtypes_VHTCap_t),
sizeof(peer_info->vht_cap));
ieee_hdr = (IEEEtypes_Header_t *)peer_info->he_cap;
memcpy_ext(priv->adapter, peer_info->he_cap,
&sta_ptr->he_cap,
sizeof(IEEEtypes_Header_t) + ieee_hdr->len,
sizeof(peer_info->he_cap));
peer_info++;
count++;
}
sta_ptr = sta_ptr->pnext;
if (count >= MLAN_MAX_TDLS_PEER_SUPPORTED)
break;
}
LEAVE();
return count;
}
/**
* @brief Set the TDLS configuration to FW.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_tdls_config(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 = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
tdls_all_config *tdls_all_cfg =
(tdls_all_config *)misc->param.tdls_config.tdls_data;
t_u8 event_buf[100];
mlan_event *pevent = (mlan_event *)event_buf;
tdls_tear_down_event *tdls_evt =
(tdls_tear_down_event *)pevent->event_buf;
sta_node *sta_ptr = MNULL;
MrvlIEtypes_Data_t *pMrvlTlv = MNULL;
t_u8 *pos = MNULL;
t_u16 remain_len = 0;
ENTER();
if (misc->param.tdls_config.tdls_action == WLAN_TDLS_TEAR_DOWN_REQ) {
sta_ptr = wlan_get_station_entry(
pmpriv, tdls_all_cfg->u.tdls_tear_down.peer_mac_addr);
if (sta_ptr && sta_ptr->external_tdls) {
pevent->bss_index = pmpriv->bss_index;
pevent->event_id = MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ;
pevent->event_len = sizeof(tdls_tear_down_event);
memcpy_ext(pmpriv->adapter,
(t_u8 *)tdls_evt->peer_mac_addr,
tdls_all_cfg->u.tdls_tear_down.peer_mac_addr,
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
tdls_evt->reason_code =
tdls_all_cfg->u.tdls_tear_down.reason_code;
wlan_recv_event(pmpriv,
MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ,
pevent);
LEAVE();
return ret;
}
}
if (misc->param.tdls_config.tdls_action == WLAN_HOST_TDLS_CONFIG) {
pmpriv->host_tdls_uapsd_support =
tdls_all_cfg->u.host_tdls_cfg.uapsd_support;
pmpriv->host_tdls_cs_support =
tdls_all_cfg->u.host_tdls_cfg.cs_support;
pos = tdls_all_cfg->u.host_tdls_cfg.tlv_buffer;
remain_len = tdls_all_cfg->u.host_tdls_cfg.tlv_len;
while (remain_len > sizeof(MrvlIEtypesHeader_t)) {
remain_len -= sizeof(MrvlIEtypesHeader_t);
pMrvlTlv = (MrvlIEtypes_Data_t *)pos;
switch (pMrvlTlv->header.type) {
case SUPPORTED_CHANNELS:
pmpriv->chan_supp_len = (t_u8)MIN(
pMrvlTlv->header.len, MAX_IE_SIZE);
memset(pmadapter, pmpriv->chan_supp, 0,
sizeof(pmpriv->chan_supp));
memcpy_ext(pmadapter, pmpriv->chan_supp,
pMrvlTlv->data, pMrvlTlv->header.len,
MAX_IE_SIZE);
DBG_HEXDUMP(MCMD_D, "TDLS supported channel",
pmpriv->chan_supp,
pmpriv->chan_supp_len);
break;
case REGULATORY_CLASS:
pmpriv->supp_regulatory_class_len = (t_u8)MIN(
pMrvlTlv->header.len, MAX_IE_SIZE);
memset(pmadapter, pmpriv->supp_regulatory_class,
0,
sizeof(pmpriv->supp_regulatory_class));
memcpy_ext(pmadapter,
pmpriv->supp_regulatory_class,
pMrvlTlv->data, pMrvlTlv->header.len,
MAX_IE_SIZE);
DBG_HEXDUMP(MCMD_D,
"TDLS supported regulatory class",
pmpriv->supp_regulatory_class,
pmpriv->supp_regulatory_class_len);
break;
default:
break;
}
remain_len -= pMrvlTlv->header.len;
pos += sizeof(MrvlIEtypesHeader_t) +
pMrvlTlv->header.len;
}
LEAVE();
return ret;
}
pioctl_req->action = MLAN_ACT_SET;
/* Send command to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
&misc->param.tdls_config);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief enable tdls config for cs and uapsd.
*
* @param pmpriv A pointer to mlan_private structure
* @param enable MTRUE/MFALSE
*
* @return
*/
t_void wlan_tdls_config(pmlan_private pmpriv, t_u8 enable)
{
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
mlan_ds_misc_tdls_config *tdls_config = MNULL;
tdls_all_config *tdls_all_cfg = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF,
(t_u8 **)&tdls_config);
if (ret != MLAN_STATUS_SUCCESS || !tdls_config) {
PRINTM(MERROR, "Memory allocation for tdls_config failed!\n");
LEAVE();
return;
}
memset(pmadapter, (t_u8 *)tdls_config, 0,
sizeof(mlan_ds_misc_tdls_config));
tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data;
tdls_all_cfg->u.tdls_config.enable = enable;
tdls_config->tdls_action = WLAN_TDLS_CONFIG;
/* Send command to firmware */
wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, HostCmd_ACT_GEN_SET,
0, MNULL, tdls_config);
PRINTM(MCMND, "tdls_config: enable=%d\n", enable);
if (tdls_config)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config);
LEAVE();
}
/**
* @brief set tdls channel switch parameters.
*
* @param pmpriv A pointer to mlan_private structure
*
* @return
*/
static t_void wlan_tdls_cs_param_config(pmlan_private pmpriv)
{
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
mlan_ds_misc_tdls_config *tdls_config = MNULL;
tdls_all_config *tdls_all_cfg = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF,
(t_u8 **)&tdls_config);
if (ret != MLAN_STATUS_SUCCESS || !tdls_config) {
PRINTM(MERROR, "Memory allocation for tdls_config failed!\n");
LEAVE();
return;
}
memset(pmadapter, (t_u8 *)tdls_config, 0,
sizeof(mlan_ds_misc_tdls_config));
tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data;
tdls_config->tdls_action = WLAN_TDLS_CS_PARAMS;
tdls_all_cfg->u.tdls_cs_params.unit_time = 2;
tdls_all_cfg->u.tdls_cs_params.threshold_otherlink = 10;
tdls_all_cfg->u.tdls_cs_params.threshold_directlink = 0;
/* Send command to firmware */
wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, HostCmd_ACT_GEN_SET,
0, MNULL, tdls_config);
if (tdls_config)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config);
LEAVE();
}
/**
* @brief start tdls channel switch
*
* @param pmpriv A pointer to mlan_private structure
* @param peer_mac_addr A pointer to peer mac address
* @param pioctl_buf A pointer to ioctl request buffer
*
* @return
*/
static t_void wlan_tdls_cs_start(pmlan_private pmpriv, t_u8 *peer_mac_addr,
pmlan_ioctl_req pioctl_buf)
{
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
mlan_ds_misc_tdls_config *tdls_config = MNULL;
tdls_all_config *tdls_all_cfg = MNULL;
mlan_ds_misc_cfg *misc = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF,
(t_u8 **)&tdls_config);
if (ret != MLAN_STATUS_SUCCESS || !tdls_config) {
PRINTM(MERROR, "Memory allocation for tdls_config failed!\n");
LEAVE();
return;
}
memset(pmadapter, (t_u8 *)tdls_config, 0,
sizeof(mlan_ds_misc_tdls_config));
if (pioctl_buf) {
misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
memcpy_ext(pmpriv->adapter, tdls_config,
&misc->param.tdls_config,
sizeof(mlan_ds_misc_tdls_config),
sizeof(mlan_ds_misc_tdls_config));
tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data;
if (tdls_all_cfg->u.tdls_chan_switch.primary_channel > 14) {
tdls_all_cfg->u.tdls_chan_switch
.secondary_channel_offset =
wlan_get_second_channel_offset(
pmpriv, tdls_all_cfg->u.tdls_chan_switch
.primary_channel);
}
PRINTM(MCMND, "Start TDLS CS: channel=%d\n",
tdls_all_cfg->u.tdls_chan_switch.primary_channel);
} else {
tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data;
tdls_config->tdls_action = WLAN_TDLS_INIT_CHAN_SWITCH;
memcpy_ext(pmpriv->adapter,
tdls_all_cfg->u.tdls_chan_switch.peer_mac_addr,
peer_mac_addr, MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
tdls_all_cfg->u.tdls_chan_switch.primary_channel =
pmpriv->tdls_cs_channel;
if (pmpriv->tdls_cs_channel > 14) {
tdls_all_cfg->u.tdls_chan_switch.band = BAND_5GHZ;
tdls_all_cfg->u.tdls_chan_switch
.secondary_channel_offset =
wlan_get_second_channel_offset(
pmpriv, pmpriv->tdls_cs_channel);
} else {
tdls_all_cfg->u.tdls_chan_switch.band = BAND_2GHZ;
}
PRINTM(MCMND, "Start TDLS CS: channel=%d\n",
pmpriv->tdls_cs_channel);
}
tdls_all_cfg->u.tdls_chan_switch.switch_time = 10;
tdls_all_cfg->u.tdls_chan_switch.switch_timeout = 16;
tdls_all_cfg->u.tdls_chan_switch.regulatory_class = 12;
tdls_all_cfg->u.tdls_chan_switch.periodicity = 1;
/* Send command to firmware */
wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, HostCmd_ACT_GEN_SET,
0, MNULL, tdls_config);
if (tdls_config)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config);
LEAVE();
}
#if 0
/**
* @brief stop tdls channel switch
*
* @param pmpriv A pointer to mlan_private structure
* @param peer_mac_addr A pointer to peer mac address
* @param pioctl_buf A pointer to command buffer
* @return
*/
static t_void wlan_tdls_cs_stop(pmlan_private pmpriv, t_u8 *peer_mac_addr)
{
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
mlan_ds_misc_tdls_config *tdls_config = MNULL;
tdls_all_config *tdls_all_cfg = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
sizeof(mlan_ds_misc_tdls_config), MLAN_MEM_DEF,
(t_u8 **)&tdls_config);
if (ret != MLAN_STATUS_SUCCESS || !tdls_config) {
PRINTM(MERROR, "Memory allocation for tdls_config failed!\n");
LEAVE();
return;
}
memset(pmadapter, (t_u8 *)tdls_config, 0,
sizeof(mlan_ds_misc_tdls_config));
tdls_all_cfg = (tdls_all_config *)tdls_config->tdls_data;
tdls_config->tdls_action = WLAN_TDLS_STOP_CHAN_SWITCH;
memcpy_ext(pmpriv->adapter,
tdls_all_cfg->u.tdls_stop_chan_switch.peer_mac_addr,
peer_mac_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
PRINTM(MCMND, "Stop TDLS CS\n");
/* Send command to firmware */
wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG, HostCmd_ACT_GEN_SET,
0, MNULL, tdls_config);
if (tdls_config)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tdls_config);
LEAVE();
}
#endif
/**
* @brief Set/Get the TDLS off channel.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_tdls_cs_channel(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 = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
ENTER();
if (MLAN_ACT_GET == pioctl_req->action)
misc->param.tdls_cs_channel = pmpriv->tdls_cs_channel;
else if (MLAN_ACT_SET == pioctl_req->action) {
pmpriv->tdls_cs_channel = misc->param.tdls_cs_channel;
}
LEAVE();
return ret;
}
/**
* @brief Set/Get the TDLS idle time.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_tdls_idle_time(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 = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
ENTER();
if (MLAN_ACT_GET == pioctl_req->action) {
misc->param.tdls_idle_time = pmpriv->tdls_idle_time;
} else if (MLAN_ACT_SET == pioctl_req->action) {
pmpriv->tdls_idle_time = misc->param.tdls_idle_time;
}
LEAVE();
return ret;
}
/**
* @brief Set the TDLS operation to FW.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_tdls_oper(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 = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mlan_ds_misc_tdls_oper *ptdls_oper = &misc->param.tdls_oper;
t_u8 event_buf[100];
mlan_event *ptdls_event = (mlan_event *)event_buf;
tdls_tear_down_event *tdls_evt =
(tdls_tear_down_event *)ptdls_event->event_buf;
sta_node *sta_ptr = MNULL;
t_u8 i = 0;
ENTER();
sta_ptr = wlan_get_station_entry(pmpriv, ptdls_oper->peer_mac);
switch (ptdls_oper->tdls_action) {
case WLAN_TDLS_ENABLE_LINK:
if (sta_ptr && (sta_ptr->status != TDLS_SETUP_FAILURE)) {
PRINTM(MMSG, "TDLS: Enable link " MACSTR " success\n",
MAC2STR(ptdls_oper->peer_mac));
sta_ptr->status = TDLS_SETUP_COMPLETE;
pmadapter->tdls_status = TDLS_IN_BASE_CHANNEL;
if (!pmpriv->txaggrctrl)
wlan_11n_send_delba_to_peer(
pmpriv,
pmpriv->curr_bss_params.bss_descriptor
.mac_address);
if (sta_ptr->HTcap.ieee_hdr.element_id ==
HT_CAPABILITY) {
sta_ptr->is_11n_enabled = MTRUE;
if (GETHT_MAXAMSDU(
sta_ptr->HTcap.ht_cap.ht_cap_info))
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_8K;
else
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_4K;
for (i = 0; i < MAX_NUM_TID; i++) {
if (sta_ptr->is_11n_enabled ||
sta_ptr->is_11ax_enabled)
sta_ptr->ampdu_sta[i] =
pmpriv->aggr_prio_tbl[i]
.ampdu_user;
else
sta_ptr->ampdu_sta[i] =
BA_STREAM_NOT_ALLOWED;
}
memset(pmpriv->adapter, sta_ptr->rx_seq, 0xff,
sizeof(sta_ptr->rx_seq));
}
wlan_restore_tdls_packets(pmpriv, ptdls_oper->peer_mac,
TDLS_SETUP_COMPLETE);
if (ISSUPP_EXTCAP_TDLS_CHAN_SWITCH(
sta_ptr->ExtCap.ext_cap)) {
wlan_tdls_config(pmpriv, MTRUE);
wlan_tdls_cs_param_config(pmpriv);
/**tdls cs start*/
if (pmpriv->tdls_cs_channel &&
pmpriv->tdls_cs_channel !=
pmpriv->curr_bss_params
.bss_descriptor.channel)
wlan_tdls_cs_start(pmpriv,
ptdls_oper->peer_mac,
MNULL);
}
} else {
PRINTM(MMSG, "TDLS: Enable link " MACSTR " fail\n",
MAC2STR(ptdls_oper->peer_mac));
/*for supplicant 2.0, we need send event to request
*teardown, *for latest supplicant, we only need return
*fail, and supplicant will send teardown packet and
*disable tdls link*/
if (sta_ptr) {
ptdls_event->bss_index = pmpriv->bss_index;
ptdls_event->event_id =
MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ;
ptdls_event->event_len =
sizeof(tdls_tear_down_event);
memcpy_ext(pmpriv->adapter,
(t_u8 *)tdls_evt->peer_mac_addr,
ptdls_oper->peer_mac,
MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
tdls_evt->reason_code =
MLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
wlan_recv_event(
pmpriv,
MLAN_EVENT_ID_DRV_TDLS_TEARDOWN_REQ,
ptdls_event);
wlan_restore_tdls_packets(pmpriv,
ptdls_oper->peer_mac,
TDLS_TEAR_DOWN);
if (sta_ptr->is_11n_enabled ||
sta_ptr->is_11ax_enabled) {
wlan_cleanup_reorder_tbl(
pmpriv, ptdls_oper->peer_mac);
wlan_11n_cleanup_txbastream_tbl(
pmpriv, ptdls_oper->peer_mac);
}
wlan_delete_station_entry(pmpriv,
ptdls_oper->peer_mac);
if (MTRUE == wlan_is_station_list_empty(pmpriv))
pmadapter->tdls_status = TDLS_NOT_SETUP;
else
pmadapter->tdls_status =
TDLS_IN_BASE_CHANNEL;
}
ret = MLAN_STATUS_FAILURE;
}
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
MNULL);
break;
case WLAN_TDLS_DISABLE_LINK:
/* Send command to firmware to delete tdls link*/
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_OPERATION,
HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, ptdls_oper);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
break;
case WLAN_TDLS_CREATE_LINK:
PRINTM(MIOCTL, "CREATE TDLS LINK\n");
if (sta_ptr && sta_ptr->status == TDLS_SETUP_INPROGRESS) {
PRINTM(MIOCTL, "We already create the link\n");
break;
}
if (!sta_ptr)
sta_ptr = wlan_add_station_entry(
pmpriv, misc->param.tdls_oper.peer_mac);
if (sta_ptr) {
sta_ptr->status = TDLS_SETUP_INPROGRESS;
sta_ptr->external_tdls = MTRUE;
wlan_hold_tdls_packets(pmpriv,
misc->param.tdls_oper.peer_mac);
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_OPERATION,
HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, ptdls_oper);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
break;
case WLAN_TDLS_CONFIG_LINK:
if (!sta_ptr || sta_ptr->status == TDLS_SETUP_FAILURE) {
PRINTM(MERROR, "Can not CONFIG TDLS Link\n");
ret = MLAN_STATUS_FAILURE;
break;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_OPERATION,
HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, ptdls_oper);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
break;
case WLAN_TDLS_INIT_CHAN_SWITCH:
if (sta_ptr &&
ISSUPP_EXTCAP_TDLS_CHAN_SWITCH(sta_ptr->ExtCap.ext_cap)) {
wlan_tdls_config(pmpriv, MTRUE);
wlan_tdls_cs_param_config(pmpriv);
/**tdls cs start*/
wlan_tdls_cs_start(pmpriv, ptdls_oper->peer_mac,
pioctl_req);
}
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
MNULL);
break;
default:
break;
}
LEAVE();
return ret;
}
/**
* @brief Get AP's ext capability
*
* @param pmpriv A pointer to mlan_adapter structure
* @param ext_cap A pointer to ExtCap_t structure
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static void wlan_get_ap_ext_cap(mlan_private *pmpriv, ExtCap_t *ext_cap)
{
pmlan_adapter pmadapter = pmpriv->adapter;
BSSDescriptor_t *pbss_desc;
pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
memset(pmadapter, ext_cap, 0, sizeof(ExtCap_t));
if (pbss_desc->pext_cap) {
memcpy_ext(pmadapter, (t_u8 *)ext_cap,
(t_u8 *)pbss_desc->pext_cap +
sizeof(IEEEtypes_Header_t),
pbss_desc->pext_cap->ieee_hdr.len, sizeof(ExtCap_t));
}
return;
}
/**
* @brief Set the TDLS operation to FW.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_tdls_get_ies(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_ds_misc_tdls_ies *tdls_ies = &misc->param.tdls_ies;
mlan_status ret = MLAN_STATUS_SUCCESS;
BSSDescriptor_t *pbss_desc;
t_u32 usr_dot_11n_dev_cap;
IEEEtypes_ExtCap_t *ext_cap = MNULL;
ExtCap_t ap_ext_cap;
IEEEtypes_HTCap_t *ht_cap = MNULL;
IEEEtypes_HTInfo_t *ht_info = MNULL;
IEEEtypes_VHTCap_t *vht_cap = MNULL;
IEEEtypes_VHTOprat_t *vht_oprat = MNULL;
IEEEtypes_AssocRsp_t *passoc_rsp = MNULL;
IEEEtypes_AID_t *aid_info = MNULL;
IEEEtypes_HECap_t *he_cap = MNULL;
IEEEtypes_HeOp_t *he_op = MNULL;
t_u8 supp_chan[] = {1, 11};
t_u8 regulatory_class[] = {1, /**current class*/
1, 2, 3, 4, 12, 22, 23, 24,
25, 27, 28, 29, 30, 32, 33}; /**list
regulatory
class*/
IEEEtypes_Generic_t *pSupp_chan = MNULL, *pRegulatory_class = MNULL;
sta_node *sta_ptr = MNULL;
ENTER();
/* We don't need peer information for TDLS setup */
if (!(tdls_ies->flags & TDLS_IE_FLAGS_SETUP))
sta_ptr = wlan_get_station_entry(pmpriv, tdls_ies->peer_mac);
pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
wlan_get_ap_ext_cap(pmpriv, &ap_ext_cap);
if (pbss_desc->bss_band & BAND_A)
usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_a;
else
usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_bg;
/** fill the extcap */
if (tdls_ies->flags & TDLS_IE_FLAGS_EXTCAP) {
ext_cap = (IEEEtypes_ExtCap_t *)tdls_ies->ext_cap;
ext_cap->ieee_hdr.element_id = EXT_CAPABILITY;
ext_cap->ieee_hdr.len = sizeof(ExtCap_t);
SET_EXTCAP_TDLS(ext_cap->ext_cap);
RESET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap);
RESET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap->ext_cap);
if (pmpriv->host_tdls_uapsd_support) {
/* uapsd in tdls confirm frame*/
if (tdls_ies->flags & TDLS_IE_FLAGS_HTINFO) {
if (sta_ptr && ISSUPP_EXTCAP_TDLS_UAPSD(
sta_ptr->ExtCap.ext_cap))
SET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap);
} else {
SET_EXTCAP_TDLS_UAPSD(ext_cap->ext_cap);
}
}
/* channel switch support */
if (pmpriv->host_tdls_cs_support &&
!IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ap_ext_cap)) {
/* channel switch in tdls confirm frame*/
if (tdls_ies->flags & TDLS_IE_FLAGS_HTINFO) {
if (sta_ptr && ISSUPP_EXTCAP_TDLS_CHAN_SWITCH(
sta_ptr->ExtCap.ext_cap))
SET_EXTCAP_TDLS_CHAN_SWITCH(
ext_cap->ext_cap);
} else {
SET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap->ext_cap);
}
}
RESET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap->ext_cap);
if ((pmadapter->fw_bands & BAND_AAC) &&
(MFALSE == wlan_is_ap_in_11ac_mode(pmpriv)))
SET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap->ext_cap);
/* if peer does not support wider bandwidth, don't set wider
* bandwidth*/
if (sta_ptr && sta_ptr->rate_len &&
!ISSUPP_EXTCAP_TDLS_WIDER_BANDWIDTH(
sta_ptr->ExtCap.ext_cap))
RESET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap->ext_cap);
DBG_HEXDUMP(MCMD_D, "TDLS extcap", tdls_ies->ext_cap,
sizeof(IEEEtypes_ExtCap_t));
}
/** default qos info is 0xf, compare with peer device qos info for tdls
* confirm */
if (tdls_ies->flags & TDLS_IE_FLAGS_QOS_INFO) {
if (sta_ptr && sta_ptr->rate_len)
tdls_ies->QosInfo = sta_ptr->qos_info & 0xf;
PRINTM(MCMND, "TDLS Qos info=0x%x\n", tdls_ies->QosInfo);
}
/** fill the htcap based on hwspec */
if (tdls_ies->flags & TDLS_IE_FLAGS_HTCAP) {
ht_cap = (IEEEtypes_HTCap_t *)tdls_ies->ht_cap;
memset(pmadapter, ht_cap, 0, sizeof(IEEEtypes_HTCap_t));
if ((sta_ptr && !ISSUPP_EXTCAP_TDLS_CHAN_SWITCH(
sta_ptr->ExtCap.ext_cap)) ||
IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ap_ext_cap))
wlan_fill_ht_cap_ie(pmpriv, ht_cap,
pbss_desc->bss_band);
else if (pmpriv->host_tdls_cs_support &&
(pmadapter->fw_bands & BAND_A))
wlan_fill_ht_cap_ie(pmpriv, ht_cap, BAND_A);
else
wlan_fill_ht_cap_ie(pmpriv, ht_cap,
pbss_desc->bss_band);
DBG_HEXDUMP(MCMD_D, "TDLS htcap", tdls_ies->ht_cap,
sizeof(IEEEtypes_HTCap_t));
}
/** if peer did not support 11AC, do not add vht related ie */
if (sta_ptr && sta_ptr->rate_len &&
(sta_ptr->vht_cap.ieee_hdr.element_id != VHT_CAPABILITY))
tdls_ies->flags &=
~(TDLS_IE_FLAGS_VHTCAP | TDLS_IE_FLAGS_VHTOPRAT |
TDLS_IE_FLAGS_AID);
/** fill the vhtcap based on hwspec */
if (tdls_ies->flags & TDLS_IE_FLAGS_VHTCAP) {
vht_cap = (IEEEtypes_VHTCap_t *)tdls_ies->vht_cap;
memset(pmadapter, vht_cap, 0, sizeof(IEEEtypes_VHTCap_t));
wlan_fill_vht_cap_ie(pmpriv, vht_cap, pbss_desc->bss_band);
if (ht_cap)
SETHT_SUPPCHANWIDTH(ht_cap->ht_cap.ht_cap_info);
DBG_HEXDUMP(MCMD_D, "TDLS VHT Cap IE", tdls_ies->vht_cap,
sizeof(IEEEtypes_VHTCap_t));
}
/** fill the vhtoperation based on hwspec */
if (tdls_ies->flags & TDLS_IE_FLAGS_VHTOPRAT) {
vht_oprat = (IEEEtypes_VHTOprat_t *)tdls_ies->vht_oprat;
memset(pmadapter, vht_oprat, 0, sizeof(IEEEtypes_VHTOprat_t));
if (sta_ptr &&
(sta_ptr->vht_cap.ieee_hdr.element_id == VHT_CAPABILITY) &&
(pbss_desc->bss_band & BAND_A)) {
wlan_fill_tdls_vht_oprat_ie(pmpriv, vht_oprat, sta_ptr);
}
if (sta_ptr)
memcpy_ext(pmadapter, &sta_ptr->vht_oprat,
tdls_ies->vht_oprat,
sizeof(IEEEtypes_VHTOprat_t),
sizeof(IEEEtypes_VHTOprat_t));
DBG_HEXDUMP(MCMD_D, "TDLS VHT Operation IE",
tdls_ies->vht_oprat, sizeof(IEEEtypes_VHTOprat_t));
}
/** fill the AID info */
if (tdls_ies->flags & TDLS_IE_FLAGS_AID) {
if (pmpriv->curr_bss_params.host_mlme)
passoc_rsp = (IEEEtypes_AssocRsp_t
*)(pmpriv->assoc_rsp_buf +
sizeof(IEEEtypes_MgmtHdr_t));
else
passoc_rsp =
(IEEEtypes_AssocRsp_t *)pmpriv->assoc_rsp_buf;
aid_info = (IEEEtypes_AID_t *)tdls_ies->aid_info;
memset(pmadapter, aid_info, 0, sizeof(IEEEtypes_AID_t));
aid_info->ieee_hdr.element_id = AID_INFO;
aid_info->ieee_hdr.len = sizeof(t_u16);
aid_info->AID = wlan_le16_to_cpu(passoc_rsp->a_id);
PRINTM(MCMND, "TDLS AID=0x%x\n", aid_info->AID);
}
/** fill the hecap based on hwspec */
if (tdls_ies->flags & TDLS_IE_FLAGS_HECAP) {
he_cap = (IEEEtypes_HECap_t *)tdls_ies->he_cap;
memset(pmadapter, he_cap, 0, sizeof(IEEEtypes_HECap_t));
wlan_fill_he_cap_ie(pmpriv, he_cap, pbss_desc->bss_band);
DBG_HEXDUMP(MCMD_D, "TDLS HE Cap IE", tdls_ies->he_cap,
sizeof(IEEEtypes_Header_t) + he_cap->ieee_hdr.len);
}
if (tdls_ies->flags & TDLS_IE_FLAGS_HEOP) {
he_op = (IEEEtypes_HeOp_t *)tdls_ies->he_op;
memset(pmadapter, he_op, 0, sizeof(IEEEtypes_HeOp_t));
wlan_fill_he_op_ie(pmpriv, he_op);
}
if (sta_ptr) {
memcpy_ext(pmadapter, &sta_ptr->he_op, tdls_ies->he_op,
sizeof(IEEEtypes_HeOp_t), sizeof(IEEEtypes_HeOp_t));
DBG_HEXDUMP(MCMD_D, "TDLS HE Operation IE", tdls_ies->he_op,
sizeof(IEEEtypes_HeOp_t));
}
/** fill the htinfo */
if (tdls_ies->flags & TDLS_IE_FLAGS_HTINFO) {
ht_info = (IEEEtypes_HTInfo_t *)tdls_ies->ht_info;
pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
ht_info->ieee_hdr.element_id = HT_OPERATION;
ht_info->ieee_hdr.len = sizeof(HTInfo_t);
ht_info->ht_info.pri_chan = pbss_desc->channel;
/* follow AP's channel bandwidth */
if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
pbss_desc->pht_info &&
ISALLOWED_CHANWIDTH40(
pbss_desc->pht_info->ht_info.field2)) {
ht_info->ht_info.field2 =
pbss_desc->pht_info->ht_info.field2;
} else {
ht_info->ht_info.field2 =
wlan_get_second_channel_offset(
pmpriv, pbss_desc->channel);
}
if (vht_oprat &&
vht_oprat->ieee_hdr.element_id == VHT_OPERATION) {
ht_info->ht_info.field2 =
wlan_get_second_channel_offset(
pmpriv, pbss_desc->channel);
ht_info->ht_info.field2 |= MBIT(2);
}
if (sta_ptr)
memcpy_ext(pmadapter, &sta_ptr->HTInfo,
tdls_ies->ht_info,
sizeof(IEEEtypes_HTInfo_t),
sizeof(IEEEtypes_HTInfo_t));
DBG_HEXDUMP(MCMD_D, "TDLS htinfo", tdls_ies->ht_info,
sizeof(IEEEtypes_HTInfo_t));
}
/** supported channels andl regulatory IE*/
if (pmpriv->host_tdls_cs_support &&
(tdls_ies->flags & TDLS_IE_FLAGS_SUPP_CS_IE) &&
!IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ap_ext_cap)) {
/** supported channels IE*/
pSupp_chan = (IEEEtypes_Generic_t *)tdls_ies->supp_chan;
pSupp_chan->ieee_hdr.element_id = SUPPORTED_CHANNELS;
if (pmpriv->chan_supp_len) {
pSupp_chan->ieee_hdr.len = pmpriv->chan_supp_len;
memcpy_ext(pmadapter, pSupp_chan->data,
pmpriv->chan_supp, pmpriv->chan_supp_len,
sizeof(pSupp_chan->data));
} else {
pSupp_chan->ieee_hdr.len = sizeof(supp_chan);
memcpy_ext(pmadapter, pSupp_chan->data, supp_chan,
sizeof(supp_chan), sizeof(pSupp_chan->data));
}
DBG_HEXDUMP(
MCMD_D, "TDLS supported channel", tdls_ies->supp_chan,
pSupp_chan->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
/**fill supported Regulatory Class IE*/
pRegulatory_class =
(IEEEtypes_Generic_t *)tdls_ies->regulatory_class;
pRegulatory_class->ieee_hdr.element_id = REGULATORY_CLASS;
if (pmpriv->supp_regulatory_class_len) {
pRegulatory_class->ieee_hdr.len =
pmpriv->supp_regulatory_class_len;
memcpy_ext(pmadapter, pRegulatory_class->data,
pmpriv->supp_regulatory_class,
pmpriv->supp_regulatory_class_len,
sizeof(pRegulatory_class->data));
} else {
pRegulatory_class->ieee_hdr.len =
sizeof(regulatory_class);
memcpy_ext(pmadapter, pRegulatory_class->data,
regulatory_class, sizeof(regulatory_class),
sizeof(pRegulatory_class->data));
}
DBG_HEXDUMP(MCMD_D, "TDLS supported regulatory class",
tdls_ies->regulatory_class,
pRegulatory_class->ieee_hdr.len +
sizeof(IEEEtypes_Header_t));
}
LEAVE();
return ret;
}
/**
* @brief Set mimo switch configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_radio_ioctl_mimo_switch_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_radio_cfg *radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_MIMO_SWITCH, 0, 0,
(t_void *)pioctl_req,
&(radio_cfg->param.mimo_switch_cfg));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get extended version information
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_get_info_ver_ext(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_get_info *pinfo = (mlan_ds_get_info *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
&pinfo->param.ver_ext.version_str_sel);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get link layer statistics
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_ioctl_link_statistic(mlan_private *pmpriv,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
/* Check 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;
}
switch (pioctl_req->action) {
case MLAN_ACT_GET:
cmd_action = HostCmd_ACT_GEN_GET;
break;
case MLAN_ACT_SET:
cmd_action = HostCmd_ACT_GEN_SET;
break;
case MLAN_ACT_CLEAR:
cmd_action = HostCmd_ACT_GEN_REMOVE;
break;
default:
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_LINK_STATS,
cmd_action, 0, (t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Get TX/RX histogram statistic
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_get_tx_rx_histogram(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_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;
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_TX_RX_PKT_STATS,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
&(pmisc->param.tx_rx_histogram));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#ifdef DEBUG_LEVEL1
/**
* @brief Set driver debug bit masks in order to enhance performance
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_set_drvdbg(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
{
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
/* Set driver debug bit masks */
mlan_drvdbg = misc->param.drvdbg;
LEAVE();
return ret;
}
#endif
/**
* @brief Rx mgmt frame forward register
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_reg_rx_mgmt_ind(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
/* Set passthru mask for mgmt frame */
pmpriv->mgmt_frame_passthru_mask = misc->param.mgmt_subtype_mask;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_MGMT_IND,
pioctl_req->action, 0, (t_void *)pioctl_req,
&misc->param.mgmt_subtype_mask);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief This function processes the 802.11 mgmt Frame
*
* @param priv A pointer to mlan_private
*
* @param payload A pointer to the received buffer
* @param payload_len Length of the received buffer
* @param prx_pd A pointer to RxPD
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private *priv, t_u8 *payload,
t_u32 payload_len, RxPD *prx_pd)
{
pmlan_adapter pmadapter = priv->adapter;
pmlan_callbacks pcb = &pmadapter->callbacks;
mlan_status ret = MLAN_STATUS_SUCCESS;
wlan_802_11_header *pieee_pkt_hdr = MNULL;
t_u16 sub_type = 0;
t_u8 *event_buf = MNULL;
mlan_event *pevent = MNULL;
t_u8 unicast = 0;
t_u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
IEEE80211_MGMT *mgmt = MNULL;
t_u8 category = 0;
t_u8 action_code = 0;
#ifdef UAP_SUPPORT
sta_node *sta_ptr = MNULL;
MrvlIETypes_MgmtFrameSet_t *tlv;
pmlan_buffer pmbuf;
#endif
ENTER();
if (payload_len > (MAX_EVENT_SIZE - sizeof(mlan_event))) {
PRINTM(MERROR, "Dropping large mgmt frame,len =%d\n",
payload_len);
LEAVE();
return ret;
}
/* Check packet type-subtype and compare with mgmt_passthru_mask
* If event is needed to host, just eventify it */
pieee_pkt_hdr = (wlan_802_11_header *)payload;
sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(pieee_pkt_hdr->frm_ctl);
if (((1 << sub_type) & priv->mgmt_frame_passthru_mask) == 0) {
PRINTM(MINFO, "Dropping mgmt frame for subtype %d snr=%d.\n",
sub_type, prx_pd->snr);
LEAVE();
return ret;
}
switch (sub_type) {
case SUBTYPE_ASSOC_REQUEST:
case SUBTYPE_REASSOC_REQUEST:
#ifdef UAP_SUPPORT
if (priv->uap_host_based & UAP_FLAG_HOST_MLME) {
PRINTM_NETINTF(MMSG, priv);
if (!memcmp(pmadapter, pieee_pkt_hdr->addr3,
priv->curr_addr, MLAN_MAC_ADDR_LENGTH)) {
PRINTM(MMSG,
"wlan: HostMlme MICRO_AP_STA_ASSOC " MACSTR
"\n",
MAC2STR(pieee_pkt_hdr->addr2));
mgmt = (IEEE80211_MGMT *)payload;
sta_ptr = wlan_add_station_entry(
priv, pieee_pkt_hdr->addr2);
if (sta_ptr) {
sta_ptr->capability = wlan_le16_to_cpu(
mgmt->u.assoc_req.capab_info);
pmbuf = wlan_alloc_mlan_buffer(
pmadapter, payload_len, 0,
MOAL_MALLOC_BUFFER);
if (pmbuf) {
PRINTM(MCMND,
"check sta capability\n");
pmbuf->data_len =
ASSOC_EVENT_FIX_SIZE;
tlv = (MrvlIETypes_MgmtFrameSet_t
*)(pmbuf->pbuf +
pmbuf->data_offset +
pmbuf->data_len);
tlv->type = wlan_cpu_to_le16(
TLV_TYPE_MGMT_FRAME);
tlv->len = sizeof(
IEEEtypes_FrameCtl_t);
memcpy_ext(
pmadapter,
(t_u8 *)&tlv
->frame_control,
&pieee_pkt_hdr->frm_ctl,
sizeof(IEEEtypes_FrameCtl_t),
sizeof(IEEEtypes_FrameCtl_t));
pmbuf->data_len += sizeof(
MrvlIETypes_MgmtFrameSet_t);
memcpy_ext(
pmadapter,
pmbuf->pbuf +
pmbuf->data_offset +
pmbuf->data_len,
payload +
sizeof(wlan_802_11_header),
payload_len -
sizeof(wlan_802_11_header),
payload_len -
sizeof(wlan_802_11_header));
pmbuf->data_len +=
payload_len -
sizeof(wlan_802_11_header);
tlv->len +=
payload_len -
sizeof(wlan_802_11_header);
tlv->len = wlan_cpu_to_le16(
tlv->len);
DBG_HEXDUMP(
MCMD_D, "assoc_req",
pmbuf->pbuf +
pmbuf->data_offset,
pmbuf->data_len);
wlan_check_sta_capability(
priv, pmbuf, sta_ptr);
wlan_free_mlan_buffer(pmadapter,
pmbuf);
}
}
} else {
PRINTM(MMSG,
"wlan: Drop MICRO_AP_STA_ASSOC " MACSTR
" from unknown BSSID " MACSTR "\n",
MAC2STR(pieee_pkt_hdr->addr2),
MAC2STR(pieee_pkt_hdr->addr3));
}
}
unicast = MTRUE;
break;
#endif
case SUBTYPE_AUTH:
unicast = MTRUE;
PRINTM_NETINTF(MMSG, priv);
PRINTM(MMSG, "wlan: HostMlme Auth received from " MACSTR "\n",
MAC2STR(pieee_pkt_hdr->addr2));
break;
case SUBTYPE_PROBE_RESP:
unicast = MTRUE;
break;
case SUBTYPE_DISASSOC:
case SUBTYPE_DEAUTH:
if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast,
MLAN_MAC_ADDR_LENGTH))
unicast = MTRUE;
#ifdef UAP_SUPPORT
if (priv->uap_host_based & UAP_FLAG_HOST_MLME) {
if (!memcmp(pmadapter, pieee_pkt_hdr->addr3,
priv->curr_addr, MLAN_MAC_ADDR_LENGTH)) {
PRINTM_NETINTF(MMSG, priv);
PRINTM(MMSG,
"wlan: HostMlme Deauth Receive from " MACSTR
"\n",
MAC2STR(pieee_pkt_hdr->addr2));
}
}
#endif
if (priv->bss_role == MLAN_BSS_ROLE_STA) {
if (priv->curr_bss_params.host_mlme) {
if (memcmp(pmadapter, pieee_pkt_hdr->addr3,
(t_u8 *)priv->curr_bss_params
.bss_descriptor.mac_address,
MLAN_MAC_ADDR_LENGTH)) {
PRINTM(MCMND,
"Dropping Deauth frame from other bssid: type=%d " MACSTR
"\n",
sub_type,
MAC2STR(pieee_pkt_hdr->addr3));
LEAVE();
return ret;
}
PRINTM_NETINTF(MMSG, priv);
PRINTM(MMSG,
"wlan: HostMlme Disconnected: sub_type=%d\n",
sub_type);
pmadapter->pending_disconnect_priv = priv;
wlan_recv_event(
priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
MNULL);
}
}
break;
case SUBTYPE_ACTION:
category = *(payload + sizeof(wlan_802_11_header));
action_code = *(payload + sizeof(wlan_802_11_header) + 1);
if (category == IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK) {
PRINTM(MINFO,
"Drop BLOCK ACK action frame: action_code=%d\n",
action_code);
LEAVE();
return ret;
}
if ((category == IEEE_MGMT_ACTION_CATEGORY_PUBLIC) &&
(action_code == BSS_20_40_COEX)) {
PRINTM(MINFO,
"Drop 20/40 BSS Coexistence Management frame\n");
LEAVE();
return ret;
}
if ((category == CATEGORY_PUBLIC) &&
(action_code == TDLS_DISCOVERY_RESPONSE)) {
pcb->moal_updata_peer_signal(pmadapter->pmoal_handle,
priv->bss_index,
pieee_pkt_hdr->addr2,
prx_pd->snr, prx_pd->nf);
PRINTM(MINFO,
"Rx: TDLS discovery response, nf=%d, snr=%d\n",
prx_pd->nf, prx_pd->snr);
}
if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast,
MLAN_MAC_ADDR_LENGTH))
unicast = MTRUE;
break;
default:
break;
}
if (unicast == MTRUE) {
if (memcmp(pmadapter, pieee_pkt_hdr->addr1, priv->curr_addr,
MLAN_MAC_ADDR_LENGTH)) {
PRINTM(MINFO,
"Dropping mgmt frame for others: type=%d " MACSTR
"\n",
sub_type, MAC2STR(pieee_pkt_hdr->addr1));
LEAVE();
return ret;
}
}
/* Allocate memory for event buffer */
ret = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE,
MLAN_MEM_DEF, &event_buf);
if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
PRINTM(MERROR, "Could not allocate buffer for event buf\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
pevent = (pmlan_event)event_buf;
pevent->bss_index = priv->bss_index;
mgmt = (IEEE80211_MGMT *)payload;
if (!priv->curr_bss_params.host_mlme && sub_type == SUBTYPE_ACTION &&
mgmt->u.ft_resp.category == FT_CATEGORY &&
mgmt->u.ft_resp.action == FT_ACTION_RESPONSE &&
mgmt->u.ft_resp.status_code == 0) {
PRINTM(MCMND, "FT Action response received\n");
#define FT_ACTION_HEAD_LEN (24 + 6 + 16)
pevent->event_id = MLAN_EVENT_ID_DRV_FT_RESPONSE;
pevent->event_len =
payload_len + MLAN_MAC_ADDR_LENGTH - FT_ACTION_HEAD_LEN;
memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
&mgmt->u.ft_resp.target_ap_addr,
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
memcpy_ext(pmadapter,
(t_u8 *)(pevent->event_buf + MLAN_MAC_ADDR_LENGTH),
payload + FT_ACTION_HEAD_LEN,
payload_len - FT_ACTION_HEAD_LEN,
pevent->event_len - MLAN_MAC_ADDR_LENGTH);
} else if (!priv->curr_bss_params.host_mlme &&
sub_type == SUBTYPE_AUTH &&
mgmt->u.auth.auth_alg == MLAN_AUTH_MODE_FT &&
mgmt->u.auth.auth_transaction == 2 &&
mgmt->u.auth.status_code == 0) {
PRINTM(MCMND, "FT auth response received \n");
#define AUTH_PACKET_LEN (24 + 6 + 6)
pevent->event_id = MLAN_EVENT_ID_DRV_FT_RESPONSE;
pevent->event_len =
payload_len + MLAN_MAC_ADDR_LENGTH - AUTH_PACKET_LEN;
memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf, mgmt->sa,
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
memcpy_ext(pmadapter,
(t_u8 *)(pevent->event_buf + MLAN_MAC_ADDR_LENGTH),
payload + AUTH_PACKET_LEN,
payload_len - AUTH_PACKET_LEN,
pevent->event_len - MLAN_MAC_ADDR_LENGTH);
} else {
pevent->event_id = MLAN_EVENT_ID_DRV_MGMT_FRAME;
pevent->event_len = payload_len + sizeof(pevent->event_id);
memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
(t_u8 *)&pevent->event_id, sizeof(pevent->event_id),
pevent->event_len);
memcpy_ext(
pmadapter,
(t_u8 *)(pevent->event_buf + sizeof(pevent->event_id)),
payload, payload_len, payload_len);
}
wlan_recv_event(priv, pevent->event_id, pevent);
if (event_buf)
pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#ifdef STA_SUPPORT
/**
* @brief Extended capabilities configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ext_capa_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (MLAN_ACT_GET == pioctl_req->action)
memcpy_ext(pmpriv->adapter, &misc->param.ext_cap,
&pmpriv->def_ext_cap, sizeof(misc->param.ext_cap),
sizeof(misc->param.ext_cap));
else if (MLAN_ACT_SET == pioctl_req->action) {
memcpy_ext(pmpriv->adapter, &pmpriv->ext_cap,
&misc->param.ext_cap, sizeof(misc->param.ext_cap),
sizeof(pmpriv->ext_cap));
/* Save default Extended Capability */
memcpy_ext(pmpriv->adapter, &pmpriv->def_ext_cap,
&pmpriv->ext_cap, sizeof(pmpriv->ext_cap),
sizeof(pmpriv->def_ext_cap));
if (pmpriv->config_bands & BAND_AAC)
SET_EXTCAP_OPERMODENTF(pmpriv->ext_cap);
}
LEAVE();
return ret;
}
/**
* @brief Check whether Extended Capabilities IE support
*
* @param pmpriv A pointer to mlan_private structure
*
* @return MTRUE or MFALSE;
*/
t_u32 wlan_is_ext_capa_support(mlan_private *pmpriv)
{
ENTER();
if (ISSUPP_EXTCAP_TDLS(pmpriv->ext_cap) ||
ISSUPP_EXTCAP_INTERWORKING(pmpriv->ext_cap) ||
ISSUPP_EXTCAP_BSS_TRANSITION(pmpriv->ext_cap) ||
ISSUPP_EXTCAP_QOS_MAP(pmpriv->ext_cap) ||
ISSUPP_EXTCAP_OPERMODENTF(pmpriv->ext_cap)) {
LEAVE();
return MTRUE;
} else {
LEAVE();
return MFALSE;
}
}
#endif
/**
* @brief Set hotspot enable/disable
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_hotspot_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (MLAN_ACT_GET == pioctl_req->action)
misc->param.hotspot_cfg = pmpriv->hotspot_cfg;
else if (MLAN_ACT_SET == pioctl_req->action)
pmpriv->hotspot_cfg = misc->param.hotspot_cfg;
LEAVE();
return ret;
}
#ifdef STA_SUPPORT
/**
* @brief Add Extended Capabilities IE
*
* @param pmpriv A pointer to mlan_private structure
* @param pbss_desc A pointer to BSSDescriptor_t structure
* @param pptlv_out A pointer to TLV to fill in
*
* @return N/A
*/
void wlan_add_ext_capa_info_ie(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
t_u8 **pptlv_out)
{
MrvlIETypes_ExtCap_t *pext_cap = MNULL;
ENTER();
pext_cap = (MrvlIETypes_ExtCap_t *)*pptlv_out;
memset(pmpriv->adapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
pext_cap->header.len = wlan_cpu_to_le16(sizeof(ExtCap_t));
if (pmpriv->adapter->ecsa_enable)
SET_EXTCAP_EXT_CHANNEL_SWITCH(pmpriv->ext_cap);
else
RESET_EXTCAP_EXT_CHANNEL_SWITCH(pmpriv->ext_cap);
if (pbss_desc && pbss_desc->multi_bssid_ap)
SET_EXTCAP_MULTI_BSSID(pmpriv->ext_cap);
if (wlan_check_11ax_twt_supported(pmpriv, pbss_desc))
SET_EXTCAP_TWT_REQ(pmpriv->ext_cap);
memcpy_ext(pmpriv->adapter, &pext_cap->ext_cap, &pmpriv->ext_cap,
sizeof(pmpriv->ext_cap), sizeof(pext_cap->ext_cap));
*pptlv_out += sizeof(MrvlIETypes_ExtCap_t);
LEAVE();
}
#endif
/**
* @brief Get OTP user data
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_otp_user_data(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mlan_status ret = MLAN_STATUS_FAILURE;
ENTER();
if (misc->param.otp_user_data.user_data_length >
MAX_OTP_USER_DATA_LEN) {
PRINTM(MERROR, "Invalid OTP user data length\n");
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return ret;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_OTP_READ_USER_DATA,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
&misc->param.otp_user_data);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief This function will search for the specific ie
*
* @param priv A pointer to mlan_private
* @param pevent A pointer to event buf
* @param sta_ptr A pointer to sta_node
*
* @return N/A
*/
void wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent,
sta_node *sta_ptr)
{
t_u16 tlv_type, tlv_len;
t_u16 frame_control, frame_sub_type = 0;
t_u8 *assoc_req_ie = MNULL;
t_u8 ie_len = 0, assoc_ie_len = 0;
IEEEtypes_HTCap_t *pht_cap = MNULL;
IEEEtypes_VHTCap_t *pvht_cap = MNULL;
IEEEtypes_Extension_t *phe_cap = MNULL;
#ifdef UAP_SUPPORT
t_u8 *ext_rate = MNULL, *erp = MNULL;
#endif
int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
MrvlIEtypesHeader_t *tlv =
(MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset +
ASSOC_EVENT_FIX_SIZE);
MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
ENTER();
while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
tlv_type = wlan_le16_to_cpu(tlv->type);
tlv_len = wlan_le16_to_cpu(tlv->len);
if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
(unsigned int)tlv_buf_left) {
PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
tlv_len, tlv_buf_left);
break;
}
if (tlv_type == TLV_TYPE_MGMT_FRAME) {
mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *)tlv;
memcpy_ext(priv->adapter, &frame_control,
(t_u8 *)&(mgmt_tlv->frame_control),
sizeof(frame_control),
sizeof(frame_control));
frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(
frame_control);
if ((mgmt_tlv->frame_control.type == 0) &&
((frame_sub_type == SUBTYPE_BEACON)
#ifdef UAP_SUPPORT
|| (frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
(frame_sub_type == SUBTYPE_REASSOC_REQUEST)
#endif
)) {
if (frame_sub_type == SUBTYPE_BEACON)
assoc_ie_len =
sizeof(IEEEtypes_Beacon_t);
#ifdef UAP_SUPPORT
else if (frame_sub_type ==
SUBTYPE_ASSOC_REQUEST)
assoc_ie_len =
sizeof(IEEEtypes_AssocRqst_t);
else if (frame_sub_type ==
SUBTYPE_REASSOC_REQUEST)
assoc_ie_len =
sizeof(IEEEtypes_ReAssocRqst_t);
#endif
ie_len = tlv_len -
sizeof(IEEEtypes_FrameCtl_t) -
assoc_ie_len;
assoc_req_ie =
(t_u8 *)tlv +
sizeof(MrvlIETypes_MgmtFrameSet_t) +
assoc_ie_len;
sta_ptr->is_wmm_enabled =
wlan_is_wmm_ie_present(priv->adapter,
assoc_req_ie,
ie_len);
PRINTM(MCMND, "STA: is_wmm_enabled=%d\n",
sta_ptr->is_wmm_enabled);
pht_cap = (IEEEtypes_HTCap_t *)
wlan_get_specific_ie(priv, assoc_req_ie,
ie_len,
HT_CAPABILITY, 0);
if (pht_cap) {
PRINTM(MCMND, "STA supports 11n\n");
sta_ptr->is_11n_enabled = MTRUE;
memcpy_ext(priv->adapter,
(t_u8 *)&sta_ptr->HTcap,
pht_cap,
sizeof(IEEEtypes_HTCap_t),
sizeof(IEEEtypes_HTCap_t));
if (GETHT_MAXAMSDU(wlan_le16_to_cpu(
pht_cap->ht_cap
.ht_cap_info)))
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_8K;
else
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_4K;
} else {
PRINTM(MCMND,
"STA doesn't support 11n\n");
}
pvht_cap = (IEEEtypes_VHTCap_t *)
wlan_get_specific_ie(priv, assoc_req_ie,
ie_len,
VHT_CAPABILITY, 0);
if (pvht_cap &&
(priv->is_11ac_enabled == MTRUE)) {
PRINTM(MCMND, "STA supports 11ac\n");
sta_ptr->is_11ac_enabled = MTRUE;
if (GET_VHTCAP_MAXMPDULEN(wlan_le32_to_cpu(
pvht_cap->vht_cap
.vht_cap_info)) ==
2)
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_12K;
else if (GET_VHTCAP_MAXMPDULEN(wlan_le32_to_cpu(
pvht_cap->vht_cap
.vht_cap_info)) ==
1)
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_8K;
else
sta_ptr->max_amsdu =
MLAN_TX_DATA_BUF_SIZE_4K;
} else {
PRINTM(MCMND,
"STA doesn't support 11ac\n");
}
phe_cap = (IEEEtypes_Extension_t *)
wlan_get_specific_ie(priv, assoc_req_ie,
ie_len, EXTENSION,
HE_CAPABILITY);
if (phe_cap &&
(priv->is_11ax_enabled == MTRUE)) {
PRINTM(MCMND, "STA supports 11ax\n");
sta_ptr->is_11ax_enabled = MTRUE;
memcpy_ext(
priv->adapter,
(t_u8 *)&sta_ptr->he_cap,
phe_cap,
phe_cap->ieee_hdr.len +
sizeof(IEEEtypes_Header_t),
sizeof(IEEEtypes_HECap_t));
sta_ptr->he_cap.ieee_hdr.len = MIN(
phe_cap->ieee_hdr.len,
sizeof(IEEEtypes_HECap_t) -
sizeof(IEEEtypes_Header_t));
} else {
PRINTM(MCMND,
"STA doesn't support 11ax\n");
}
#ifdef UAP_SUPPORT
/* Note: iphone6 does not have ERP_INFO */
ext_rate = wlan_get_specific_ie(
priv, assoc_req_ie, ie_len,
EXTENDED_SUPPORTED_RATES, 0);
erp = wlan_get_specific_ie(priv, assoc_req_ie,
ie_len, ERP_INFO, 0);
if (!ext_rate)
PRINTM(MCMND,
"STA doesn't support EXTENDED_SUPPORTED_RATES\n");
if (!erp)
PRINTM(MCMND,
"STA doesn't support ERP_INFO\n");
if (sta_ptr->is_11ax_enabled) {
if (priv->uap_channel <= 14)
sta_ptr->bandmode = BAND_GAX;
else
sta_ptr->bandmode = BAND_AAX;
} else if (sta_ptr->is_11ac_enabled) {
if (priv->uap_channel <= 14)
sta_ptr->bandmode = BAND_GAC;
else
sta_ptr->bandmode = BAND_AAC;
} else if (sta_ptr->is_11n_enabled) {
if (priv->uap_channel <= 14)
sta_ptr->bandmode = BAND_GN;
else
sta_ptr->bandmode = BAND_AN;
} else if (ext_rate || erp) {
if (priv->uap_channel <= 14)
sta_ptr->bandmode = BAND_G;
else
sta_ptr->bandmode = BAND_A;
} else
sta_ptr->bandmode = BAND_B;
#endif
#ifdef DRV_EMBEDDED_AUTHENTICATOR
if (IsAuthenticatorEnabled(priv->psapriv))
authenticator_get_sta_security_info(
priv->psapriv,
sta_ptr->cm_connectioninfo,
assoc_req_ie, ie_len);
#endif
break;
}
}
tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
sizeof(MrvlIEtypesHeader_t));
}
LEAVE();
return;
}
/**
* @brief check if WMM ie present.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pbuf A pointer to IE buffer
* @param buf_len IE buffer len
*
* @return MTRUE/MFALSE
*/
t_u8 wlan_is_wmm_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, t_u16 buf_len)
{
t_u16 bytes_left = buf_len;
IEEEtypes_ElementId_e element_id;
t_u8 *pcurrent_ptr = pbuf;
t_u8 element_len;
t_u16 total_ie_len;
IEEEtypes_VendorSpecific_t *pvendor_ie;
const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
t_u8 find_wmm_ie = MFALSE;
ENTER();
/* Process variable IE */
while (bytes_left >= 2) {
element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
element_len = *((t_u8 *)pcurrent_ptr + 1);
total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
if (bytes_left < total_ie_len) {
PRINTM(MERROR, "InterpretIE: Error in processing IE, "
"bytes left < IE length\n");
bytes_left = 0;
continue;
}
switch (element_id) {
case VENDOR_SPECIFIC_221:
pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
wmm_oui, sizeof(wmm_oui))) {
find_wmm_ie = MTRUE;
PRINTM(MINFO, "find WMM IE\n");
}
break;
default:
break;
}
pcurrent_ptr += element_len + 2;
/* Need to account for IE ID and IE Len */
bytes_left -= (element_len + 2);
if (find_wmm_ie)
break;
}
LEAVE();
return find_wmm_ie;
}
/**
* @brief This function will search for the specific ie
*
*
* @param priv A pointer to mlan_private
* @param ie_buf A pointer to ie_buf
* @param ie_len total ie length
* @param id ie's id
* @param ext_id ie's extension id
*
* @return ie's poiner or MNULL
*/
t_u8 *wlan_get_specific_ie(pmlan_private priv, t_u8 *ie_buf, t_u8 ie_len,
IEEEtypes_ElementId_e id, t_u8 ext_id)
{
t_u32 bytes_left = ie_len;
t_u8 *pcurrent_ptr = ie_buf;
t_u16 total_ie_len;
t_u8 *ie_ptr = MNULL;
IEEEtypes_ElementId_e element_id;
t_u8 element_len;
t_u8 element_eid;
ENTER();
DBG_HEXDUMP(MDAT_D, "ie", ie_buf, ie_len);
while (bytes_left >= 2) {
element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
element_len = *((t_u8 *)pcurrent_ptr + 1);
element_eid = *((t_u8 *)pcurrent_ptr + 2);
total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
if (bytes_left < total_ie_len) {
PRINTM(MERROR, "InterpretIE: Error in processing IE, "
"bytes left < IE length\n");
break;
}
if ((!ext_id && element_id == id) ||
(id == EXTENSION && element_id == id &&
ext_id == element_eid)) {
PRINTM(MCMND, "Find IE: id=%d ext_id=%d\n", id, ext_id);
DBG_HEXDUMP(MCMD_D, "IE", pcurrent_ptr, total_ie_len);
ie_ptr = pcurrent_ptr;
break;
}
pcurrent_ptr += element_len + 2;
/* Need to account for IE ID and IE Len */
bytes_left -= (element_len + 2);
}
LEAVE();
return ie_ptr;
}
/**
* @brief Get pm info
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success
*/
mlan_status wlan_get_pm_info(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_pm_cfg *pm_cfg = MNULL;
ENTER();
pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
pm_cfg->param.ps_info.is_suspend_allowed = MTRUE;
wlan_request_cmd_lock(pmadapter);
if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
MNULL, MNULL) ||
pmadapter->curr_cmd || !wlan_bypass_tx_list_empty(pmadapter) ||
!wlan_wmm_lists_empty(pmadapter)
#if defined(SDIO) || defined(PCIE)
|| wlan_pending_interrupt(pmadapter)
#endif
) {
pm_cfg->param.ps_info.is_suspend_allowed = MFALSE;
#if defined(SDIO) || defined(PCIE)
PRINTM(MIOCTL,
"PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d irq_pending=%d\n",
util_peek_list(pmadapter->pmoal_handle,
&pmadapter->cmd_pending_q, MNULL, MNULL),
pmadapter->curr_cmd, wlan_wmm_lists_empty(pmadapter),
wlan_bypass_tx_list_empty(pmadapter),
wlan_pending_interrupt(pmadapter));
#else
PRINTM(MIOCTL,
"PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d\n",
util_peek_list(pmadapter->pmoal_handle,
&pmadapter->cmd_pending_q, MNULL, MNULL),
pmadapter->curr_cmd, wlan_wmm_lists_empty(pmadapter),
wlan_bypass_tx_list_empty(pmadapter));
#endif
}
wlan_release_cmd_lock(pmadapter);
LEAVE();
return ret;
}
/**
* @brief Get hs wakeup reason
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success
*/
mlan_status wlan_get_hs_wakeup_reason(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
pmlan_ds_pm_cfg pm_cfg = MNULL;
mlan_status ret = MLAN_STATUS_FAILURE;
ENTER();
pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
/* Send command to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_HS_WAKEUP_REASON,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
&pm_cfg->param.wakeup_reason);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get radio status
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_radio_ioctl_radio_ctl(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_radio_cfg *radio_cfg = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
if (pmadapter->radio_on == radio_cfg->param.radio_on_off) {
ret = MLAN_STATUS_SUCCESS;
goto exit;
} else {
if (pmpriv->media_connected == MTRUE) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
cmd_action = HostCmd_ACT_GEN_SET;
}
} else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RADIO_CONTROL,
cmd_action, 0, (t_void *)pioctl_req,
&radio_cfg->param.radio_on_off);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set/Get antenna configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_radio_ioctl_ant_cfg(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_radio_cfg *radio_cfg = MNULL;
t_u16 cmd_action = 0;
mlan_ds_ant_cfg *ant_cfg = MNULL;
mlan_ds_ant_cfg_1x1 *ant_cfg_1x1 = MNULL;
ENTER();
radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
if (IS_STREAM_2X2(pmadapter->feature_control))
ant_cfg = &radio_cfg->param.ant_cfg;
if (pioctl_req->action == MLAN_ACT_SET) {
/* User input validation */
if (IS_STREAM_2X2(pmadapter->feature_control)) {
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
if (IS_CARD9098(pmadapter->card_type) ||
IS_CARD9097(pmadapter->card_type) ||
IS_CARDNW62X(pmadapter->card_type)) {
ant_cfg->tx_antenna &= 0x0303;
ant_cfg->rx_antenna &= 0x0303;
/** 2G antcfg TX */
if (ant_cfg->tx_antenna & 0x00FF) {
pmadapter->user_htstream &= ~0xF0;
pmadapter->user_htstream |=
(bitcount(ant_cfg->tx_antenna &
0x00FF)
<< 4);
}
/* 5G antcfg tx */
if (ant_cfg->tx_antenna & 0xFF00) {
pmadapter->user_htstream &= ~0xF000;
pmadapter->user_htstream |=
(bitcount(ant_cfg->tx_antenna &
0xFF00)
<< 12);
}
/* 2G antcfg RX */
if (ant_cfg->rx_antenna & 0x00FF) {
pmadapter->user_htstream &= ~0xF;
pmadapter->user_htstream |= bitcount(
ant_cfg->rx_antenna & 0x00FF);
}
/* 5G antcfg RX */
if (ant_cfg->rx_antenna & 0xFF00) {
pmadapter->user_htstream &= ~0xF00;
pmadapter->user_htstream |=
(bitcount(ant_cfg->rx_antenna &
0xFF00)
<< 8);
}
PRINTM(MCMND,
"user_htstream=0x%x, tx_antenna=0x%x >rx_antenna=0x%x\n",
pmadapter->user_htstream,
ant_cfg->tx_antenna,
ant_cfg->rx_antenna);
} else {
#endif
ant_cfg->tx_antenna &= 0x0003;
ant_cfg->rx_antenna &= 0x0003;
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
}
#endif
if (!ant_cfg->tx_antenna ||
bitcount(ant_cfg->tx_antenna & 0x00FF) >
pmadapter->number_of_antenna ||
bitcount(ant_cfg->tx_antenna & 0xFF00) >
pmadapter->number_of_antenna) {
PRINTM(MERROR,
"Invalid TX antenna setting: 0x%x\n",
ant_cfg->tx_antenna);
pioctl_req->status_code =
MLAN_ERROR_INVALID_PARAMETER;
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (ant_cfg->rx_antenna) {
if (bitcount(ant_cfg->rx_antenna & 0x00FF) >
pmadapter->number_of_antenna ||
bitcount(ant_cfg->rx_antenna & 0xFF00) >
pmadapter->number_of_antenna) {
PRINTM(MERROR,
"Invalid RX antenna setting: 0x%x\n",
ant_cfg->rx_antenna);
pioctl_req->status_code =
MLAN_ERROR_INVALID_PARAMETER;
ret = MLAN_STATUS_FAILURE;
goto exit;
}
} else
ant_cfg->rx_antenna = ant_cfg->tx_antenna;
} else if (!radio_cfg->param.ant_cfg_1x1.antenna ||
((radio_cfg->param.ant_cfg_1x1.antenna !=
RF_ANTENNA_AUTO) &&
(radio_cfg->param.ant_cfg_1x1.antenna & 0xFFFC))) {
PRINTM(MERROR, "Invalid antenna setting\n");
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
ret = MLAN_STATUS_FAILURE;
goto exit;
}
cmd_action = HostCmd_ACT_GEN_SET;
} else
cmd_action = HostCmd_ACT_GEN_GET;
/* Cast it to t_u16, antenna mode for command
* HostCmd_CMD_802_11_RF_ANTENNA requires 2 bytes */
if (!IS_STREAM_2X2(pmadapter->feature_control))
ant_cfg_1x1 = &radio_cfg->param.ant_cfg_1x1;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA,
cmd_action, 0, (t_void *)pioctl_req,
(IS_STREAM_2X2(pmadapter->feature_control)) ?
(t_void *)ant_cfg :
(t_void *)ant_cfg_1x1);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Get rate bitmap
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status wlan_rate_ioctl_get_rate_bitmap(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set rate bitmap
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status wlan_rate_ioctl_set_rate_bitmap(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_ds_rate *ds_rate = MNULL;
mlan_status ret = MLAN_STATUS_FAILURE;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
t_u16 *bitmap_rates = MNULL;
ENTER();
ds_rate = (mlan_ds_rate *)pioctl_req->pbuf;
bitmap_rates = ds_rate->param.rate_cfg.bitmap_rates;
PRINTM(MINFO,
"RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x"
"%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
"IsRateAuto=%d, DataRate=%d\n",
bitmap_rates[17], bitmap_rates[16], bitmap_rates[15],
bitmap_rates[14], bitmap_rates[13], bitmap_rates[12],
bitmap_rates[11], bitmap_rates[10], bitmap_rates[9],
bitmap_rates[8], bitmap_rates[7], bitmap_rates[6],
bitmap_rates[5], bitmap_rates[4], bitmap_rates[3],
bitmap_rates[2], bitmap_rates[1], bitmap_rates[0],
pmpriv->is_data_rate_auto, pmpriv->data_rate);
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
(t_void *)bitmap_rates);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get rate value
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
static mlan_status wlan_rate_ioctl_get_rate_value(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_ds_rate *rate = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
rate = (mlan_ds_rate *)pioctl_req->pbuf;
rate->param.rate_cfg.is_rate_auto = pmpriv->is_data_rate_auto;
pioctl_req->data_read_written =
sizeof(mlan_rate_cfg_t) + MLAN_SUB_COMMAND_SIZE;
/* If not connected, set rate to the lowest in each band */
if (pmpriv->media_connected != MTRUE) {
if (pmpriv->config_bands & (BAND_B | BAND_G)) {
/* Return the lowest supported rate for BG band */
rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
} else if (pmpriv->config_bands & (BAND_A | BAND_B)) {
/* Return the lowest supported rate for A band */
rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
} else if (pmpriv->config_bands & BAND_A) {
/* Return the lowest supported rate for A band */
rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
} else if (pmpriv->config_bands & BAND_G) {
/* Return the lowest supported rate for G band */
rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
} else if (pmpriv->config_bands & BAND_B) {
/* Return the lowest supported rate for B band */
rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
} else if (pmpriv->config_bands & BAND_GN) {
/* Return the lowest supported rate for N band */
rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
} else {
PRINTM(MMSG, "Invalid Band 0x%x\n",
pmpriv->config_bands);
}
} else {
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY,
HostCmd_ACT_GEN_GET, 0,
(t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
}
LEAVE();
return ret;
}
/**
* @brief Set rate value
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status wlan_rate_ioctl_set_rate_value(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_ds_rate *ds_rate = MNULL;
WLAN_802_11_RATES rates;
t_u8 *rate = MNULL;
int rate_index = 0;
t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
t_u32 i = 0;
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
ds_rate = (mlan_ds_rate *)pioctl_req->pbuf;
if (ds_rate->param.rate_cfg.is_rate_auto) {
memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
/* Support all HR/DSSS rates */
bitmap_rates[0] = 0x000F;
/* Support all OFDM rates */
bitmap_rates[1] = 0x00FF;
/* Rates talbe [0] HR/DSSS,[1] OFDM,[2..9] HT,[10..17] VHT */
/* Support all HT-MCSs rate */
for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3 - 8; i++)
bitmap_rates[i + 2] = 0xFFFF;
bitmap_rates[9] = 0x3FFF;
/* Support all VHT-MCSs rate */
for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 10; i++)
bitmap_rates[i + 10] = 0x03FF; /* 10 Bits valid */
} else {
memset(pmadapter, rates, 0, sizeof(rates));
wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
(pmpriv->bss_mode ==
MLAN_BSS_MODE_INFRA) ?
pmpriv->config_bands :
pmadapter->adhoc_start_band,
rates);
rate = rates;
for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) {
PRINTM(MINFO, "Rate=0x%X Wanted=0x%X\n", rate[i],
ds_rate->param.rate_cfg.rate);
if ((rate[i] & 0x7f) ==
(ds_rate->param.rate_cfg.rate & 0x7f))
break;
}
if ((i < WLAN_SUPPORTED_RATES && !rate[i]) ||
(i == WLAN_SUPPORTED_RATES)) {
PRINTM(MERROR,
"The fixed data rate 0x%X is out "
"of range\n",
ds_rate->param.rate_cfg.rate);
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
ret = MLAN_STATUS_FAILURE;
goto exit;
}
memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
rate_index = wlan_data_rate_to_index(
pmadapter, ds_rate->param.rate_cfg.rate);
/* Only allow b/g rates to be set */
if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
rate_index <= MLAN_RATE_INDEX_HRDSSS3)
bitmap_rates[0] = 1 << rate_index;
else {
rate_index -= 1; /* There is a 0x00 in the table */
if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
rate_index <= MLAN_RATE_INDEX_OFDM7)
bitmap_rates[1] = 1 << (rate_index -
MLAN_RATE_INDEX_OFDM0);
}
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
bitmap_rates);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Get rate index
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status wlan_rate_ioctl_get_rate_index(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set rate index
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
static mlan_status wlan_rate_ioctl_set_rate_index(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
t_u32 rate_index;
t_u32 rate_format;
t_u32 nss;
t_u32 i;
mlan_ds_rate *ds_rate = MNULL;
mlan_status ret = MLAN_STATUS_FAILURE;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
int tx_mcs_supp = GET_TXMCSSUPP(pmpriv->usr_dev_mcs_support);
ENTER();
ds_rate = (mlan_ds_rate *)pioctl_req->pbuf;
rate_format = ds_rate->param.rate_cfg.rate_format;
nss = ds_rate->param.rate_cfg.nss;
rate_index = ds_rate->param.rate_cfg.rate;
if (ds_rate->param.rate_cfg.is_rate_auto) {
memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
/* Rates talbe [0]: HR/DSSS;[1]: OFDM; [2..9] HT; */
/* Support all HR/DSSS rates */
bitmap_rates[0] = 0x000F;
/* Support all OFDM rates */
bitmap_rates[1] = 0x00FF;
/* Support all HT-MCSs rate */
for (i = 2; i < 9; i++)
bitmap_rates[i] = 0xFFFF;
bitmap_rates[9] = 0x3FFF;
/* [10..17] VHT */
/* Support all VHT-MCSs rate for NSS 1 and 2 */
for (i = 10; i < 12; i++)
bitmap_rates[i] = 0x03FF; /* 10 Bits valid */
/* Set to 0 as default value for all other NSSs */
for (i = 12; i < 17; i++)
bitmap_rates[i] = 0x0;
/* [18..25] HE */
/* Support all HE-MCSs rate for NSS1 and 2 */
for (i = 18; i < 20; i++)
bitmap_rates[i] = 0x0FFF;
for (i = 20; i < NELEMENTS(bitmap_rates); i++)
bitmap_rates[i] = 0x0;
} else {
PRINTM(MINFO, "Rate index is %d\n", rate_index);
if ((rate_format == MLAN_RATE_FORMAT_HT) &&
(rate_index > MLAN_RATE_INDEX_MCS7 &&
rate_index <= MLAN_RATE_INDEX_MCS15) &&
(tx_mcs_supp < 2)) {
PRINTM(MERROR,
"HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n",
rate_index, pmpriv->usr_dev_mcs_support);
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
if (rate_format == MLAN_RATE_FORMAT_LG) {
/* Bitmap of HR/DSSS rates */
if (rate_index <= MLAN_RATE_INDEX_HRDSSS3) {
bitmap_rates[0] = 1 << rate_index;
ret = MLAN_STATUS_SUCCESS;
/* Bitmap of OFDM rates */
} else if ((rate_index >= MLAN_RATE_INDEX_OFDM0) &&
(rate_index <= MLAN_RATE_INDEX_OFDM7)) {
bitmap_rates[1] = 1 << (rate_index -
MLAN_RATE_INDEX_OFDM0);
ret = MLAN_STATUS_SUCCESS;
}
} else if (rate_format == MLAN_RATE_FORMAT_HT) {
if (rate_index <= MLAN_RATE_INDEX_MCS32) {
bitmap_rates[2 + (rate_index / 16)] =
1 << (rate_index % 16);
ret = MLAN_STATUS_SUCCESS;
}
}
if (rate_format == MLAN_RATE_FORMAT_VHT) {
if ((rate_index <= MLAN_RATE_INDEX_MCS9) &&
(MLAN_RATE_NSS1 <= nss) &&
(nss <= MLAN_RATE_NSS2)) {
bitmap_rates[10 + nss - MLAN_RATE_NSS1] =
(1 << rate_index);
ret = MLAN_STATUS_SUCCESS;
}
}
if (rate_format == MLAN_RATE_FORMAT_HE) {
if (IS_FW_SUPPORT_11AX(pmadapter)) {
if ((rate_index <= MLAN_RATE_INDEX_MCS11) &&
(MLAN_RATE_NSS1 <= nss) &&
(nss <= MLAN_RATE_NSS2)) {
bitmap_rates[18 + nss - MLAN_RATE_NSS1] =
(1 << rate_index);
ret = MLAN_STATUS_SUCCESS;
}
} else {
PRINTM(MERROR,
"Error! Fw doesn't support 11AX\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
}
if (ret == MLAN_STATUS_FAILURE) {
PRINTM(MERROR, "Invalid MCS index=%d. \n", rate_index);
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
}
PRINTM(MINFO,
"RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x"
"%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
"IsRateAuto=%d, DataRate=%d\n",
bitmap_rates[17], bitmap_rates[16], bitmap_rates[15],
bitmap_rates[14], bitmap_rates[13], bitmap_rates[12],
bitmap_rates[11], bitmap_rates[10], bitmap_rates[9],
bitmap_rates[8], bitmap_rates[7], bitmap_rates[6],
bitmap_rates[5], bitmap_rates[4], bitmap_rates[3],
bitmap_rates[2], bitmap_rates[1], bitmap_rates[0],
pmpriv->is_data_rate_auto, pmpriv->data_rate);
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
(t_void *)bitmap_rates);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Rate configuration command handler
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
* otherwise fail
*/
mlan_status wlan_rate_ioctl_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_ds_rate *rate = MNULL;
mlan_status status = MLAN_STATUS_SUCCESS;
ENTER();
rate = (mlan_ds_rate *)pioctl_req->pbuf;
if (rate->param.rate_cfg.rate_type == MLAN_RATE_BITMAP) {
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_rate_ioctl_get_rate_bitmap(pmadapter,
pioctl_req);
else
status = wlan_rate_ioctl_set_rate_bitmap(pmadapter,
pioctl_req);
} else if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) {
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_rate_ioctl_get_rate_value(pmadapter,
pioctl_req);
else
status = wlan_rate_ioctl_set_rate_value(pmadapter,
pioctl_req);
} else {
if (pioctl_req->action == MLAN_ACT_GET)
status = wlan_rate_ioctl_get_rate_index(pmadapter,
pioctl_req);
else
status = wlan_rate_ioctl_set_rate_index(pmadapter,
pioctl_req);
}
LEAVE();
return status;
}
/**
* @brief Get data rates
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_rate_ioctl_get_data_rate(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (pioctl_req->action != MLAN_ACT_GET) {
ret = MLAN_STATUS_FAILURE;
goto exit;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY,
HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
exit:
LEAVE();
return ret;
}
/**
* @brief Set/Get remain on channel setting
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_radio_ioctl_remain_chan_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_radio_cfg *radio_cfg = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_REMAIN_ON_CHANNEL,
cmd_action, 0, (t_void *)pioctl_req,
&radio_cfg->param.remain_chan);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#ifdef WIFI_DIRECT_SUPPORT
/**
* @brief Set/Get wifi_direct_mode
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_bss_ioctl_wifi_direct_mode(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_bss *bss = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
bss = (mlan_ds_bss *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_WIFI_DIRECT_MODE_CONFIG,
cmd_action, 0, (t_void *)pioctl_req,
&bss->param.wfd_mode);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get p2p config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_misc_p2p_config(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
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_P2P_PARAMS_CONFIG, cmd_action,
0, (t_void *)pioctl_req,
&misc_cfg->param.p2p_config);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#endif
/**
* @brief Set/Get GPIO TSF Latch config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_misc_gpio_tsf_latch_config(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
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_GPIO_TSF_LATCH_PARAM_CONFIG,
cmd_action, 0, (t_void *)pioctl_req,
&misc_cfg->param.gpio_tsf_latch_config);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get TSF info
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_misc_get_tsf_info(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;
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_GPIO_TSF_LATCH_PARAM_CONFIG,
cmd_action, 0, (t_void *)pioctl_req,
&misc_cfg->param.tsf_info);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set coalesce config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_coalesce_cfg(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
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_COALESCE_CFG, cmd_action, 0,
(t_void *)pioctl_req,
&misc_cfg->param.coalesce_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get/Set USB packet aggregation 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
*/
mlan_status wlan_misc_ioctl_aggr_ctrl(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_PACKET_AGGR_CTRL, cmd_action,
0, (t_void *)pioctl_req,
&misc->param.aggr_params);
if (ret == MLAN_STATUS_SUCCESS) {
ret = MLAN_STATUS_PENDING;
}
LEAVE();
return ret;
}
#ifdef USB
/**
* @brief Get/Set USB packet aggregation 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
*/
mlan_status wlan_misc_ioctl_usb_aggr_ctrl(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
if (pmadapter->pcard_usb->fw_usb_aggr == MFALSE) {
PRINTM(MERROR, "USB aggregation not supported by FW\n");
pioctl_req->status_code = MLAN_ERROR_CMD_INVALID;
LEAVE();
return MLAN_STATUS_FAILURE;
}
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 request to firmware */
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE,
cmd_action, 0, (t_void *)pioctl_req,
&misc->param.usb_aggr_params);
if (ret == MLAN_STATUS_SUCCESS) {
ret = MLAN_STATUS_PENDING;
}
LEAVE();
return ret;
}
#endif
/**
* @brief Get/Set Tx control configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_txcontrol(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
pmpriv->pkt_tx_ctrl = misc->param.tx_control;
else
misc->param.tx_control = pmpriv->pkt_tx_ctrl;
LEAVE();
return ret;
}
#ifdef RX_PACKET_COALESCE
/**
* @brief Get/Set RX packet coalescing configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_rx_pkt_coalesce_config(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_PKT_COALESCE_CFG,
cmd_action, 0, (t_void *)pioctl_req,
&misc->param.rx_coalesce);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#endif
/**
* @brief Is any uAP started or STA connected?
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MTRUE/MFALSE
*/
t_bool wlan_check_interface_active(mlan_adapter *pmadapter)
{
t_bool ret = MFALSE;
pmlan_private pmpriv;
int i;
if (pmadapter == MNULL)
return MFALSE;
for (i = 0; i < pmadapter->priv_num; i++) {
pmpriv = pmadapter->priv[i];
if (pmpriv) {
#ifdef UAP_SUPPORT
if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
ret = pmpriv->uap_bss_started;
else
#endif
if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
ret = pmpriv->media_connected;
}
if (ret)
return MTRUE;
}
return MFALSE;
}
/**
* @brief Get/Set DFS REPEATER mode
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_dfs_repeater_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
t_u16 cmd_action = 0;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
/* Make sure no interface is active
* before setting the dfs repeater mode
*/
if (wlan_check_interface_active(pmadapter)) {
PRINTM(MMSG, "DFS-Repeater active priv found,"
" skip enabling the mode.\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
cmd_action = HostCmd_ACT_GEN_SET;
} else {
cmd_action = HostCmd_ACT_GEN_GET;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_DFS_REPEATER_MODE, cmd_action, 0,
(t_void *)pioctl_req, &misc->param.dfs_repeater);
done:
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get Low Power Mode
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_low_pwr_mode(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCMD_CONFIG_LOW_POWER_MODE,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
&misc->param.low_pwr_mode);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Configure PMIC in Firmware
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_pmic_configure(pmlan_adapter pmadapter,
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, HOST_CMD_PMIC_CONFIGURE,
HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/* @brief Set/Get CW Mode Level control
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_cwmode_ctrl(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
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 request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CW_MODE_CTRL, cmd_action, 0,
(t_void *)pioctl_req, &misc->param.cwmode);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief push value to stack
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param len Length of value
* @param val A pointer to value
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
inline mlan_status push_n(pmlan_adapter pmadapter, mef_stack *s, t_u8 len,
t_u8 *val)
{
if ((s->sp + len) <= MAX_NUM_STACK_BYTES) {
memcpy_ext(pmadapter, s->byte + s->sp, val, len,
MAX_NUM_STACK_BYTES - s->sp);
s->sp += len;
return MLAN_STATUS_SUCCESS;
} else {
PRINTM(MERROR, "Stack is full\n");
return MLAN_STATUS_FAILURE;
}
}
/**
* @brief push value to stack accoring to operand type
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param op A pointer to mef_op
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
inline mlan_status mef_push(pmlan_adapter pmadapter, mef_stack *s, mef_op *op)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u8 nbytes;
switch (op->operand_type) {
case OPERAND_DNUM:
ret = push_n(pmadapter, s, 4, op->val);
if (ret == MLAN_STATUS_SUCCESS)
ret = push_n(pmadapter, s, 1, &op->operand_type);
else
ret = MLAN_STATUS_FAILURE;
break;
case OPERAND_BYTE_SEQ:
nbytes = op->val[0];
if (MLAN_STATUS_SUCCESS ==
push_n(pmadapter, s, nbytes, op->val + 1) &&
MLAN_STATUS_SUCCESS == push_n(pmadapter, s, 1, op->val) &&
MLAN_STATUS_SUCCESS ==
push_n(pmadapter, s, 1, &op->operand_type))
ret = MLAN_STATUS_SUCCESS;
else
ret = MLAN_STATUS_FAILURE;
break;
default:
ret = push_n(pmadapter, s, 1, &op->operand_type);
break;
}
return ret;
}
/**
* @brief push dnum filter to stack
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param filter A pointer to filter item
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
static mlan_status push_filter_dnum_eq(pmlan_adapter pmadapter, mef_stack *s,
mef_filter_t *filter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u32 dnum;
mef_op op;
ENTER();
if (!filter) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (filter->fill_flag != (FILLING_TYPE | FILLING_PATTERN |
FILLING_OFFSET | FILLING_NUM_BYTES)) {
PRINTM(MERROR, "Filter item fill error\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Format of decimal num:
* | 5 bytes | 5 bytes | 5 bytes | 1 byte | |
* pattern | offset | num of bytes | type (TYPE_DNUM_EQ) |
*/
/* push pattern */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_DNUM;
dnum = filter->pattern;
memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push offset */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_DNUM;
dnum = filter->offset;
memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push num of bytes */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_DNUM;
dnum = filter->num_bytes;
memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push type */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = TYPE_DNUM_EQ;
ret = mef_push(pmadapter, s, &op);
done:
LEAVE();
return ret;
}
/**
* @brief push byte_eq filter to stack
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param filter A pointer to filter item
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
static mlan_status push_filter_byte_eq(pmlan_adapter pmadapter, mef_stack *s,
mef_filter_t *filter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u32 dnum;
mef_op op;
ENTER();
if (!filter) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (filter->fill_flag != (FILLING_TYPE | FILLING_REPEAT |
FILLING_BYTE_SEQ | FILLING_OFFSET)) {
PRINTM(MERROR, "Filter item fill error\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Format of decimal num:
* | 5 bytes | val | 5 bytes | 1 byte | |
* repeat | bytes seq | offset | type (TYPE_BYTE_EQ) |
*/
/* push repeat */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_DNUM;
dnum = filter->repeat;
memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push bytes seq */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_BYTE_SEQ;
op.val[0] = filter->num_byte_seq;
memcpy_ext(pmadapter, &op.val[1], filter->byte_seq,
filter->num_byte_seq, MAX_NUM_BYTE_SEQ);
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push offset */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_DNUM;
dnum = filter->offset;
memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push type */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = TYPE_BYTE_EQ;
ret = mef_push(pmadapter, s, &op);
done:
LEAVE();
return ret;
}
/**
* @brief push bite_eq filter to stack
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param filter A pointer to filter item
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
static mlan_status push_filter_bit_eq(pmlan_adapter pmadapter, mef_stack *s,
mef_filter_t *filter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u32 dnum;
mef_op op;
ENTER();
if (!filter) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (filter->fill_flag != (FILLING_TYPE | FILLING_REPEAT |
FILLING_BYTE_SEQ | FILLING_OFFSET)) {
PRINTM(MERROR, "Filter item fill error\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Format of decimal num:
* | val | 5 bytes | val | 1 byte | |
* bytes seq | offset | mask seq | type (TYPE_BIT_EQ) |
*/
/* push bytes seq */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_BYTE_SEQ;
op.val[0] = filter->num_byte_seq;
memcpy_ext(pmadapter, &op.val[1], filter->byte_seq,
filter->num_byte_seq, MAX_NUM_BYTE_SEQ);
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push offset */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_DNUM;
dnum = filter->offset;
memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push mask seq */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = OPERAND_BYTE_SEQ;
op.val[0] = filter->num_mask_seq;
memcpy_ext(pmadapter, &op.val[1], filter->mask_seq,
filter->num_mask_seq, MAX_NUM_BYTE_SEQ);
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS)
goto done;
/* push type */
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = TYPE_BIT_EQ;
ret = mef_push(pmadapter, s, &op);
done:
LEAVE();
return ret;
}
/**
* @brief push filter to stack
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param filter A pointer to filter item
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
static mlan_status wlan_push_filter(pmlan_adapter pmadapter, mef_stack *s,
mef_filter_t *filter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
switch (filter->type) {
case TYPE_DNUM_EQ:
ret = push_filter_dnum_eq(pmadapter, s, filter);
break;
case TYPE_BYTE_EQ:
ret = push_filter_byte_eq(pmadapter, s, filter);
break;
case TYPE_BIT_EQ:
ret = push_filter_bit_eq(pmadapter, s, filter);
break;
default:
PRINTM(MERROR, "Invalid filter type\n");
ret = MLAN_STATUS_FAILURE;
break;
}
return ret;
}
/**
* @brief generate mef data
*
* @param pmadapter A pointer to mlan_adapter structure
* @param s A pointer to mef_stack
* @param entry A pointer to mef_entry_t
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
static mlan_status wlan_generate_mef_filter_stack(pmlan_adapter pmadapter,
mef_stack *s,
mef_entry_t *entry)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mef_op op;
int i;
ENTER();
for (i = 0; i < entry->filter_num; i++) {
ret = wlan_push_filter(pmadapter, s, &entry->filter_item[i]);
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "push filter to stack error\n");
goto done;
}
if (i != 0) {
memset(pmadapter, &op, 0, sizeof(op));
op.operand_type = entry->rpn[i];
ret = mef_push(pmadapter, s, &op);
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "push filter rpn error\n");
goto done;
}
}
}
done:
LEAVE();
return ret;
}
/**
* @brief Set the mef entries to firmware
*
* @param pmpriv A pointer to mlan_private structure
* @param pmadapter A pointer to mlan_adapter structure
* @param pmef A pointer to mef_cfg structure
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
mlan_status wlan_set_mef_entry(mlan_private *pmpriv, pmlan_adapter pmadapter,
mef_cfg_data *pmef)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cmd *hostcmd;
HostCmd_DS_GEN *hostcmd_hdr;
HostCmd_DS_MEF_CFG *mef_hdr;
mef_entry_header *entry_hdr;
mef_stack *stack;
mef_entry_t *pentry;
t_u8 *buf;
t_u32 i, buf_len;
pmlan_callbacks pcb;
ENTER();
if (pmef->entry_num > MAX_NUM_ENTRIES) {
PRINTM(MERROR, "Too many entries\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
pcb = &pmadapter->callbacks;
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 cmd data buffer\n");
ret = MLAN_STATUS_FAILURE;
goto err_handle;
}
/** Fill the cmd header data*/
memset(pmadapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
buf = hostcmd->cmd;
hostcmd_hdr = (HostCmd_DS_GEN *)buf;
hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
buf_len = S_DS_GEN;
/** Fill HostCmd_DS_MEF_CFG*/
mef_hdr = (HostCmd_DS_MEF_CFG *)(buf + buf_len);
mef_hdr->criteria = wlan_cpu_to_le32(pmef->criteria);
mef_hdr->nentries = wlan_cpu_to_le16(pmef->entry_num);
buf_len += sizeof(HostCmd_DS_MEF_CFG);
/** generate mef entry data*/
for (i = 0, pentry = pmef->pentry; i < pmef->entry_num; i++, pentry++) {
/** Fill entry header data*/
entry_hdr = (mef_entry_header *)(buf + buf_len);
entry_hdr->mode = pentry->mode;
entry_hdr->action = pentry->action;
buf_len += sizeof(mef_entry_header);
/** Fill Stack data*/
stack = (mef_stack *)(buf + buf_len);
ret = wlan_generate_mef_filter_stack(pmadapter, stack, pentry);
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "Generate mef data error\n");
goto err_handle;
}
buf_len += (stack->sp + sizeof(stack->sp));
}
hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
hostcmd->len = wlan_cpu_to_le32(buf_len);
DBG_HEXDUMP(MCMD_D, "MEF DATA", (t_u8 *)hostcmd, buf_len + 4);
/** Send command to firmware*/
ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)MNULL,
(t_void *)hostcmd);
err_handle:
if (hostcmd)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd);
done:
LEAVE();
return ret;
}
/*
* @brief generate Host_CMD_MEF_CFG cmd data to firmware
*
* @param pmpriv A pointer to mlan_private structure
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or FAIL
*/
mlan_status wlan_process_mef_cfg_cmd(mlan_private *pmpriv,
pmlan_adapter pmadapter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_callbacks pcb;
mef_cfg_data mef;
mef_entry_t *pentry = MNULL;
mef_entry *pmef;
t_u16 entry_num = 0;
ENTER();
pcb = &pmadapter->callbacks;
memset(pmadapter, &mef, 0, sizeof(mef_cfg_data));
/** check how many entries in adapter*/
pmef = &pmadapter->entry_cfg;
entry_num += pmef->enable_autoarp_entry;
entry_num += pmef->num_wowlan_entry;
entry_num += pmef->num_ipv6_ns_offload;
if (!entry_num && !pmef->clear_mef_entry) {
PRINTM(MIOCTL, "No filter entries\n");
goto done;
}
if (entry_num) {
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
sizeof(mef_entry_t) * entry_num,
MLAN_MEM_DEF, (t_u8 **)&mef.pentry);
if (ret != MLAN_STATUS_SUCCESS || mef.pentry == MNULL) {
PRINTM(MERROR, "Failed to allocate cmd data buffer\n");
ret = MLAN_STATUS_FAILURE;
goto err_handle;
}
}
/** Fill mef_cfg structure*/
mef.criteria = pmef->criteria;
mef.entry_num = entry_num;
memset(pmadapter, mef.pentry, 0, sizeof(mef_entry_t) * entry_num);
pentry = mef.pentry;
/** Fill mef_entry_t structure*/
/** Copy Auto arp response entry*/
if (pmef->enable_autoarp_entry) {
memcpy_ext(pmadapter, pentry, &pmef->entry[5],
sizeof(mef_entry_t), sizeof(mef_entry_t));
pentry += pmef->enable_autoarp_entry;
}
/** Copy wowlan entry*/
if (pmef->num_wowlan_entry) {
memcpy_ext(pmadapter, pentry, &pmef->entry[6],
sizeof(mef_entry_t), sizeof(mef_entry_t));
pentry += pmef->num_wowlan_entry;
}
/** Copy IPv6 NS message offload entry */
if (pmef->num_ipv6_ns_offload)
memcpy_ext(pmadapter, pentry, &pmef->entry[7],
sizeof(mef_entry_t), sizeof(mef_entry_t));
/** Set Entries to firmware*/
ret = wlan_set_mef_entry(pmpriv, pmadapter, &mef);
if (ret != MLAN_STATUS_SUCCESS)
PRINTM(MERROR, "Set MEF entries error\n");
err_handle:
if (mef.pentry)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)mef.pentry);
done:
LEAVE();
return ret;
}
/* @brief Get/Set NV-FLT-CONFIG parameters
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_misc_ioctl_mef_flt_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_misc_cfg *misc_cfg = MNULL;
mlan_ds_misc_mef_flt_cfg *mef_cfg = MNULL;
mef_entry *pmef = MNULL;
ENTER();
misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
mef_cfg = &misc_cfg->param.mef_flt_cfg;
pmef = &pmadapter->entry_cfg;
switch (pioctl_req->action) {
case MLAN_ACT_SET:
if (mef_cfg->mef_act_type == MEF_ACT_WOWLAN) {
pmef->num_wowlan_entry = 1;
pmef->criteria |= mef_cfg->criteria;
memcpy_ext(pmadapter, &pmef->entry[6],
&mef_cfg->mef_entry, sizeof(mef_entry_t),
sizeof(mef_entry_t));
}
if (mef_cfg->mef_act_type == MEF_ACT_IPV6_NS) {
pmef->num_ipv6_ns_offload = 1;
pmef->criteria |= mef_cfg->criteria;
memcpy_ext(pmadapter, &pmef->entry[7],
&mef_cfg->mef_entry, sizeof(mef_entry_t),
sizeof(mef_entry_t));
}
/** Set AUTO ARP Entry to adapter*/
if (mef_cfg->mef_act_type == MEF_ACT_AUTOARP) {
if (mef_cfg->op_code & MLAN_IPADDR_OP_AUTO_ARP_RESP) {
pmef->enable_autoarp_entry = 1;
pmef->criteria |= mef_cfg->criteria;
memcpy_ext(pmadapter, &pmef->entry[5],
&mef_cfg->mef_entry,
sizeof(mef_entry_t),
sizeof(mef_entry_t));
if (MLAN_STATUS_SUCCESS !=
wlan_process_mef_cfg_cmd(
pmadapter
->priv[pioctl_req->bss_index],
pmadapter))
PRINTM(MERROR,
"Set MEF Entries Error\n");
} else if (!(mef_cfg->op_code &
MLAN_IPADDR_OP_IP_REMOVE)) {
pmef->enable_autoarp_entry = 0;
pmef->num_wowlan_entry = 0;
pmef->num_ipv6_ns_offload = 0;
pmef->clear_mef_entry = 1;
memset(pmadapter, &pmef->entry[5], 0,
sizeof(mef_entry_t));
memset(pmadapter, &pmef->entry[6], 0,
sizeof(mef_entry_t));
memset(pmadapter, &pmef->entry[7], 0,
sizeof(mef_entry_t));
if (MLAN_STATUS_SUCCESS !=
wlan_process_mef_cfg_cmd(
pmadapter
->priv[pioctl_req->bss_index],
pmadapter))
PRINTM(MERROR,
"Clear MEF Entries Error\n");
}
}
break;
case MLAN_ACT_GET:
if (mef_cfg->mef_act_type == MEF_ACT_WOWLAN)
memcpy_ext(pmadapter, &mef_cfg->mef_entry,
&pmef->entry[6], sizeof(mef_entry_t),
sizeof(mef_entry_t));
break;
default:
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
ret = MLAN_STATUS_FAILURE;
break;
}
LEAVE();
return ret;
}
/**
* @brief Set/Get WPA passphrase for esupplicant
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_sec_ioctl_passphrase(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;
t_u16 cmd_action = 0;
#ifdef STA_SUPPORT
BSSDescriptor_t *pbss_desc;
int i = 0;
#endif
ENTER();
sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
#ifdef DRV_EMBEDDED_SUPPLICANT
if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA &&
!IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) {
if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY)
SupplicantQueryPassphrase(
pmpriv->psapriv,
(void *)&sec->param.passphrase);
else if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
SupplicantClearPMK(pmpriv->psapriv,
(void *)&sec->param.passphrase);
else
SupplicantSetPassphrase(pmpriv->psapriv,
(void *)&sec->param.passphrase);
LEAVE();
return ret;
}
#endif
if (!IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) {
LEAVE();
return ret;
}
if (pioctl_req->action == MLAN_ACT_SET) {
if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
cmd_action = HostCmd_ACT_GEN_REMOVE;
else
cmd_action = HostCmd_ACT_GEN_SET;
} else if (pioctl_req->action == MLAN_ACT_CLEAR) {
cmd_action = HostCmd_ACT_GEN_REMOVE;
} else {
if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) {
#ifdef STA_SUPPORT
if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA &&
sec->param.passphrase.ssid.ssid_len == 0) {
i = wlan_find_bssid_in_list(
pmpriv,
(t_u8 *)&sec->param.passphrase.bssid,
MLAN_BSS_MODE_AUTO);
if (i >= 0) {
pbss_desc = &pmadapter->pscan_table[i];
memcpy_ext(pmadapter,
&sec->param.passphrase.ssid,
&pbss_desc->ssid,
sizeof(mlan_802_11_ssid),
sizeof(mlan_802_11_ssid));
memset(pmadapter,
&sec->param.passphrase.bssid, 0,
MLAN_MAC_ADDR_LENGTH);
PRINTM(MINFO,
"PSK_QUERY: found ssid=%s\n",
sec->param.passphrase.ssid.ssid);
}
} else
#endif
memset(pmadapter, &sec->param.passphrase.bssid,
0, MLAN_MAC_ADDR_LENGTH);
}
cmd_action = HostCmd_ACT_GEN_GET;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PMK, cmd_action,
0, (t_void *)pioctl_req, (t_void *)sec);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set per packet Txctl and Rxinfo configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_misc_per_pkt_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 = MNULL;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
pmpriv->rx_pkt_info = MFALSE;
if (misc->param.txrx_pkt_ctrl & RX_PKT_INFO)
pmpriv->rx_pkt_info = MTRUE;
LEAVE();
return ret;
}
/**
* @brief Set/Get region code
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_region(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;
int i;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_GET) {
misc->param.region_code = pmadapter->region_code;
} else {
if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
PRINTM(MERROR,
"ForceRegionRule is set in the on-chip OTP"
" memory\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
/* Use the region code to search for the index */
if (misc->param.region_code == region_code_index[i]) {
pmadapter->region_code =
(t_u16)misc->param.region_code;
break;
}
}
/* It's unidentified region code */
if (i >= MRVDRV_MAX_REGION_CODE) {
PRINTM(MERROR, "Region Code not identified\n");
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmadapter->cfp_code_bg = misc->param.region_code;
pmadapter->cfp_code_a = misc->param.region_code;
if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
pmadapter->config_bands |
pmadapter->adhoc_start_band)) {
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
ret = MLAN_STATUS_FAILURE;
}
}
pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
LEAVE();
return ret;
}
/**
* @brief Configure GPIO independent reset
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_ind_rst_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_u16 cmd_action = 0;
ENTER();
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_INDEPENDENT_RESET_CFG,
cmd_action, 0, (t_void *)pioctl_req,
(t_void *)&misc->param.ind_rst_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get timestamp from firmware
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_get_tsf(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->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
else {
PRINTM(MERROR, "No support set tsf!");
return MLAN_STATUS_FAILURE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_TSF, cmd_action, 0,
(t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Create custom regulatory 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_chan_reg_cfg(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->action == MLAN_ACT_GET)
cmd_action = HostCmd_ACT_GEN_GET;
else {
PRINTM(MERROR, "No support set channel region cfg!");
return MLAN_STATUS_FAILURE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, cmd_action,
0, (t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Check operating class validation
*
* @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_operclass_validation(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = MNULL;
t_u8 channel, oper_class;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
channel = misc->param.bw_chan_oper.channel;
oper_class = misc->param.bw_chan_oper.oper_class;
if (pioctl_req->action == MLAN_ACT_GET) {
ret = wlan_check_operclass_validation(pmpriv, channel,
oper_class);
} else {
PRINTM(MERROR, "Unsupported cmd_action\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
LEAVE();
return ret;
}
/**
* @brief Get Region channel power setting
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_get_rgchnpwr_cfg(pmlan_adapter pmadapter,
mlan_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();
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, cmd_action,
0, (t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get/Set mc_aggr_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_mc_aggr_cfg(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
cmd_action = pioctl_req->action;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MC_AGGR_CFG, cmd_action, 0,
(t_void *)pioctl_req,
(t_void *)&misc->param.mc_aggr_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief get channel load results
*
* @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_ch_load_results(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
mlan_private *pmpriv = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
if (pioctl_req == MNULL)
return MLAN_STATUS_FAILURE;
pmpriv = pmadapter->priv[pioctl_req->bss_index];
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
cmd_action = pioctl_req->action;
/* Send request to firmware */
if (pmpriv->ch_load_param == 255) {
return MLAN_STATUS_FAILURE;
} else {
misc->param.ch_load.ch_load_param = pmpriv->ch_load_param;
misc->param.ch_load.noise = pmpriv->noise;
}
LEAVE();
return ret;
}
/**
* @brief get channel load
*
* @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_ch_load(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
mlan_private *pmpriv = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
if (pioctl_req == MNULL)
return MLAN_STATUS_FAILURE;
pmpriv = pmadapter->priv[pioctl_req->bss_index];
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
cmd_action = pioctl_req->action;
/* Send request to firmware */
pmpriv->ch_load_param = 255; /* Default value for identifying
update/non-updated value*/
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_CH_LOAD, cmd_action, 0,
(t_void *)pioctl_req,
(t_void *)&misc->param.ch_load);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get CHAN_TPRC setting
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_get_chan_trpc_cfg(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
mlan_ds_misc_cfg *misc = MNULL;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
cmd_action = HostCmd_ACT_GEN_GET;
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CHANNEL_TRPC_CONFIG, cmd_action,
0, (t_void *)pioctl_req,
(t_void *)&misc->param.trpc_cfg);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Get non-global operating class
*
* @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_oper_class(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = MNULL;
t_u8 channel, bandwidth, oper_class = 0;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
channel = misc->param.bw_chan_oper.channel;
switch (misc->param.bw_chan_oper.bandwidth) {
case 20:
bandwidth = BW_20MHZ;
break;
case 40:
bandwidth = BW_40MHZ;
break;
case 80:
bandwidth = BW_80MHZ;
break;
default:
bandwidth = BW_20MHZ;
break;
}
if (pioctl_req->action == MLAN_ACT_GET) {
ret = wlan_get_curr_oper_class(pmpriv, channel, bandwidth,
&oper_class);
misc->param.bw_chan_oper.oper_class = oper_class;
} else {
PRINTM(MERROR, "Unsupported cmd_action\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
LEAVE();
return ret;
}
/**
* @brief config dynamic bandwidth
*
* @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_fw_dump_event(pmlan_adapter pmadapter,
mlan_ioctl_req *pioctl_req)
{
pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
t_u16 cmd_action = 0;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
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 {
PRINTM(MERROR, "Unsupported cmd_action\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FW_DUMP_EVENT, cmd_action, 0,
(t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get the network monitor configuration.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_net_monitor(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv;
mlan_ds_misc_cfg *misc;
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 cmd_action = 0;
ENTER();
if (!pioctl_req) {
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmpriv = pmadapter->priv[pioctl_req->bss_index];
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (misc->param.net_mon.enable_net_mon == CHANNEL_SPEC_SNIFFER_MODE) {
/* Net monitor IOCTL not allowed in connected state */
if (pmpriv->media_connected == MTRUE) {
PRINTM(MERROR,
"IOCTL not allowed in connected state\n");
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
LEAVE();
return MLAN_STATUS_FAILURE;
}
}
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_NET_MONITOR,
cmd_action, 0, (t_void *)pioctl_req,
&misc->param.net_mon);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief config boot sleep
*
* @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_bootsleep(pmlan_adapter pmadapter,
pmlan_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 {
PRINTM(MERROR, "Unsupported cmd_action 0x%x\n",
pioctl_req->action);
LEAVE();
return MLAN_STATUS_FAILURE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_BOOT_SLEEP, cmd_action, 0,
(t_void *)pioctl_req, &misc->param.boot_sleep);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get Infra/Ad-hoc band configuration
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success, otherwise fail
*/
mlan_status wlan_radio_ioctl_band_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
t_u32 i, global_band = 0;
t_u32 infra_band = 0;
t_u32 adhoc_band = 0;
t_u32 adhoc_channel = 0;
mlan_ds_radio_cfg *radio_cfg = MNULL;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
ENTER();
radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET) {
infra_band = radio_cfg->param.band_cfg.config_bands;
adhoc_band = radio_cfg->param.band_cfg.adhoc_start_band;
adhoc_channel = radio_cfg->param.band_cfg.adhoc_channel;
/* SET Infra band */
if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
/* SET Ad-hoc Band */
if ((adhoc_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (!adhoc_band)
adhoc_band = pmadapter->adhoc_start_band;
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i] &&
pmadapter->priv[i] != pmpriv &&
GET_BSS_ROLE(pmadapter->priv[i]) ==
MLAN_BSS_ROLE_STA)
global_band |=
(t_u32)pmadapter->priv[i]->config_bands;
}
global_band |= infra_band;
if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
global_band | adhoc_band)) {
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
LEAVE();
return MLAN_STATUS_FAILURE;
}
#ifdef STA_SUPPORT
if (wlan_11d_set_universaltable(pmpriv,
global_band | adhoc_band)) {
pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
LEAVE();
return MLAN_STATUS_FAILURE;
}
#endif
pmpriv->config_bands = infra_band;
pmadapter->config_bands = global_band;
pmadapter->adhoc_start_band = adhoc_band;
pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
#ifdef STA_SUPPORT
/*
* If no adhoc_channel is supplied verify if the existing
* adhoc channel compiles with new adhoc_band
*/
if (!adhoc_channel) {
if (!wlan_find_cfp_by_band_and_channel(
pmadapter, pmadapter->adhoc_start_band,
pmpriv->adhoc_channel)) {
/* Pass back the default channel */
radio_cfg->param.band_cfg.adhoc_channel =
DEFAULT_AD_HOC_CHANNEL;
if ((pmadapter->adhoc_start_band & BAND_A)) {
radio_cfg->param.band_cfg.adhoc_channel =
DEFAULT_AD_HOC_CHANNEL_A;
}
}
} else {
/* Return error if adhoc_band and adhoc_channel
* combination is invalid
*/
if (!wlan_find_cfp_by_band_and_channel(
pmadapter, pmadapter->adhoc_start_band,
(t_u16)adhoc_channel)) {
pioctl_req->status_code =
MLAN_ERROR_INVALID_PARAMETER;
LEAVE();
return MLAN_STATUS_FAILURE;
}
pmpriv->adhoc_channel = (t_u8)adhoc_channel;
}
#endif
} else {
/* Infra Bands */
radio_cfg->param.band_cfg.config_bands = pmpriv->config_bands;
/* Adhoc Band */
radio_cfg->param.band_cfg.adhoc_start_band =
pmadapter->adhoc_start_band;
/* Adhoc Channel */
radio_cfg->param.band_cfg.adhoc_channel = pmpriv->adhoc_channel;
/* FW support Bands */
radio_cfg->param.band_cfg.fw_bands = pmadapter->fw_bands;
PRINTM(MINFO, "Global config band = %d\n",
pmadapter->config_bands);
#ifdef STA_SUPPORT
#endif
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Rx Abort 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_rxabortcfg(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_RX_ABORT_CFG, cmd_action, 0,
(t_void *)pioctl_req,
&(pmisc->param.rx_abort_cfg));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Rx Abort Cfg ext
*
* @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_rxabortcfg_ext(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_RX_ABORT_CFG_EXT, cmd_action,
0, (t_void *)pioctl_req,
&(pmisc->param.rx_abort_cfg_ext));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Dot11mc unassociated FTM 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_dot11mc_unassoc_ftm_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_DOT11MC_UNASSOC_FTM_CFG,
cmd_action, 0, (t_void *)pioctl_req,
&(pmisc->param.dot11mc_unassoc_ftm_cfg));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Tx ampdu protection 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
*/
mlan_status wlan_misc_ioctl_tx_ampdu_prot_mode(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_TX_AMPDU_PROT_MODE,
cmd_action, 0, (t_void *)pioctl_req,
&(pmisc->param.tx_ampdu_prot_mode));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Rate adapt config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_rate_adapt_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_RATE_ADAPT_CFG, cmd_action,
0, (t_void *)pioctl_req,
&(pmisc->param.rate_adapt_cfg));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief CCK Desense config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_cck_desense_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_CCK_DESENSE_CFG, cmd_action,
0, (t_void *)pioctl_req,
&(pmisc->param.cck_desense_cfg));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief config dynamic bandwidth
*
* @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_dyn_bw(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 {
PRINTM(MERROR, "Unsupported cmd_action\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
/* Send request to firmware */
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DYN_BW, cmd_action, 0,
(t_void *)pioctl_req, &misc->param.dyn_bw);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief Set/Get low power mode configuration parameter
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS --success
*/
mlan_status wlan_power_ioctl_set_get_lpm(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 *pm_cfg = MNULL;
t_u16 cmd_action = 0, lpm = 0;
ENTER();
pm_cfg = (mlan_ds_power_cfg *)pioctl_req->pbuf;
cmd_action = HostCmd_ACT_GEN_GET;
if (pioctl_req->action == MLAN_ACT_SET) {
cmd_action = HostCmd_ACT_GEN_SET;
lpm = pm_cfg->param.lpm;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_LOW_POWER_MODE_CFG,
cmd_action, 0, (t_void *)pioctl_req, &lpm);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
/**
* @brief RF Test Mode config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_rf_test_cfg(pmlan_adapter pmadapter,
pmlan_ioctl_req pioctl_req)
{
mlan_private *pmpriv = MNULL;
mlan_ds_misc_cfg *pmisc = MNULL;
mlan_status ret = MLAN_STATUS_FAILURE;
t_u16 cmd_action = 0;
ENTER();
if (!pioctl_req)
goto done;
pmpriv = pmadapter->priv[pioctl_req->bss_index];
pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
switch (pmisc->sub_command) {
case MLAN_OID_MISC_RF_TEST_GENERIC:
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_MFG_COMMAND,
cmd_action, 0, (t_void *)pioctl_req,
&(pmisc->param.mfg_generic_cfg));
break;
case MLAN_OID_MISC_RF_TEST_TX_CONT:
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else {
PRINTM(MERROR, "Unsupported cmd_action\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND,
cmd_action, 0, (t_void *)pioctl_req,
&(pmisc->param.mfg_tx_cont));
break;
case MLAN_OID_MISC_RF_TEST_TX_FRAME:
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else {
PRINTM(MERROR, "Unsupported cmd_action\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND,
cmd_action, 0, (t_void *)pioctl_req,
&(pmisc->param.mfg_tx_frame2));
break;
case MLAN_OID_MISC_RF_TEST_HE_POWER:
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else {
PRINTM(MERROR, "Unsupported cmd_action\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND,
cmd_action, 0, (t_void *)pioctl_req,
&(pmisc->param.mfg_he_power));
break;
}
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
done:
LEAVE();
return ret;
}
/**
* @brief Range ext mode config
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status wlan_misc_ioctl_range_ext(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_RANGE_EXT, cmd_action, 0,
(t_void *)pioctl_req,
&(pmisc->param.range_ext_mode));
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#ifdef UAP_SUPPORT
/**
* @brief set wacp 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
*/
mlan_status wlan_misc_ioctl_wacp_mode(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
mlan_ds_misc_cfg *misc = MNULL;
t_u16 cmd_action;
ENTER();
misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
if (pioctl_req->action == MLAN_ACT_SET)
cmd_action = HostCmd_ACT_GEN_SET;
else
cmd_action = HostCmd_ACT_GEN_GET;
ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action,
0, (t_void *)pioctl_req,
(t_void *)&misc->param.wacp_mode);
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
LEAVE();
return ret;
}
#endif
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;
}