/**
 * @file mlan_misc.c
 *
 *  @brief This file include miscellaneous functions for MLAN module
 *
 *
 *  Copyright 2009-2024 NXP
 *
 *  This software file (the File) is distributed by NXP
 *  under the terms of the GNU General Public License Version 2, June 1991
 *  (the License).  You may use, redistribute and/or modify the File in
 *  accordance with the terms and conditions of the License, a copy of which
 *  is available by writing to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
 *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
 *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
 *  this warranty disclaimer.
 *
 */

/*************************************************************
Change Log:
    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
/********************************************************
			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] = {0};
	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 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_tx_frame(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;

	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_FRAME,
			       HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
			       &misc->param.tx_frame);
	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->tx_pause = pmpriv->tx_pause;
		debug_info->bypass_pkt_count =
			util_scalar_read(pmadapter->pmoal_handle,
					 &pmadapter->bypass_pkt_count,
					 pmadapter->callbacks.moal_spin_lock,
					 pmadapter->callbacks.moal_spin_unlock);
		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(%d)!\n",
		       pmadapter->pm_wakeup_timeout);
		pmadapter->pm_wakeup_timeout++;
		pmadapter->pm_wakeup_flag = MTRUE;
		wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
				MLAN_EVENT_ID_DRV_DEFER_HANDLING, 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;
	t_u32 mem_flags = MLAN_MEM_DEF | MLAN_MEM_DMA;

	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 */
	if (malloc_flag & MOAL_MALLOC_BUFFER) {
		buf_size =
			(t_u32)(sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT);
		if (malloc_flag & MOAL_MEM_FLAG_ATOMIC)
			mem_flags |= MLAN_MEM_FLAG_ATOMIC;
		if (malloc_flag & MOAL_MEM_FLAG_DIRTY)
			mem_flags |= MLAN_MEM_FLAG_DIRTY;
		ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
				       mem_flags, (t_u8 **)&pmbuf);
		if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
			pmbuf = MNULL;
			goto exit;
		}

		if (malloc_flag & MOAL_MEM_FLAG_DIRTY)
			memset(pmadapter, pmbuf, 0x00,
			       sizeof(*pmbuf) + head_room);

		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;
	} else if (malloc_flag & 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;
	}

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;
			upto_tv_sec += (delay / 1000000);
			upto_tv_usec += (delay % 1000000);
			break;
		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;
	t_u16 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);
		/* restore mac address */
		memcpy_ext(pmpriv->adapter, pmpriv->curr_addr,
			   pmpriv->adapter->permanent_addr,
			   MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
		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)) {
				pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
				LEAVE();
				return MLAN_STATUS_FAILURE;
			}

			if (wlan_11d_set_universaltable(pmpriv, global_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, HostCmd_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(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || 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(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || 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(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || 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(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || 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(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || defined(SD9097) || defined(SD9177) ||             \
	defined(SDIW615) || defined(USBIW615)
	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;
	}
	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);
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) {
		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))) {
		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;

	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));
			memcpy_ext(priv->adapter, peer_info->he_cap,
				   &sta_ptr->he_cap, sizeof(IEEEtypes_HECap_t),
				   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;
	}
	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 */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG,
			       HostCmd_ACT_GEN_SET, 0, MNULL, tdls_config);
	if (ret)
		PRINTM(MERROR, "Error sending cmd to FW\n");

	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;
	}

	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 */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG,
			       HostCmd_ACT_GEN_SET, 0, MNULL, tdls_config);
	if (ret)
		PRINTM(MERROR, "Error sending cmd to FW\n");

	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;
	}

	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 */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TDLS_CONFIG,
			       HostCmd_ACT_GEN_SET, 0, MNULL, tdls_config);
	if (ret)
		PRINTM(MERROR, "Error sending cmd to FW\n");

	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 config rtt
 *
 *  @param pmadapter	A pointer to mlan_adapter structure
 *  @param pioctl_req	A pointer to ioctl request buffer
 *
 *  @return		MLAN_STATUS_PENDING --success, otherwise fail
 */
mlan_status wlan_config_rtt(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
{
	pmlan_private pmpriv = MNULL;
	mlan_ds_misc_cfg *misc = MNULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!pioctl_req) {
		PRINTM(MERROR, "MLAN IOCTL information is not present\n");
		ret = MLAN_STATUS_FAILURE;
		goto exit;
	}

	misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	pmpriv = pmadapter->priv[pioctl_req->bss_index];

	/* Send request to firmware */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FTM_CONFIG_SESSION_PARAMS,
			       HostCmd_ACT_GEN_SET, OID_RTT_REQUEST,
			       (t_void *)pioctl_req, &(misc->param.rtt_params));

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

exit:
	LEAVE();
	return ret;
}

/**
 *  @brief cancel rtt
 *
 *  @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_cancel_rtt(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
{
	pmlan_private pmpriv = MNULL;
	mlan_ds_misc_cfg *misc = MNULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!pioctl_req) {
		PRINTM(MERROR, "MLAN IOCTL information is not present\n");
		ret = MLAN_STATUS_FAILURE;
		goto exit;
	}

	misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	pmpriv = pmadapter->priv[pioctl_req->bss_index];

	/* Send request to firmware */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FTM_CONFIG_SESSION_PARAMS,
			       HostCmd_ACT_GEN_SET, OID_RTT_CANCEL,
			       (t_void *)pioctl_req, &(misc->param.rtt_cancel));

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

exit:
	LEAVE();
	return ret;
}

/**
 *  @brief rtt responder 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_rtt_responder_cfg(pmlan_adapter pmadapter,
				   pmlan_ioctl_req pioctl_req)
{
	pmlan_private pmpriv = MNULL;
	mlan_ds_misc_cfg *misc = MNULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!pioctl_req) {
		PRINTM(MERROR, "MLAN IOCTL information is not present\n");
		ret = MLAN_STATUS_FAILURE;
		goto exit;
	}

	misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	pmpriv = pmadapter->priv[pioctl_req->bss_index];

	/* Send request to firmware */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FTM_CONFIG_RESPONDER,
			       HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
			       &(misc->param.rtt_rsp_cfg));

	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, HostCmd_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) {
			/* Igone DeAuth/DisAssoc frame from OLD AP during
			 * Roaming */
			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)) ||
				    !priv->assoc_rsp_size ||
				    !memcmp(pmadapter, pieee_pkt_hdr->addr3,
					    (t_u8 *)priv->curr_bss_params
						    .prev_bssid,
					    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 " MACSTR
				       "\n",
				       sub_type, MAC2STR(pieee_pkt_hdr->addr3));
				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->bss_role == MLAN_BSS_ROLE_STA &&
	    !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->bss_role == MLAN_BSS_ROLE_STA &&
		   !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;
}

/**
 *  @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;
	}
}

/**
 *  @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;
}

/**
 *  @brief Set multi ap flag
 *
 *  @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_multi_ap_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.multi_ap_flag = pmpriv->multi_ap_flag;
	else if (MLAN_ACT_SET == pioctl_req->action)
		pmpriv->multi_ap_flag = misc->param.multi_ap_flag;

	LEAVE();
	return ret;
}

#ifdef STA_SUPPORT
/**
 *  @brief This function check if we should enable beacon protection support
 *
 *  @param pbss_desc    A pointer to BSSDescriptor_t structure
 *
 *  @return        MTRUE/MFALSE
 */
static t_u8 wlan_check_beacon_prot_supported(mlan_private *pmpriv,
					     BSSDescriptor_t *pbss_desc)
{
	if (pbss_desc && pbss_desc->pext_cap) {
		if (pbss_desc->pext_cap->ieee_hdr.len < 11)
			return MFALSE;
		if (!ISSUPP_EXTCAP_EXT_BEACON_PROT(
			    pbss_desc->pext_cap->ext_cap))
			return MFALSE;
	}
	if (!IS_FW_SUPPORT_BEACON_PROT(pmpriv->adapter))
		return MFALSE;
	return MTRUE;
}

/**
 *  @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 (pmpriv->adapter->pcard_info->support_11mc) {
		SET_EXTCAP_FTMI(pmpriv->ext_cap);
		SET_EXTCAP_INTERNETWORKING(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);

	if (wlan_check_beacon_prot_supported(pmpriv, pbss_desc))
		SET_EXTCAP_BEACON_PROT(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;
}

#ifdef UAP_SUPPORT
/**
 *  @brief	Check 11B support Rates
 *
 *
 *  @param pmadapter	Private mlan adapter structure
 *
 *  @return MTRUE/MFALSE
 *
 */
static t_u8 wlan_check_ie_11b_support_rates(pIEEEtypes_Generic_t prates)
{
	int i;
	t_u8 rate;
	t_u8 ret = MTRUE;
	for (i = 0; i < prates->ieee_hdr.len; i++) {
		rate = prates->data[i] & 0x7f;
		if ((rate != 0x02) && (rate != 0x04) && (rate != 0x0b) &&
		    (rate != 0x16)) {
			ret = MFALSE;
			break;
		}
	}
	return ret;
}
#endif

/**
 *  @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 *rate = MNULL;
	t_u8 b_only = MFALSE;
#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 */
				rate = wlan_get_specific_ie(priv, assoc_req_ie,
							    ie_len,
							    SUPPORTED_RATES, 0);
				if (rate)
					b_only = wlan_check_ie_11b_support_rates(
						(pIEEEtypes_Generic_t)rate);
				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 (priv->uap_channel <= 14) {
					if (b_only)
						sta_ptr->bandmode = BAND_B;
					else
						sta_ptr->bandmode = BAND_G;
				} else
					sta_ptr->bandmode = BAND_A;
#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_u16 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(USB9097) || defined(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || defined(SD9097)
			if (IS_CARD9098(pmadapter->card_type) ||
			    IS_CARD9097(pmadapter->card_type) ||
			    IS_CARDAW693(pmadapter->card_type) ||
			    IS_CARDIW624(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(USB9097) || defined(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || defined(SD9097)
			}
#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 Set 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_handle_antcfg(mlan_private *pmpriv, t_u32 init_antcfg)
{
	mlan_ds_ant_cfg ant_cfg;
	mlan_ds_ant_cfg_1x1 ant_cfg_1x1;
	mlan_status ret = MLAN_STATUS_SUCCESS;
	pmlan_adapter pmadapter = pmpriv->adapter;
	ENTER();

	memset(pmadapter, &ant_cfg, 0, sizeof(ant_cfg));
	memset(pmadapter, &ant_cfg_1x1, 0, sizeof(ant_cfg_1x1));
	if (IS_STREAM_2X2(pmadapter->feature_control)) {
		if (IS_CARD9098(pmadapter->card_type) ||
		    IS_CARD9097(pmadapter->card_type) ||
		    IS_CARDIW624(pmadapter->card_type) ||
		    IS_CARDAW693(pmadapter->card_type)) {
			ant_cfg.tx_antenna = ant_cfg.rx_antenna = init_antcfg;
		} else {
			ant_cfg.tx_antenna = (init_antcfg & 0x0030) >> 4;
			ant_cfg.rx_antenna = init_antcfg & 0x0003;
		}
	} else
		ant_cfg_1x1.antenna = init_antcfg;

	/* User input validation */
	if (IS_STREAM_2X2(pmadapter->feature_control)) {
#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) ||                \
	defined(PCIE9097) || defined(USB9097) || defined(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || defined(SD9097)
		if (IS_CARD9098(pmadapter->card_type) ||
		    IS_CARD9097(pmadapter->card_type) ||
		    IS_CARDAW693(pmadapter->card_type) ||
		    IS_CARDIW624(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(USB9097) || defined(SDIW624) ||           \
	defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) ||        \
	defined(USBIW624) || defined(SD9097)
		}
#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);
			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);
				goto exit;
			}
		} else
			ant_cfg.rx_antenna = ant_cfg.tx_antenna;
	} else if (!ant_cfg_1x1.antenna ||
		   ((ant_cfg_1x1.antenna != RF_ANTENNA_AUTO) &&
		    (ant_cfg_1x1.antenna & 0xFFFC))) {
		PRINTM(MERROR, "Invalid antenna setting\n");
		goto exit;
	}

	/* Send request to firmware */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA,
			       HostCmd_ACT_GEN_SET, 0, MNULL,
			       (IS_STREAM_2X2(pmadapter->feature_control)) ?
				       (t_void *)&ant_cfg :
				       (t_void *)&ant_cfg_1x1);
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->config_bands, 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;

	if (pioctl_req->action == MLAN_ACT_SET) {
		if (pmpriv->adapter->remain_on_channel &&
		    !radio_cfg->param.remain_chan.remove) {
			PRINTM(MCMND, "Ignore New Remain on channe: chan=%d\n",
			       radio_cfg->param.remain_chan.channel);
			LEAVE();
			return MLAN_STATUS_FAILURE;
		}
	}

	/* 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, HostCmd_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, HostCmd_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, HostCmd_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, HostCmd_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/Get CROSS CHIP SYNCH 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_cross_chip_synch(pmlan_adapter pmadapter,
					     pmlan_ioctl_req pioctl_req)
{
	mlan_status ret = MLAN_STATUS_SUCCESS;
	mlan_ds_misc_cfg *misc_cfg = MNULL;
	t_u16 cmd_action = 0;
	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];

	ENTER();

	misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
	if (pioctl_req->action == MLAN_ACT_SET)
		cmd_action = HostCmd_ACT_GEN_SET;
	else if (pioctl_req->action == MLAN_ACT_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_CROSS_CHIP_SYNCH, 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 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;
}

/**
 *  @brief Get/Set channel time and buffer weight 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_multi_chan_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_MULTI_CHAN_CONFIG,
			       cmd_action, 0, (t_void *)pioctl_req,
			       &misc->param.multi_chan_cfg);

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

	LEAVE();
	return ret;
}

/**
 *  @brief Get/Set multi-channel policy setting
 *
 *  @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_multi_chan_policy(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) {
		if (pmadapter->dfs_repeater) {
			PRINTM(MMSG,
			       "DFS-Repeater is on, can not enable DRCS\n");
			ret = MLAN_STATUS_FAILURE;
			goto fail;
		}
		cmd_action = HostCmd_ACT_GEN_SET;
	} else {
		cmd_action = HostCmd_ACT_GEN_GET;
	}

	/* Send request to firmware */
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MULTI_CHAN_POLICY,
			       cmd_action, 0, (t_void *)pioctl_req,
			       &misc->param.multi_chan_policy);

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;
fail:
	LEAVE();
	return ret;
}

/**
 *  @brief Get/Set DRCS 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_drcs_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_DRCS_CONFIG, cmd_action, 0,
			       (t_void *)pioctl_req, &misc->param.drcs_cfg);

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

	LEAVE();
	return ret;
}

/**
 *  @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;
		}

		/* If DRCS is on then we should not set
		 * DFS-repeater mode */
		if (pmadapter->mc_policy) {
			PRINTM(MERROR,
			       "DFS-repeater cannot be started when DRCS is on\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_CMD_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_CMD_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, HostCmd_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 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*/
	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;
	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;

	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)) {
			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_region_power_cfg(pmlan_adapter pmadapter,
				       pmlan_ioctl_req pioctl_req)
{
	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
	mlan_status ret = MLAN_STATUS_SUCCESS;
	ENTER();

	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_REGION_POWER_CFG,
			       HostCmd_ACT_GEN_SET, 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_ds_misc_cfg *misc_cfg = MNULL;
	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!");
		LEAVE();
		return MLAN_STATUS_FAILURE;
	}

	misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
	if (misc_cfg &&
	    misc_cfg->param.custom_reg_domain.region.country_code[0] != '\0' &&
	    misc_cfg->param.custom_reg_domain.region.country_code[1] != '\0') {
		/* Copy the driver country code in the custom_reg_domain. The
		 * cmd response handler will use it to compare with the FW
		 * country code
		 */
		pmadapter->country_code[0] =
			misc_cfg->param.custom_reg_domain.region.country_code[0];
		pmadapter->country_code[1] =
			misc_cfg->param.custom_reg_domain.region.country_code[1];
		pmadapter->country_code[2] = '\0';
	}

	/* Send 2G/5G CFP table 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;
	t_u8 bandwidth;
	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;
	bandwidth = misc->param.bw_chan_oper.bandwidth;

	if (pioctl_req->action == MLAN_ACT_GET) {
		ret = wlan_check_operclass_validation(pmpriv, channel,
						      oper_class, bandwidth);
	} 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;
		misc->param.ch_load.rx_quality = pmpriv->rx_quality;
	}

	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_CMD_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 (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 gpio cfg
 *
 *  @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_gpiocfg(pmlan_adapter pmadapter,
			      pmlan_ioctl_req pioctl_req)
{
	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
	mlan_ds_misc_cfg *misc = MNULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;
	t_u16 cmd_action = 0;

	ENTER();

	misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	if (pioctl_req->action == MLAN_ACT_GET)
		cmd_action = HostCmd_ACT_GEN_GET;
	else
		cmd_action = HostCmd_ACT_GEN_SET;

	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GPIO_CFG, cmd_action, 0,
			       (t_void *)pioctl_req, (t_void *)misc);

	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;
	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;

		/* 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;
		}

		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)) {
			pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
			LEAVE();
			return MLAN_STATUS_FAILURE;
		}
#ifdef STA_SUPPORT
		if (wlan_11d_set_universaltable(pmpriv, global_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;

#ifdef STA_SUPPORT
#endif

	} else {
		/* Infra Bands   */
		radio_cfg->param.band_cfg.config_bands = pmpriv->config_bands;
		/* 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 OFDM DESENSE 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_ofdmdesense_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_OFDM_DESENSE_CFG, cmd_action,
			       0, (t_void *)pioctl_req,
			       &(pmisc->param.ofdm_desense_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 nav mitigation parameter
 *
 *  @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_nav_mitigation(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_NAV_MITIGATION_CFG,
			       cmd_action, 0, (t_void *)pioctl_req,
			       &(pmisc->param.nav_mitigation));
	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

	LEAVE();
	return ret;
}

/**
 *  @brief led config parameter
 *
 *  @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_led(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_802_11_LED_CONTROL,
			       cmd_action, 0, (t_void *)pioctl_req,
			       &(pmisc->param.led_config));
	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_CONFIG_TRIGGER_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_trigger_config));
		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;

	case MLAN_OID_MISC_OTP_MAC_RD_WR:
		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");
			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_otp_mac_addr_rd_wr));
		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;
}

/**
 *   @brief twt_report 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_twt_report(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();

	cmd_action = HostCmd_ACT_GEN_GET;
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TWT_CFG, cmd_action, 0,
			       (t_void *)pioctl_req,
			       &(pmisc->param.twt_report_info));
	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

	LEAVE();
	return ret;
}

/**
 *  @brief Perform warm reset
 *
 *  @param pmadapter	A pointer to mlan_adapter structure
 *  @param pioctl_req	A pointer to ioctl request buffer
 *
 *  @return		MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE
 */
mlan_status wlan_misc_ioctl_warm_reset(pmlan_adapter pmadapter,
				       pmlan_ioctl_req pioctl_req)
{
	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
	mlan_status ret = MLAN_STATUS_SUCCESS;
	pmlan_callbacks pcb = &pmadapter->callbacks;
	pmlan_buffer pmbuf;
	t_s32 i = 0;
	t_u16 mc_policy = pmadapter->mc_policy;
	mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	ENTER();
	mlan_block_rx_process(pmadapter, MTRUE);

	/* Cancel all pending commands and complete ioctls */
	if (misc->param.fw_reload)
		wlan_cancel_all_pending_cmd(pmadapter, MTRUE);

	/** Init all the head nodes and free all the locks here */
	for (i = 0; i < pmadapter->priv_num; i++)
		wlan_free_priv(pmadapter->priv[i]);

	while ((pmbuf = (pmlan_buffer)util_dequeue_list(
			pmadapter->pmoal_handle, &pmadapter->rx_data_queue,
			pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
		pmadapter->ops.data_complete(pmadapter, pmbuf,
					     MLAN_STATUS_FAILURE);
	}
	pmadapter->rx_pkts_queued = 0;

	/* Initialize adapter structure */
	wlan_init_adapter(pmadapter);
	pmadapter->hw_status = WlanHardwareStatusInitializing;

	/* Initialize private structures */
	for (i = 0; i < pmadapter->priv_num; i++) {
		if (pmadapter->priv[i]) {
			/* Reset to sta role */
#ifdef WIFI_DIRECT_SUPPORT
			if (pmadapter->priv[i]->bss_type ==
			    MLAN_BSS_TYPE_WIFIDIRECT)
				pmadapter->priv[i]->bss_role =
					MLAN_BSS_ROLE_STA;
#endif
			wlan_init_priv(pmadapter->priv[i]);
		}
	}
	mlan_block_rx_process(pmadapter, MFALSE);

	if (misc->param.fw_reload != MTRUE) {
		/* Restart the firmware */
		ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
				       HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
		if (ret)
			goto done;
	}

	/* Issue firmware initialize commands for first BSS,
	 * for other interfaces it will be called after getting
	 * the last init command response of previous interface
	 */
	pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
	if (!pmpriv) {
		ret = MLAN_STATUS_FAILURE;
		LEAVE();
		return ret;
	}
	ret = wlan_adapter_get_hw_spec(pmpriv->adapter);
	if (ret == MLAN_STATUS_FAILURE) {
		LEAVE();
		return ret;
	}
	ret = pmpriv->ops.init_cmd(pmpriv, MTRUE);
	if (ret == MLAN_STATUS_FAILURE) {
		LEAVE();
		return ret;
	}
	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MULTI_CHAN_POLICY,
			       HostCmd_ACT_GEN_SET, 0, MNULL, &mc_policy);
	if (ret == MLAN_STATUS_FAILURE) {
		LEAVE();
		return ret;
	}
	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;
	if (ret == MLAN_STATUS_PENDING)
		pmadapter->pwarm_reset_ioctl_req = pioctl_req;
done:
	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, HostCmd_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_CMD_DS_GET_SENSOR_TEMP,
			       cmd_action, 0, (t_void *)pioctl_req, MNULL);

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

	LEAVE();
	return ret;
}

/**
 *  @brief This function sets up country code and downloads CMD to FW
 *
 *  @param pmadapter    A pointer to mlan_adapter structure
 *  @param pioctl_req   Pointer to the IOCTL request buffer
 *
 *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status wlan_misc_ioctl_country_code(pmlan_adapter pmadapter,
					 mlan_ioctl_req *pioctl_req)
{
	mlan_status ret = MLAN_STATUS_SUCCESS;
	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
	mlan_ds_misc_country_code *country_code = MNULL;
	mlan_ds_misc_cfg *cfg_misc = MNULL;
	t_u8 cfp_bg = 0, cfp_a = 0;

	ENTER();

	cfg_misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
	country_code = &cfg_misc->param.country_code;

	if (pioctl_req->action == MLAN_ACT_SET) {
		if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
			PRINTM(MERROR,
			       "ForceRegionRule is set in the on-chip OTP"
			       "memory\n");
			ret = MLAN_STATUS_FAILURE;
			goto done;
		}
		/* Update region code and table based on country code */
		if (wlan_misc_country_2_cfp_table_code(
			    pmadapter, country_code->country_code, &cfp_bg,
			    &cfp_a)) {
			PRINTM(MERROR, "Country code not found!\n");
			pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
			ret = MLAN_STATUS_FAILURE;
			goto done;
		}
		pmadapter->cfp_code_bg = cfp_bg;
		pmadapter->cfp_code_a = cfp_a;
		if (cfp_a)
			pmadapter->region_code = cfp_a;
		else if (cfp_bg)
			pmadapter->region_code = cfp_bg;
		else
			pmadapter->region_code = 0;
		if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
					 pmadapter->config_bands)) {
			pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
			ret = MLAN_STATUS_FAILURE;
			goto done;
		}
		memcpy_ext(pmadapter, pmadapter->country_code,
			   country_code->country_code, COUNTRY_CODE_LEN,
			   COUNTRY_CODE_LEN);
	} else {
		/* GET operation */
		memcpy_ext(pmadapter, country_code->country_code,
			   pmadapter->country_code, COUNTRY_CODE_LEN,
			   COUNTRY_CODE_LEN);
	}

done:
	LEAVE();
	return ret;
}

/**
 *  @brief get/set rx flush time
 *
 *  @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_reorder_flush_time(pmlan_adapter pmadapter,
					       mlan_ioctl_req *pioctl_req)
{
	mlan_ds_misc_cfg *misc = MNULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	if (pioctl_req->action == MLAN_ACT_SET) {
		if (misc->param.flush_time.flush_time_ac_be_bk >=
		    MIN_FLUSH_TIME)
			pmadapter->flush_time_ac_be_bk =
				misc->param.flush_time.flush_time_ac_be_bk;
		if (misc->param.flush_time.flush_time_ac_vi_vo >=
		    MIN_FLUSH_TIME)
			pmadapter->flush_time_ac_vi_vo =
				misc->param.flush_time.flush_time_ac_vi_vo;
	}
	misc->param.flush_time.flush_time_ac_be_bk =
		pmadapter->flush_time_ac_be_bk;
	misc->param.flush_time.flush_time_ac_vi_vo =
		pmadapter->flush_time_ac_vi_vo;
	PRINTM(MCMND, "flush time: BE/BK=%d ms  VI/VO=%d ms\n",
	       pmadapter->flush_time_ac_be_bk, pmadapter->flush_time_ac_vi_vo);
	LEAVE();
	return ret;
}

/**
 *  @brief configure edmac parameters
 *
 *  @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_edmac_cfg(pmlan_adapter pmadapter,
				      pmlan_ioctl_req pioctl_req)
{
	mlan_ds_misc_cfg *misc = MNULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;
	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];

	ENTER();

	misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;

	if (MLAN_ACT_SET == pioctl_req->action) {
		misc->param.edmac_cfg.ed_ctrl_2g = 0x1;
		misc->param.edmac_cfg.ed_offset_2g = 0x8;
		misc->param.edmac_cfg.ed_ctrl_5g = 0x1;
		misc->param.edmac_cfg.ed_offset_5g = 0x8;
		misc->param.edmac_cfg.ed_bitmap_txq_lock = 0x1e00FF;
	} else {
		misc->param.edmac_cfg.ed_ctrl_2g = 0x0;
		misc->param.edmac_cfg.ed_ctrl_5g = 0x0;
	}

	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_EDMAC_CFG,
			       HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
			       (t_void *)&misc->param.edmac_cfg);

	if (ret == MLAN_STATUS_SUCCESS)
		ret = MLAN_STATUS_PENDING;

	LEAVE();
	return ret;
}

/**
 *  @brief Add 2 variables securely, to prevent overflow.
 *
 *  @param datain	Pointer to 1st variable
 *  @param add		2nd variable value to add to 1st variable
 *  @param dataout	Pointer to variable where sum is to be stored
 *  @param type		Datatype of 1st and 2nd variable
 *
 *  @return			MTRUE if success or MFALSE if overflow error
 */
t_bool wlan_secure_add(t_void *datain, t_s32 add, t_void *dataout,
		       data_type type)
{
	t_bool status = MTRUE;

	switch (type) {
	case TYPE_SINT8:
		if (add > SINT8_MAX || *(t_s8 *)datain > SINT8_MAX - add)
			goto fail;
		else
			*(t_s8 *)dataout = *(t_s8 *)datain + add;
		break;

	case TYPE_UINT8:
		if (add > UINT8_MAX || *(t_u8 *)datain > UINT8_MAX - add)
			goto fail;
		else
			*(t_u8 *)dataout = *(t_u8 *)datain + add;
		break;

	case TYPE_SINT16:
		if (add > SINT16_MAX || *(t_s16 *)datain > SINT16_MAX - add)
			goto fail;
		else
			*(t_s16 *)dataout = *(t_s16 *)datain + add;
		break;

	case TYPE_UINT16:
		if (add > UINT16_MAX || *(t_u16 *)datain > UINT16_MAX - add)
			goto fail;
		else
			*(t_u16 *)dataout = *(t_u16 *)datain + add;
		break;

	case TYPE_SINT32:
		if (*(t_s32 *)datain > SINT32_MAX - add)
			goto fail;
		else
			*(t_s32 *)dataout = *(t_s32 *)datain + add;
		break;

	case TYPE_UINT32:
		if (*(t_u32 *)datain > UINT32_MAX - add)
			goto fail;
		else
			*(t_u32 *)dataout = *(t_u32 *)datain + add;
		break;

	case TYPE_SINT64:
		if (*(t_s64 *)datain > SINT64_MAX - add)
			goto fail;
		else
			*(t_s64 *)dataout = *(t_s64 *)datain + add;
		break;

	case TYPE_UINT64:
		if (*(t_u64 *)datain > UINT64_MAX - add)
			goto fail;
		else
			*(t_u64 *)dataout = *(t_u64 *)datain + add;
		break;

	case TYPE_PTR:
		if (*(t_ptr *)datain > PTR_MAX - add)
			goto fail;
		else
			*(t_ptr *)dataout = *(t_ptr *)datain + add;
		break;

	default:
		status = MFALSE;
		break;
	}
ret:
	return status;

fail:
	status = MFALSE;
	goto ret;
}

/**
 *  @brief Subtract 2 variables securely, to prevent underflow.
 *
 *  @param datain	Pointer to 1st variable
 *  @param add		2nd variable value to subtract from 1st variable
 *  @param dataout	Pointer to variable where diff is to be stored
 *  @param type		Datatype of 1st and 2nd variable
 *
 *  @return			MTRUE if success or MFALSE if underflow error
 */
t_bool wlan_secure_sub(t_void *datain, t_s32 sub, t_void *dataout,
		       data_type type)
{
	t_u8 status = MTRUE;

	switch (type) {
	case TYPE_SINT8:
		if (*(t_s8 *)datain >= (t_s8)SINT8_MIN + sub)
			*(t_s8 *)dataout = *(t_s8 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_UINT8:
		if (*(t_u8 *)datain >= sub)
			*(t_u8 *)dataout = *(t_u8 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_SINT16:
		if (*(t_s16 *)datain >= (t_s16)SINT16_MIN + sub)
			*(t_s16 *)dataout = *(t_s16 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_UINT16:
		if (*(t_u16 *)datain >= sub)
			*(t_u16 *)dataout = *(t_u16 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_SINT32:
		if (*(t_s32 *)datain >= (t_s32)SINT32_MIN + sub)
			*(t_s32 *)dataout = *(t_s32 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_UINT32:
		if (*(t_u32 *)datain >= sub)
			*(t_u32 *)dataout = *(t_u32 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_SINT64:
		if (*(t_s64 *)datain >= (t_s64)SINT64_MIN + sub)
			*(t_s64 *)dataout = *(t_s64 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_UINT64:
		if (*(t_u64 *)datain >= sub)
			*(t_u64 *)dataout = *(t_u64 *)datain - sub;
		else
			goto fail;
		break;

	case TYPE_PTR:
		if (*(t_ptr *)datain >= sub)
			*(t_ptr *)dataout = *(t_ptr *)datain - sub;
		else
			goto fail;
		break;

	default:
		status = MFALSE;
		break;
	}
ret:
	return status;

fail:
	status = MFALSE;
	goto ret;
}