
/** @file  moal_eth_ioctl.c
 *
 * @brief This file contains private ioctl functions
 *
 *
 * Copyright 2014-2022 NXP
 *
 * NXP CONFIDENTIAL
 * The source code contained or described herein and all documents related to
 * the source code (Materials) are owned by NXP, its
 * suppliers and/or its licensors. Title to the Materials remains with NXP,
 * its suppliers and/or its licensors. The Materials contain
 * trade secrets and proprietary and confidential information of NXP, its
 * suppliers and/or its licensors. The Materials are protected by worldwide
 * copyright and trade secret laws and treaty provisions. No part of the
 * Materials may be used, copied, reproduced, modified, published, uploaded,
 * posted, transmitted, distributed, or disclosed in any way without NXP's prior
 * express written permission.
 *
 * No license under any patent, copyright, trade secret or other intellectual
 * property right is granted to or conferred upon you by disclosure or delivery
 * of the Materials, either expressly, by implication, inducement, estoppel or
 * otherwise. Any license under such intellectual property rights must be
 * express and approved by NXP in writing.
 *
 *  Alternatively, this software may be distributed under the terms of GPL v2.
 *  SPDX-License-Identifier:    GPL-2.0
 *
 */

/************************************************************************
Change log:
    01/05/2012: initial version
************************************************************************/

#include "moal_main.h"
#include "moal_eth_ioctl.h"
#include "mlan_ioctl.h"
#if defined(STA_WEXT) || defined(UAP_WEXT)
#include "moal_priv.h"
#endif

#if defined(STA_CFG80211) || defined(UAP_CFG80211)
#include "moal_cfg80211.h"
#endif
#ifdef UAP_SUPPORT
#include "moal_uap.h"
#endif
#ifdef USB
#include "moal_usb.h"
#endif
#ifdef SDIO
#include "moal_sdio.h"
#endif
#ifdef PCIE
#include "moal_pcie.h"
#endif
#ifdef STA_CFG80211
#include "moal_sta_cfg80211.h"
#endif
#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
#include "moal_cfg80211_util.h"
#endif
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
#include <linux/compat.h>
#endif

#define CMD_BUF_LEN 4096

/********************************************************
			Local Variables
********************************************************/

/** Bands supported in Infra mode */
static t_u16 SupportedInfraBand[] = {
	BAND_B,
	BAND_B | BAND_G,
	BAND_G,
	BAND_GN,
	BAND_B | BAND_G | BAND_GN,
	BAND_G | BAND_GN,
	BAND_A,
	BAND_B | BAND_A,
	BAND_B | BAND_G | BAND_A,
	BAND_G | BAND_A,
	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
	BAND_A | BAND_G | BAND_AN | BAND_GN,
	BAND_A | BAND_AN,
	BAND_GN | BAND_GAC,
	BAND_B | BAND_G | BAND_GN | BAND_GAC,
	BAND_G | BAND_GN | BAND_GAC,
	BAND_GN | BAND_GAC | BAND_GAX,
	BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
	BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC,
	BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
	BAND_A | BAND_AN | BAND_AAC,
	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC |
		BAND_AAX,
	BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
	BAND_A | BAND_AN | BAND_AAC | BAND_AAX,
};

/** Bands supported in Ad-Hoc mode */
static t_u16 SupportedAdhocBand[] = {
	BAND_B,
	BAND_B | BAND_G,
	BAND_G,
	BAND_A,
};

/********************************************************
			Global Variables
********************************************************/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
#ifdef UAP_SUPPORT
/** Network device handlers for uAP */
extern const struct net_device_ops woal_uap_netdev_ops;
#endif
#ifdef STA_SUPPORT
/** Network device handlers for STA */
extern const struct net_device_ops woal_netdev_ops;
#endif
#endif

/********************************************************
			Global Functions
********************************************************/
/**
 * @brief Parse a string to extract numerical arguments
 *
 * @param pos           Pointer to the arguments string
 * @param data          Pointer to the arguments buffer
 * @param datalen       Length of the arguments buffer
 * @param user_data_len Pointer to the number of arguments extracted
 *
 * @return              MLAN_STATUS_SUCCESS
 */
mlan_status parse_arguments(t_u8 *pos, int *data, int datalen,
			    int *user_data_len)
{
	int i, j, k;
	char cdata[10];
	int is_hex = 0;

	if (strlen(pos) == 0) {
		*user_data_len = 0;
		return MLAN_STATUS_SUCCESS;
	}

	memset(cdata, 0, sizeof(cdata));
	for (i = 0, j = 0, k = 0; i <= (int)strlen(pos); i++) {
		if ((k == 0) && (i <= (int)(strlen(pos) - 2))) {
			if ((pos[i] == '0') && (pos[i + 1] == 'x')) {
				is_hex = 1;
				i = i + 2;
			}
		}
		if (pos[i] == '\0' || pos[i] == ' ') {
			if (j >= datalen) {
				j++;
				break;
			}
			if (is_hex) {
				data[j] = woal_atox(cdata);
				is_hex = 0;
			} else {
				if (woal_atoi(&data[j], cdata) !=
				    MLAN_STATUS_SUCCESS)
					;
			}
			j++;
			k = 0;
			memset(cdata, 0, sizeof(cdata));
			if (pos[i] == '\0')
				break;
		} else {
			if (k >= (int)sizeof(cdata)) {
				PRINTM(MERROR, "Invalid numerical arguments\n");
				break;
			}
			cdata[k] = pos[i];
			k++;
		}
	}

	*user_data_len = j;
	return MLAN_STATUS_SUCCESS;
}

/********************************************************
			Local Functions
********************************************************/

#if defined(STA_CFG80211) && defined(UAP_CFG80211)
/**
 *  @brief Set wps & p2p ie in AP mode
 *
 *  @param priv         Pointer to priv stucture
 *  @param ie           Pointer to ies data
 *  @param len          Length of data
 *
 *  @return             MLAN_STATUS_SUCCESS -- success, otherwise fail
 */
mlan_status woal_set_ap_wps_p2p_ie(moal_private *priv, t_u8 *ie, size_t len)
{
	mlan_status ret = MLAN_STATUS_SUCCESS;
	t_u8 *pos = ie;
	int ie_len;

	ENTER();

	ie_len = len - 2;
	if (ie_len <= 0) {
		PRINTM(MERROR, "IE len error: %d\n", ie_len);
		ret = -EFAULT;
		goto done;
	}

	/* Android cmd format:
	 * "SET_AP_WPS_P2P_IE 1"  -- beacon IE
	 * "SET_AP_WPS_P2P_IE 2"  -- proberesp IE
	 * "SET_AP_WPS_P2P_IE 4"  -- assocresp IE
	 */
	if (*pos == '1') {
		/* set the beacon wps/p2p ies */
		pos += 2;
		if (MLAN_STATUS_SUCCESS !=
		    woal_cfg80211_mgmt_frame_ie(
			    priv, pos, ie_len, NULL, 0, NULL, 0, NULL, 0,
			    MGMT_MASK_BEACON_WPS_P2P, MOAL_IOCTL_WAIT)) {
			PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
			ret = -EFAULT;
			goto done;
		}
	} else if (*pos == '2') {
		/* set the probe resp ies */
		pos += 2;
		if (MLAN_STATUS_SUCCESS !=
		    woal_cfg80211_mgmt_frame_ie(
			    priv, NULL, 0, pos, ie_len, NULL, 0, NULL, 0,
			    MGMT_MASK_PROBE_RESP, MOAL_IOCTL_WAIT)) {
			PRINTM(MERROR, "Failed to set probe resp ie\n");
			ret = -EFAULT;
			goto done;
		}
	} else if (*pos == '4') {
		/* set the assoc resp ies */
		pos += 2;
		if (MLAN_STATUS_SUCCESS !=
		    woal_cfg80211_mgmt_frame_ie(
			    priv, NULL, 0, NULL, 0, pos, ie_len, NULL, 0,
			    MGMT_MASK_ASSOC_RESP, MOAL_IOCTL_WAIT)) {
			PRINTM(MERROR, "Failed to set assoc resp ie\n");
			ret = -EFAULT;
			goto done;
		}
	}

done:
	LEAVE();
	return ret;
}
#endif

#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
/**
 *  @brief Set miracast mode
 *
 *  @param priv         Pointer to priv stucture
 *  @param pdata        Pointer to cmd buffer
 *  @param len          Length of data
 *
 *  @return             MLAN_STATUS_SUCCESS -- success, otherwise fail
 */
static mlan_status woal_set_miracast_mode(moal_private *priv, t_u8 *pdata,
					  size_t len)
{
	mlan_status ret = MLAN_STATUS_SUCCESS;
	t_u8 *pos = pdata;

	ENTER();
	if (!pos || (len == 0)) {
		PRINTM(MERROR, "%s: Null buf!\n", __func__);
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}
	while (!isdigit(*pos) && --len > 0)
		pos++;
	switch (*pos) {
	case '0':
		/* disable miracast mode */
		priv->phandle->miracast_mode = 0;
		break;
	case '1':
		/* Source */
		priv->phandle->miracast_mode = 1;
		break;
	case '2':
		/* Sink */
		priv->phandle->miracast_mode = 2;
		break;
	default:
		PRINTM(MERROR, "%s: Unknown miracast mode (%c)\n",
		       priv->netdev->name, *pos);
		ret = MLAN_STATUS_FAILURE;
		break;
	}
done:
	LEAVE();
	return ret;
}
#endif
#endif

/**
 *  @brief Get Driver Version
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_get_priv_driver_version(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	int len = 0, ret = -1;
	char buf[MLAN_MAX_VER_STR_LEN];

	ENTER();

	if (!respbuf) {
		LEAVE();
		return 0;
	}

	memset(buf, 0, sizeof(buf));

	/* Get version string to local buffer */
	woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
	len = strlen(buf);

	if (len) {
		/* Copy back the retrieved version string */
		PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
		ret = MIN(len, (int)(respbuflen - 1));
		moal_memcpy_ext(priv->phandle, respbuf, buf, ret,
				respbuflen - 1);
	} else {
		ret = -1;
		PRINTM(MERROR, "Get version failed!\n");
	}

	LEAVE();
	return ret;
}
/**
 *  @brief Hostcmd interface from application
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *  @param wait_option  Wait option
 *
 *  @return             Number of bytes written, negative for failure.
 */
int woal_priv_hostcmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
		      t_u8 wait_option)
{
	int ret = 0;
	t_u8 *data_ptr;
	t_u32 buf_len = 0;
	HostCmd_Header cmd_header;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD));
	buf_len = *((t_u32 *)data_ptr);
	moal_memcpy_ext(priv->phandle, &cmd_header, data_ptr + sizeof(buf_len),
			sizeof(HostCmd_Header), sizeof(HostCmd_Header));

	PRINTM(MINFO, "Host command len = %d\n",
	       woal_le16_to_cpu(cmd_header.size));
	if (woal_le16_to_cpu(cmd_header.size) > MRVDRV_SIZE_OF_CMD_BUFFER) {
		LEAVE();
		return -EINVAL;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto error;
	}
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_SET;
	misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
	/* get the whole command */
	moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd,
			data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.len,
			MRVDRV_SIZE_OF_CMD_BUFFER);

	status = woal_request_ioctl(priv, req, wait_option);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto error;
	}
	ret = misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_NXP) +
	      strlen(PRIV_CMD_HOSTCMD);
	if (ret > (int)respbuflen) {
		ret = -EFAULT;
		goto error;
	}
	moal_memcpy_ext(
		priv->phandle, data_ptr + sizeof(buf_len),
		misc_cfg->param.hostcmd.cmd, misc_cfg->param.hostcmd.len,
		respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD) +
			      sizeof(buf_len)));
	moal_memcpy_ext(priv->phandle, data_ptr,
			(t_u8 *)&misc_cfg->param.hostcmd.len, sizeof(t_u32),
			sizeof(t_u32));

error:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               configure 11ax HE capability or HE operation
 *
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param len          length used
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_setget_priv_11axcmdcfg(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen, t_u8 wait_option)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11ax_cmd_cfg *cfg = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int header_len = 0, user_data_len = 0;
	int data[4] = {0};
	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cmd_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11AX_CFG;
	req->action = MLAN_ACT_SET;

	cfg = (mlan_ds_11ax_cmd_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_11AX_CMD_CFG;

	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);
	PRINTM(MINFO, "data_len=%d,data=%d,%d,%d\n", user_data_len, data[0],
	       data[1], data[2]);

	if (user_data_len > 4 || user_data_len == 0) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	} else if (user_data_len == 1) {
		req->action = MLAN_ACT_GET;
	}

	switch (data[0]) {
	case MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET:
		cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
		cfg->param.sr_cfg.type = MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID;
		cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_obss_pd_offset);
		cfg->param.sr_cfg.param.obss_pd_offset.offset[0] = data[1];
		cfg->param.sr_cfg.param.obss_pd_offset.offset[1] = data[2];
		break;
	case MLAN_11AXCMD_CFG_ID_SR_ENABLE:
		cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
		cfg->param.sr_cfg.type = MRVL_DOT11AX_ENABLE_SR_TLV_ID;
		cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_sr_control);
		cfg->param.sr_cfg.param.sr_control.control = data[1];
		break;
	case MLAN_11AXCMD_CFG_ID_BEAM_CHANGE:
		cfg->sub_id = MLAN_11AXCMD_BEAM_SUBID;
		cfg->param.beam_cfg.value = data[1];
		break;
	case MLAN_11AXCMD_CFG_ID_HTC_ENABLE:
		cfg->sub_id = MLAN_11AXCMD_HTC_SUBID;
		cfg->param.htc_cfg.value = data[1];
		break;
	case MLAN_11AXCMD_CFG_ID_TXOP_RTS:
		cfg->sub_id = MLAN_11AXCMD_TXOPRTS_SUBID;
		cfg->param.txop_cfg.rts_thres = data[1];
		break;
	case MLAN_11AXCMD_CFG_ID_TX_OMI:
		cfg->sub_id = MLAN_11AXCMD_TXOMI_SUBID;
		cfg->param.txomi_cfg.omi = data[1];
		cfg->param.txomi_cfg.tx_option = data[2];
		cfg->param.txomi_cfg.num_data_pkts = data[3];
		break;
	case MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME:
		cfg->sub_id = MLAN_11AXCMD_OBSS_TOLTIME_SUBID;
		cfg->param.toltime_cfg.tol_time = data[1];
		break;
	default:
		PRINTM(MERROR, "unknown 11axcmd\n");
		ret = -EFAULT;
		goto done;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf, &req->action,
			sizeof(req->action), sizeof(req->action));
	respbuf += sizeof(req->action);

	cfg = (mlan_ds_11ax_cmd_cfg *)respbuf;
	moal_memcpy_ext(priv->phandle, cfg, req->pbuf,
			sizeof(mlan_ds_11ax_cmd_cfg), respbuflen);

	ret = sizeof(req->action) + sizeof(mlan_ds_11ax_cmd_cfg);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief             Set/get range ext mode
 *
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param len          length used
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_setget_priv_range_ext(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[1];
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RANGE_EXT);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_RANGE_EXT;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid Parameter\n");
			ret = -EFAULT;
			goto done;
		}
		if (data[0] < 0 || data[0] > 2) {
			PRINTM(MERROR,
			       "Invalid Parameter: range_ext mode 0-2\n");
			ret = -EFAULT;
			goto done;
		}
		misc->param.range_ext_mode = (t_u8)data[0];
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.range_ext_mode;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Custom IE setting
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_customie(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int ret = 0;
	t_u8 *data_ptr;
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ds_misc_custom_ie *pcustom_ie = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE));

	pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((pcustom_ie->len == 0) ||
	    (pcustom_ie->len == sizeof(pcustom_ie->ie_data_list[0].ie_index)))
		ioctl_req->action = MLAN_ACT_GET;
	else
		ioctl_req->action = MLAN_ACT_SET;

	moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, pcustom_ie,
			sizeof(mlan_ds_misc_custom_ie),
			sizeof(mlan_ds_misc_custom_ie));

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
	moal_memcpy_ext(priv->phandle, pcustom_ie, &misc->param.cust_ie,
			sizeof(mlan_ds_misc_custom_ie),
			respbuflen -
				(strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE)));
	ret = sizeof(mlan_ds_misc_custom_ie);
	if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
		/* send a separate error code to indicate error from driver */
		ret = EFAULT;
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get Band and Adhoc-band setting
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_bandcfg(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int ret = 0;
	unsigned int i;
	int data[3];
	int user_data_len = 0;
	t_u32 infra_band = 0;
	t_u32 adhoc_band = 0;
	t_u32 adhoc_channel = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_radio_cfg *radio_cfg = NULL;
	mlan_ds_band_cfg *band_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BANDCFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_BANDCFG),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		LEAVE();
		return -EINVAL;
	}

	if (user_data_len > 0) {
		if (priv->media_connected == MTRUE) {
			LEAVE();
			return -EOPNOTSUPP;
		}
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto error;
	}
	radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
	radio_cfg->sub_command = MLAN_OID_BAND_CFG;
	req->req_id = MLAN_IOCTL_RADIO_CFG;

	if (user_data_len == 0) {
		/* Get config_bands, adhoc_start_band and adhoc_channel values
		 * from MLAN
		 */
		req->action = MLAN_ACT_GET;
	} else {
		/* To support only <b/bg/bgn/n/aac/gac> */
		infra_band = data[0];

		for (i = 0; i < (sizeof(SupportedInfraBand) /
				 sizeof(SupportedInfraBand[0]));
		     i++)
			if (infra_band == SupportedInfraBand[i])
				break;
		if (i == sizeof(SupportedInfraBand)) {
			ret = -EINVAL;
			goto error;
		}

		/* Set Adhoc band */
		if (user_data_len >= 2) {
			adhoc_band = data[1];
			for (i = 0; i < (sizeof(SupportedAdhocBand) /
					 sizeof(SupportedAdhocBand[0]));
			     i++)
				if (adhoc_band == SupportedAdhocBand[i])
					break;
			if (i == sizeof(SupportedAdhocBand)) {
				ret = -EINVAL;
				goto error;
			}
		}

		/* Set Adhoc channel */
		if (user_data_len >= 3) {
			adhoc_channel = data[2];
			if (adhoc_channel == 0) {
				/* Check if specified adhoc channel is non-zero
				 */
				ret = -EINVAL;
				goto error;
			}
		}
		/* Set config_bands and adhoc_start_band values to MLAN */
		req->action = MLAN_ACT_SET;
		radio_cfg->param.band_cfg.config_bands = infra_band;
		radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
		radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto error;
	}

	band_cfg = (mlan_ds_band_cfg *)respbuf;

	moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg,
			sizeof(mlan_ds_band_cfg), respbuflen);

	ret = sizeof(mlan_ds_band_cfg);

error:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get 11n configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_httxcfg(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	t_u32 data[2];
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTTXCFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_HTTXCFG),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 2) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if (user_data_len == 0) {
		/* Get 11n tx parameters from MLAN */
		req->action = MLAN_ACT_GET;
		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
	} else {
		cfg_11n->param.tx_cfg.httxcap = data[0];
		PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
		if (user_data_len == 2) {
			if (data[1] != BAND_SELECT_BG &&
			    data[1] != BAND_SELECT_A &&
			    data[1] != BAND_SELECT_BOTH) {
				PRINTM(MERROR, "Invalid band selection\n");
				ret = -EINVAL;
				goto done;
			}
			cfg_11n->param.tx_cfg.misc_cfg = data[1];
			PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
		}
		/* Update 11n tx parameters in MLAN */
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	data[0] = cfg_11n->param.tx_cfg.httxcap;
	PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);

	if (req->action == MLAN_ACT_GET) {
		cfg_11n->param.tx_cfg.httxcap = 0;
		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
		data[1] = cfg_11n->param.tx_cfg.httxcap;
		PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
	}

	moal_memcpy_ext(priv->phandle, respbuf, data, sizeof(data), respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get 11n capability information
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_htcapinfo(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int data[2];
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	woal_ht_cap_info *ht_cap = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTCAPINFO))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_HTCAPINFO),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 2) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if (user_data_len == 0) {
		/* Get 11n tx parameters from MLAN */
		req->action = MLAN_ACT_GET;
		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
	} else {
		cfg_11n->param.htcap_cfg.htcap = data[0];
		PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
		if (user_data_len == 2) {
			if (data[1] != BAND_SELECT_BG &&
			    data[1] != BAND_SELECT_A &&
			    data[1] != BAND_SELECT_BOTH) {
				PRINTM(MERROR, "Invalid band selection\n");
				ret = -EINVAL;
				goto done;
			}
			cfg_11n->param.htcap_cfg.misc_cfg = data[1];
			PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
		}
		/* Update 11n tx parameters in MLAN */
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	data[0] = cfg_11n->param.htcap_cfg.htcap;
	PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]);

	if (req->action == MLAN_ACT_GET) {
		cfg_11n->param.htcap_cfg.htcap = 0;
		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
		data[1] = cfg_11n->param.htcap_cfg.htcap;
		PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]);
	}

	ht_cap = (woal_ht_cap_info *)respbuf;
	ht_cap->ht_cap_info_bg = data[0];
	ht_cap->ht_cap_info_a = data[1];
	ret = sizeof(woal_ht_cap_info);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get add BA parameters
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_addbapara(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int data[5];
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	woal_addba *addba = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAPARA))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_ADDBAPARA),
				data, ARRAY_SIZE(data), &user_data_len);

		if (user_data_len != ARRAY_SIZE(data)) {
			PRINTM(MERROR, "Invalid number of arguments\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
			PRINTM(MERROR, "Incorrect addba timeout value.\n");
			ret = -EFAULT;
			goto done;
		}
		if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE ||
		    data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
			PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
			ret = -EFAULT;
			goto done;
		}
		if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
			PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
			ret = -EFAULT;
			goto done;
		}
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if (user_data_len == 0) {
		/* Get add BA parameters from MLAN */
		req->action = MLAN_ACT_GET;
	} else {
		cfg_11n->param.addba_param.timeout = data[0];
		cfg_11n->param.addba_param.txwinsize = data[1];
		cfg_11n->param.addba_param.rxwinsize = data[2];
		cfg_11n->param.addba_param.txamsdu = data[3];
		cfg_11n->param.addba_param.rxamsdu = data[4];
		PRINTM(MINFO,
		       "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
		       data[0], data[1], data[2], data[3], data[4]);
		/* Update add BA parameters in MLAN */
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	addba = (woal_addba *)respbuf;

	addba->time_out = cfg_11n->param.addba_param.timeout;
	addba->tx_win_size = cfg_11n->param.addba_param.txwinsize;
	addba->rx_win_size = cfg_11n->param.addba_param.rxwinsize;
	addba->tx_amsdu = cfg_11n->param.addba_param.txamsdu;
	addba->rx_amsdu = cfg_11n->param.addba_param.rxamsdu;
	PRINTM(MINFO,
	       "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
	       addba->time_out, addba->tx_win_size, addba->rx_win_size,
	       addba->tx_amsdu, addba->rx_amsdu);

	ret = sizeof(woal_addba);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Delete selective BA based on parameters
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_delba(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	t_u32 data[2] = {0xFF, 0xFF};
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_ds_11n_delba *del_ba = NULL;
	int ret = 0;
	int user_data_len = 0;
	int header_len = 0;
	t_u8 *mac_pos = NULL;
	t_u8 peer_mac[ETH_ALEN] = {0};
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELBA);

	if ((int)strlen(respbuf) == header_len) {
		/* Incorrect number of arguments */
		PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
		ret = -EINVAL;
		goto done;
	}

	mac_pos = strstr(respbuf + header_len, " ");
	if (mac_pos)
		mac_pos = strstr(mac_pos + 1, " ");
	if (mac_pos) {
#define MAC_STRING_LENGTH 17
		if (strlen(mac_pos + 1) != MAC_STRING_LENGTH) {
			PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
			ret = -EINVAL;
			goto done;
		}
		woal_mac2u8(peer_mac, mac_pos + 1);
		*mac_pos = '\0';
	}

	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (mac_pos)
		user_data_len++;

	if (user_data_len > 3 || (!(data[0] & (DELBA_TX | DELBA_RX))) ||
	    (data[1] != DELBA_ALL_TIDS && !(data[1] <= 7))) {
		/* Incorrect number of arguments */
		PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	req->req_id = MLAN_IOCTL_11N_CFG;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_DELBA;

	del_ba = &cfg_11n->param.del_ba;
	memset(del_ba, 0, sizeof(mlan_ds_11n_delba));
	del_ba->direction = (t_u8)data[0];
	del_ba->tid = DELBA_ALL_TIDS;
	if (user_data_len > 1)
		del_ba->tid = (t_u8)data[1];
	if (user_data_len > 2)
		moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, peer_mac,
				ETH_ALEN, MLAN_MAC_ADDR_LENGTH);

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);

	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	ret = snprintf(respbuf, CMD_BUF_LEN, "OK. BA deleted successfully.\n") +
	      1;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get the reject addba requst conditions
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_rejectaddbareq(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	t_u32 data[1];
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_REJECTADDBAREQ))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_REJECTADDBAREQ),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_REJECT_ADDBA_REQ;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if (user_data_len == 0) {
		/* Get the reject addba req conditions*/
		req->action = MLAN_ACT_GET;
	} else {
		/* Set the reject addba req conditions */
		cfg_11n->param.reject_addba_req.conditions = data[0];
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (req->action == MLAN_ACT_GET) {
		snprintf(respbuf, CMD_BUF_LEN, "0x%x",
			 cfg_11n->param.reject_addba_req.conditions);
		ret = strlen(respbuf) + 1;
	} else {
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get the addba reject setting
 *
 *  @param priv         A pointer to moal_private structure
 *  @param action       Action set or get
 *  @param addba_reject A pointer to addba_reject array.
 *
 *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
 * otherwise fail
 */
static mlan_status woal_ioctl_addba_reject(moal_private *priv, t_u32 action,
					   t_u8 *addba_reject)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
	req->req_id = MLAN_IOCTL_11N_CFG;

	req->action = action;
	if (action == MLAN_ACT_SET)
		moal_memcpy_ext(priv->phandle, cfg_11n->param.addba_reject,
				addba_reject,
				sizeof(cfg_11n->param.addba_reject),
				sizeof(cfg_11n->param.addba_reject));
	/* Send IOCTL request to MLAN */
	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (ret != MLAN_STATUS_SUCCESS)
		goto done;
	if (action == MLAN_ACT_GET)
		moal_memcpy_ext(priv->phandle, addba_reject,
				cfg_11n->param.addba_reject,
				sizeof(cfg_11n->param.addba_reject),
				MAX_NUM_TID);
done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get addba prio_tbl
 *
 *  @param priv         A pointer to moal_private structure
 *  @param action       Action set or get
 *  @param aggr_prio_tbl  A pointer to mlan_ds_11n_aggr_prio_tbl.
 *
 *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
 * otherwise fail
 */
mlan_status woal_ioctl_aggr_prio_tbl(moal_private *priv, t_u32 action,
				     mlan_ds_11n_aggr_prio_tbl *aggr_prio_tbl)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
	req->req_id = MLAN_IOCTL_11N_CFG;

	req->action = action;
	if (action == MLAN_ACT_SET)
		moal_memcpy_ext(priv->phandle, &cfg_11n->param.aggr_prio_tbl,
				aggr_prio_tbl,
				sizeof(mlan_ds_11n_aggr_prio_tbl),
				sizeof(mlan_ds_11n_aggr_prio_tbl));
	/* Send IOCTL request to MLAN */
	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (ret != MLAN_STATUS_SUCCESS)
		goto done;
	if (action == MLAN_ACT_GET)
		moal_memcpy_ext(priv->phandle, aggr_prio_tbl,
				&cfg_11n->param.aggr_prio_tbl,
				sizeof(mlan_ds_11n_aggr_prio_tbl),
				sizeof(mlan_ds_11n_aggr_prio_tbl));
done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get addba_param
 *
 *  @param priv         A pointer to moal_private structure
 *  @param action       Action set or get
 *  @param addba_param  A pointer to mlan_ds_11n_addba_param.
 *
 *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
 * otherwise fail
 */
static mlan_status woal_ioctl_addba_param(moal_private *priv, t_u32 action,
					  mlan_ds_11n_addba_param *addba_param)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
	req->req_id = MLAN_IOCTL_11N_CFG;

	req->action = action;
	if (action == MLAN_ACT_SET)
		moal_memcpy_ext(priv->phandle, &cfg_11n->param.addba_param,
				addba_param, sizeof(mlan_ds_11n_addba_param),
				sizeof(mlan_ds_11n_addba_param));
	/* Send IOCTL request to MLAN */
	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (ret != MLAN_STATUS_SUCCESS)
		goto done;
	if (action == MLAN_ACT_GET)
		moal_memcpy_ext(priv->phandle, addba_param,
				&cfg_11n->param.addba_param,
				sizeof(mlan_ds_11n_addba_param),
				sizeof(mlan_ds_11n_addba_param));
done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *   @brief Configuring rx block-ack window size
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise failure
 */
static int woal_set_rx_ba_winsize(moal_private *priv, t_u8 *respbuf,
				  int respbuflen)
{
	int data[2];
	t_u8 addba_reject[MAX_NUM_TID];
	mlan_ds_11n_addba_param addba_param;
	int ret = 0;
	int user_data_len = 0;

	ENTER();

	memset((char *)data, 0, sizeof(data));
	if (respbuf && strlen(respbuf) > 0)
		parse_arguments(respbuf, data, ARRAY_SIZE(data),
				&user_data_len);

	if (user_data_len != 2) {
		PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
		ret = -EINVAL;
		goto done;
	}
	if (data[0] > 7 || data[0] < 0) {
		PRINTM(MERROR, "Invalid tid %d\n", data[0]);
		ret = -EINVAL;
		goto done;
	}
	if (data[1] < 0) {
		PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
		ret = -EINVAL;
		goto done;
	}
	memset(addba_reject, 0, sizeof(addba_reject));
	if (MLAN_STATUS_SUCCESS !=
	    woal_ioctl_addba_reject(priv, MLAN_ACT_GET, addba_reject)) {
		ret = -EFAULT;
		goto done;
	}
	/* disable tx ba */
	if (data[1] == 0) {
		addba_reject[data[0]] = MTRUE;
		if (MLAN_STATUS_SUCCESS !=
		    woal_ioctl_addba_reject(priv, MLAN_ACT_SET, addba_reject))
			ret = -EFAULT;
	} else {
		if (addba_reject[data[0]] == MTRUE) {
			addba_reject[data[0]] = MFALSE;
			if (MLAN_STATUS_SUCCESS !=
			    woal_ioctl_addba_reject(priv, MLAN_ACT_SET,
						    addba_reject)) {
				ret = -EFAULT;
				goto done;
			}
		}
		memset(&addba_param, 0, sizeof(addba_param));
		if (MLAN_STATUS_SUCCESS !=
		    woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
			ret = -EFAULT;
			goto done;
		}
		if (data[1] != (int)addba_param.rxwinsize) {
			addba_param.rxwinsize = data[1];
			if (MLAN_STATUS_SUCCESS !=
			    woal_ioctl_addba_param(priv, MLAN_ACT_SET,
						   &addba_param))
				ret = -EFAULT;
		}
	}
done:
	LEAVE();
	return ret;
}
/**
 *   @brief Configuring trx block-ack window size
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise failure
 */
static int woal_set_tx_ba_winsize(moal_private *priv, t_u8 *respbuf,
				  int respbuflen)
{
	int data[2];
	mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
	mlan_ds_11n_addba_param addba_param;
	t_u8 tos_to_tid_inv[] = {0x02, 0x00, 0x01, 0x03,
				 0x04, 0x05, 0x06, 0x07};
	int ret = 0;
	int user_data_len = 0;

	ENTER();

	memset((char *)data, 0, sizeof(data));
	if (respbuf && strlen(respbuf) > 0)
		parse_arguments(respbuf, data, ARRAY_SIZE(data),
				&user_data_len);

	if (user_data_len != 2) {
		PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
		ret = -EINVAL;
		goto done;
	}
	if (data[0] > 7 || data[0] < 0) {
		PRINTM(MERROR, "Invalid tid %d\n", data[0]);
		ret = -EINVAL;
		goto done;
	}
	if (data[1] < 0) {
		PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
		ret = -EINVAL;
		goto done;
	}
	memset(&aggr_prio_tbl, 0, sizeof(aggr_prio_tbl));
	if (MLAN_STATUS_SUCCESS !=
	    woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_GET, &aggr_prio_tbl)) {
		ret = -EFAULT;
		goto done;
	}
	/* disable tx ba */
	if (data[1] == 0) {
		if (aggr_prio_tbl.ampdu[data[0]] != 0xff) {
			aggr_prio_tbl.ampdu[data[0]] = 0xff;
			if (MLAN_STATUS_SUCCESS !=
			    woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
						     &aggr_prio_tbl))
				ret = -EFAULT;
		}
	} else {
		if (aggr_prio_tbl.ampdu[data[0]] == 0xff) {
			aggr_prio_tbl.ampdu[data[0]] = tos_to_tid_inv[data[0]];
			if (MLAN_STATUS_SUCCESS !=
			    woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
						     &aggr_prio_tbl)) {
				ret = -EFAULT;
				goto done;
			}
		}
		memset(&addba_param, 0, sizeof(addba_param));
		if (MLAN_STATUS_SUCCESS !=
		    woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
			ret = -EFAULT;
			goto done;
		}
		if (data[1] != (int)addba_param.txwinsize) {
			addba_param.txwinsize = data[1];
			if (MLAN_STATUS_SUCCESS !=
			    woal_ioctl_addba_param(priv, MLAN_ACT_SET,
						   &addba_param))
				ret = -EFAULT;
		}
	}
done:
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get aggregation priority table configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_aggrpriotbl(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	int data[MAX_NUM_TID * 2], i, j;
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRPRIOTBL))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_AGGRPRIOTBL),
				data, ARRAY_SIZE(data), &user_data_len);

		if (user_data_len != ARRAY_SIZE(data)) {
			PRINTM(MERROR, "Invalid number of arguments\n");
			ret = -EINVAL;
			goto done;
		}
		for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
			if ((data[i] > 7 && data[i] != 0xff) ||
			    (data[i + 1] > 7 && data[i + 1] != 0xff)) {
				PRINTM(MERROR,
				       "Invalid priority, valid value 0-7 or 0xff.\n");
				ret = -EFAULT;
				goto done;
			}
		}
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if (user_data_len == 0) {
		/* Get aggr priority table from MLAN */
		req->action = MLAN_ACT_GET;
	} else {
		for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
			cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
			cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
		}
		/* Update aggr priority table in MLAN */
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	for (i = 0, j = 0; i < (MAX_NUM_TID * 2); i = i + 2, ++j) {
		respbuf[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
		respbuf[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
	}

	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get Add BA reject configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_addbareject(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	int data[MAX_NUM_TID], i;
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAREJECT))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_ADDBAREJECT),
				data, ARRAY_SIZE(data), &user_data_len);

		if (user_data_len != ARRAY_SIZE(data)) {
			PRINTM(MERROR, "Invalid number of arguments\n");
			ret = -EINVAL;
			goto done;
		}
		for (i = 0; i < user_data_len; i++) {
			if (data[i] != 0 && data[i] != 1) {
				PRINTM(MERROR,
				       "addba reject only takes argument as 0 or 1\n");
				ret = -EFAULT;
				goto done;
			}
		}
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if (user_data_len == 0) {
		/* Get add BA reject configuration from MLAN */
		req->action = MLAN_ACT_GET;
	} else {
		for (i = 0; i < user_data_len; i++)
			cfg_11n->param.addba_reject[i] = data[i];
		/* Update add BA reject configuration in MLAN */
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	for (i = 0; i < MAX_NUM_TID; i++)
		respbuf[i] = cfg_11n->param.addba_reject[i];

	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get 11AC configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_vhtcfg(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	int data[6];
	mlan_ioctl_req *req = NULL;
	mlan_ds_11ac_cfg *cfg_11ac = NULL;
	mlan_ds_11ac_vht_cfg *vhtcfg = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG))) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	memset((char *)data, 0, sizeof(data));
	parse_arguments(respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG),
			data, ARRAY_SIZE(data), &user_data_len);

	if ((user_data_len > 6) || (user_data_len < 2)) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
	cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
	req->req_id = MLAN_IOCTL_11AC_CFG;

	/* Band */
	if ((data[0] < 0) || (data[0] > 2)) {
		PRINTM(MERROR, "Invalid band selection\n");
		ret = -EINVAL;
		goto done;
	} else {
		if (data[0] == BAND_SELECT_BOTH) {
			cfg_11ac->param.vht_cfg.band =
				(BAND_SELECT_BG | BAND_SELECT_A);
		} else {
			cfg_11ac->param.vht_cfg.band = data[0];
		}
		PRINTM(MINFO, "GET/SET: vhtcfg band: 0x%x\n", data[0]);
	}

	/* Tx/Rx */
	if ((data[1] <= 0) || (data[1] > 3)) {
		PRINTM(MERROR, "Invalid Tx/Rx selection\n");
		ret = -EINVAL;
		goto done;
	} else {
		cfg_11ac->param.vht_cfg.txrx = data[1];
		PRINTM(MINFO, "GET/SET: vhtcfg txrx: 0x%x\n", data[1]);
	}

	if (user_data_len == 2) {
		/* GET operation */
		if (data[0] == BAND_SELECT_BOTH) {
			/* if get both bands, get BG first */
			cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG;
		}
		if (priv->bss_role == MLAN_BSS_ROLE_UAP)
			cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;

		req->action = MLAN_ACT_GET;
	} else {
		if (user_data_len == 3) {
			PRINTM(MERROR, "Invalid number of arguments\n");
			ret = -EINVAL;
			goto done;
		}
		if (user_data_len >= 4) {
			/* BW cfg */
			if ((data[2] < 0) || (data[2] > 1) ||
			    ((data[2] == 1) && (data[0] & BAND_SELECT_BG))) {
				PRINTM(MERROR, "Invalid BW cfg selection\n");
				ret = -EINVAL;
				goto done;
			} else {
				cfg_11ac->param.vht_cfg.bwcfg = data[2];
				PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n",
				       data[2]);
			}

			cfg_11ac->param.vht_cfg.vht_cap_info = data[3];
			PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n",
			       data[3]);
		}
		if (user_data_len == 4) {
			data[4] = 0xffffffff;
			data[5] = 0xffffffff;
		}
		if (user_data_len == 5) {
			PRINTM(MERROR, "Invalid number of arguments\n");
			ret = -EINVAL;
			goto done;
		}
		if (user_data_len >= 4) {
			cfg_11ac->param.vht_cfg.vht_tx_mcs = data[4];
			cfg_11ac->param.vht_cfg.vht_rx_mcs = data[5];
		}
		/* Update 11AC parameters in MLAN */
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	/* number of vhtcfg entries */
	*respbuf = 1;
	vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1);
	moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
			sizeof(mlan_ds_11ac_vht_cfg), respbuflen - 1);
	ret = 1 + sizeof(mlan_ds_11ac_vht_cfg);

	if ((req->action == MLAN_ACT_GET) && (data[0] == BAND_SELECT_BOTH)) {
		cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
		/* number of vhtcfg entries */
		*respbuf = 2;
		vhtcfg++;
		moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
				sizeof(mlan_ds_11ac_vht_cfg),
				respbuflen - 1 - sizeof(mlan_ds_11ac_vht_cfg));
		ret += sizeof(mlan_ds_11ac_vht_cfg);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get 11AC Operating Mode Notification configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_opermodecfg(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	int data[2];
	mlan_ioctl_req *req = NULL;
	mlan_ds_11ac_cfg *cfg_11ac = NULL;
	mlan_ds_11ac_opermode_cfg *opermodecfg = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	memset((char *)data, 0, sizeof(data));
	parse_arguments(respbuf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_OPERMODECFG),
			data, ARRAY_SIZE(data), &user_data_len);

	if ((user_data_len != 0) && (user_data_len != 2)) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	if (user_data_len == 2) {
		/* Channel width */
		if ((data[0] < 1) || (data[0] > 4)) {
			PRINTM(MERROR, "Invalid channel width: 0x%x\n",
			       data[0]);
			ret = -EINVAL;
			goto done;
		}
		/* nss */
		if ((data[1] < 1) || (data[1] > 8)) {
			PRINTM(MERROR, "Invalid nss: 0x%x\n", data[1]);
			ret = -EINVAL;
			goto done;
		}
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
	cfg_11ac->sub_command = MLAN_OID_11AC_OPERMODE_CFG;
	req->req_id = MLAN_IOCTL_11AC_CFG;

	if (user_data_len == 0) {
		req->action = MLAN_ACT_GET;
	} else {
		req->action = MLAN_ACT_SET;
		cfg_11ac->param.opermode_cfg.bw = data[0];
		cfg_11ac->param.opermode_cfg.nss = data[1];
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	opermodecfg = (mlan_ds_11ac_opermode_cfg *)respbuf;
	moal_memcpy_ext(priv->phandle, opermodecfg,
			&(cfg_11ac->param.opermode_cfg), sizeof(*opermodecfg),
			respbuflen);
	ret = sizeof(*opermodecfg);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get 11AC configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_get_priv_datarate(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_rate *rate = NULL;
	mlan_data_rate *data_rate = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	rate = (mlan_ds_rate *)req->pbuf;
	rate->sub_command = MLAN_OID_GET_DATA_RATE;
	req->req_id = MLAN_IOCTL_RATE;
	req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data_rate = (mlan_data_rate *)respbuf;

	moal_memcpy_ext(priv->phandle, data_rate, &rate->param.data_rate,
			sizeof(mlan_data_rate), respbuflen);

	ret = sizeof(mlan_data_rate);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get tx rate configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	t_u32 data[4];
	mlan_ioctl_req *req = NULL;
	mlan_ds_rate *rate = NULL;
	woal_tx_rate_cfg *ratecfg = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;
	txrate_setting *rate_setting = NULL;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXRATECFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_TXRATECFG),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 4) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_RATE;
	rate = (mlan_ds_rate *)req->pbuf;
	rate->sub_command = MLAN_OID_RATE_CFG;
	rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;

	if (user_data_len == 0) {
		/* Get operation */
		req->action = MLAN_ACT_GET;
	} else {
		/* Set operation */
		req->action = MLAN_ACT_SET;
		/* format */
		if ((data[0] != AUTO_RATE) && (data[0] >= 4)) {
			PRINTM(MERROR, "Invalid format selection\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == AUTO_RATE) {
			/* auto */
			rate->param.rate_cfg.is_rate_auto = 1;
		} else {
			/* fixed rate */
			PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]);
			if ((data[0] != AUTO_RATE) &&
			    (data[0] > MLAN_RATE_FORMAT_HE)) {
				PRINTM(MERROR, "Invalid format selection\n");
				ret = -EINVAL;
				goto done;
			}
			rate->param.rate_cfg.rate_format = data[0];

			if (user_data_len >= 2) {
				PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
				       data[1]);
				/* sanity check */
				if (((data[0] == MLAN_RATE_FORMAT_LG) &&
				     (data[1] > MLAN_RATE_INDEX_OFDM7)) ||
				    ((data[0] == MLAN_RATE_FORMAT_HT) &&
				     (data[1] != 32) && (data[1] > 15)) ||
				    ((data[0] == MLAN_RATE_FORMAT_VHT) &&
				     (data[1] > MLAN_RATE_INDEX_MCS9)) ||
				    ((data[0] == MLAN_RATE_FORMAT_HE) &&
				     (data[1] > MLAN_RATE_INDEX_MCS11))) {
					PRINTM(MERROR,
					       "Invalid index selection\n");
					ret = -EINVAL;
					goto done;
				}

				PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
				       data[1]);
				rate->param.rate_cfg.rate = data[1];
			}

			if (data[0] == 2 || data[0] == 3) {
				PRINTM(MINFO, "SET: txratefg nss: 0x%x\n",
				       data[2]);
				/* NSS is supported up to 2 */
				if ((data[2] <= 0) || (data[2] >= 3)) {
					PRINTM(MERROR,
					       "Invalid nss selection\n");
					ret = -EINVAL;
					goto done;
				}
				rate->param.rate_cfg.nss = data[2];
			}
			if (user_data_len == 4) {
				rate->param.rate_cfg.rate_setting =
					data[3] & ~0x0C00;
				PRINTM(MIOCTL,
				       "SET: txratefg HE Rate Setting: 0x%x\n",
				       data[3]);

/* HE Preamble type */
//#define HE_SU_PREAMBLE 0
#define HE_ER_PREAMBLE 1

/* HE ER SU Type */
#define HE_ER_SU_BANDWIDTH_TONE242 0
#define HE_ER_SU_BANDWIDTH_TONE106 1

				rate_setting = (txrate_setting *)&data[3];

				if (data[0] == MLAN_RATE_FORMAT_HE) {
					if (rate_setting->preamble ==
					    HE_ER_PREAMBLE) {
						if (rate_setting->bandwidth ==
						    HE_ER_SU_BANDWIDTH_TONE242) {
							if ((data[1] >
							     MLAN_RATE_INDEX_MCS2) ||
							    data[2] >
								    MLAN_RATE_NSS1) {
								PRINTM(MERROR,
								       "Invalid rate and MCS or NSS configuration for 242 tone\n");
								ret = -EINVAL;
								goto done;
							}
						} else if (rate_setting
								   ->bandwidth ==
							   HE_ER_SU_BANDWIDTH_TONE106) {
							if ((data[1] !=
							     MLAN_RATE_INDEX_MCS0) ||
							    data[2] !=
								    MLAN_RATE_NSS1) {
								PRINTM(MERROR,
								       "Invalid rate and MCS or NSS configuration\n for 106 tone");
								ret = -EINVAL;
								goto done;
							}
						} else {
							PRINTM(MERROR,
							       "Invalid Bandwidth for HE ER Preamble\n");
							ret = -EINVAL;
							goto done;
						}
					}
					if ((rate_setting->dcm) &&
					    (rate_setting->stbc == 0)) {
						if ((data[1] ==
						     MLAN_RATE_INDEX_MCS2) ||
						    (data[1] >
						     MLAN_RATE_INDEX_MCS4)) {
							PRINTM(MERROR,
							       "Invalid MCS configuration if DCM is supported\n");
							ret = -EINVAL;
							goto done;
						}
					}
				}
			} else {
				rate->param.rate_cfg.rate_setting = 0xffff;
			}
		}
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	ratecfg = (woal_tx_rate_cfg *)respbuf;
	if (rate->param.rate_cfg.is_rate_auto == MTRUE) {
		ratecfg->rate_format = 0xFF;
	} else {
		/* fixed rate */
		ratecfg->rate_format = rate->param.rate_cfg.rate_format;
		ratecfg->rate_index = rate->param.rate_cfg.rate;
		if (rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_VHT ||
		    rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_HE)
			ratecfg->nss = rate->param.rate_cfg.nss;
		ratecfg->rate_setting = rate->param.rate_cfg.rate_setting;
	}

	ret = sizeof(woal_tx_rate_cfg);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
/**
 *  @brief Get statistics information
 *
 *  @param priv         A pointer to moal_private structure
 *  @param wait_option  Wait option
 *  @param stats        A pointer to mlan_ds_get_stats structure
 *
 *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
 * otherwise fail
 */
mlan_status woal_get_stats_info(moal_private *priv, t_u8 wait_option,
				mlan_ds_get_stats *stats)
{
	mlan_ds_get_info *info = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	ENTER();

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
	if (req == NULL) {
		status = MLAN_STATUS_FAILURE;
		goto done;
	}

	/* Fill request buffer */
	info = (mlan_ds_get_info *)req->pbuf;
	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
		info->sub_command = MLAN_OID_GET_STATS;
	else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
		info->sub_command = MLAN_OID_GET_UAP_STATS_LOG;
	req->req_id = MLAN_IOCTL_GET_INFO;
	req->action = MLAN_ACT_GET;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, wait_option);
	if (status == MLAN_STATUS_SUCCESS) {
		if (stats)
			moal_memcpy_ext(priv->phandle, stats,
					&info->param.stats,
					sizeof(mlan_ds_get_stats),
					sizeof(mlan_ds_get_stats));
#if defined(STA_WEXT) || defined(UAP_WEXT)
		priv->w_stats.discard.fragment = info->param.stats.fcs_error;
		priv->w_stats.discard.retries = info->param.stats.retry;
		priv->w_stats.discard.misc = info->param.stats.ack_failure;
#endif
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return status;
}

/**
 *  @brief Get wireless stats information
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_get_priv_getlog(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_get_stats *stats;
	ENTER();

	if (respbuflen < sizeof(*stats)) {
		PRINTM(MERROR, "Get log: respbuflen (%d) too small!",
		       (int)respbuflen);
		ret = -EFAULT;
		goto done;
	}
	stats = (mlan_ds_get_stats *)respbuf;
	if (MLAN_STATUS_SUCCESS !=
	    woal_get_stats_info(priv, MOAL_IOCTL_WAIT, stats)) {
		PRINTM(MERROR, "Get log: Failed to get stats info!");
		ret = -EFAULT;
		goto done;
	}

	if (priv->phandle->fw_getlog_enable)
		ret = sizeof(mlan_ds_get_stats);
	else
		ret = sizeof(mlan_ds_get_stats_org);

done:
	LEAVE();
	return ret;
}
#endif

/**
 *  @brief Set/Get esupplicant mode configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_esuppmode(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	t_u32 data[3];
	mlan_ioctl_req *req = NULL;
	mlan_ds_sec_cfg *sec = NULL;
	woal_esuppmode_cfg *esupp_mode = NULL;
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!priv->phandle->card_info->embedded_supp) {
		PRINTM(MERROR, "Not supported cmd on this card\n");
		ret = -EOPNOTSUPP;
		goto done;
	}
	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ESUPPMODE))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_ESUPPMODE),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_SEC_CFG;
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;

	if (user_data_len == 0) {
		/* Get operation */
		req->action = MLAN_ACT_GET;
	} else {
		/* Set operation */
		req->action = MLAN_ACT_SET;
		/* RSN mode */
		sec->param.esupp_mode.rsn_mode = data[0];
		/* Pairwise cipher */
		sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF);
		/* Group cipher */
		sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF);
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	esupp_mode = (woal_esuppmode_cfg *)respbuf;
	esupp_mode->rsn_mode =
		(t_u16)((sec->param.esupp_mode.rsn_mode) & 0xFFFF);
	esupp_mode->pairwise_cipher =
		(t_u8)((sec->param.esupp_mode.act_paircipher) & 0xFF);
	esupp_mode->group_cipher =
		(t_u8)((sec->param.esupp_mode.act_groupcipher) & 0xFF);

	ret = sizeof(woal_esuppmode_cfg);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get esupplicant passphrase configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_setget_priv_passphrase(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_sec_cfg *sec = NULL;
	int ret = 0, action = -1, i = 0;
	char *begin, *end, *opt;
	t_u16 len = 0;
	t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
	t_u8 *mac = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!priv->phandle->card_info->embedded_supp) {
		PRINTM(MERROR, "Not supported cmd on this card\n");
		ret = -EOPNOTSUPP;
		goto done;
	}

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE))) {
		PRINTM(MERROR, "No arguments provided\n");
		ret = -EINVAL;
		goto done;
	}

	/* Parse the buf to get the cmd_action */
	begin = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE);
	end = woal_strsep(&begin, ';', '/');
	if (end)
		action = woal_atox(end);
	if (action < 0 || action > 2 || end[1] != '\0') {
		PRINTM(MERROR, "Invalid action argument %s\n", end);
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_SEC_CFG;
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
	if (action == 0)
		req->action = MLAN_ACT_GET;
	else
		req->action = MLAN_ACT_SET;

	while (begin) {
		end = woal_strsep(&begin, ';', '/');
		opt = woal_strsep(&end, '=', '/');
		if (!opt || !end || !end[0]) {
			PRINTM(MERROR, "Invalid option\n");
			ret = -EINVAL;
			break;
		} else if (!strnicmp(opt, "ssid", strlen(opt))) {
			if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
				PRINTM(MERROR,
				       "SSID length exceeds max length\n");
				ret = -EFAULT;
				break;
			}
			sec->param.passphrase.ssid.ssid_len = strlen(end);
			moal_memcpy_ext(priv->phandle,
					sec->param.passphrase.ssid.ssid, end,
					strlen(end), MLAN_MAX_SSID_LENGTH);
			PRINTM(MINFO, "ssid=%s, len=%d\n",
			       sec->param.passphrase.ssid.ssid,
			       (int)sec->param.passphrase.ssid.ssid_len);
		} else if (!strnicmp(opt, "bssid", strlen(opt))) {
			woal_mac2u8((t_u8 *)&sec->param.passphrase.bssid, end);
		} else if (!strnicmp(opt, "psk", strlen(opt)) &&
			   req->action == MLAN_ACT_SET) {
			if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
				PRINTM(MERROR, "Invalid PMK length\n");
				ret = -EINVAL;
				break;
			}
			woal_ascii2hex(
				(t_u8 *)(sec->param.passphrase.psk.pmk.pmk),
				end, MLAN_PMK_HEXSTR_LENGTH / 2);
			sec->param.passphrase.psk_type = MLAN_PSK_PMK;
		} else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
			   req->action == MLAN_ACT_SET) {
			if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
			    strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
				PRINTM(MERROR,
				       "Invalid length for passphrase\n");
				ret = -EINVAL;
				break;
			}
			sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
			moal_memcpy_ext(
				priv->phandle,
				sec->param.passphrase.psk.passphrase.passphrase,
				end,
				sizeof(sec->param.passphrase.psk.passphrase
					       .passphrase),
				sizeof(sec->param.passphrase.psk.passphrase
					       .passphrase));
			sec->param.passphrase.psk.passphrase.passphrase_len =
				strlen(end);
			PRINTM(MINFO, "passphrase=%s, len=%d\n",
			       sec->param.passphrase.psk.passphrase.passphrase,
			       (int)sec->param.passphrase.psk.passphrase
				       .passphrase_len);
		} else if (!strnicmp(opt, "sae_password", strlen(opt)) &&
			   req->action == MLAN_ACT_SET) {
			if (strlen(end) < MLAN_MIN_SAE_PASSWORD_LENGTH ||
			    strlen(end) > MLAN_MAX_SAE_PASSWORD_LENGTH) {
				PRINTM(MERROR,
				       "Invalid length for sae password\n");
				ret = -EINVAL;
				break;
			}
			sec->param.passphrase.psk_type = MLAN_PSK_SAE_PASSWORD;
			moal_memcpy_ext(
				priv->phandle,
				sec->param.passphrase.psk.sae_password
					.sae_password,
				end,
				sizeof(sec->param.passphrase.psk.sae_password
					       .sae_password),
				sizeof(sec->param.passphrase.psk.sae_password
					       .sae_password));
			sec->param.passphrase.psk.sae_password.sae_password_len =
				strlen(end);
			PRINTM(MINFO, "sae_password=%s, len=%d\n",
			       sec->param.passphrase.psk.sae_password
				       .sae_password,
			       (int)sec->param.passphrase.psk.sae_password
				       .sae_password_len);
		} else {
			PRINTM(MERROR, "Invalid option %s\n", opt);
			ret = -EINVAL;
			break;
		}
	}
	if (ret)
		goto done;

	if (action == 2)
		sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
	else if (action == 0)
		sec->param.passphrase.psk_type = MLAN_PSK_QUERY;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	memset(respbuf, 0, respbuflen);
	if (sec->param.passphrase.ssid.ssid_len) {
		len += snprintf(respbuf + len, CMD_BUF_LEN, "ssid:");
		moal_memcpy_ext(priv->phandle, respbuf + len,
				sec->param.passphrase.ssid.ssid,
				sec->param.passphrase.ssid.ssid_len,
				respbuflen - len);
		len += sec->param.passphrase.ssid.ssid_len;
		len += snprintf(respbuf + len, CMD_BUF_LEN, " ");
	}
	if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
		mac = (t_u8 *)&sec->param.passphrase.bssid;
		len += snprintf(respbuf + len, CMD_BUF_LEN, "bssid:");
		for (i = 0; i < ETH_ALEN - 1; ++i)
			len += snprintf(respbuf + len, CMD_BUF_LEN,
					"%02x:", mac[i]);
		len += snprintf(respbuf + len, CMD_BUF_LEN, "%02x ", mac[i]);
	}
	if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
		len += snprintf(respbuf + len, CMD_BUF_LEN, "psk:");
		for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
			len += snprintf(respbuf + len, CMD_BUF_LEN, "%02x",
					sec->param.passphrase.psk.pmk.pmk[i]);
		len += snprintf(respbuf + len, CMD_BUF_LEN, "\n");
	}
	if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE)
		len += snprintf(
			respbuf + len, CMD_BUF_LEN, "passphrase:%s\n",
			sec->param.passphrase.psk.passphrase.passphrase);
	if (sec->param.passphrase.psk_type == MLAN_PSK_SAE_PASSWORD)
		len += snprintf(
			respbuf + len, CMD_BUF_LEN, "sae_password:%s\n",
			sec->param.passphrase.psk.sae_password.sae_password);

	ret = len;
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Deauthenticate
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_deauth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	int ret = 0;
	t_u8 mac[ETH_ALEN];

	ENTER();

	if (strlen(respbuf) > (strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH))) {
		/* Deauth mentioned BSSID */
		woal_mac2u8(mac, respbuf + strlen(CMD_NXP) +
					 strlen(PRIV_CMD_DEAUTH));
		if (MLAN_STATUS_SUCCESS !=
		    woal_disconnect(priv, MOAL_IOCTL_WAIT, mac,
				    DEF_DEAUTH_REASON_CODE)) {
			ret = -EFAULT;
			goto done;
		}
	} else {
		if (MLAN_STATUS_SUCCESS !=
		    woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
				    DEF_DEAUTH_REASON_CODE))
			ret = -EFAULT;
	}

done:
	LEAVE();
	return ret;
}

#ifdef UAP_SUPPORT
/**
 *  @brief uap station deauth ioctl handler
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_ap_deauth(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	t_u8 *data_ptr;
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_bss *bss = NULL;
	mlan_deauth_param deauth_param;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH));
	memset(&deauth_param, 0, sizeof(mlan_deauth_param));
	moal_memcpy_ext(priv->phandle, &deauth_param, data_ptr,
			sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));

	PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n",
	       MAC2STR(deauth_param.mac_addr), deauth_param.reason_code);

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	bss = (mlan_ds_bss *)ioctl_req->pbuf;

	bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
	ioctl_req->req_id = MLAN_IOCTL_BSS;
	ioctl_req->action = MLAN_ACT_SET;

	moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param,
			sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(
		priv->phandle, data_ptr, &ioctl_req->status_code, sizeof(t_u32),
		respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH)));
	ret = sizeof(t_u32);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);
	LEAVE();
	return ret;
}

/**
 *  @brief uap get station list handler
 *
 *  @param dev      A pointer to net_device structure
 *  @param req      A pointer to ifreq structure
 *  @return         0 --success, otherwise fail
 */
static int woal_priv_get_sta_list(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_get_info *info = NULL;
	mlan_ds_sta_list *sta_list = NULL;
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	/* Allocate an IOCTL request buffer */
	ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
		sizeof(mlan_ds_get_info) +
		(MAX_STA_LIST_IE_SIZE * MAX_NUM_CLIENTS));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	info = (mlan_ds_get_info *)ioctl_req->pbuf;
	info->sub_command = MLAN_OID_UAP_STA_LIST;
	ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
	ioctl_req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	sta_list = (mlan_ds_sta_list *)(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_GET_STA_LIST));
	moal_memcpy_ext(
		priv->phandle, sta_list, &info->param.sta_list,
		ioctl_req->data_read_written,
		respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_STA_LIST)));
	ret = ioctl_req->data_read_written + strlen(CMD_NXP) +
	      strlen(PRIV_CMD_GET_STA_LIST);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);
	LEAVE();
	return ret;
}

/**
 *  @brief uap bss_config handler
 *
 *  @param dev      A pointer to net_device structure
 *  @param req      A pointer to ifreq structure
 *  @return         0 --success, otherwise fail
 */
static int woal_priv_bss_config(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_bss *bss = NULL;
	mlan_ioctl_req *ioctl_req = NULL;
	t_u32 action = 0;
	int offset = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	offset = strlen(CMD_NXP) + strlen(PRIV_CMD_BSS_CONFIG);
	moal_memcpy_ext(priv->phandle, (u8 *)&action, respbuf + offset,
			sizeof(action), sizeof(action));
	offset += sizeof(action);

	/* Allocate an IOCTL request buffer */
	ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
		sizeof(mlan_ds_bss));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	bss = (mlan_ds_bss *)ioctl_req->pbuf;
	bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
	ioctl_req->req_id = MLAN_IOCTL_BSS;
	if (action == 1) {
		ioctl_req->action = MLAN_ACT_SET;
		/* Get the BSS config from user */
		moal_memcpy_ext(priv->phandle, &bss->param.bss_config,
				respbuf + offset, sizeof(mlan_uap_bss_param),
				sizeof(mlan_uap_bss_param));
	} else {
		ioctl_req->action = MLAN_ACT_GET;
	}

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (ioctl_req->action == MLAN_ACT_GET) {
		moal_memcpy_ext(priv->phandle, respbuf + offset,
				&bss->param.bss_config,
				sizeof(mlan_uap_bss_param),
				respbuflen - (t_u32)offset);
	}
	ret = sizeof(mlan_uap_bss_param);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);
	LEAVE();
	return ret;
}
#endif

#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
/**
 *  @brief Set/Get BSS role
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_bssrole(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	t_u32 data[1];
	int ret = 0;
	int user_data_len = 0;
	t_u8 action = MLAN_ACT_GET;

	ENTER();

	memset((char *)data, 0, sizeof(data));
	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BSSROLE))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_BSSROLE),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len >= 2) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto error;
	}

	if (user_data_len == 0) {
		action = MLAN_ACT_GET;
	} else {
		if ((data[0] != MLAN_BSS_ROLE_STA &&
		     data[0] != MLAN_BSS_ROLE_UAP) ||
		    priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
			PRINTM(MWARN, "Invalid BSS role\n");
			ret = -EINVAL;
			goto error;
		}
		if (data[0] == GET_BSS_ROLE(priv)) {
			PRINTM(MWARN, "Already BSS is in desired role\n");
			goto done;
		}
		action = MLAN_ACT_SET;
		/* Reset interface */
		if (MLAN_STATUS_SUCCESS !=
		    woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE)) {
			PRINTM(MERROR, "%s: woal_reset_intf failed \n",
			       __func__);
			ret = -EFAULT;
			goto error;
		}
	}

	if (MLAN_STATUS_SUCCESS !=
	    woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, (t_u8 *)data)) {
		ret = -EFAULT;
		goto error;
	}

	if (user_data_len) {
		/* Initialize private structures */
		woal_init_priv(priv, MOAL_IOCTL_WAIT);
		/* Enable interfaces */
		netif_device_attach(priv->netdev);
		woal_start_queue(priv->netdev);
	}

done:
	memset(respbuf, 0, respbuflen);
	respbuf[0] = (t_u8)data[0];
	ret = 1;

error:
	LEAVE();
	return ret;
}
#endif /* STA_SUPPORT && UAP_SUPPORT */
#endif /* WIFI_DIRECT_SUPPORT */

#ifdef STA_SUPPORT
/**
 *  @brief Set user scan
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_setuserscan(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	wlan_user_scan_cfg *scan_cfg;
	int ret = 0;

	ENTER();

	scan_cfg = (wlan_user_scan_cfg *)kmalloc(sizeof(wlan_user_scan_cfg),
						 GFP_KERNEL);
	if (!scan_cfg) {
		PRINTM(MERROR, "Malloc buffer failed\n");
		LEAVE();
		return -ENOMEM;
	}

	/* Create the scan_cfg structure */
	memset(scan_cfg, 0, sizeof(wlan_user_scan_cfg));

	/* We expect the scan_cfg structure to be passed in respbuf */
	moal_memcpy_ext(priv->phandle, (char *)scan_cfg,
			respbuf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_SETUSERSCAN),
			sizeof(wlan_user_scan_cfg), sizeof(wlan_user_scan_cfg));
	moal_memcpy_ext(priv->phandle, scan_cfg->random_mac, priv->random_mac,
			ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
	/* Call for scan */
	if (MLAN_STATUS_FAILURE == woal_do_scan(priv, scan_cfg))
		ret = -EFAULT;
	kfree(scan_cfg);
	LEAVE();
	return ret;
}

/**
 *  @brief Get channel statistics
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_chanstats(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	mlan_scan_resp scan_resp;
	chan_stats *stats = NULL;
	int ret = 0;
	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	mdelay(10);
	memset(&scan_resp, 0, sizeof(scan_resp));
	if (MLAN_STATUS_SUCCESS !=
	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
		ret = -EFAULT;
		goto done;
	}
	memset(respbuf, 0, respbuflen);
	stats = (chan_stats *)respbuf;
	stats->num_in_chan_stats = scan_resp.num_in_chan_stats;
	ret = sizeof(ChanStatistics_t) * stats->num_in_chan_stats;
	moal_memcpy_ext(priv->phandle, (t_u8 *)stats->stats,
			(t_u8 *)scan_resp.pchan_stats, ret, respbuflen);
	ret += sizeof(stats->num_in_chan_stats);
done:
	LEAVE();
	return ret;
}

/**
 *  @brief Retrieve the scan response/beacon table
 *
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *  @param scan_resp    A pointer to mlan_scan_resp structure
 *  @param scan_start   Argument
 *
 *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
 */
static int moal_ret_get_scan_table_ioctl(t_u8 *respbuf, t_u32 respbuflen,
					 mlan_scan_resp *scan_resp,
					 t_u32 scan_start)
{
	pBSSDescriptor_t pbss_desc, scan_table;
	wlan_ioctl_get_scan_table_info *prsp_info;
	int ret_code;
	int ret_len;
	int space_left;
	t_u8 *pcurrent;
	t_u8 *pbuffer_end;
	t_u32 num_scans_done;

	ENTER();

	num_scans_done = 0;
	ret_code = MLAN_STATUS_SUCCESS;

	prsp_info = (wlan_ioctl_get_scan_table_info *)respbuf;
	pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf;

	pbuffer_end = respbuf + respbuflen - 1;
	space_left = pbuffer_end - pcurrent;
	scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table);

	PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
	PRINTM(MINFO, "GetScanTable: length avail = %d\n", respbuflen);

	if (!scan_start) {
		PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");

		/* Use to get current association saved descriptor */
		pbss_desc = scan_table;

		ret_code = wlan_get_scan_table_ret_entry(pbss_desc, &pcurrent,
							 &space_left);

		if (ret_code == MLAN_STATUS_SUCCESS)
			num_scans_done = 1;

	} else {
		scan_start--;

		while (space_left &&
		       (scan_start + num_scans_done <
			scan_resp->num_in_scan_table) &&
		       (ret_code == MLAN_STATUS_SUCCESS)) {
			pbss_desc =
				(scan_table + (scan_start + num_scans_done));

			PRINTM(MINFO,
			       "GetScanTable: get current BSS Descriptor [%d]\n",
			       scan_start + num_scans_done);

			ret_code = wlan_get_scan_table_ret_entry(
				pbss_desc, &pcurrent, &space_left);

			if (ret_code == MLAN_STATUS_SUCCESS)
				num_scans_done++;
		}
	}

	prsp_info->scan_number = num_scans_done;
	ret_len = (int)(pcurrent - respbuf);

	LEAVE();
	return ret_len;
}

/**
 *  @brief Get scan table
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_getscantable(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_scan *scan = NULL;
	t_u32 scan_start;
	mlan_status status = MLAN_STATUS_SUCCESS;
	moal_handle *handle = priv->phandle;

	ENTER();

	/* First make sure scanning is not in progress */
	if (handle->scan_pending_on_block == MTRUE) {
		ret = -EAGAIN;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	scan = (mlan_ds_scan *)req->pbuf;
	req->req_id = MLAN_IOCTL_SCAN;
	req->action = MLAN_ACT_GET;

	/* Get the whole command from user */
	moal_memcpy_ext(handle, &scan_start,
			respbuf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_GETSCANTABLE),
			sizeof(scan_start), sizeof(scan_start));
	if (scan_start)
		scan->sub_command = MLAN_OID_SCAN_NORMAL;
	else
		scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status == MLAN_STATUS_SUCCESS) {
		ret = moal_ret_get_scan_table_ioctl(respbuf, respbuflen,
						    &scan->param.scan_resp,
						    scan_start);
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
/**
 *  @brief Extended capabilities configuration
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_extcapcfg(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret, header;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	IEEEtypes_Header_t *ie;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		LEAVE();
		return 0;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	header = strlen(CMD_NXP) + strlen(PRIV_CMD_EXTCAPCFG);
	if ((int)strlen(respbuf) == header)
		/* GET operation */
		req->action = MLAN_ACT_GET;
	else {
		/* SET operation */
		ie = (IEEEtypes_Header_t *)(respbuf + header);
		if (ie->len > sizeof(ExtCap_t)) {
			PRINTM(MERROR,
			       "Extended Capability lenth is invalid\n");
			ret = -EFAULT;
			goto done;
		}
		req->action = MLAN_ACT_SET;
		memset(&cfg->param.ext_cap, 0, sizeof(ExtCap_t));
		moal_memcpy_ext(priv->phandle, &cfg->param.ext_cap, ie + 1,
				ie->len, sizeof(ExtCap_t));
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	memset(respbuf, 0, respbuflen);
	ie = (IEEEtypes_Header_t *)respbuf;
	ie->element_id = EXT_CAPABILITY;
	ie->len = sizeof(ExtCap_t);
	moal_memcpy_ext(priv->phandle, ie + 1, &cfg->param.ext_cap,
			sizeof(ExtCap_t),
			respbuflen - sizeof(IEEEtypes_Header_t));

	ret = sizeof(IEEEtypes_Header_t) + ie->len;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif

/*
 *  @brief Set/Get reorder flush time
 *
 *  @param priv                 A pointer to moal_private structure
 *  @param action               Action set or get
 *  @param data                 A pointer to the data buf
 *
 *  @return                     MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
 * success, otherwise fail
 */
static mlan_status woal_set_get_reorder_flush_time(moal_private *priv,
						   t_u32 action, int *data)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	ENTER();

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_REORDER_FLUSH_TIME;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = action;

	if (action == MLAN_ACT_SET) {
		misc->param.flush_time.flush_time_ac_be_bk = (t_u16)data[0];
		misc->param.flush_time.flush_time_ac_vi_vo = (t_u16)data[1];
	}

	/* Send IOCTL request to MLAN */
	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (ret == MLAN_STATUS_SUCCESS) {
		data[0] = misc->param.flush_time.flush_time_ac_be_bk;
		data[1] = misc->param.flush_time.flush_time_ac_vi_vo;
	}
done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get AMPDU reordering flush time configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_reorder_flush_time(moal_private *priv,
						t_u8 *respbuf, t_u32 respbuflen)
{
	t_u32 data[2];
	int ret = 0;
	int user_data_len = 0;
	t_u8 action;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_REORDER_FLUSH_TIME))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_REORDER_FLUSH_TIME),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len >= 3) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len == 0)
		action = MLAN_ACT_GET;
	else
		action = MLAN_ACT_SET;

	if (MLAN_STATUS_SUCCESS !=
	    woal_set_get_reorder_flush_time(priv, action, data)) {
		ret = -EFAULT;
		goto done;
	}
	sprintf(respbuf, "BE/BK=%d VI/VO=%d", data[0], data[1]);
	ret = strlen(respbuf) + 1;
done:
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get deep sleep mode configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_setgetdeepsleep(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	t_u32 data[2];
	int ret = 0;
	int user_data_len = 0;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DEEPSLEEP))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_DEEPSLEEP),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len >= 3) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len == 0) {
		if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
			ret = -EFAULT;
			goto done;
		}
		snprintf(respbuf, CMD_BUF_LEN, "%d %d", data[0], data[1]);
		ret = strlen(respbuf) + 1;
	} else {
		if (data[0] == DEEP_SLEEP_OFF) {
			PRINTM(MINFO, "Exit Deep Sleep Mode\n");
			ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE,
						  0);
			if (ret != MLAN_STATUS_SUCCESS) {
				ret = -EINVAL;
				goto done;
			}
		} else if (data[0] == DEEP_SLEEP_ON) {
			PRINTM(MINFO, "Enter Deep Sleep Mode\n");
			if (user_data_len != 2)
				data[1] = 0;
			ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE,
						  data[1]);
			if (ret != MLAN_STATUS_SUCCESS) {
				ret = -EINVAL;
				goto done;
			}
		} else {
			PRINTM(MERROR, "Unknown option = %u\n", data[0]);
			ret = -EINVAL;
			goto done;
		}
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
	}

done:
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get IP address configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_setgetipaddr(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0, op_code = 0, data_length = 0, header = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (priv->bss_type != MLAN_BSS_TYPE_STA) {
		PRINTM(MIOCTL, "Bss type[%d]: Not STA, ignore it\n",
		       priv->bss_type);
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
		goto done;
	}

	header = strlen(CMD_NXP) + strlen(PRIV_CMD_IPADDR);
	data_length = strlen(respbuf) - header;

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;

	if (data_length < 1) { /* GET */
		req->action = MLAN_ACT_GET;
	} else {
		/* Make sure we have the operation argument */
		if (data_length > 2 && respbuf[header + 1] != ';') {
			PRINTM(MERROR,
			       "No operation argument. Separate with ';'\n");
			ret = -EINVAL;
			goto done;
		} else {
			respbuf[header + 1] = '\0';
		}
		req->action = MLAN_ACT_SET;

		/* Only one IP is supported in current firmware */
		memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
		if (data_length > 2)
			in4_pton(&respbuf[header + 2],
				 MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
				 misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
		misc->param.ipaddr_cfg.ip_addr_num = 1;
		misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;

		if (woal_atoi(&op_code, &respbuf[header]) !=
		    MLAN_STATUS_SUCCESS) {
			ret = -EINVAL;
			goto done;
		}
		misc->param.ipaddr_cfg.op_code = (t_u32)op_code;
	}

	req->req_id = MLAN_IOCTL_MISC_CFG;
	misc->sub_command = MLAN_OID_MISC_IP_ADDR;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
			 misc->param.ipaddr_cfg.op_code,
			 misc->param.ipaddr_cfg.ip_addr[0][0],
			 misc->param.ipaddr_cfg.ip_addr[0][1],
			 misc->param.ipaddr_cfg.ip_addr[0][2],
			 misc->param.ipaddr_cfg.ip_addr[0][3]);
		ret = IPADDR_MAX_BUF + 1;
	} else {
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get WPS session configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_setwpssession(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_wps_cfg *pwps = NULL;
	t_u32 data[1];
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	memset((char *)data, 0, sizeof(data));
	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_WPSSESSION))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_WPSSESSION),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	pwps = (mlan_ds_wps_cfg *)req->pbuf;

	req->req_id = MLAN_IOCTL_WPS_CFG;
	req->action = MLAN_ACT_SET;
	pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;

	if (data[0] == 1)
		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
	else
		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Get OTP user data
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_otpuserdata(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	int data[1];
	int user_data_len = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ds_misc_otp_user_data *otp = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_OTPUSERDATA))) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	memset((char *)data, 0, sizeof(data));
	parse_arguments(respbuf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_OTPUSERDATA),
			data, ARRAY_SIZE(data), &user_data_len);

	if (user_data_len != 1) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	req->action = MLAN_ACT_GET;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA;
	misc->param.otp_user_data.user_data_length = data[0];

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	otp = (mlan_ds_misc_otp_user_data *)req->pbuf;

	if (req->action == MLAN_ACT_GET) {
		ret = MIN(otp->user_data_length, data[0]);
		moal_memcpy_ext(priv->phandle, respbuf, otp->user_data, ret,
				respbuflen);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set / Get country code
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_countrycode(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	int ret = 0;
	/* char data[COUNTRY_CODE_LEN] = {0, 0, 0}; */
	int header = 0, data_length = 0; /* wrq->u.data.length; */
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *pcfg_misc = NULL;
	mlan_ds_misc_country_code *country_code = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header = strlen(CMD_NXP) + strlen(PRIV_CMD_COUNTRYCODE);
	data_length = strlen(respbuf) - header;

	if (data_length > COUNTRY_CODE_LEN) {
		PRINTM(MERROR, "Invalid argument!\n");
		ret = -EINVAL;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
	country_code = &pcfg_misc->param.country_code;
	pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (data_length <= 1) {
		req->action = MLAN_ACT_GET;
	} else {
		memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
		moal_memcpy_ext(priv->phandle, country_code->country_code,
				respbuf + header, COUNTRY_CODE_LEN,
				COUNTRY_CODE_LEN);
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		ret = data_length = COUNTRY_CODE_LEN;
		memset(respbuf + header, 0, COUNTRY_CODE_LEN);
		moal_memcpy_ext(priv->phandle, respbuf,
				country_code->country_code, COUNTRY_CODE_LEN,
				respbuflen);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Get country code
 *
 *  @param priv         A pointer to moal_private structure
 *  @param country      A pointer to country string
 *
 *  @return             0--success, otherwise failure
 */
static int woal_get_countrycode(moal_private *priv, t_u8 *country)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *pcfg_misc = NULL;
	mlan_ds_misc_country_code *country_code = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
	country_code = &pcfg_misc->param.country_code;
	pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, country, country_code->country_code,
			COUNTRY_CODE_LEN, COUNTRY_CODE_LEN);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Get cfp information
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfp_misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
	cfp_misc->sub_command = MLAN_OID_MISC_CFP_INFO;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (respbuflen < req->data_read_written) {
		PRINTM(MERROR, "response buffer length is too short!\n");
		ret = -EINVAL;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)req->pbuf,
			req->data_read_written, respbuflen);
	ret = req->data_read_written;
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get TCP Ack enhancement configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_setgettcpackenh(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	t_u32 data[2] = {0, 0};
	int ret = 0;
	int user_data_len = 0;

	ENTER();
	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TCPACKENH))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_TCPACKENH),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len == 0) {
		/* get operation */
		data[0] = priv->enable_tcp_ack_enh;
		data[1] = priv->tcp_ack_max_hold;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	} else {
		/* set operation */
		if (user_data_len >= 3) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] > 1 || data[1] > TCP_ACK_MAX_HOLD) {
			PRINTM(MERROR, "Invalid argument\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == MTRUE) {
			PRINTM(MINFO, "Enabling TCP Ack enhancement\n");
			priv->enable_tcp_ack_enh = MTRUE;
		} else if (data[0] == MFALSE) {
			PRINTM(MINFO, "Disabling TCP Ack enhancement\n");
			priv->enable_tcp_ack_enh = MFALSE;
			/* release the tcp sessions if any */
			woal_flush_tcp_sess_queue(priv);
		}
		if (user_data_len >= 2) {
			PRINTM(MINFO, "TCP drop Ack configure: %d\n", data[1]);
			priv->tcp_ack_max_hold = data[1];
		}
		data[0] = priv->enable_tcp_ack_enh;
		data[1] = priv->tcp_ack_max_hold;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	}

done:
	LEAVE();
	return ret;
}

#ifdef REASSOCIATION
/**
 *  @brief Set Asynced ESSID
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *  @param bBSSID       A variable that bssid is set or not
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_assocessid(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen, t_u8 bBSSID)
{
	mlan_ssid_bssid ssid_bssid;
	moal_handle *handle = priv->phandle;
	int ret = 0;
	int header_len = 0;
	int copy_len = 0;
	char buf[64];
	t_u8 buflen = 0;
	t_u8 i = 0;
	t_u8 mac_idx = 0;

	ENTER();

	if (bBSSID)
		header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCBSSID);
	else
		header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCESSID);

	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "No argument, invalid operation!\n");
		ret = -EINVAL;
		LEAVE();
		return ret;
	}
	copy_len = strlen(respbuf) - header_len;
	buflen = MIN(copy_len, (int)(sizeof(buf) - 1));
	memset(buf, 0, sizeof(buf));
	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
	moal_memcpy_ext(handle, buf, respbuf + header_len, buflen, sizeof(buf));
	priv->assoc_with_mac = MFALSE;

	/* check if has parameter BSSID */
	if (bBSSID) {
		if (buflen < (3 * ETH_ALEN) + 2) {
			PRINTM(MERROR,
			       "Associate: Insufficient length in IOCTL input\n");
			/* buffer should be at least 3 characters per BSSID
			 *octet "00:"
			 **   plus a space separater and at least 1 char in the
			 *SSID
			 */
			ret = -EINVAL;
			goto setessid_ret;
		}
		for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' ');
		     i++) {
			if (buf[i] == ':') {
				mac_idx++;
			} else {
				ssid_bssid.bssid[mac_idx] =
					(t_u8)woal_atox(buf + i);
				while ((i < buflen) && isxdigit(buf[i + 1]))
					/* Skip entire hex value */
					i++;
			}
		}
		/* Skip one space between the BSSID and start of the SSID */
		i++;
		PRINTM(MMSG, "Trying to associate AP BSSID = [" MACSTR "]\n",
		       MAC2STR(ssid_bssid.bssid));
		priv->assoc_with_mac = MTRUE;
	}

	ssid_bssid.ssid.ssid_len = buflen - i;
	/* Check the size of the ssid_len */
	if (ssid_bssid.ssid.ssid_len > MLAN_MAX_SSID_LENGTH + 1) {
		PRINTM(MERROR, "ssid_bssid.ssid.ssid_len = %d\n",
		       ssid_bssid.ssid.ssid_len);
		ret = -E2BIG;
		goto setessid_ret;
	}

	/* Copy the SSID */
	moal_memcpy_ext(handle, ssid_bssid.ssid.ssid, buf + i,
			ssid_bssid.ssid.ssid_len, MLAN_MAX_SSID_LENGTH);

	if (!ssid_bssid.ssid.ssid_len ||
	    (MFALSE == woal_ssid_valid(&ssid_bssid.ssid))) {
		PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
		ret = -EINVAL;
		goto setessid_ret;
	}

	PRINTM(MMSG, "Trying to associate AP SSID = %s\n",
	       (char *)ssid_bssid.ssid.ssid);

	/* Cancel re-association */
	priv->reassoc_required = MFALSE;

	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
		PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
		ret = -EBUSY;
		LEAVE();
		return ret;
	}

	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);

	if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
		PRINTM(MIOCTL, "Already connect to the network\n");
		ret = snprintf(respbuf, CMD_BUF_LEN,
			       "Has already connected to this ESSID!\n") +
		      1;
		goto setessid_ret;
	}
	moal_memcpy_ext(handle, &priv->prev_ssid_bssid, &ssid_bssid,
			sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid));
	priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
	priv->auto_assoc_priv.auto_assoc_trigger_flag =
		AUTO_ASSOC_TYPE_DRV_ASSOC;
	priv->auto_assoc_priv.drv_assoc.status = MTRUE;
	if (priv->auto_assoc_priv.auto_assoc_type_on &
	    (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
		PRINTM(MINFO, " auto assoc: trigger driver auto re-assoc\n");
	} else {
		PRINTM(MINFO, " Set Asynced ESSID: trigger auto re-assoc\n");
	}
	priv->reassoc_required = MTRUE;
	priv->phandle->is_reassoc_timer_set = MTRUE;
	woal_mod_timer(&priv->phandle->reassoc_timer, 0);
	ret = snprintf(respbuf, CMD_BUF_LEN, "%s\n", buf) + 1;

setessid_ret:
	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
	LEAVE();
	return ret;
}
#endif

/**
 *  @brief Set/Get deep auto assoc configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_setgetautoassoc(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
#ifdef REASSOCIATION
	moal_handle *handle = priv->phandle;
#endif
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	t_u32 data[5];
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTOASSOC))) {
		PRINTM(MERROR, "No argument, invalid operation!\n");
		ret = -EINVAL;
		goto done;
	} else {
		/* GET/SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_AUTOASSOC),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (sizeof(t_u32) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (data[0] != AUTO_ASSOC_TYPE_DRV_ASSOC &&
	    data[0] != AUTO_ASSOC_TYPE_DRV_RECONN &&
	    data[0] != AUTO_ASSOC_TYPE_FW_RECONN) {
		PRINTM(MERROR, "Invalid auto assoc type option = %u\n",
		       data[0]);
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len == 1) {
		/* Get operation */
		if (data[0] == AUTO_ASSOC_TYPE_FW_RECONN) {
			/* Get fw auto re-connect parameters */
			req = woal_alloc_mlan_ioctl_req(
				sizeof(mlan_ds_misc_cfg));
			if (req == NULL) {
				LEAVE();
				return -ENOMEM;
			}

			misc = (mlan_ds_misc_cfg *)req->pbuf;
			misc->sub_command = MLAN_OID_MISC_AUTO_ASSOC;
			req->req_id = MLAN_IOCTL_MISC_CFG;
			req->action = MLAN_ACT_GET;

			status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
			if (status != MLAN_STATUS_SUCCESS) {
				ret = -EFAULT;
				if (status != MLAN_STATUS_PENDING)
					kfree(req);
				goto done;
			} else {
				data[2] = misc->param.fw_auto_reconnect
						  .fw_reconn_counter;
				if (data[2] == 0) {
					data[1] = 0;
					snprintf(respbuf, CMD_BUF_LEN, "%d %d",
						 data[0], data[1]);
					ret = strlen(respbuf) + 1;
				} else {
					data[1] = 1;
					data[3] = misc->param.fw_auto_reconnect
							  .fw_reconn_interval;
					data[4] = misc->param.fw_auto_reconnect
							  .fw_reconn_flags;
					snprintf(respbuf, CMD_BUF_LEN,
						 "%d %d 0x%x 0x%x 0x%x",
						 data[0], data[1], data[2],
						 data[3], data[4]);
					ret = strlen(respbuf) + 1;
				}
				kfree(req);
			}
		} else {
			if (priv->auto_assoc_priv.auto_assoc_type_on &
			    (0x1 << (data[0] - 1))) {
				data[1] = 1;
				if (data[0] == AUTO_ASSOC_TYPE_DRV_RECONN) {
					/* Get driver auto re-connect parameters
					 */
					data[2] = priv->auto_assoc_priv
							  .drv_reconnect
							  .retry_count;
					data[3] = priv->auto_assoc_priv
							  .drv_reconnect
							  .retry_interval;
				} else {
					/* Get driver auto assoc parameters */
					data[2] =
						priv->auto_assoc_priv.drv_assoc
							.retry_count;
					data[3] =
						priv->auto_assoc_priv.drv_assoc
							.retry_interval;
				}
				snprintf(respbuf, CMD_BUF_LEN,
					 "%d %d 0x%x 0x%x", data[0], data[1],
					 data[2], data[3]);
				ret = strlen(respbuf) + 1;
			} else {
				data[1] = 0;
				snprintf(respbuf, CMD_BUF_LEN, "%d %d", data[0],
					 data[1]);
				ret = strlen(respbuf) + 1;
			}
		}
	} else {
		/* Set operation */
		if (data[1] == MFALSE) {
			/* Set Disable */
			if (user_data_len > 2) {
				PRINTM(MERROR,
				       "Invalid number of arguments for setting Disable\n");
				ret = -EINVAL;
				goto done;
			}
			priv->auto_assoc_priv.auto_assoc_type_on &=
				~(0x1 << (data[0] - 1));
		} else if (data[1] == MTRUE) {
			/* Set Enable */
			if (user_data_len > 2) {
				if (data[2] == 0 || data[2] > 0xFF) {
					PRINTM(MERROR,
					       "Invalid auto assoc retry count option = %u\n",
					       data[2]);
					ret = -EINVAL;
					goto done;
				}
				if (user_data_len > 3) {
					if (data[3] > 0xFF) {
						PRINTM(MERROR,
						       "Invalid auto assoc interval option = %u\n",
						       data[3]);
						ret = -EINVAL;
						goto done;
					}
				} else {
					data[3] = 0xa; /* Default retry
							  interval: 10 seconds
							*/
				}
			} else {
				data[2] = 0xff; /* Default retry count: retry
						   forever */
				data[3] = 0xa; /* Default retry interval: 10
						  seconds */
			}
			priv->auto_assoc_priv.auto_assoc_type_on |=
				0x1 << (data[0] - 1);
		} else {
			PRINTM(MERROR,
			       "Invalid auto assoc on/off option = %u\n",
			       data[1]);
			ret = -EINVAL;
			goto done;
		}

		if (data[0] == AUTO_ASSOC_TYPE_FW_RECONN) {
			/* Set fw auto re-connect operation */
			if (user_data_len == 5) {
				if (data[4] > 0x1) {
					PRINTM(MERROR,
					       "Invalid fw auto re-connect flag option = %u\n",
					       data[4]);
					ret = -EINVAL;
					goto done;
				}
			} else {
				data[4] = 0; /* Default fw auto re-connect flags
					      */
			}
			req = woal_alloc_mlan_ioctl_req(
				sizeof(mlan_ds_misc_cfg));
			if (req == NULL) {
				LEAVE();
				return -ENOMEM;
			}

			misc = (mlan_ds_misc_cfg *)req->pbuf;
			misc->sub_command = MLAN_OID_MISC_AUTO_ASSOC;
			req->req_id = MLAN_IOCTL_MISC_CFG;
			req->action = MLAN_ACT_SET;

			if (data[1] == MFALSE) {
				/* Set fw auto re-connect Disable */
				misc->param.fw_auto_reconnect.fw_reconn_counter =
					0;
				misc->param.fw_auto_reconnect
					.fw_reconn_interval = 0;
				misc->param.fw_auto_reconnect.fw_reconn_flags =
					0;
			} else {
				/* Set fw auto re-connect Enable */
				misc->param.fw_auto_reconnect.fw_reconn_counter =
					data[2];
				misc->param.fw_auto_reconnect
					.fw_reconn_interval = data[3];
				misc->param.fw_auto_reconnect.fw_reconn_flags =
					data[4];
			}

			status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
			if (status != MLAN_STATUS_SUCCESS) {
				ret = -EFAULT;
				if (status != MLAN_STATUS_PENDING)
					kfree(req);
				goto done;
			} else {
				kfree(req);
			}
		} else {
			if (user_data_len == 5) {
				PRINTM(MERROR,
				       "The fifth parameter is only used for FW auto re-connect!\n");
				ret = -EINVAL;
				goto done;
			}
			if (data[0] == AUTO_ASSOC_TYPE_DRV_RECONN) {
				/* Set driver auto re-connect operation */
				if (data[1] == MFALSE) {
					if (!(priv->auto_assoc_priv
						      .auto_assoc_type_on &
					      (0x1
					       << (AUTO_ASSOC_TYPE_DRV_ASSOC -
						   1)))) {
						priv->auto_assoc_priv
							.drv_reconnect.status =
							MFALSE;
#ifdef REASSOCIATION
						handle->reassoc_on &=
							~MBIT(priv->bss_index);
						priv->reassoc_on = MFALSE;
						priv->reassoc_required = MFALSE;
						if (!handle->reassoc_on &&
						    handle->is_reassoc_timer_set ==
							    MTRUE) {
							woal_cancel_timer(
								&handle->reassoc_timer);
							handle->is_reassoc_timer_set =
								MFALSE;
						}
#endif
					}
				}
#ifdef REASSOCIATION
				else {
					handle->reassoc_on |=
						MBIT(priv->bss_index);
					priv->reassoc_on = MTRUE;
				}
#endif
				priv->auto_assoc_priv.drv_reconnect.retry_count =
					data[2];
				priv->auto_assoc_priv.drv_reconnect
					.retry_interval = data[3];
			}
			if (data[0] == AUTO_ASSOC_TYPE_DRV_ASSOC) {
				/* Set driver auto assoc operation */
				if (data[1] == MFALSE) {
					if (!(priv->auto_assoc_priv
						      .auto_assoc_type_on &
					      (0x1
					       << (AUTO_ASSOC_TYPE_DRV_RECONN -
						   1)))) {
						priv->auto_assoc_priv.drv_assoc
							.status = MFALSE;
#ifdef REASSOCIATION
						handle->reassoc_on &=
							~MBIT(priv->bss_index);
						priv->reassoc_on = MFALSE;
						priv->reassoc_required = MFALSE;
						if (!handle->reassoc_on &&
						    handle->is_reassoc_timer_set ==
							    MTRUE) {
							woal_cancel_timer(
								&handle->reassoc_timer);
							handle->is_reassoc_timer_set =
								MFALSE;
						}
#endif
					}
				}
#ifdef REASSOCIATION
				else {
					handle->reassoc_on |=
						MBIT(priv->bss_index);
					priv->reassoc_on = MTRUE;
				}
#endif
				priv->auto_assoc_priv.drv_assoc.retry_count =
					data[2];
				priv->auto_assoc_priv.drv_assoc.retry_interval =
					data[3];
			}
		}
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
	}

done:
	LEAVE();
	return ret;
}

/**
 *  @brief Get wakeup reason
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_getwakeupreason(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_pm_cfg *pm_cfg = NULL;
	t_u32 data;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_WAKEUPREASON))) {
		/* GET operation */
		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
		if (req == NULL) {
			LEAVE();
			return -ENOMEM;
		}

		pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
		pm_cfg->sub_command = MLAN_OID_PM_HS_WAKEUP_REASON;
		req->req_id = MLAN_IOCTL_PM_CFG;
		req->action = MLAN_ACT_GET;

		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			if (status != MLAN_STATUS_PENDING)
				kfree(req);
			goto done;
		} else {
			data = pm_cfg->param.wakeup_reason.hs_wakeup_reason;
			snprintf(respbuf, CMD_BUF_LEN, " %d", data);
			ret = strlen(respbuf) + 1;
			kfree(req);
		}
	} else {
		PRINTM(MERROR, "Not need argument, invalid operation!\n");
		ret = -EINVAL;
		goto done;
	}

done:
	LEAVE();
	return ret;
}

#ifdef STA_SUPPORT
/**
 *  @brief Set / Get listen interval
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_listeninterval(moal_private *priv, t_u8 *respbuf,
					    t_u32 respbuflen)
{
	int data[1];
	int user_data_len = 0;
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_bss *pcfg_bss = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_LISTENINTERVAL))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_LISTENINTERVAL),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	pcfg_bss = (mlan_ds_bss *)req->pbuf;
	pcfg_bss->sub_command = MLAN_OID_BSS_LISTEN_INTERVAL;
	req->req_id = MLAN_IOCTL_BSS;

	if (user_data_len) {
		pcfg_bss->param.listen_interval = (t_u16)data[0];
		req->action = MLAN_ACT_SET;
	} else {
		req->action = MLAN_ACT_GET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (req->action == MLAN_ACT_GET) {
		snprintf(respbuf, CMD_BUF_LEN, "%d",
			 pcfg_bss->param.listen_interval);
		ret = strlen(respbuf) + 1;
	} else {
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}
#endif

#ifdef DEBUG_LEVEL1
/**
 *  @brief Set / Get driver debug level
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_drvdbg(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int data[4];
	int user_data_len = 0;
	int ret = 0;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DRVDBG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_DRVDBG),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len) {
		/* Get the driver debug bit masks from user */
		drvdbg = data[0];
		/* Set the driver debug bit masks into mlan */
		if (woal_set_drvdbg(priv, drvdbg)) {
			PRINTM(MERROR, "Set drvdbg failed!\n");
			ret = MLAN_STATUS_FAILURE;
			goto done;
		}
	}

	ret = sizeof(drvdbg);

	moal_memcpy_ext(priv->phandle, respbuf, &drvdbg, sizeof(drvdbg),
			respbuflen);

	printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
#ifdef DEBUG_LEVEL2
	printk(KERN_ALERT "MINFO  (%08x) %s\n", MINFO,
	       (drvdbg & MINFO) ? "X" : "");
	printk(KERN_ALERT "MWARN  (%08x) %s\n", MWARN,
	       (drvdbg & MWARN) ? "X" : "");
	printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
	       (drvdbg & MENTRY) ? "X" : "");
#endif
	printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D,
	       (drvdbg & MMPA_D) ? "X" : "");
	printk(KERN_ALERT "MIF_D  (%08x) %s\n", MIF_D,
	       (drvdbg & MIF_D) ? "X" : "");
	printk(KERN_ALERT "MFW_D  (%08x) %s\n", MFW_D,
	       (drvdbg & MFW_D) ? "X" : "");
	printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
	       (drvdbg & MEVT_D) ? "X" : "");
	printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
	       (drvdbg & MCMD_D) ? "X" : "");
	printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
	       (drvdbg & MDAT_D) ? "X" : "");
	printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D,
	       (drvdbg & MREG_D) ? "X" : "");
	printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
	       (drvdbg & MIOCTL) ? "X" : "");
	printk(KERN_ALERT "MINTR  (%08x) %s\n", MINTR,
	       (drvdbg & MINTR) ? "X" : "");
	printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
	       (drvdbg & MEVENT) ? "X" : "");
	printk(KERN_ALERT "MCMND  (%08x) %s\n", MCMND,
	       (drvdbg & MCMND) ? "X" : "");
	printk(KERN_ALERT "MDATA  (%08x) %s\n", MDATA,
	       (drvdbg & MDATA) ? "X" : "");
	printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
	       (drvdbg & MERROR) ? "X" : "");
	printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
	       (drvdbg & MFATAL) ? "X" : "");
	printk(KERN_ALERT "MMSG   (%08x) %s\n", MMSG,
	       (drvdbg & MMSG) ? "X" : "");

done:
	LEAVE();
	return ret;
}

#endif

/**
 *  @brief management frame filter wakeup config
 *
 *  @param priv             A pointer to moal_private structure
 *  @param respbuf          A pointer to response buffer
 *  @param respbuflen       Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_mgmt_filter(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_pm_cfg *pm_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int header_len = 0, data_len = 0;
	int ret = 0;
	t_u16 action;
	t_u8 *argument;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
	pm_cfg->sub_command = MLAN_OID_PM_MGMT_FILTER;
	ioctl_req->req_id = MLAN_IOCTL_PM_CFG;

	header_len = strlen(PRIV_CMD_MGMT_FILTER) + strlen(CMD_NXP);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		argument = (t_u8 *)(respbuf + header_len);
		data_len = respbuflen - header_len;
		if (data_len > (int)(MAX_MGMT_FRAME_FILTER *
				     sizeof(mlan_mgmt_frame_wakeup))) {
			PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
			ret = -EINVAL;
			goto done;
		}
		moal_memcpy_ext(priv->phandle,
				(t_u8 *)pm_cfg->param.mgmt_filter, argument,
				data_len, sizeof(pm_cfg->param.mgmt_filter));
		action = MLAN_ACT_SET;
	}

	ioctl_req->action = action;
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

#define PARAMETER_GPIO_INDICATION 1
#define PARAMETER_EXTEND_HSCFG 2
#define PARAMETER_HS_WAKEUP_INTERVAL 3
#define PARAMETER_MIN_WAKE_HOLDOFF 4
/**
 *  @brief Set/Get Host Sleep configuration
 *
 *  @param priv             A pointer to moal_private structure
 *  @param respbuf          A pointer to response buffer
 *  @param respbuflen       Available length of response buffer
 *  @param invoke_hostcmd   MTRUE --invoke HostCmd, otherwise MFALSE
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_hscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
			   BOOLEAN invoke_hostcmd)
{
	int data[15] = {0};
	int *temp_data, type;
	int user_data_len = 0;
	int ret = 0;
	mlan_ds_hs_cfg hscfg, hscfg_temp;
	t_u16 action;
	mlan_bss_info bss_info;
	int is_negative = MFALSE;
	t_u8 *arguments = NULL;

	ENTER();

	memset(data, 0, sizeof(data));
	memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
	memset(&hscfg_temp, 0, sizeof(mlan_ds_hs_cfg));

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		arguments = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG);
		if (*arguments == '-') {
			is_negative = MTRUE;
			arguments += 1;
		}
		parse_arguments(arguments, data, ARRAY_SIZE(data),
				&user_data_len);

		if (is_negative == MTRUE) {
			if (data[0] == 1) {
				data[0] = -1;
			} else {
				PRINTM(MERROR, "Invalid arguments\n");
				ret = -EINVAL;
				goto done;
			}
		}
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		LEAVE();
		return -EINVAL;
	}

	if (user_data_len == 0) {
		action = MLAN_ACT_GET;
	} else {
		if (user_data_len >= 1 && user_data_len <= 15) {
			action = MLAN_ACT_SET;
		} else {
			PRINTM(MERROR, "Invalid arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}

	/* HS config is blocked if HS is already activated */
	if (user_data_len && (data[0] != (int)HOST_SLEEP_CFG_CANCEL ||
			      invoke_hostcmd == MFALSE)) {
		memset(&bss_info, 0, sizeof(bss_info));
		ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
		if (ret != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
		if (bss_info.is_hs_configured) {
			PRINTM(MERROR, "HS already configured\n");
			ret = -EFAULT;
			goto done;
		}
	}

	/* Do a GET first if some arguments are not provided */
	if (user_data_len >= 1 && user_data_len < 11) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
					   &hscfg_temp)) {
			PRINTM(MERROR, "Unable to get HS params\n");
		}
	}
	hscfg.conditions = hscfg_temp.conditions;
	hscfg.gpio = hscfg_temp.gpio;
	hscfg.gap = hscfg_temp.gap;

	if (user_data_len)
		hscfg.conditions = data[0];
	if (user_data_len >= 2)
		hscfg.gpio = data[1];
	if (user_data_len >= 3)
		hscfg.gap = data[2];
	user_data_len = user_data_len - 3;
	if (user_data_len > 0) {
		temp_data = data + 3;
		while ((user_data_len > 0) && temp_data) {
			type = *temp_data;
			switch (type) {
			case PARAMETER_GPIO_INDICATION:
				if (user_data_len >= 2)
					hscfg.ind_gpio = *(++temp_data);
				else {
					PRINTM(MERROR,
					       "Invaild number of parameters\n");
					ret = -EINVAL;
					goto done;
				}
				if (user_data_len >= 3) {
					hscfg.level = *(++temp_data);
					if (hscfg.level != 0 &&
					    hscfg.level != 1) {
						PRINTM(MERROR,
						       "Invalid indication gpio arguments\n");
						ret = -EINVAL;
						goto done;
					}
				}
				hscfg.param_type_ind = type;
				user_data_len = user_data_len - 3;
				temp_data++;
				break;
			case PARAMETER_EXTEND_HSCFG:
				if (user_data_len >= 4) {
					hscfg.event_force_ignore =
						*(++temp_data);
					hscfg.event_use_ext_gap =
						*(++temp_data);
					hscfg.ext_gap = *(++temp_data);
					hscfg.gpio_wave = *(++temp_data);
				} else {
					PRINTM(MERROR,
					       "Invaild number of parameters\n");
					ret = -EINVAL;
					goto done;
				}
				/* Force_ignore_gpio and ext_gap_gpio should not
				 * set the same bit(s)*/
				if ((hscfg.event_force_ignore &
				     hscfg.event_use_ext_gap) ||
				    (hscfg.gpio_wave != 1 &&
				     hscfg.gpio_wave != 0)) {
					PRINTM(MERROR,
					       "Invalid arguments for extend hscfg\n");
					ret = -EINVAL;
					goto done;
				}
				hscfg.param_type_ext = type;
				user_data_len = user_data_len - 5;
				temp_data++;
				break;
			case PARAMETER_HS_WAKEUP_INTERVAL:
				if (user_data_len >= 2)
					hscfg.hs_wake_interval = *(++temp_data);
				else {
					PRINTM(MERROR,
					       "Invaild number of parameters\n");
					ret = -EINVAL;
					goto done;
				}
				user_data_len = user_data_len - 2;
				temp_data++;
				break;
			case PARAMETER_MIN_WAKE_HOLDOFF:
				if (user_data_len >= 2)
					hscfg.min_wake_holdoff = *(++temp_data);
				else {
					PRINTM(MERROR,
					       "Invaild number of parameters\n");
					ret = -EINVAL;
					goto done;
				}
				user_data_len = user_data_len - 2;
				temp_data++;
				break;
			default:
				PRINTM(MERROR, "Unsupported type\n");
				ret = -EINVAL;
				goto done;
			}
		}
	}

	if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
		/* Need to issue an extra IOCTL first to set up parameters */
		hscfg.is_invoke_hostcmd = MFALSE;
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
					   &hscfg)) {
			ret = -EFAULT;
			goto done;
		}
	}
	hscfg.is_invoke_hostcmd = invoke_hostcmd;
	if (MLAN_STATUS_SUCCESS !=
	    woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
		ret = -EFAULT;
		goto done;
	}

	if (action == MLAN_ACT_GET) {
		/* Return the current driver host sleep configurations */
		moal_memcpy_ext(priv->phandle, respbuf, &hscfg,
				sizeof(mlan_ds_hs_cfg), respbuflen);
		ret = sizeof(mlan_ds_hs_cfg);
	}
done:
	LEAVE();
	return ret;
}

/**
 *  @brief Process Set Host Sleep parameters from proc buffer
 *
 *  @param handle       A pointer to moal_handle structure
 *  @param pbuf         A pointer to buffer for host sleep parameters
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
int woal_process_proc_hssetpara(moal_handle *handle, t_u8 *buf)
{
	int data[15] = {0};
	int user_data_len = 0;
	int ret = 0;
	t_u8 respbuf[500];
	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);

	ENTER();
	if (!priv) {
		LEAVE();
		return ret;
	}
	memset((char *)data, 0, sizeof(data));
	parse_arguments(buf, data, ARRAY_SIZE(data), &user_data_len);
	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		LEAVE();
		return -EINVAL;
	}
	if (user_data_len >= 1 && user_data_len <= 15) {
		snprintf(respbuf, 500, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG, buf);
		ret = woal_priv_hscfg(priv, respbuf, sizeof(respbuf), MFALSE);
	}
	LEAVE();
	return ret;
}

/**
 *  @brief Set Host Sleep parameters
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int data[15] = {0};
	int user_data_len = 0;
	int ret = 0;

	ENTER();

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))) {
		PRINTM(MERROR, "Invalid arguments\n");
		ret = -EINVAL;
		goto done;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_HSSETPARA),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		LEAVE();
		return -EINVAL;
	}

	if (user_data_len >= 1 && user_data_len <= 15) {
		snprintf(respbuf, CMD_BUF_LEN, "%s%s%s", CMD_NXP,
			 PRIV_CMD_HSCFG,
			 respbuf + (strlen(CMD_NXP) +
				    strlen(PRIV_CMD_HSSETPARA)));
		respbuflen = strlen(respbuf);
		ret = woal_priv_hscfg(priv, respbuf, respbuflen, MFALSE);
		goto done;
	}
done:
	LEAVE();
	return ret;
}

/**
 * @brief Set/Get scan configuration parameters
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_set_get_scancfg(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0;
	int data[9];
	mlan_ds_scan *scan = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	memset(data, 0, sizeof(data));
	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_SCANCFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_SCANCFG),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		LEAVE();
		return -EINVAL;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	scan = (mlan_ds_scan *)req->pbuf;
	scan->sub_command = MLAN_OID_SCAN_CONFIG;
	req->req_id = MLAN_IOCTL_SCAN;

	if (user_data_len) {
		moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
				sizeof(data), sizeof(scan->param.scan_cfg));
		if (scan->param.scan_cfg.scan_type > MLAN_SCAN_TYPE_PASSIVE) {
			PRINTM(MERROR, "Invalid argument for scan type\n");
			ret = -EINVAL;
			goto done;
		}
		if (scan->param.scan_cfg.scan_mode > MLAN_SCAN_MODE_ANY) {
			PRINTM(MERROR, "Invalid argument for scan mode\n");
			ret = -EINVAL;
			goto done;
		}
		if (scan->param.scan_cfg.scan_probe > MAX_PROBES) {
			PRINTM(MERROR, "Invalid argument for scan probes\n");
			ret = -EINVAL;
			goto done;
		}
		if ((scan->param.scan_cfg.scan_time.specific_scan_time >
		     MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) ||
		    (scan->param.scan_cfg.scan_time.active_scan_time >
		     MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) ||
		    (scan->param.scan_cfg.scan_time.passive_scan_time >
		     MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME)) {
			PRINTM(MERROR, "Invalid argument for scan time\n");
			ret = -EINVAL;
			goto done;
		}
		if (scan->param.scan_cfg.passive_to_active_scan >
		    MLAN_PASS_TO_ACT_SCAN_DIS) {
			PRINTM(MERROR,
			       "Invalid argument for Passive to Active Scan\n");
			ret = -EINVAL;
			goto done;
		}
		if (scan->param.scan_cfg.ext_scan > MLAN_EXT_SCAN_ENH) {
			PRINTM(MERROR, "Invalid argument for extended scan\n");
			ret = -EINVAL;
			goto done;
		}
		if (scan->param.scan_cfg.scan_chan_gap >
		    MRVDRV_MAX_SCAN_CHAN_GAP_TIME) {
			PRINTM(MERROR,
			       "Invalid argument for scan channel gap\n");
			ret = -EINVAL;
			goto done;
		}

		req->action = MLAN_ACT_SET;
		moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
				sizeof(data), sizeof(scan->param.scan_cfg));
	} else
		req->action = MLAN_ACT_GET;
	if (scan->param.scan_cfg.scan_time.specific_scan_time &&
	    req->action == MLAN_ACT_SET) {
		priv->phandle->user_scan_cfg = MTRUE;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf, &scan->param.scan_cfg,
			sizeof(mlan_scan_cfg), respbuflen);
	ret = sizeof(mlan_scan_cfg);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Get Netlink Number
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written, negative for failure.
 */
static int woal_priv_getnlnum(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int ret = 0;
	int data = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null in %s\n", __FUNCTION__);
		ret = -EFAULT;
		goto done;
	}

	data = priv->phandle->netlink_num;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	LEAVE();
	return ret;
}

/**
 *  @brief Set / Get packet aggregation control
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_aggrctrl(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int data[1];
	int user_data_len = 0;
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *pcfg_misc = NULL;
	moal_handle *handle = priv->phandle;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!handle || !handle->card) {
		PRINTM(MERROR, "Handle or card is null\n");
		ret = -EFAULT;
		goto done;
	}

	memset((char *)data, 0, sizeof(data));
	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRCTRL))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		if (woal_is_any_interface_active(priv->phandle)) {
			PRINTM(MERROR,
			       "aggrctrl are not allowed to change after BSS active!\n");
			ret = -EFAULT;
			goto done;
		}
		/* SET operation */
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_AGGRCTRL),
				data, ARRAY_SIZE(data), &user_data_len);

		if (sizeof(int) * user_data_len > sizeof(data)) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
	pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	/* Get the values first, then modify these values if user had modified
	 * them */
	if (user_data_len == 0)
		req->action = MLAN_ACT_GET;
	else {
		req->action = MLAN_ACT_SET;
		pcfg_misc->param.aggr_params.tx.enable = (t_u16)data[0];
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		/* MLAN will return CMD_INVALID if FW does not support this
		 * feature */
		if (MLAN_ERROR_CMD_INVALID == req->status_code)
			ret = -EOPNOTSUPP;
		else
			ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(handle, respbuf, (t_u8 *)&pcfg_misc->param.aggr_params,
			sizeof(mlan_ds_misc_aggr_ctrl), respbuflen);
	ret = sizeof(mlan_ds_misc_aggr_ctrl);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

#ifdef USB
/**
 *  @brief Set / Get USB packet aggregation control
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_usbaggrctrl(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	int data[8];
	int user_data_len = 0;
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *pcfg_misc = NULL;
	moal_handle *handle = priv->phandle;
	struct usb_card_rec *cardp = NULL;
	int i = 0, usb_resubmit_urbs = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!handle || !handle->card) {
		PRINTM(MERROR, "Handle or card is null\n");
		ret = -EFAULT;
		goto done;
	}
	cardp = (struct usb_card_rec *)handle->card;

	memset((char *)data, 0, sizeof(data));
	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_USBAGGRCTRL))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_USBAGGRCTRL),
				data, ARRAY_SIZE(data), &user_data_len);

		if (sizeof(int) * user_data_len > sizeof(data)) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
	pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	/* Get the values first, then modify these values if user had modified
	 * them */
	req->action = MLAN_ACT_GET;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		/* MLAN will return CMD_INVALID if FW does not support this
		 * feature */
		if (MLAN_ERROR_CMD_INVALID == req->status_code)
			ret = -EOPNOTSUPP;
		else
			ret = -EFAULT;
		goto done;
	}

	if (user_data_len == 0) {
		moal_memcpy_ext(handle, respbuf,
				(t_u8 *)&pcfg_misc->param.usb_aggr_params,
				sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
		ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
		goto done;
	}

	switch (user_data_len) {
	case 8:
		if (data[7] < 0) {
			PRINTM(MERROR, "Invalid Rx timeout value (%d)\n",
			       data[7]);
			ret = -EINVAL;
			goto done;
		}
		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_tmo =
			(t_u16)data[7];
		/* fall through */
	case 7:
		if (data[6] < 0 || (data[6] > 10000 &&
				    data[6] != MLAN_USB_TX_AGGR_TIMEOUT_DYN)) {
			PRINTM(MERROR, "Invalid Tx timeout value (%d)\n",
			       data[6]);
			ret = -EINVAL;
			goto done;
		}
		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_tmo =
			(t_u16)data[6];
		/* fall through */
	case 6:
		if ((data[5] < 512) || ((data[5] % 512) != 0)) {
			PRINTM(MERROR, "Invalid Rx alignment value (%d)\n",
			       data[5]);
			ret = -EINVAL;
			goto done;
		}
		if (cardp->rx_deaggr_ctrl.enable &&
		    pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align !=
			    (t_u16)data[5])
			usb_resubmit_urbs = 1;
		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align =
			(t_u16)data[5];
		/* fall through */
	case 5:
		if ((data[4] < 2048) || ((data[4] % 2048) != 0)) {
			PRINTM(MERROR, "Invalid Tx alignment value (%d)\n",
			       data[4]);
			ret = -EINVAL;
			goto done;
		}
		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_align =
			(t_u16)data[4];
		/* fall through */
	case 4:
		if ((data[3] == 2) || (data[3] == 4) || (data[3] == 8) ||
		    (data[3] == 16)) {
			pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
				.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
		} else if ((data[3] == 4096) || (data[3] == 8192) ||
			   (data[3] == 16384) || (data[3] == 32768)) {
			pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
				.aggr_mode = MLAN_USB_AGGR_MODE_LEN;
		} else {
			PRINTM(MERROR, "Invalid Rx max size/num value (%d)\n",
			       data[3]);
			ret = -EINVAL;
			goto done;
		}
		if (cardp->rx_deaggr_ctrl.enable &&
		    pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max !=
			    (t_u16)data[3])
			usb_resubmit_urbs = 1;
		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max =
			(t_u16)data[3];
		/* fall through */
	case 3:
		if ((data[2] == 2) || (data[2] == 4) || (data[2] == 8) ||
		    (data[2] == 16)) {
			pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
				MLAN_USB_AGGR_MODE_NUM;
		} else if ((data[2] == 4096) || (data[2] == 8192) ||
			   (data[2] == 16384) || (data[2] == 32768)) {
			pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
				MLAN_USB_AGGR_MODE_LEN;
		} else {
			PRINTM(MERROR, "Invalid Tx max size/num value (%d)\n",
			       data[2]);
			ret = -EINVAL;
			goto done;
		}
		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_max =
			(t_u16)data[2];
		/* fall through */
	case 2:
		if ((data[1] != 0) && (data[1] != 1)) {
			PRINTM(MERROR, "Invalid Rx enable value (%d)\n",
			       data[1]);
			ret = -EINVAL;
			goto done;
		}
		if (pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable !=
		    (t_u16)data[1])
			usb_resubmit_urbs = 1;
		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable =
			(t_u16)data[1];
		/* fall through */
	case 1:
		if ((data[0] != 0) && (data[0] != 1)) {
			PRINTM(MERROR, "Invalid Tx enable value (%d)\n",
			       data[0]);
			ret = -EINVAL;
			goto done;
		}
		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.enable =
			(t_u16)data[0];
	default:
		break;
	}

	pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_SET;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(handle, respbuf,
			(t_u8 *)&pcfg_misc->param.usb_aggr_params,
			sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
	ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);

	/* Keep a copy of the latest Tx aggregation parameters in MOAL */
	moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl,
			&pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl,
			sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg));

	if (usb_resubmit_urbs) {
		/* Indicate resubmition from here */
		cardp->resubmit_urbs = 1;
		/* Rx SG parameters has changed or disabled, kill the URBs, they
		   will be resubmitted after saving the parameters to USB card
		 */
		if (atomic_read(&cardp->rx_data_urb_pending)) {
			for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
				if (cardp->rx_data_list[i].urb) {
					usb_kill_urb(
						cardp->rx_data_list[i].urb);
				}
			}
		}
	}

	/* Keep a copy of the latest Rx deaggregation parameters in MOAL */
	moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl,
			&pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl,
			sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg));

	if (usb_resubmit_urbs) {
		/* Ensure the next data URBs will use the modified parameters */
		if (!atomic_read(&cardp->rx_data_urb_pending)) {
			/* Submit multiple Rx data URBs */
			woal_usb_submit_rx_data_urbs(handle);
		}
		cardp->resubmit_urbs = 0;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}
#endif

#ifdef STA_SUPPORT
/**
 * @brief Set AP settings
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful, otherwise fail
 */
static int woal_priv_set_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	int ret = 0;
	t_u8 *data_ptr;
	const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {255, 255, 255, 255, 255, 255};
	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
	mlan_ssid_bssid ssid_bssid;
	mlan_bss_info bss_info;
	struct mwreq *mwr;
	struct sockaddr *awrq;

	ENTER();
	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AP));

	mwr = (struct mwreq *)data_ptr;

	if (mwr->u.ap_addr.sa_family != ARPHRD_ETHER) {
		ret = -EINVAL;
		goto done;
	}

	awrq = (struct sockaddr *)&(mwr->u.ap_addr);

	PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
	       MAC2STR((t_u8 *)awrq->sa_data));

	if (MLAN_STATUS_SUCCESS !=
	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
		ret = -EFAULT;
		goto done;
	}

#ifdef REASSOCIATION
	/* Cancel re-association */
	priv->reassoc_required = MFALSE;
#endif

	/* zero_mac means disconnect */
	if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
		woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
				DEF_DEAUTH_REASON_CODE);
		goto done;
	}

	/* Broadcast MAC means search for best network */
	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));

	if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
		/* Check if we are already assoicated to the AP */
		if (bss_info.media_connected == MTRUE) {
			if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
				goto done;
		}
		moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data,
				ETH_ALEN, sizeof(mlan_802_11_mac_addr));
	}

	if (MLAN_STATUS_SUCCESS !=
	    woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
		PRINTM(MERROR,
		       "ASSOC: WAP: MAC address not found in BSSID List\n");
		ret = -ENETUNREACH;
		goto done;
	}
	/* Zero SSID implies use BSSID to connect */
	memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
	if (MLAN_STATUS_SUCCESS !=
	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
		ret = -EFAULT;
		goto done;
	}

#ifdef REASSOCIATION
	memset(&bss_info, 0, sizeof(bss_info));
	if (MLAN_STATUS_SUCCESS !=
	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
			&bss_info.ssid, sizeof(mlan_802_11_ssid),
			sizeof(mlan_802_11_ssid));
	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
			&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
			sizeof(mlan_802_11_mac_addr));
#endif /* REASSOCIATION */

done:
	LEAVE();
	return ret;
}
#endif

/**
 * @brief Set BSS mode
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful, otherwise fail
 */
static int woal_priv_set_bss_mode(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_bss *bss = NULL;
	mlan_ioctl_req *req = NULL;
	struct mwreq *mwr;
	t_u8 *data_ptr;
	t_u32 mode;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_BSS_MODE));

	mwr = (struct mwreq *)data_ptr;
	mode = mwr->u.mode;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	bss = (mlan_ds_bss *)req->pbuf;
	bss->sub_command = MLAN_OID_BSS_MODE;
	req->req_id = MLAN_IOCTL_BSS;
	req->action = MLAN_ACT_SET;

	switch (mode) {
	case MW_MODE_INFRA:
		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
		break;
	case MW_MODE_ADHOC:
		bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
		break;
	case MW_MODE_AUTO:
		bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
		break;
	default:
		ret = -EINVAL;
		break;
	}
	if (ret)
		goto done;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef STA_SUPPORT
/**
 * @brief Set power management
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful, otherwise fail
 */
static int woal_priv_set_power(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	struct mwreq *mwr;
	t_u8 *data_ptr;
	int ret = 0, disabled;

	ENTER();

	if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
		PRINTM(MIOCTL, "block set power in hw_test mode\n");
		LEAVE();
		return ret;
	}

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_POWER));

	mwr = (struct mwreq *)data_ptr;
	disabled = mwr->u.power.disabled;

	if (MLAN_STATUS_SUCCESS !=
	    woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled,
				    mwr->u.power.flags, MOAL_IOCTL_WAIT)) {
		return -EFAULT;
	}
	LEAVE();
	return ret;
}

/**
 *  @brief Set essid
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful, otherwise fail
 */
static int woal_priv_set_essid(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	mlan_802_11_ssid req_ssid;
	mlan_ssid_bssid ssid_bssid;
	moal_handle *handle = priv->phandle;
#ifdef REASSOCIATION
	mlan_bss_info bss_info;
#endif
	int ret = 0;
	t_u32 mode = 0;
	struct mwreq *mwr;
	t_u8 *data_ptr;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_ESSID));

	mwr = (struct mwreq *)data_ptr;

#ifdef REASSOCIATION
	/* Cancel re-association */
	priv->reassoc_required = MFALSE;

	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
		PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
		LEAVE();
		return -EBUSY;
	}
#endif /* REASSOCIATION */

	/* Check the size of the string */
	if (mwr->u.essid.length > MW_ESSID_MAX_SIZE - 1) {
		ret = -E2BIG;
		goto setessid_ret;
	}
	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
	memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));

	req_ssid.ssid_len = mwr->u.essid.length;

	/* Check if we asked for 'any' or 'particular' */
	if (!mwr->u.essid.flags) {
#ifdef REASSOCIATION
		if (!req_ssid.ssid_len) {
			memset(&priv->prev_ssid_bssid.ssid, 0x00,
			       sizeof(mlan_802_11_ssid));
			memset(&priv->prev_ssid_bssid.bssid, 0x00,
			       MLAN_MAC_ADDR_LENGTH);
			goto setessid_ret;
		}
#endif
		/* Do normal SSID scanning */
		if (MLAN_STATUS_SUCCESS !=
		    woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
			ret = -EFAULT;
			goto setessid_ret;
		}
	} else {
		/* Set the SSID */
		moal_memcpy_ext(handle, req_ssid.ssid, mwr->u.essid.pointer,
				req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
		if (!req_ssid.ssid_len ||
		    (MFALSE == woal_ssid_valid(&req_ssid))) {
			PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
			ret = -EINVAL;
			goto setessid_ret;
		}

		PRINTM(MINFO, "Requested new SSID = %s\n",
		       (char *)req_ssid.ssid);
		moal_memcpy_ext(handle, &ssid_bssid.ssid, &req_ssid,
				sizeof(mlan_802_11_ssid),
				sizeof(mlan_802_11_ssid));
		if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
			PRINTM(MIOCTL, "Already connect to the network\n");
			goto setessid_ret;
		}

		priv->auto_assoc_priv.drv_assoc.status = MFALSE;
		priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
#ifdef REASSOCIATION
		if (priv->reassoc_on == MTRUE) {
			if (priv->auto_assoc_priv.auto_assoc_type_on &
			    (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
				if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
					woal_set_scan_type(
						priv, MLAN_SCAN_TYPE_PASSIVE);
				MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
				moal_memcpy_ext(handle,
						&priv->prev_ssid_bssid.ssid,
						&req_ssid,
						sizeof(mlan_802_11_ssid),
						sizeof(mlan_802_11_ssid));
				priv->auto_assoc_priv.auto_assoc_trigger_flag =
					AUTO_ASSOC_TYPE_DRV_ASSOC;
				priv->auto_assoc_priv.drv_assoc.status = MTRUE;
				priv->reassoc_required = MTRUE;
				priv->phandle->is_reassoc_timer_set = MTRUE;
				PRINTM(MINFO,
				       " auto assoc: trigger driver auto re-assoc\n");
				woal_mod_timer(&priv->phandle->reassoc_timer,
					       0);
				ret = MLAN_STATUS_SUCCESS;

				LEAVE();
				return ret;
			}
		}
#endif

		if (mwr->u.essid.flags != 0xFFFF) {
			if (MLAN_STATUS_SUCCESS !=
			    woal_find_essid(priv, &ssid_bssid,
					    MOAL_IOCTL_WAIT)) {
				/* Do specific SSID scanning */
				if (MLAN_STATUS_SUCCESS !=
				    woal_request_scan(priv, MOAL_IOCTL_WAIT,
						      &req_ssid)) {
					ret = -EFAULT;
					goto setessid_ret;
				}
			}
		}
	}

	mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);

	if (mode != MW_MODE_ADHOC) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_find_best_network(priv, MOAL_IOCTL_WAIT,
					   &ssid_bssid)) {
			ret = -EFAULT;
			goto setessid_ret;
		}
	}
#ifdef UAP_SUPPORT
	else if (MLAN_STATUS_SUCCESS !=
		 woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
		/* Adhoc start, Check the channel command */
		woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
#endif

	/* Connect to BSS by ESSID */
	memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);

	if (MLAN_STATUS_SUCCESS !=
	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
		ret = -EFAULT;
		goto setessid_ret;
	}

#ifdef REASSOCIATION
	memset(&bss_info, 0, sizeof(bss_info));
	if (MLAN_STATUS_SUCCESS !=
	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
		ret = -EFAULT;
		goto setessid_ret;
	}
	moal_memcpy_ext(handle, &priv->prev_ssid_bssid.ssid, &bss_info.ssid,
			sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
	moal_memcpy_ext(handle, &priv->prev_ssid_bssid.bssid, &bss_info.bssid,
			MLAN_MAC_ADDR_LENGTH, sizeof(mlan_802_11_mac_addr));
#endif /* REASSOCIATION */

setessid_ret:
	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
#ifdef REASSOCIATION
	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
#endif
	LEAVE();
	return ret;
}

/**
 *  @brief Set authentication mode parameters
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful, otherwise fail
 */
static int woal_priv_set_auth(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	struct mwreq *mwr;
	t_u8 *data_ptr;
	int ret = 0;
	t_u32 auth_mode = 0;
	t_u32 encrypt_mode = 0;
	t_u8 group_enc = 1;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AUTH));

	mwr = (struct mwreq *)data_ptr;

	switch (mwr->u.param.flags & MW_AUTH_INDEX) {
	case MW_AUTH_CIPHER_PAIRWISE:
		group_enc = 0;
		/* fall through */
	case MW_AUTH_CIPHER_GROUP:
		if (mwr->u.param.value & MW_AUTH_CIPHER_NONE)
			encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
		else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP40)
			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
		else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP104)
			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
		else if (mwr->u.param.value & MW_AUTH_CIPHER_TKIP)
			encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
		else if (mwr->u.param.value & MW_AUTH_CIPHER_CCMP)
			encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode, group_enc))
			ret = -EFAULT;
		break;
	case MW_AUTH_80211_AUTH_ALG:
		switch (mwr->u.param.value) {
		case MW_AUTH_ALG_SHARED_KEY:
			PRINTM(MINFO, "Auth mode shared key!\n");
			auth_mode = MLAN_AUTH_MODE_SHARED;
			break;
		case MW_AUTH_ALG_LEAP:
			PRINTM(MINFO, "Auth mode LEAP!\n");
			auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
			break;
		case MW_AUTH_ALG_OPEN_SYSTEM:
			PRINTM(MINFO, "Auth mode open!\n");
			auth_mode = MLAN_AUTH_MODE_OPEN;
			break;
		case MW_AUTH_ALG_SHARED_KEY | MW_AUTH_ALG_OPEN_SYSTEM:
		default:
			PRINTM(MINFO, "Auth mode auto!\n");
			auth_mode = MLAN_AUTH_MODE_AUTO;
			break;
		}
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
			ret = -EFAULT;
		break;
	case MW_AUTH_WPA_ENABLED:
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT,
					mwr->u.param.value))
			ret = -EFAULT;
		break;
#define MW_AUTH_WAPI_ENABLED 0x20
	case MW_AUTH_WAPI_ENABLED:
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT,
					 mwr->u.param.value))
			ret = -EFAULT;
		break;
	case MW_AUTH_WPA_VERSION:
		/* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
		priv->wpa_version = mwr->u.param.value;
		break;
	case MW_AUTH_KEY_MGMT:
		/* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
		priv->key_mgmt = mwr->u.param.value;
		break;
	case MW_AUTH_TKIP_COUNTERMEASURES:
	case MW_AUTH_DROP_UNENCRYPTED:
	case MW_AUTH_RX_UNENCRYPTED_EAPOL:
	case MW_AUTH_ROAMING_CONTROL:
	case MW_AUTH_PRIVACY_INVOKED:
		break;
	default:
		ret = -EOPNOTSUPP;
		break;
	}
	LEAVE();
	return ret;
}

/**
 *  @brief Get current BSSID
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful else negative value
 */
static int woal_priv_get_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	struct mwreq *mwr;
	t_u8 *data_ptr;
	int ret = 0;
	mlan_bss_info bss_info;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP));

	mwr = (struct mwreq *)data_ptr;

	memset(&bss_info, 0, sizeof(bss_info));

	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
	if (ret != MLAN_STATUS_SUCCESS)
		return -EFAULT;

	if (bss_info.media_connected == MTRUE) {
		moal_memcpy_ext(priv->phandle, mwr->u.ap_addr.sa_data,
				&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0)
				sizeof(mwr->u.ap_addr.sa_data_min));
#else
				sizeof(mwr->u.ap_addr.sa_data));
#endif
	} else {
		memset(mwr->u.ap_addr.sa_data, 0, MLAN_MAC_ADDR_LENGTH);
	}
	mwr->u.ap_addr.sa_family = ARPHRD_ETHER;
	ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP) + sizeof(struct mwreq);

	LEAVE();
	return ret;
}

/**
 *  @brief  Get power management
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful else negative value
 */
static int woal_priv_get_power(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	struct mwreq *mwr;
	t_u8 *data_ptr;
	int ret = 0, ps_mode;

	ENTER();

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER));

	mwr = (struct mwreq *)data_ptr;

	if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
							   &ps_mode, 0,
							   MOAL_IOCTL_WAIT)) {
		return -EFAULT;
	}

	if (ps_mode)
		mwr->u.power.disabled = 0;
	else
		mwr->u.power.disabled = 1;

	mwr->u.power.value = 0;
	ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER) +
	      sizeof(struct mwreq);
	LEAVE();
	return ret;
}

/**
 * @brief Set/Get power save mode
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_set_get_psmode(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int ret = 0;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	t_u32 action = MLAN_ACT_GET;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSMODE);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		action = MLAN_ACT_SET;
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (data != 0 && data != 1) {
		PRINTM(MERROR, "Invalid psmode=%d\n", data);
		ret = -EINVAL;
		goto done;
	}

	/* Flip the value */
	data = !data;

	if (MLAN_STATUS_SUCCESS !=
	    woal_set_get_power_mgmt(priv, action, &data, 0, MOAL_IOCTL_WAIT)) {
		ret = -EFAULT;
		goto done;
	}

	if (action == MLAN_ACT_SET)
		data = !data;

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	LEAVE();
	return ret;
}
#endif /* STA_SUPPORT */

/**
 * @brief Performs warm reset
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         Number of bytes written if successful else negative value
 */
static int woal_priv_warmreset(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret = 0;
	moal_handle *handle = priv->phandle;
	moal_handle *ref_handle;
	moal_private *ref_priv;
	ENTER();
	ret = woal_pre_warmreset(priv);
	if (ret)
		goto done;
	ref_handle = (moal_handle *)handle->pref_mac;
	if (ref_handle) {
		ref_priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
		if (ref_priv) {
			ret = woal_pre_warmreset(ref_priv);
			if (ret)
				goto done;
			ret = woal_warmreset(ref_priv);
			if (ret)
				goto done;
		}
	}
	ret = woal_warmreset(priv);
done:
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get TX power configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         0 --success, otherwise fail
 */
static int woal_priv_txpowercfg(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int data[5];
	int user_data_len;
	int ret = 0;
	mlan_bss_info bss_info;
	mlan_ds_power_cfg *pcfg = NULL;
	mlan_ioctl_req *req = NULL;
	t_u8 *arguments = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	ENTER();

	memset(data, 0, sizeof(data));
	memset(&bss_info, 0, sizeof(bss_info));
	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
	if (ret != MLAN_STATUS_SUCCESS)
		return -EFAULT;

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		arguments =
			respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG);
		parse_arguments(arguments, data, ARRAY_SIZE(data),
				&user_data_len);
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	pcfg = (mlan_ds_power_cfg *)req->pbuf;
	pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
	req->req_id = MLAN_IOCTL_POWER_CFG;

	if (!user_data_len)
		req->action = MLAN_ACT_GET;
	else {
		/* SET operation */
		req->action = MLAN_ACT_SET;
		if (sizeof(int) * user_data_len > sizeof(data)) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
		switch (user_data_len) {
		case 1:
			if (data[0] == 0xFF)
				pcfg->param.power_ext.power_group[0]
					.rate_format = TX_PWR_CFG_AUTO_CTRL_OFF;
			else
				ret = -EINVAL;
			break;
		case 3:
		case 5:
			switch (data[0]) {
			case 0: /* LG */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_LG;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW20;
				break;
			case 1: /* 20 MHz HT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_HT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW20;
				break;
			case 2: /* 40 MHz HT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_HT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW40;
				break;
			case 3: /* 1 NSS 20 MHZ VHT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_VHT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW20;
				pcfg->param.power_ext.power_group[0].nss = 1;
				break;
			case 4: /* 2 NSS 20 MHZ VHT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_VHT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW20;
				pcfg->param.power_ext.power_group[0].nss = 2;
				break;
			case 5: /* 1 NSS 40 MHZ VHT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_VHT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW40;
				pcfg->param.power_ext.power_group[0].nss = 1;
				break;
			case 6: /* 2 NSS 40 MHZ VHT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_VHT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_HT_BW40;
				pcfg->param.power_ext.power_group[0].nss = 2;
				break;
			case 7: /* 1 NSS 80 MHZ VHT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_VHT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_VHT_BW80;
				pcfg->param.power_ext.power_group[0].nss = 1;
				break;
			case 8: /* 2 NSS 80 MHZ VHT */
				pcfg->param.power_ext.power_group[0]
					.rate_format = MLAN_RATE_FORMAT_VHT;
				pcfg->param.power_ext.power_group[0].bandwidth =
					MLAN_VHT_BW80;
				pcfg->param.power_ext.power_group[0].nss = 2;
				break;
			default:
				ret = -EINVAL;
				break;
			}
			pcfg->param.power_ext.power_group[0].first_rate_ind =
				data[1];
			pcfg->param.power_ext.power_group[0].last_rate_ind =
				data[1];
			if (data[2] < bss_info.min_power_level) {
				PRINTM(MERROR,
				       "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
				       data[2], (int)bss_info.min_power_level,
				       (int)bss_info.max_power_level);
				ret = -EINVAL;
				break;
			}
			if (data[2] > bss_info.max_power_level) {
				PRINTM(MERROR,
				       "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
				       data[2], (int)bss_info.min_power_level,
				       (int)bss_info.max_power_level);
				ret = -EINVAL;
				break;
			}
			pcfg->param.power_ext.power_group[0].power_min =
				data[2];
			pcfg->param.power_ext.power_group[0].power_max =
				data[2];
			pcfg->param.power_ext.power_group[0].power_step = 0;
			pcfg->param.power_ext.num_pwr_grp = 1;

			break;
		default:
			ret = -EINVAL;
			break;
		}
		if (ret)
			goto done;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (!user_data_len) {
		/* GET operation */
		moal_memcpy_ext(priv->phandle, respbuf,
				(t_u8 *)&pcfg->param.power_ext,
				sizeof(pcfg->param.power_ext.num_pwr_grp) +
					(MIN(pcfg->param.power_ext.num_pwr_grp,
					     MAX_POWER_GROUP) *
					 sizeof(mlan_power_group)),
				respbuflen);
		ret = sizeof(pcfg->param.power_ext.num_pwr_grp) +
		      (MIN(pcfg->param.power_ext.num_pwr_grp, MAX_POWER_GROUP) *
		       sizeof(mlan_power_group));
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Set/Get PS configuration parameters
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_pscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	int data[7] = {0}, ret = 0;
	mlan_ds_pm_cfg *pm_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int allowed = 3;
	int i = 3;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	allowed++; /* For beacon missing timeout parameter */
	allowed += 2; /* For delay to PS and PS mode parameters */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSCFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
	}

	if (user_data_len && user_data_len > allowed) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
	pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
	req->req_id = MLAN_IOCTL_PM_CFG;
	if (user_data_len) {
		if ((data[0] < PS_NULL_DISABLE)) {
			PRINTM(MERROR,
			       "Invalid argument for PS null interval\n");
			ret = -EINVAL;
			goto done;
		}
		if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) &&
		    (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) &&
		    ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) ||
		     (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
			PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
			ret = -EINVAL;
			goto done;
		}

		if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) &&
		    (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
			PRINTM(MERROR,
			       "Invalid argument for listen interval\n");
			ret = -EINVAL;
			goto done;
		}

		if ((data[i] != DISABLE_BCN_MISS_TO) &&
		    ((data[i] < MIN_BCN_MISS_TO) ||
		     (data[i] > MAX_BCN_MISS_TO))) {
			PRINTM(MERROR,
			       "Invalid argument for beacon miss timeout\n");
			ret = -EINVAL;
			goto done;
		}
		i++;
		if (user_data_len < allowed - 1)
			data[i] = DELAY_TO_PS_UNCHANGED;
		else if ((data[i] < MIN_DELAY_TO_PS) ||
			 (data[i] > MAX_DELAY_TO_PS)) {
			PRINTM(MERROR, "Invalid argument for delay to PS\n");
			ret = -EINVAL;
			goto done;
		}
		i++;
		if ((data[i] != PS_MODE_UNCHANGED) &&
		    (data[i] != PS_MODE_AUTO) && (data[i] != PS_MODE_POLL) &&
		    (data[i] != PS_MODE_NULL)) {
			PRINTM(MERROR, "Invalid argument for PS mode\n");
			ret = -EINVAL;
			goto done;
		}
		i++;
		req->action = MLAN_ACT_SET;
		moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_cfg, data,
				sizeof(data), sizeof(pm_cfg->param.ps_cfg));
	} else
		req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, data, &pm_cfg->param.ps_cfg,
			MIN((sizeof(int) * allowed),
			    sizeof(pm_cfg->param.ps_cfg)),
			sizeof(data));
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
			sizeof(int) * allowed, respbuflen);
	ret = sizeof(int) * allowed;
	if (req->action == MLAN_ACT_SET) {
		pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
		pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
		pm_cfg->param.ps_mode = 1;
		req->req_id = MLAN_IOCTL_PM_CFG;
		req->action = MLAN_ACT_SET;
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Set/Get PS configuration parameters
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_bcntimeoutcfg(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	int data[4] = {0}, ret = 0;
	mlan_ds_pm_cfg *pm_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int allowed = 4;
	int i = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCNTIMEOUTCFG);

	memset((char *)data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);
	if (user_data_len != allowed) {
		PRINTM(MERROR, "Invalid args num: input=%d allowed=%d\n",
		       user_data_len, allowed);
		ret = -EINVAL;
		goto done;
	}
	for (i = 0; i < allowed; i++) {
		if (data[i] <= 0) {
			PRINTM(MERROR, "Invalid data[%d]=%d\n", i, data[i]);
			ret = -EINVAL;
			goto done;
		}
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
	pm_cfg->sub_command = MLAN_OID_PM_CFG_BCN_TIMEOUT;
	req->req_id = MLAN_IOCTL_PM_CFG;
	req->action = MLAN_ACT_SET;
	pm_cfg->param.bcn_timeout.bcn_miss_tmo_window = (t_u16)data[0];
	pm_cfg->param.bcn_timeout.bcn_miss_tmo_period = (t_u16)data[1];
	pm_cfg->param.bcn_timeout.bcn_rq_tmo_window = (t_u16)data[2];
	pm_cfg->param.bcn_timeout.bcn_rq_tmo_period = (t_u16)data[3];

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Set/Get sleep period
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_sleeppd(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_pm_cfg *pm_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
	pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
	req->req_id = MLAN_IOCTL_PM_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEPPD);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len) {
		if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
		    (data == 0) || (data == SLEEP_PERIOD_RESERVED_FF)) {
			req->action = MLAN_ACT_SET;
			pm_cfg->param.sleep_period = data;
		} else {
			ret = -EINVAL;
			goto done;
		}
	} else
		req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (!user_data_len) {
		data = pm_cfg->param.sleep_period;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Set/Get Tx control flag
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_txcontrol(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	misc_cfg->sub_command = MLAN_OID_MISC_TXCONTROL;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXCONTROL);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len) {
		req->action = MLAN_ACT_SET;
		misc_cfg->param.tx_control = (t_u32)data;
	} else {
		req->action = MLAN_ACT_GET;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (!user_data_len) {
		data = misc_cfg->param.tx_control;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Read/Write adapter registers value
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_regrdwr(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int data[3];
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_reg_mem *reg_mem = NULL;
	int user_data_len = 0, header_len = 0;
	t_u8 *arguments = NULL, *space_ind = NULL;
	t_u32 is_negative_val = MFALSE;
	mlan_status status = MLAN_STATUS_SUCCESS;
	gfp_t flag;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
	reg_mem->sub_command = MLAN_OID_REG_RW;
	req->req_id = MLAN_IOCTL_REG_MEM;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGRDWR);

	if ((int)strlen(respbuf) == header_len) {
		ret = -EINVAL;
		goto done;
	}
	/* SET operation */
	memset((char *)data, 0, sizeof(data));
	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
	arguments = kzalloc(strlen(respbuf) * sizeof(char), flag);
	if (arguments == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	strncpy(arguments, respbuf + header_len,
		strlen(respbuf) * sizeof(char));
	space_ind = strstr((char *)arguments, " ");
	if (space_ind)
		space_ind = strstr(space_ind + 1, " ");
	if (space_ind) {
		if (*(char *)(space_ind + 1) == '-') {
			is_negative_val = MTRUE;
			arguments[space_ind + 1 - arguments] = '\0';
			strncat(arguments, space_ind + 2,
				(strlen(respbuf) * sizeof(char)) - 1);
		}
	}
	parse_arguments(arguments, data, ARRAY_SIZE(data), &user_data_len);
	if (is_negative_val == MTRUE)
		data[2] *= -1;

	if (user_data_len == 2) {
		req->action = MLAN_ACT_GET;
	} else if (user_data_len == 3) {
		req->action = MLAN_ACT_SET;
	} else {
		ret = -EINVAL;
		goto done;
	}

	reg_mem->param.reg_rw.type = (t_u32)data[0];
	reg_mem->param.reg_rw.offset = (t_u32)data[1];
	if (user_data_len == 3)
		reg_mem->param.reg_rw.value = (t_u32)data[2];

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		moal_memcpy_ext(priv->phandle, respbuf, &reg_mem->param.reg_rw,
				sizeof(reg_mem->param.reg_rw), respbuflen);
		ret = sizeof(reg_mem->param.reg_rw);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	kfree(arguments);
	LEAVE();
	return ret;
}

/**
 * @brief Read the EEPROM contents of the card
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_rdeeprom(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int data[2];
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_reg_mem *reg_mem = NULL;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
	reg_mem->sub_command = MLAN_OID_EEPROM_RD;
	req->req_id = MLAN_IOCTL_REG_MEM;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RDEEPROM);

	if ((int)strlen(respbuf) == header_len) {
		ret = -EINVAL;
		goto done;
	}
	/* SET operation */
	memset((char *)data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len == 2) {
		req->action = MLAN_ACT_GET;
	} else {
		ret = -EINVAL;
		goto done;
	}

	reg_mem->param.rd_eeprom.offset = (t_u16)data[0];
	reg_mem->param.rd_eeprom.byte_count = (t_u16)data[1];

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		moal_memcpy_ext(priv->phandle, respbuf,
				&reg_mem->param.rd_eeprom,
				sizeof(reg_mem->param.rd_eeprom), respbuflen);
		ret = sizeof(reg_mem->param.rd_eeprom);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief Read/Write device memory value
 *
 * @param priv         A pointer to moal_private structure
 * @param respbuf      A pointer to response buffer
 * @param respbuflen   Available length of response buffer
 *
 * @return         0 --success, otherwise fail
 */
static int woal_priv_memrdwr(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int data[2];
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_reg_mem *reg_mem = NULL;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
	reg_mem->sub_command = MLAN_OID_MEM_RW;
	req->req_id = MLAN_IOCTL_REG_MEM;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MEMRDWR);

	if ((int)strlen(respbuf) == header_len) {
		ret = -EINVAL;
		goto done;
	}
	/* SET operation */
	memset((char *)data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len == 1) {
		PRINTM(MINFO, "MEM_RW: GET\n");
		req->action = MLAN_ACT_GET;
	} else if (user_data_len == 2) {
		PRINTM(MINFO, "MEM_RW: SET\n");
		req->action = MLAN_ACT_SET;
	} else {
		ret = -EINVAL;
		goto done;
	}

	reg_mem->param.mem_rw.addr = (t_u32)data[0];
	if (user_data_len == 2)
		reg_mem->param.mem_rw.value = (t_u32)data[1];

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		moal_memcpy_ext(priv->phandle, respbuf, &reg_mem->param.mem_rw,
				sizeof(reg_mem->param.mem_rw), respbuflen);
		ret = sizeof(reg_mem->param.mem_rw);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef SDIO
/**
 *  @brief Cmd52 read/write register
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
 */
static int woal_priv_sdcmd52rw(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	t_u8 rw = 0, func, data = 0;
	int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
	int user_data_len = 0, header_len = 0;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDCMD52RW);
	memset((t_u8 *)buf, 0, sizeof(buf));

	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	parse_arguments(respbuf + header_len, buf, ARRAY_SIZE(buf),
			&user_data_len);

	if (user_data_len < 2 || user_data_len > 3) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}

	func = (t_u8)buf[0];
	if (func > 7) {
		PRINTM(MERROR, "Invalid function number!\n");
		ret = -EINVAL;
		goto done;
	}
	reg = (t_u32)buf[1];
	if (user_data_len == 2) {
		rw = 0; /* CMD52 read */
		PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
	}
	if (user_data_len == 3) {
		rw = 1; /* CMD52 write */
		data = (t_u8)buf[2];
		PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
		       func, reg, data);
	}

	if (!rw) {
#ifdef SDIO_MMC
		sdio_claim_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		if (func)
			data = sdio_readb(
				((struct sdio_mmc_card *)priv->phandle->card)
					->func,
				reg, &ret);
		else
			data = sdio_f0_readb(
				((struct sdio_mmc_card *)priv->phandle->card)
					->func,
				reg, &ret);
		sdio_release_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		if (ret) {
			PRINTM(MERROR,
			       "sdio_readb: reading register 0x%X failed\n",
			       reg);
			goto done;
		}
#else
		if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
		    0) {
			PRINTM(MERROR,
			       "sdio_read_ioreg: reading register 0x%X failed\n",
			       reg);
			ret = MLAN_STATUS_FAILURE;
			goto done;
		}
#endif /* SDIO_MMC */
	} else {
#ifdef SDIO_MMC
		sdio_claim_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		if (func)
			sdio_writeb(
				((struct sdio_mmc_card *)priv->phandle->card)
					->func,
				data, reg, &ret);
		else
			sdio_f0_writeb(
				((struct sdio_mmc_card *)priv->phandle->card)
					->func,
				data, reg, &ret);
		sdio_release_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		if (ret) {
			PRINTM(MERROR,
			       "sdio_writeb: writing register 0x%X failed\n",
			       reg);
			goto done;
		}
#else
		if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
		    0) {
			PRINTM(MERROR,
			       "sdio_write_ioreg: writing register 0x%X failed\n",
			       reg);
			ret = MLAN_STATUS_FAILURE;
			goto done;
		}
#endif /* SDIO_MMC */
	}

	/* Action = GET */
	buf[0] = data;

	moal_memcpy_ext(priv->phandle, respbuf, &buf, sizeof(int), respbuflen);
	ret = sizeof(int);

done:
	LEAVE();
	return ret;
}
#endif /* SDIO */

#ifdef STA_SUPPORT
/**
 *  @brief arpfilter ioctl function
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return		0 --success, otherwise fail
 */
static int woal_priv_arpfilter(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ioctl_req *req = NULL;
	t_u8 *data_ptr = NULL;
	t_u32 buf_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_GEN_IE;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_SET;
	misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;

	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_ARPFILTER));
	buf_len = *((t_u16 *)data_ptr);
	misc->param.gen_ie.len = buf_len;
	moal_memcpy_ext(priv->phandle, (void *)(misc->param.gen_ie.ie_data),
			data_ptr + sizeof(buf_len), buf_len, MAX_IE_SIZE);

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif /* STA_SUPPORT */

/**
 *  @brief Set / Get Auto ARP Response configuration
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_auto_arp(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int data[4];
	int user_data_len = 0;
	int ret = 0;
	moal_handle *handle = NULL;

	ENTER();

	if (priv == NULL) {
		PRINTM(MERROR, "Invalid priv\n");
		goto done;
	}
	handle = priv->phandle;

	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_ARP))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_AUTO_ARP),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len) {
		/* Get the enable/disable value from user */
		handle->hs_auto_arp = data[0];
		PRINTM(MIOCTL, "Auto ARP : %s\n",
		       handle->hs_auto_arp ? "enable" : "disable");
	}

	moal_memcpy_ext(handle, respbuf, &handle->hs_auto_arp,
			sizeof(handle->hs_auto_arp), respbuflen);
	ret = sizeof(handle->hs_auto_arp);

done:
	LEAVE();
	return ret;
}

/**
 *  @brief Get/Set deauth control
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_deauth_ctrl(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	mlan_ds_snmp_mib *cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0, header_len = 0, data = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_snmp_mib *)req->pbuf;
	cfg->sub_command = MLAN_OID_SNMP_MIB_CTRL_DEAUTH;
	req->req_id = MLAN_IOCTL_SNMP_MIB;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH_CTRL);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		req->action = MLAN_ACT_SET;
		cfg->param.deauthctrl = (t_u8)data;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data = (int)cfg->param.deauthctrl;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#define MRVL_TLV_HEADER_SIZE 4
/**
 *  @brief              Get/Set per packet Txctl and Rxinfo configuration
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_per_pkt_cfg(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	t_u8 *pos = NULL;
	int left_len, header_len = 0;
	mlan_per_pkt_cfg *perpkt = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PER_PKT_CFG);
	pos = respbuf + header_len;
	left_len = respbuflen - header_len;

	if (priv->phandle->card_info->per_pkt_cfg_support == 0) {
		PRINTM(MERROR, "Device not support per packet configuration\n");
		ret = -EFAULT;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_PER_PKT_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (*pos == 0) {
		/* GET operation */
		pos++;
		if (priv->tx_protocols.protocol_num) {
			perpkt = (mlan_per_pkt_cfg *)pos;
			perpkt->type = TLV_TYPE_PER_PKT_CFG;
			perpkt->tx_rx_control = TX_PKT_CTRL;
			perpkt->proto_type_num =
				priv->tx_protocols.protocol_num;
			moal_memcpy_ext(priv->phandle, perpkt->ether_type,
					priv->tx_protocols.protocols,
					perpkt->proto_type_num * sizeof(t_u16),
					MAX_NUM_ETHER_TYPE * sizeof(t_u16));
			perpkt->len =
				(perpkt->proto_type_num + 1) * sizeof(t_u16);
			pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
		}
		if (priv->rx_protocols.protocol_num) {
			perpkt = (mlan_per_pkt_cfg *)pos;
			perpkt->type = TLV_TYPE_PER_PKT_CFG;
			perpkt->tx_rx_control = RX_PKT_INFO;
			perpkt->proto_type_num =
				priv->rx_protocols.protocol_num;
			moal_memcpy_ext(priv->phandle, perpkt->ether_type,
					priv->rx_protocols.protocols,
					perpkt->proto_type_num * sizeof(t_u16),
					MAX_NUM_ETHER_TYPE * sizeof(t_u16));
			perpkt->len =
				(perpkt->proto_type_num + 1) * sizeof(t_u16);
			pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
		}
		ret = pos - respbuf;
		goto done;
	} else if (*pos == 1) {
		/* SET operation */
		req->action = MLAN_ACT_SET;
		pos++;
		left_len--;
		while (*pos == TLV_TYPE_PER_PKT_CFG && (left_len > 2)) {
			perpkt = (mlan_per_pkt_cfg *)pos;
			if (perpkt->tx_rx_control & TX_PKT_CTRL) {
				priv->tx_protocols.protocol_num =
					perpkt->proto_type_num;
				if (perpkt->proto_type_num <=
				    MAX_NUM_ETHER_TYPE)
					moal_memcpy_ext(
						priv->phandle,
						priv->tx_protocols.protocols,
						perpkt->ether_type,
						perpkt->proto_type_num *
							sizeof(t_u16),
						MAX_NUM_ETHER_TYPE *
							sizeof(t_u16));
			}
			if (perpkt->tx_rx_control & RX_PKT_INFO) {
				priv->rx_protocols.protocol_num =
					perpkt->proto_type_num;
				if (perpkt->proto_type_num <=
				    MAX_NUM_ETHER_TYPE)
					moal_memcpy_ext(
						priv->phandle,
						priv->rx_protocols.protocols,
						perpkt->ether_type,
						perpkt->proto_type_num *
							sizeof(t_u16),
						MAX_NUM_ETHER_TYPE *
							sizeof(t_u16));
			}
			if (!perpkt->tx_rx_control) {
				memset(&priv->tx_protocols, 0,
				       sizeof(dot11_protocol));
				memset(&priv->rx_protocols, 0,
				       sizeof(dot11_protocol));
			}
			pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
			left_len -= (perpkt->len + MRVL_TLV_HEADER_SIZE);
		}
	} else
		goto done;

	if (perpkt != NULL)
		misc->param.txrx_pkt_ctrl = perpkt->tx_rx_control;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief              Get Region Channel Power
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_chnrgpwr(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int header_len = 0;
	t_u8 *pos = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	header_len = strlen(PRIV_CMD_GET_CHNRGPWR);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_GET_REGIONPWR_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	ret = header_len + sizeof(t_u16) + misc->param.rgchnpwr_cfg.length;
	pos = respbuf + header_len;
	moal_memcpy_ext(priv->phandle, pos, &misc->param.rgchnpwr_cfg,
			sizeof(t_u16) + misc->param.rgchnpwr_cfg.length,
			respbuflen - header_len);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief              Get TX/RX histogram statistic
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_txpwrlimit(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ds_misc_chan_trpc_cfg *trpc_cfg = NULL;
	int header_len = 0;
	t_u8 *pos = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	header_len = strlen(PRIV_CMD_GET_TXPWR_LIMIT);
	trpc_cfg = (mlan_ds_misc_chan_trpc_cfg *)(respbuf + header_len);
	if ((trpc_cfg->sub_band != 0) && (trpc_cfg->sub_band != 0x10) &&
	    (trpc_cfg->sub_band != 0x11) && (trpc_cfg->sub_band != 0x12) &&
	    (trpc_cfg->sub_band != 0x13) && (trpc_cfg->sub_band != 0x20) &&
	    (trpc_cfg->sub_band != 0x21) && (trpc_cfg->sub_band != 0x22) &&
	    (trpc_cfg->sub_band != 0x23) && (trpc_cfg->sub_band != 0x24) &&
	    (trpc_cfg->sub_band != 0x25) && (trpc_cfg->sub_band != 0x26) &&
	    (trpc_cfg->sub_band != 0x27)) {
		PRINTM(MERROR, "Invalid subband=0x%x\n", trpc_cfg->sub_band);
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_GET_CHAN_TRPC_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;
	misc->param.trpc_cfg.sub_band = trpc_cfg->sub_band;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	ret = header_len + sizeof(t_u16) + sizeof(t_u16) +
	      misc->param.trpc_cfg.length;
	pos = respbuf + header_len;
	moal_memcpy_ext(priv->phandle, pos, &misc->param.trpc_cfg,
			sizeof(t_u16) + sizeof(t_u16) +
				misc->param.trpc_cfg.length,
			respbuflen - header_len);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#if defined(STA_CFG80211) || defined(UAP_CFG80211)
/**
 *  @brief              Get TX/RX histogram statistic
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_getcfgchanlist(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int ret = 0;
	int num_chan = 0;
	wlan_ieee80211_chan_list *plist = NULL;
	struct ieee80211_supported_band *sband;
	struct wiphy *wiphy = NULL;
	t_u8 band;
	int i;

	ENTER();
	if (priv && priv->wdev)
		wiphy = priv->wdev->wiphy;
	if (!wiphy) {
		PRINTM(MERROR, "wiphy is NULL\n");
		ret = -EFAULT;
		goto done;
	}
	plist = (wlan_ieee80211_chan_list *)respbuf;
	for (band = NL80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; ++band) {
		sband = wiphy->bands[band];
		if (sband) {
			for (i = 0; i < sband->n_channels; i++) {
				plist->chan_list[i + num_chan].center_freq =
					sband->channels[i].center_freq;
				plist->chan_list[i + num_chan].hw_value =
					sband->channels[i].hw_value;
				plist->chan_list[i + num_chan].flags =
					sband->channels[i].flags;
				plist->chan_list[i + num_chan].max_power =
					sband->channels[i].max_power;
#if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
				plist->chan_list[i + num_chan].dfs_state =
					sband->channels[i].dfs_state;
#endif
			}
			num_chan += sband->n_channels;
		}
	}
	plist->num_chan = num_chan;
	ret = sizeof(wlan_ieee80211_chan_list) +
	      sizeof(wlan_ieee80211_chan) * num_chan;
done:
	LEAVE();
	return ret;
}
#endif

/**
 *  @brief              Get TX/RX histogram statistic
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_rx_tx_histogram(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	tx_rx_histogram *tx_rx_info = NULL;
	int header_len = 0;
	t_u8 *pos = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	header_len = strlen(PRIV_CMD_TX_RX_HISTOGRAM);
	tx_rx_info = (tx_rx_histogram *)(respbuf + header_len);
	if (tx_rx_info->enable > 2 ||
	    (tx_rx_info->enable == GET_TX_RX_HISTOGRAM &&
	     (tx_rx_info->action > 3 || tx_rx_info->action <= 0))) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_GET_TX_RX_HISTOGRAM;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if (tx_rx_info->enable == GET_TX_RX_HISTOGRAM) {
		misc->param.tx_rx_histogram.enable = ENABLE_TX_RX_HISTOGRAM;
		misc->param.tx_rx_histogram.action = (t_u16)tx_rx_info->action;
	} else {
		misc->param.tx_rx_histogram.enable = tx_rx_info->enable;
		misc->param.tx_rx_histogram.action |=
			FLAG_TX_HISTOGRAM | FLAG_RX_HISTOGRAM;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	ret = header_len + 2 * sizeof(t_u8);
	if (tx_rx_info->enable & GET_TX_RX_HISTOGRAM) {
		pos = respbuf + header_len + 2 * sizeof(t_u8);
		/* Save tx/rx histogram size */
		moal_memcpy_ext(priv->phandle, pos,
				&misc->param.tx_rx_histogram.size,
				sizeof(misc->param.tx_rx_histogram.size),
				respbuflen - (header_len + 2 * sizeof(t_u8)));
		ret += sizeof(misc->param.tx_rx_histogram.size);
		pos += sizeof(misc->param.tx_rx_histogram.size);
		moal_memcpy_ext(
			priv->phandle, pos, &misc->param.tx_rx_histogram.value,
			misc->param.tx_rx_histogram.size,
			respbuflen - (header_len + 2 * sizeof(t_u8)) -
				sizeof(misc->param.tx_rx_histogram.size));
		ret += misc->param.tx_rx_histogram.size;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get hotspot mode configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         0 --success, otherwise fail
 */
static int woal_priv_hotspotcfg(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOTSPOTCFG);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
	}
	if (user_data_len >= 2) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	} else {
		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
		if (req == NULL) {
			ret = -ENOMEM;
			goto done;
		}

		cfg = (mlan_ds_misc_cfg *)req->pbuf;
		if (user_data_len == 0) {
			req->action = MLAN_ACT_GET;
		} else {
			cfg->param.hotspot_cfg = data;
			req->action = MLAN_ACT_SET;
		}
	}
	cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	data = cfg->param.hotspot_cfg;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get Mgmt Frame passthru mask
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         0 --success, otherwise fail
 */
static int woal_priv_mgmt_frame_passthru_ctrl(moal_private *priv, t_u8 *respbuf,
					      t_u32 respbuflen)
{
	int ret = 0;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *mgmt_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MGMT_FRAME_CTRL);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
	}

	if (user_data_len >= 2) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	} else {
		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
		if (req == NULL) {
			ret = -ENOMEM;
			goto done;
		}
		mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf;
		req->req_id = MLAN_IOCTL_MISC_CFG;
		mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;

		if (user_data_len == 0) { /* Get */
			req->action = MLAN_ACT_GET;
		} else { /* Set */
			mgmt_cfg->param.mgmt_subtype_mask = data;
			req->action = MLAN_ACT_SET;
		}
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data = mgmt_cfg->param.mgmt_subtype_mask;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Private IOCTL entry to send an ADDTS TSPEC
 *
 *  Receive a ADDTS command from the application.  The command structure
 *    contains a TSPEC and timeout in milliseconds.  The timeout is performed
 *    in the firmware after the ADDTS command frame is sent.
 *
 *  The TSPEC is received in the API as an opaque block. The firmware will
 *    send the entire data block, including the bytes after the TSPEC.  This
 *    is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
 *    action frame.
 *
 *  The IOCTL structure contains two return fields:
 *    - The firmware command result, which indicates failure and timeouts
 *    - The IEEE Status code which contains the corresponding value from
 *      any ADDTS response frame received.
 *
 *  In addition, the opaque TSPEC data block passed in is replaced with the
 *    TSPEC received in the ADDTS response frame.  In case of failure, the
 *    AP may modify the TSPEC on return and in the case of success, the
 *    medium time is returned as calculated by the AP.  Along with the TSPEC,
 *    any IEs that are sent in the ADDTS response are also returned and can be
 *    parsed using the IOCTL length as an indicator of extra elements.
 *
 *  The return value to the application layer indicates a driver execution
 *    success or failure.  A successful return could still indicate a firmware
 *    failure or AP negotiation failure via the commandResult field copied
 *    back to the application.
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_wmm_addts_req_ioctl(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_wmm_cfg *cfg = NULL;
	wlan_ioctl_wmm_addts_req_t addts_ioctl;
	int ret = 0, header_len = 0, copy_len = sizeof(addts_ioctl);
	t_u8 *data_ptr;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ADDTS);
	data_ptr = respbuf + header_len;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_WMM_CFG;
	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;

	memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));

	moal_memcpy_ext(priv->phandle, (t_u8 *)&addts_ioctl, data_ptr,
			sizeof(addts_ioctl), sizeof(addts_ioctl));

	cfg->param.addts.timeout = addts_ioctl.timeout_ms;
	cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len;

	moal_memcpy_ext(priv->phandle, cfg->param.addts.ie_data,
			addts_ioctl.ie_data, cfg->param.addts.ie_data_len,
			MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	addts_ioctl.cmd_result = cfg->param.addts.result;
	addts_ioctl.ieee_status_code = (t_u8)cfg->param.addts.status_code;
	addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;

	moal_memcpy_ext(priv->phandle, addts_ioctl.ie_data,
			cfg->param.addts.ie_data, cfg->param.addts.ie_data_len,
			MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);

	copy_len = (sizeof(addts_ioctl) - sizeof(addts_ioctl.ie_data) +
		    cfg->param.addts.ie_data_len);

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&addts_ioctl, copy_len,
			respbuflen);
	ret = copy_len;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Private IOCTL entry to send a DELTS TSPEC
 *
 *  Receive a DELTS command from the application.  The command structure
 *    contains a TSPEC and reason code along with space for a command result
 *    to be returned.  The information is packaged is sent to the wlan_cmd.c
 *    firmware command prep and send routines for execution in the firmware.
 *
 *  The reason code is not used for WMM implementations but is indicated in
 *    the 802.11e specification.
 *
 *  The return value to the application layer indicates a driver execution
 *    success or failure.  A successful return could still indicate a firmware
 *    failure via the cmd_result field copied back to the application.
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_wmm_delts_req_ioctl(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_wmm_cfg *cfg = NULL;
	wlan_ioctl_wmm_delts_req_t delts_ioctl;
	int ret = 0, header_len = 0, copy_len = 0;
	t_u8 *data_ptr;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELTS);
	data_ptr = respbuf + header_len;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_WMM_CFG;
	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;

	memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));

	if ((int)strlen(respbuf) > header_len) {
		copy_len = MIN(strlen(data_ptr), sizeof(delts_ioctl));
		moal_memcpy_ext(priv->phandle, (t_u8 *)&delts_ioctl, data_ptr,
				copy_len, sizeof(delts_ioctl));

		cfg->param.delts.status_code =
			(t_u32)delts_ioctl.ieee_reason_code;
		cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len;

		moal_memcpy_ext(priv->phandle, cfg->param.delts.ie_data,
				delts_ioctl.ie_data,
				cfg->param.delts.ie_data_len,
				MLAN_WMM_TSPEC_SIZE);

		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}

		/* Return the firmware command result back to the application
		 * layer */
		delts_ioctl.cmd_result = cfg->param.delts.result;
		copy_len = sizeof(delts_ioctl);
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&delts_ioctl,
				copy_len, respbuflen);
		ret = copy_len;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Private IOCTL entry to get/set a specified AC Queue's parameters
 *
 *  Receive a AC Queue configuration command which is used to get, set, or
 *    default the parameters associated with a specific WMM AC Queue.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         0 --success, otherwise fail
 */
static int woal_priv_qconfig(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_wmm_cfg *pwmm = NULL;
	mlan_ds_wmm_queue_config *pqcfg = NULL;
	wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
	t_u8 *data_ptr;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_WMM_CFG;
	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;

	memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
	pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg;
	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG));

	moal_memcpy_ext(priv->phandle, (t_u8 *)&qcfg_ioctl, data_ptr,
			sizeof(qcfg_ioctl), sizeof(qcfg_ioctl));
	pqcfg->action = qcfg_ioctl.action;
	pqcfg->access_category = qcfg_ioctl.access_category;
	pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
	qcfg_ioctl.action = pqcfg->action;
	qcfg_ioctl.access_category = pqcfg->access_category;
	qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
	moal_memcpy_ext(priv->phandle, data_ptr, (t_u8 *)&qcfg_ioctl,
			sizeof(qcfg_ioctl),
			respbuflen -
				(strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG)));
	ret = strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG) + sizeof(qcfg_ioctl);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Private IOCTL entry to get the status of the WMM queues
 *
 *  Return the following information for each WMM AC:
 *        - WMM IE Acm Required
 *        - Firmware Flow Required
 *        - Firmware Flow Established
 *        - Firmware Queue Enabled
 *        - Firmware Delivery Enabled
 *        - Firmware Trigger Enabled
 *
 *  @param priv    Pointer to the moal_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_wmm_queue_status_ioctl(moal_private *priv, t_u8 *respbuf,
					    t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_wmm_cfg *pwmm = NULL;
	wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
	int ret = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_QSTATUS);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_WMM_CFG;
	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;

	if ((int)strlen(respbuf) == header_len) {
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}

		memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
		moal_memcpy_ext(priv->phandle, (void *)&qstatus_ioctl,
				(void *)&pwmm->param.q_status,
				sizeof(qstatus_ioctl), sizeof(qstatus_ioctl));
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&qstatus_ioctl,
				sizeof(qstatus_ioctl), respbuflen);
		ret = sizeof(qstatus_ioctl);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Private IOCTL entry to get the status of the WMM Traffic Streams
 *
 *  @param priv    Pointer to the moal_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_wmm_ts_status_ioctl(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_wmm_cfg *pwmm = NULL;
	wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
	int ret = 0, header_len = 0;
	t_u8 *data_ptr;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TS_STATUS);
	data_ptr = respbuf + header_len;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_WMM_CFG;
	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
	pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;

	memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));

	moal_memcpy_ext(priv->phandle, (t_u8 *)&ts_status_ioctl, data_ptr,
			sizeof(ts_status_ioctl), sizeof(ts_status_ioctl));

	memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
	pwmm->param.ts_status.tid = ts_status_ioctl.tid;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
	moal_memcpy_ext(priv->phandle, (void *)&ts_status_ioctl,
			(void *)&pwmm->param.ts_status, sizeof(ts_status_ioctl),
			sizeof(ts_status_ioctl));
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&ts_status_ioctl,
			sizeof(ts_status_ioctl), respbuflen);
	ret = sizeof(ts_status_ioctl);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get MAC control
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_macctrl(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int data = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MAC_CTRL);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (user_data_len == 0)
		req->action = MLAN_ACT_GET;
	else {
		cfg->param.mac_ctrl = (t_u32)data;
		req->action = MLAN_ACT_SET;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.mac_ctrl,
			sizeof(data), respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Get connection status
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_getwap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	int ret = 0;
#ifdef STA_SUPPORT
	mlan_bss_info bss_info;
#endif

	ENTER();

#ifdef STA_SUPPORT
	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
		memset(&bss_info, 0, sizeof(bss_info));

		ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
		if (ret != MLAN_STATUS_SUCCESS)
			return -EFAULT;

		if (bss_info.media_connected == MTRUE) {
			moal_memcpy_ext(priv->phandle, respbuf,
					(t_u8 *)&bss_info.bssid,
					MLAN_MAC_ADDR_LENGTH, respbuflen);
		} else {
			memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
		}
	}
#endif
#ifdef UAP_SUPPORT
	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
		if (priv->bss_started) {
			moal_memcpy_ext(priv->phandle, respbuf,
					priv->current_addr,
					MLAN_MAC_ADDR_LENGTH, respbuflen);
		} else {
			memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
		}
	}
#endif
	ret = MLAN_MAC_ADDR_LENGTH;
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get Region Code
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_region_code(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	int data = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGION_CODE);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_REGION;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (user_data_len == 0)
		req->action = MLAN_ACT_GET;
	else {
		cfg->param.region_code = (t_u32)data;
		req->action = MLAN_ACT_SET;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.region_code,
			sizeof(data), respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get channel time and buffer weight
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_multi_chan_config(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	t_u8 *data_ptr;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_MULTI_CHAN_CFG);
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MULTI_CHAN_CFG);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		user_data_len = sizeof(mlan_ds_multi_chan_cfg);
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_MULTI_CHAN_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (user_data_len == 0) {
		req->action = MLAN_ACT_GET;
	} else {
		req->action = MLAN_ACT_SET;
		moal_memcpy_ext(priv->phandle, &cfg->param.multi_chan_cfg,
				data_ptr, sizeof(mlan_ds_multi_chan_cfg),
				sizeof(mlan_ds_multi_chan_cfg));
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf,
			(mlan_ds_multi_chan_cfg *)&cfg->param.multi_chan_cfg,
			req->buf_len, respbuflen);
	ret = req->buf_len;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get multi_channel policy setting
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_multi_chan_policy(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	int data = 0;
	t_u16 enable;
	t_u8 action;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MULTI_CHAN_POLICY);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len == 0) {
		action = MLAN_ACT_GET;
	} else {
		action = MLAN_ACT_SET;
		enable = (t_u16)data;
	}

	if (MLAN_STATUS_SUCCESS !=
	    woal_mc_policy_cfg(priv, &enable, MOAL_IOCTL_WAIT, action)) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf, &enable, sizeof(t_u16),
			respbuflen);
	ret = sizeof(t_u16);

done:
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get drcs time slicing parameters
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_drcs_time_slicing_cfg(moal_private *priv, t_u8 *respbuf,
					   t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	mlan_ds_drcs_cfg *drcs_cfg = NULL;
	t_u8 *data_ptr;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	int data[8];
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_DRCS_CFG);
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DRCS_CFG);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(data_ptr, data, ARRAY_SIZE(data),
				&user_data_len);
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_DRCS_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (user_data_len == 0) {
		req->action = MLAN_ACT_GET;
	} else {
		req->action = MLAN_ACT_SET;
		drcs_cfg = (mlan_ds_drcs_cfg *)&cfg->param.drcs_cfg[0];
		drcs_cfg->chantime = (t_u8)data[0];
		drcs_cfg->switchtime = (t_u8)data[1];
		drcs_cfg->undozetime = (t_u8)data[2];
		drcs_cfg->mode = (t_u8)data[3];
		/* Set the same parameters for two channels*/
		if (user_data_len < (int)ARRAY_SIZE(data))
			drcs_cfg->chan_idx = 0x03;
		else {
			/* Set the different parameters for two channels*/
			drcs_cfg->chan_idx = 0x1;
			drcs_cfg = (mlan_ds_drcs_cfg *)&cfg->param.drcs_cfg[1];
			drcs_cfg->chan_idx = 0x2;
			drcs_cfg->chantime = (t_u8)data[4];
			drcs_cfg->switchtime = (t_u8)data[5];
			drcs_cfg->undozetime = (t_u8)data[6];
			drcs_cfg->mode = (t_u8)data[7];
		}
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.drcs_cfg,
			req->buf_len, respbuflen);
	ret = req->buf_len;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get FW side mac address
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_fwmacaddr(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	t_u8 data[ETH_ALEN];
	int ret = 0;
	int header_len = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_bss *bss = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_FWMACADDR);

	/* Allocate an IOCTL request buffer */
	req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	/* Fill request buffer */
	bss = (mlan_ds_bss *)req->pbuf;
	bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
	req->req_id = MLAN_IOCTL_BSS;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		req->action = MLAN_ACT_SET;
		memset(data, 0, sizeof(data));
		woal_mac2u8(data, respbuf + header_len);
		moal_memcpy_ext(priv->phandle, bss->param.mac_addr, data,
				ETH_ALEN, sizeof(mlan_802_11_mac_addr));
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, bss->param.mac_addr,
			sizeof(data), respbuflen);
	ret = sizeof(data);
	HEXDUMP("FW MAC Addr:", respbuf, ETH_ALEN);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#if defined(STA_CFG80211) || defined(UAP_CFG80211)
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
/**
 *  @brief Set offchannel
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_offchannel(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int data[4];
	int ret = 0;
	t_u8 status = 1;
	t_u8 chan_type = CHAN_NO_HT;
	int user_data_len = 0, header_len = 0;

	ENTER();

	memset(data, 0, sizeof(data));

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_OFFCHANNEL);

	if (header_len == (int)strlen(respbuf)) {
		/* Query current remain on channel status */
		if (priv->phandle->remain_on_channel)
			ret = snprintf(
				      respbuf, CMD_BUF_LEN,
				      "There is pending remain on channel from bss %d\n",
				      priv->phandle->remain_bss_index) +
			      1;
		else
			ret = snprintf(
				      respbuf, CMD_BUF_LEN,
				      "There is no pending remain on channel\n") +
			      1;
		goto done;
	} else
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}

	if (user_data_len >= 1) {
		if ((data[0] != 0) && (data[0] != 1)) {
			PRINTM(MERROR, "action (%d) must be either 0 or 1\n",
			       data[0]);
			ret = -EINVAL;
			goto done;
		}
	}
	if (user_data_len == 2) {
		if (data[0] == 1) {
			PRINTM(MERROR,
			       "channel and duration must both the mentioned\n");
			ret = -EINVAL;
			goto done;
		} else {
			PRINTM(MWARN,
			       "extra arguments are ignored since action is 'cancel'\n");
		}
	}
	if (user_data_len >= 3) {
		if (data[0] == 1) {
			if (data[1] < 0) {
				PRINTM(MERROR, "channel cannot be negative\n");
				ret = -EINVAL;
				goto done;
			}
			if (data[2] < 0) {
				PRINTM(MERROR, "duration cannot be negative\n");
				ret = -EINVAL;
				goto done;
			}
			if (user_data_len == 4) {
				if (data[3] &&
				    (data[3] != CHANNEL_BW_40MHZ_ABOVE) &&
				    (data[3] != CHANNEL_BW_40MHZ_BELOW) &&
				    (data[3] != CHANNEL_BW_80MHZ)) {
					PRINTM(MERROR, "invalid bandwidth");
					ret = -EINVAL;
					goto done;
				}
				switch (data[3]) {
				case CHANNEL_BW_40MHZ_ABOVE:
					chan_type = CHAN_HT40PLUS;
					break;
				case CHANNEL_BW_40MHZ_BELOW:
					chan_type = CHAN_HT40MINUS;
					break;
				case CHANNEL_BW_80MHZ:
					chan_type = CHAN_VHT80;
					break;
				default:
					break;
				}
			}
		}
	}

	if (data[0] == 0) {
		if (!priv->phandle->remain_on_channel) {
			ret = snprintf(
				      respbuf, CMD_BUF_LEN,
				      "There is no pending remain on channel to be canceled\n") +
			      1;
			goto done;
		}
		if (woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
							MTRUE, &status, NULL, 0,
							0)) {
			PRINTM(MERROR, "remain_on_channel: Failed to cancel\n");
			ret = -EFAULT;
			goto done;
		}
		if (status == MLAN_STATUS_SUCCESS)
			priv->phandle->remain_on_channel = MFALSE;
	} else if (data[0] == 1) {
		if (woal_cfg80211_remain_on_channel_cfg(
			    priv, MOAL_IOCTL_WAIT, MFALSE, &status,
			    ieee80211_get_channel(
				    priv->wdev->wiphy,
				    ieee80211_channel_to_frequency(
					    data[1]
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
					    ,
					    (data[1] <= 14 ?
						     IEEE80211_BAND_2GHZ :
						     IEEE80211_BAND_5GHZ)
#endif
						    )),
			    chan_type, (t_u32)data[2])) {
			PRINTM(MERROR, "remain_on_channel: Failed to start\n");
			ret = -EFAULT;
			goto done;
		}
		if (status == MLAN_STATUS_SUCCESS) {
			priv->phandle->remain_on_channel = MTRUE;
			priv->phandle->remain_bss_index = priv->bss_index;
		}
	}

	if (status != MLAN_STATUS_SUCCESS)
		ret = -EFAULT;
	else
		ret = snprintf(respbuf, CMD_BUF_LEN, "OK\n") + 1;

done:
	LEAVE();
	return ret;
}
#endif
#endif

/**
 *  @brief Set/Get dscp map
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_set_get_dscp_map(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int ret = MLAN_STATUS_SUCCESS;
	t_u8 *pos = NULL;
	int copy_size = 0, header_len = 0;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DSCP_MAP);
	if ((int)strlen(respbuf) != header_len) {
		/* SET operation */
		pos = respbuf + header_len;
		moal_memcpy_ext(priv->phandle, priv->dscp_map, pos,
				sizeof(priv->dscp_map), sizeof(priv->dscp_map));
	}

	copy_size = MIN(sizeof(priv->dscp_map), respbuflen);
	moal_memcpy_ext(priv->phandle, respbuf, priv->dscp_map, copy_size,
			respbuflen);
	ret = copy_size;

	LEAVE();
	return ret;
}

/**
 *  @brief Get extended driver version
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_driver_verext(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_get_info *info = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int copy_size = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	info = (mlan_ds_get_info *)req->pbuf;
	info->sub_command = MLAN_OID_GET_VER_EXT;
	req->req_id = MLAN_IOCTL_GET_INFO;
	req->action = MLAN_ACT_GET;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_VEREXT);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	info->param.ver_ext.version_str_sel = data;
	if (((t_s32)(info->param.ver_ext.version_str_sel)) < 0) {
		PRINTM(MERROR, "Invalid arguments!\n");
		ret = -EINVAL;
		goto done;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	/*
	 * Set the amount to copy back to the application as the minimum of the
	 *   available assoc resp data or the buffer provided by the application
	 */
	copy_size = MIN(strlen(info->param.ver_ext.version_str), respbuflen);
	moal_memcpy_ext(priv->phandle, respbuf, info->param.ver_ext.version_str,
			copy_size, respbuflen);
	ret = copy_size;
	PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
	       info->param.ver_ext.version_str);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef USB
#ifdef CONFIG_USB_SUSPEND
/**
 *  @brief This function makes USB device to suspend.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_enter_usb_suspend(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	int ret = 0;

	ENTER();
	ret = woal_enter_usb_suspend(priv->phandle);
	moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
	ret = sizeof(int);

	LEAVE();
	return ret;
}

/**
 *  @brief This function makes USB device to resume.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_exit_usb_suspend(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int ret = 0;

	ENTER();
	ret = woal_exit_usb_suspend(priv->phandle);
	moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
	ret = sizeof(int);

	LEAVE();
	return ret;
}
#endif /* CONFIG_USB_SUSPEND */
#endif

#if defined(STA_SUPPORT) && defined(STA_WEXT)
/**
 *  @brief SET/Get radio
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_radio_ctrl(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0, option = 0;
	int user_data_len = 0, header_len = 0;
	mlan_bss_info bss_info;

	ENTER();

	memset(&bss_info, 0, sizeof(bss_info));

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RADIO_CTRL);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &option, 1,
				&user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	if (user_data_len == 1) {
		/* Set radio */
		if (option < 0 || option > 1) {
			PRINTM(MERROR, "Invalid arguments!\n");
			ret = -EINVAL;
			goto done;
		}
		if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option))
			ret = -EFAULT;
		goto done;
	} else {
		/* Get radio status */
		ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
		if (ret != MLAN_STATUS_SUCCESS)
			return -EFAULT;
		moal_memcpy_ext(priv->phandle, respbuf, &bss_info.radio_on,
				sizeof(bss_info.radio_on), respbuflen);
		ret = sizeof(bss_info.radio_on);
	}
done:
	LEAVE();
	return ret;
}
#endif

/**
 *  @brief Implement WMM enable command
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_wmm_cfg(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_wmm_cfg *wmm = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	wmm = (mlan_ds_wmm_cfg *)req->pbuf;
	wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
	req->req_id = MLAN_IOCTL_WMM_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WMM_CFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			/* Set wmm */
			if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
				PRINTM(MERROR, "Invalid arguments!\n");
				ret = -EINVAL;
				goto done;
			}
			req->action = MLAN_ACT_SET;
			if (data == CMD_DISABLED)
				wmm->param.wmm_enable = MFALSE;
			else
				wmm->param.wmm_enable = MTRUE;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, &wmm->param.wmm_enable,
			sizeof(wmm->param.wmm_enable), respbuflen);
	ret = sizeof(wmm->param.wmm_enable);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Implement Mininum BA Threshold cfg command
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_min_ba_threshold_cfg(moal_private *priv, t_u8 *respbuf,
					  t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_MIN_BA_THRESHOLD;
	req->req_id = MLAN_IOCTL_11N_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIN_BA_THRESH_CFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			/* Set minimum BA Threshold */
			if ((data < 0) || (data > 16)) {
				PRINTM(MERROR,
				       "Error: Valid minimum BA threshold range (0-16)!\n");
				ret = -EINVAL;
				goto done;
			}
			req->action = MLAN_ACT_SET;
			cfg_11n->param.min_ba_threshold = data;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf,
			&cfg_11n->param.min_ba_threshold,
			sizeof(cfg_11n->param.min_ba_threshold), respbuflen);
	ret = sizeof(cfg_11n->param.min_ba_threshold);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#if defined(STA_SUPPORT)
/**
 *  @brief Implement 802.11D enable command
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_11d_cfg(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_11d_cfg *pcfg_11d = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
	pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
	req->req_id = MLAN_IOCTL_11D_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
				PRINTM(MERROR, "Invalid arguments!\n");
				ret = -EINVAL;
				goto done;
			}
			req->action = MLAN_ACT_SET;
			if (data == CMD_DISABLED)
				pcfg_11d->param.enable_11d = MFALSE;
			else
				pcfg_11d->param.enable_11d = MTRUE;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, &pcfg_11d->param.enable_11d,
			sizeof(pcfg_11d->param.enable_11d), respbuflen);
	ret = sizeof(pcfg_11d->param.enable_11d);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Implement 802.11D clear chan table command
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise fail
 */
static int woal_priv_11d_clr_chan_tbl(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	mlan_ds_11d_cfg *pcfg_11d = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CLR_TBL);

	if ((int)strlen(respbuf) != header_len) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
	pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
	req->req_id = MLAN_IOCTL_11D_CFG;
	req->action = MLAN_ACT_SET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif

#ifndef OPCHAN
/**
 *  @brief Set/Get WWS mode
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_wws_cfg(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_misc_cfg *wws = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	wws = (mlan_ds_misc_cfg *)req->pbuf;
	wws->sub_command = MLAN_OID_MISC_WWS;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WWS_CFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
				PRINTM(MERROR,
				       "Invalid arguments, WWS config not changed!\n");
				ret = -EINVAL;
				goto done;
			}
			req->action = MLAN_ACT_SET;
			wws->param.wws_cfg = (t_u16)data;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, &wws->param.wws_cfg,
			sizeof(wws->param.wws_cfg), respbuflen);
	ret = sizeof(wws->param.wws_cfg);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif

#if defined(REASSOCIATION)
/**
 *  @brief Set/Get reassociation settings
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_reassoc(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	moal_handle *handle = priv->phandle;
	int data = 0;
	int ret = 0;
	int user_data_len = 0, header_len = 0;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REASSOCTRL);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		data = (int)(priv->reassoc_on);
		moal_memcpy_ext(handle, respbuf, &data, sizeof(data),
				respbuflen);
		ret = sizeof(data);
	} else {
#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
		if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
			if (priv->host_mlme) {
				PRINTM(MERROR,
				       "Don't support reassoctrl in host_mlme mode\n");
				ret = -EFAULT;
				LEAVE();
				return ret;
			}
		}
#endif
#endif
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			if (data == 0) {
				handle->reassoc_on &= ~MBIT(priv->bss_index);
				priv->reassoc_on = MFALSE;
				priv->reassoc_required = MFALSE;
				if (!handle->reassoc_on &&
				    handle->is_reassoc_timer_set == MTRUE) {
					woal_cancel_timer(
						&handle->reassoc_timer);
					handle->is_reassoc_timer_set = MFALSE;
				}
			} else if (data == 1) {
				handle->reassoc_on |= MBIT(priv->bss_index);
				priv->reassoc_on = MTRUE;
			} else {
				PRINTM(MERROR, "Invalid arguments!\n");
				ret = -EINVAL;
			}
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
		}
	}

	LEAVE();
	return ret;
}
#endif /* REASSOCIATION */

/**
 *  @brief Get Transmit buffer size
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_txbuf_cfg(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int buf_size = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
	req->req_id = MLAN_IOCTL_11N_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXBUF_CFG);

	if ((int)strlen(respbuf) != header_len) {
		PRINTM(MERROR,
		       "Don't support set Tx buffer size after driver loaded!\n");
		ret = -EINVAL;
		goto done;
	} else {
		/* Get Tx buffer size from MLAN */
		req->action = MLAN_ACT_GET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	buf_size = cfg_11n->param.tx_buf_size;
	moal_memcpy_ext(priv->phandle, respbuf, &buf_size, sizeof(buf_size),
			respbuflen);
	ret = sizeof(buf_size);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef STA_SUPPORT
/**
 *  @brief Set/Get auth type
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_auth_type(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int auth_type = 0;
	t_u32 auth_mode;
	int ret = 0;
	int user_data_len = 0, header_len = 0;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTH_TYPE);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		if (MLAN_STATUS_SUCCESS !=
		    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
			ret = -EFAULT;
			goto done;
		}
		user_data_len = 0;
		auth_type = auth_mode;
		moal_memcpy_ext(priv->phandle, respbuf, &auth_type,
				sizeof(auth_type), respbuflen);
		ret = sizeof(auth_type);
		goto done;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &auth_type, 1,
				&user_data_len);
		if (user_data_len == 1) {
			PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
			if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
			     (auth_type > MLAN_AUTH_MODE_OWE)) &&
			    (auth_type != MLAN_AUTH_MODE_AUTO)) {
				ret = -EINVAL;
				goto done;
			}
			auth_mode = auth_type;
			if (MLAN_STATUS_SUCCESS !=
			    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT,
					       auth_mode)) {
				ret = -EFAULT;
				goto done;
			}
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
		}
	}

done:
	LEAVE();
	return ret;
}
#endif

/**
 *  @brief Set/get user provisioned local power constraint
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_11h_local_pwr_constraint(moal_private *priv, t_u8 *respbuf,
					      t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_11h_cfg *ds_11hcfg = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
	ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
	req->req_id = MLAN_IOCTL_11H_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_POWER_CONS);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			req->action = MLAN_ACT_SET;
			ds_11hcfg->param.usr_local_power_constraint =
				(t_s8)data;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		data = (int)ds_11hcfg->param.usr_local_power_constraint;
		moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
				respbuflen);
		ret = sizeof(data);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/get HT stream configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_ht_stream_cfg(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_11n_cfg *cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_11n_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
	req->req_id = MLAN_IOCTL_11N_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HT_STREAM_CFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			if (data != HT_STREAM_MODE_1X1 &&
			    data != HT_STREAM_MODE_2X2) {
				PRINTM(MERROR, "Invalid arguments!\n");
				ret = -EINVAL;
				goto done;
			}
			req->action = MLAN_ACT_SET;
			cfg->param.stream_cfg = data;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data = ((mlan_ds_11n_cfg *)req->pbuf)->param.stream_cfg;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set mimo switch configurations
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_mimo_switch(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	int data[2] = {0};
	mlan_ds_radio_cfg *radio = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	radio = (mlan_ds_radio_cfg *)req->pbuf;
	radio->sub_command = MLAN_OID_MIMO_SWITCH;
	req->req_id = MLAN_IOCTL_RADIO_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIMO_SWITCH);

	if ((int)strlen(respbuf) > header_len) {
		/* SET operation */
		req->action = MLAN_ACT_SET;
		parse_arguments(respbuf + header_len, data, 2, &user_data_len);
		if (user_data_len == 2) {
			radio->param.mimo_switch_cfg.txpath_antmode = data[0];
			radio->param.mimo_switch_cfg.rxpath_antmode = data[1];
		} else {
			PRINTM(MERROR, "Invalid arguments!\n");
			ret = -EINVAL;
			goto done;
		}
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
	} else {
		PRINTM(MERROR, "Invalid arguments!\n");
		ret = -EINVAL;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Get thermal reading
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_thermal(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	mlan_ds_misc_cfg *cfg = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0, header_len = 0, data = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_THERMAL;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_THERMAL);

	if ((int)strlen(respbuf) != header_len) {
		PRINTM(MERROR, "Set is not supported for this command\n");
		ret = -EINVAL;
		goto done;
	}
	req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data = (int)cfg->param.thermal;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get beacon interval
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_beacon_interval(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	int data = 0;
	mlan_ds_bss *bss = NULL;
	mlan_ioctl_req *req = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	bss = (mlan_ds_bss *)req->pbuf;
	bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
	req->req_id = MLAN_IOCTL_BSS;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCN_INTERVAL);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
		if (user_data_len == 1) {
			if ((data < MLAN_MIN_BEACON_INTERVAL) ||
			    (data > MLAN_MAX_BEACON_INTERVAL)) {
				PRINTM(MERROR, "Invalid arguments!\n");
				ret = -EINVAL;
				goto done;
			}
			req->action = MLAN_ACT_SET;
			bss->param.bcn_interval = data;
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data = ((mlan_ds_bss *)req->pbuf)->param.bcn_interval;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef STA_SUPPORT
/**
 *  @brief Get signal
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_signal(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
/** Input data size */
#define IN_DATA_SIZE 2
/** Output data size */
#define OUT_DATA_SIZE 12
	int ret = 0;
	int in_data[IN_DATA_SIZE];
	int out_data[OUT_DATA_SIZE];
	mlan_ds_get_signal signal;
	int data_length = 0;
	int user_data_len = 0, header_len = 0;

	ENTER();

	memset(in_data, 0, sizeof(in_data));
	memset(out_data, 0, sizeof(out_data));

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL);

	if ((int)strlen(respbuf) != header_len)
		parse_arguments(respbuf + header_len, in_data, IN_DATA_SIZE,
				&user_data_len);

	if (priv->media_connected == MFALSE) {
		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
		ret = -ENOTSUPP;
		goto done;
	}

	if (user_data_len) {
		if (user_data_len > IN_DATA_SIZE) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}

	switch (user_data_len) {
	case 0: /* No checking, get everything */
		break;
	case 2: /* Check subtype range */
		if (in_data[1] < 1 || in_data[1] > 4) {
			ret = -EINVAL;
			goto done;
		}
		/* Fall through */
	case 1: /* Check type range */
		if (in_data[0] < 1 || in_data[0] > 3) {
			ret = -EINVAL;
			goto done;
		}
		break;
	default:
		ret = -EINVAL;
		goto done;
	}

	memset(&signal, 0, sizeof(mlan_ds_get_signal));
	if (MLAN_STATUS_SUCCESS !=
	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
		ret = -EFAULT;
		goto done;
	}
	PRINTM(MINFO, "RSSI Beacon Last   : %d\n", (int)signal.bcn_rssi_last);
	PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg);
	PRINTM(MINFO, "RSSI Data Last     : %d\n", (int)signal.data_rssi_last);
	PRINTM(MINFO, "RSSI Data Average  : %d\n", (int)signal.data_rssi_avg);
	PRINTM(MINFO, "SNR Beacon Last    : %d\n", (int)signal.bcn_snr_last);
	PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg);
	PRINTM(MINFO, "SNR Data Last      : %d\n", (int)signal.data_snr_last);
	PRINTM(MINFO, "SNR Data Average   : %d\n", (int)signal.data_snr_avg);
	PRINTM(MINFO, "NF Beacon Last     : %d\n", (int)signal.bcn_nf_last);
	PRINTM(MINFO, "NF Beacon Average  : %d\n", (int)signal.bcn_nf_avg);
	PRINTM(MINFO, "NF Data Last       : %d\n", (int)signal.data_nf_last);
	PRINTM(MINFO, "NF Data Average    : %d\n", (int)signal.data_nf_avg);

	/* Check type */
	switch (in_data[0]) {
	case 0: /* Send everything */
		out_data[data_length++] = signal.bcn_rssi_last;
		out_data[data_length++] = signal.bcn_rssi_avg;
		out_data[data_length++] = signal.data_rssi_last;
		out_data[data_length++] = signal.data_rssi_avg;
		out_data[data_length++] = signal.bcn_snr_last;
		out_data[data_length++] = signal.bcn_snr_avg;
		out_data[data_length++] = signal.data_snr_last;
		out_data[data_length++] = signal.data_snr_avg;
		out_data[data_length++] = signal.bcn_nf_last;
		out_data[data_length++] = signal.bcn_nf_avg;
		out_data[data_length++] = signal.data_nf_last;
		out_data[data_length++] = signal.data_nf_avg;
		break;
	case 1: /* RSSI */
		/* Check subtype */
		switch (in_data[1]) {
		case 0: /* Everything */
			out_data[data_length++] = signal.bcn_rssi_last;
			out_data[data_length++] = signal.bcn_rssi_avg;
			out_data[data_length++] = signal.data_rssi_last;
			out_data[data_length++] = signal.data_rssi_avg;
			break;
		case 1: /* bcn last */
			out_data[data_length++] = signal.bcn_rssi_last;
			break;
		case 2: /* bcn avg */
			out_data[data_length++] = signal.bcn_rssi_avg;
			break;
		case 3: /* data last */
			out_data[data_length++] = signal.data_rssi_last;
			break;
		case 4: /* data avg */
			out_data[data_length++] = signal.data_rssi_avg;
			break;
		default:
			break;
		}
		break;
	case 2: /* SNR */
		/* Check subtype */
		switch (in_data[1]) {
		case 0: /* Everything */
			out_data[data_length++] = signal.bcn_snr_last;
			out_data[data_length++] = signal.bcn_snr_avg;
			out_data[data_length++] = signal.data_snr_last;
			out_data[data_length++] = signal.data_snr_avg;
			break;
		case 1: /* bcn last */
			out_data[data_length++] = signal.bcn_snr_last;
			break;
		case 2: /* bcn avg */
			out_data[data_length++] = signal.bcn_snr_avg;
			break;
		case 3: /* data last */
			out_data[data_length++] = signal.data_snr_last;
			break;
		case 4: /* data avg */
			out_data[data_length++] = signal.data_snr_avg;
			break;
		default:
			break;
		}
		break;
	case 3: /* NF */
		/* Check subtype */
		switch (in_data[1]) {
		case 0: /* Everything */
			out_data[data_length++] = signal.bcn_nf_last;
			out_data[data_length++] = signal.bcn_nf_avg;
			out_data[data_length++] = signal.data_nf_last;
			out_data[data_length++] = signal.data_nf_avg;
			break;
		case 1: /* bcn last */
			out_data[data_length++] = signal.bcn_nf_last;
			break;
		case 2: /* bcn avg */
			out_data[data_length++] = signal.bcn_nf_avg;
			break;
		case 3: /* data last */
			out_data[data_length++] = signal.data_nf_last;
			break;
		case 4: /* data avg */
			out_data[data_length++] = signal.data_nf_avg;
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}

	moal_memcpy_ext(priv->phandle, respbuf, out_data,
			(data_length * sizeof(int)), respbuflen);
	ret = data_length * sizeof(int);

done:
	LEAVE();
	return ret;
}

static int woal_signal_ext_enable(moal_private *priv, t_u8 enable)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_snmp_mib *snmp = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	snmp = (mlan_ds_snmp_mib *)req->pbuf;
	snmp->sub_command = MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE;
	req->req_id = MLAN_IOCTL_SNMP_MIB;
	req->action = MLAN_ACT_SET;
	snmp->param.signalext_enable = enable;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Get signal
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_signal_ext(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
#define PATH_SIZE 13
	int ret = 0;
	int data = 0, path = 0, data_len = 0;
	int user_data_len = 0, header_len = 0;
	int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
	mlan_ioctl_req *req = NULL;
	mlan_ds_get_info *info = NULL;
	mlan_ds_get_signal signal_get[MAX_PATH_NUM];
	mlan_status status = MLAN_STATUS_SUCCESS;
	int path_num;
	t_u8 enable = 1;

	ENTER();

	if (priv->media_connected == MFALSE) {
		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
		ret = -ENOTSUPP;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT);

	if ((int)strlen(respbuf) != header_len) {
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	if (data < PATH_ALL || data > PATH_AB) {
		PRINTM(MERROR, "Wrong arguments\n");
		ret = -EINVAL;
		goto done;
	}

	/** Enable signalext feature in firmware */
	if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
		ret = -EFAULT;
		goto done;
	}
	woal_sched_timeout(1000);
	enable = 0;

	/* Fill request buffer */
	info = (mlan_ds_get_info *)req->pbuf;
	info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
	req->req_id = MLAN_IOCTL_GET_INFO;
	req->action = MLAN_ACT_GET;
	info->param.path_id = (t_u16)data;

	/* Send IOCTL request to MLAN */
	if (MLAN_STATUS_SUCCESS !=
	    woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
		woal_signal_ext_enable(priv, enable);
		ret = -EFAULT;
		goto done;
	}
	if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
		ret = -EFAULT;
		goto done;
	}
	path_num = 1;
	if (data == PATH_ALL) {
		moal_memcpy_ext(priv->phandle, signal_get,
				info->param.signal_ext, sizeof(signal_get),
				sizeof(signal_get));
		path_num = MAX_PATH_NUM;
	} else
		moal_memcpy_ext(priv->phandle, signal_get,
				info->param.signal_ext,
				sizeof(mlan_ds_get_signal), sizeof(signal_get));

	for (path = 0; path < path_num; path++) {
		if (signal_get[path].selector == PATH_AB)
			PRINTM(MINFO, "PATH A+B:\n");
		else if (signal_get[path].selector == PATH_A)
			PRINTM(MINFO, "PATH A:\n");
		else if (signal_get[path].selector == PATH_B)
			PRINTM(MINFO, "PATH B:\n");
		PRINTM(MINFO, "RSSI Beacon Last   : %d\n",
		       (int)signal_get[path].bcn_rssi_last);
		PRINTM(MINFO, "RSSI Beacon Average: %d\n",
		       (int)signal_get[path].bcn_rssi_avg);
		PRINTM(MINFO, "RSSI Data Last     : %d\n",
		       (int)signal_get[path].data_rssi_last);
		PRINTM(MINFO, "RSSI Data Average  : %d\n",
		       (int)signal_get[path].data_rssi_avg);
		PRINTM(MINFO, "SNR Beacon Last    : %d\n",
		       (int)signal_get[path].bcn_snr_last);
		PRINTM(MINFO, "SNR Beacon Average : %d\n",
		       (int)signal_get[path].bcn_snr_avg);
		PRINTM(MINFO, "SNR Data Last      : %d\n",
		       (int)signal_get[path].data_snr_last);
		PRINTM(MINFO, "SNR Data Average   : %d\n",
		       (int)signal_get[path].data_snr_avg);
		PRINTM(MINFO, "NF Beacon Last     : %d\n",
		       (int)signal_get[path].bcn_nf_last);
		PRINTM(MINFO, "NF Beacon Average  : %d\n",
		       (int)signal_get[path].bcn_nf_avg);
		PRINTM(MINFO, "NF Data Last       : %d\n",
		       (int)signal_get[path].data_nf_last);
		PRINTM(MINFO, "NF Data Average    : %d\n",
		       (int)signal_get[path].data_nf_avg);
		out_data[data_len++] = (int)signal_get[path].selector;
		out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
		out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
		out_data[data_len++] = (int)signal_get[path].data_rssi_last;
		out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
		out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
		out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
		out_data[data_len++] = (int)signal_get[path].data_snr_last;
		out_data[data_len++] = (int)signal_get[path].data_snr_avg;
		out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
		out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
		out_data[data_len++] = (int)signal_get[path].data_nf_last;
		out_data[data_len++] = (int)signal_get[path].data_nf_avg;
	}
	moal_memcpy_ext(
		priv->phandle, respbuf, out_data,
		(MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
		respbuflen);
	ret = data_len * sizeof(int);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Get signalext v2
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_signal_ext_v2(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
#define PATH_SIZE 13
	int ret = 0;
	int data = 0, path = 0, data_len = 0;
	int user_data_len = 0, header_len = 0;
	int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
	mlan_ioctl_req *req = NULL;
	mlan_ds_get_info *info = NULL;
	mlan_ds_get_signal signal_get[MAX_PATH_NUM];
	mlan_status status = MLAN_STATUS_SUCCESS;
	int path_num;

	ENTER();

	if (priv->media_connected == MFALSE) {
		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
		ret = -ENOTSUPP;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT_V2);
	if ((int)strlen(respbuf) != header_len) {
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
	}

	if (user_data_len > 1) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		goto done;
	}
	if (data < PATH_ALL || data > PATH_AB) {
		PRINTM(MERROR, "Wrong arguments\n");
		ret = -EINVAL;
		goto done;
	}

	/* Fill request buffer */
	info = (mlan_ds_get_info *)req->pbuf;
	info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
	req->req_id = MLAN_IOCTL_GET_INFO;
	req->action = MLAN_ACT_GET;
	info->param.path_id = (t_u16)data;

	/* Send IOCTL request to MLAN */
	if (MLAN_STATUS_SUCCESS !=
	    woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
		PRINTM(MERROR,
		       "Enable signalextcfg: mlanutl mlanX signalextcfg 1"
		       " before issuing this command\n");
		ret = -EFAULT;
		goto done;
	}
	path_num = 1;

	if (data == PATH_ALL) {
		moal_memcpy_ext(priv->phandle, signal_get,
				info->param.signal_ext, sizeof(signal_get),
				sizeof(signal_get));
		path_num = MAX_PATH_NUM;
	} else
		moal_memcpy_ext(priv->phandle, signal_get,
				info->param.signal_ext,
				sizeof(mlan_ds_get_signal), sizeof(signal_get));

	PRINTM(MMSG, "data=%d path_num=%d\n", data, path_num);

	for (path = 0; path < path_num; path++) {
		if (signal_get[path].selector == PATH_AB)
			PRINTM(MINFO, "PATH A+B:\n");
		else if (signal_get[path].selector == PATH_A)
			PRINTM(MINFO, "PATH A:\n");
		else if (signal_get[path].selector == PATH_B)
			PRINTM(MINFO, "PATH B:\n");
		PRINTM(MINFO, "RSSI Beacon Last   : %d\n",
		       (int)signal_get[path].bcn_rssi_last);
		PRINTM(MINFO, "RSSI Beacon Average: %d\n",
		       (int)signal_get[path].bcn_rssi_avg);
		PRINTM(MINFO, "RSSI Data Last     : %d\n",
		       (int)signal_get[path].data_rssi_last);
		PRINTM(MINFO, "RSSI Data Average  : %d\n",
		       (int)signal_get[path].data_rssi_avg);
		PRINTM(MINFO, "SNR Beacon Last    : %d\n",
		       (int)signal_get[path].bcn_snr_last);
		PRINTM(MINFO, "SNR Beacon Average : %d\n",
		       (int)signal_get[path].bcn_snr_avg);
		PRINTM(MINFO, "SNR Data Last      : %d\n",
		       (int)signal_get[path].data_snr_last);
		PRINTM(MINFO, "SNR Data Average   : %d\n",
		       (int)signal_get[path].data_snr_avg);
		PRINTM(MINFO, "NF Beacon Last     : %d\n",
		       (int)signal_get[path].bcn_nf_last);
		PRINTM(MINFO, "NF Beacon Average  : %d\n",
		       (int)signal_get[path].bcn_nf_avg);
		PRINTM(MINFO, "NF Data Last       : %d\n",
		       (int)signal_get[path].data_nf_last);
		PRINTM(MINFO, "NF Data Average    : %d\n",
		       (int)signal_get[path].data_nf_avg);
		out_data[data_len++] = (int)signal_get[path].selector;
		out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
		out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
		out_data[data_len++] = (int)signal_get[path].data_rssi_last;
		out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
		out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
		out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
		out_data[data_len++] = (int)signal_get[path].data_snr_last;
		out_data[data_len++] = (int)signal_get[path].data_snr_avg;
		out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
		out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
		out_data[data_len++] = (int)signal_get[path].data_nf_last;
		out_data[data_len++] = (int)signal_get[path].data_nf_avg;
	}
	moal_memcpy_ext(
		priv->phandle, respbuf, out_data,
		(MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
		respbuflen);
	ret = data_len * sizeof(int);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set signalext cfg
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             The result of this processing.
 */
static int woal_priv_signalext_cfg(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	int enable = 0;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	ENTER();
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SIGNALEXT_CFG);
	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "Invalid arguments!\n");
		ret = -EINVAL;
		goto done;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &enable, 1,
				&user_data_len);
		if (user_data_len == 1) {
			if (enable != 0x0 && enable != 0x1) {
				PRINTM(MERROR, "Invalid arguments!\n");
				ret = -EINVAL;
				goto done;
			}
			ret = woal_signal_ext_enable(priv, enable);
		} else {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
	}
done:
	LEAVE();
	return ret;
}
#endif /* #ifdef STA_SUPPORT */

#if defined(STA_SUPPORT)
/**
 * @brief               Make PMF bit required/optional
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 -- success, otherwise fail
 */
static int woal_priv_set_get_pmfcfg(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int data[2] = {0, 0};
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	mlan_ds_misc_pmfcfg *pmfcfg;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!priv->phandle->card_info->embedded_supp) {
		PRINTM(MERROR, "Not supported cmd on this card\n");
		ret = -EOPNOTSUPP;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PMFCFG);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
	}

	if (user_data_len > 2) {
		PRINTM(MERROR, "Invalid number of arguments\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	pmfcfg = (mlan_ds_misc_pmfcfg *)&cfg->param.pmfcfg;
	cfg->sub_command = MLAN_OID_MISC_PMFCFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (user_data_len == 0)
		req->action = MLAN_ACT_GET;
	else {
		pmfcfg->mfpc = (t_u8)data[0];
		pmfcfg->mfpr = (t_u8)data[1];
		req->action = MLAN_ACT_SET;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.pmfcfg,
			sizeof(mlan_ds_misc_pmfcfg), respbuflen);
	ret = sizeof(mlan_ds_misc_pmfcfg);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif

/**
 * @brief               Get/Set inactivity timeout extend
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_inactivity_timeout_ext(moal_private *priv, t_u8 *respbuf,
					    t_u32 respbuflen)
{
	int data[4];
	mlan_ioctl_req *req = NULL;
	mlan_ds_pm_cfg *pmcfg = NULL;
	pmlan_ds_inactivity_to inac_to = NULL;
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_INACTIVITYTO);
	memset(data, 0, sizeof(data));
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
	}

	if (user_data_len != 0 && user_data_len != 3 && user_data_len != 4) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
	inac_to = &pmcfg->param.inactivity_to;
	pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
	req->req_id = MLAN_IOCTL_PM_CFG;
	req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (user_data_len) {
		inac_to->timeout_unit = data[0];
		inac_to->unicast_timeout = data[1];
		inac_to->mcast_timeout = data[2];
		if (user_data_len == 4)
			inac_to->ps_entry_timeout = data[3];
		req->action = MLAN_ACT_SET;

		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
	} else {
		data[0] = inac_to->timeout_unit;
		data[1] = inac_to->unicast_timeout;
		data[2] = inac_to->mcast_timeout;
		data[3] = inac_to->ps_entry_timeout;

		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Enable/Disable amsdu_aggr_ctrl
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_11n_amsdu_aggr_ctrl(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	int ret = 0, data[2] = {0};
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AMSDU_AGGR_CTRL);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, 1, &user_data_len);

		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of parameters\n");
			ret = -EINVAL;
			goto done;
		}
		req->action = MLAN_ACT_SET;
		cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
	data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get Transmit beamforming capabilities
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_tx_bf_cap_ioctl(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *bf_cfg = NULL;
	int ret = 0, bf_cap = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CAP);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
	bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
	req->req_id = MLAN_IOCTL_11N_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &bf_cap, 1,
				&user_data_len);

		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of parameters\n");
			ret = -EINVAL;
			goto done;
		}
		req->action = MLAN_ACT_SET;
		bf_cfg->param.tx_bf_cap = bf_cap;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	bf_cap = bf_cfg->param.tx_bf_cap;

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&bf_cap, sizeof(bf_cap),
			respbuflen);
	ret = sizeof(bf_cap);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef SDIO
/**
 * @brief               Turn on/off the sdio clock
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              Number of bytes written, negative for failure.
 */
static int woal_priv_sdio_clock_ioctl(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int ret = 0;
	int data = 2;
	int user_data_len = 0, header_len = 0;
	/* Initialize the clock state as on */
	static int clock_state = 1;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDIO_CLOCK);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&clock_state,
				sizeof(clock_state), respbuflen);
		ret = sizeof(clock_state);
		goto done;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);

		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of parameters\n");
			ret = -EINVAL;
			goto done;
		}
	}
	switch (data) {
	case CMD_DISABLED:
		PRINTM(MINFO, "SDIO clock is turned off\n");
		ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
		clock_state = data;
		break;
	case CMD_ENABLED:
		PRINTM(MINFO, "SDIO clock is turned on\n");
		ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
		clock_state = data;
		break;
	default:
		ret = -EINVAL;
		PRINTM(MINFO, "sdioclock: wrong parameter\n");
		break;
	}
done:
	LEAVE();
	return ret;
}
#endif

#ifdef SDIO
/**
 * @brief               Set SDIO Multi-point aggregation control parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_sdio_mpa_ctrl(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0, data[6];
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	memset(data, 0, sizeof(data));
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MPA_CTRL);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);

		if (user_data_len > 6) {
			PRINTM(MERROR, "Invalid number of parameters\n");
			ret = -EINVAL;
			goto done;
		}
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;
	/* Get the values first, then modify these values if
	 * user had modified them */

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
		ret = -EFAULT;
		goto done;
	}

	if (user_data_len == 0) {
		data[0] = misc->param.mpa_ctrl.tx_enable;
		data[1] = misc->param.mpa_ctrl.rx_enable;
		data[2] = misc->param.mpa_ctrl.tx_buf_size;
		data[3] = misc->param.mpa_ctrl.rx_buf_size;
		data[4] = misc->param.mpa_ctrl.tx_max_ports;
		data[5] = misc->param.mpa_ctrl.rx_max_ports;

		PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0],
		       data[1], data[2], data[3], data[4], data[5]);

		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
		goto done;
	}

	switch (user_data_len) {
	case 6:
		misc->param.mpa_ctrl.rx_max_ports = data[5];
		/* fall through */
	case 5:
		misc->param.mpa_ctrl.tx_max_ports = data[4];
		/* fall through */
	case 4:
		misc->param.mpa_ctrl.rx_buf_size = data[3];
		/* fall through */
	case 3:
		misc->param.mpa_ctrl.tx_buf_size = data[2];
		/* fall through */
	case 2:
		misc->param.mpa_ctrl.rx_enable = data[1];
		/* fall through */
	case 1:
		/* Set cmd */
		req->action = MLAN_ACT_SET;

		PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0],
		       data[1], data[2], data[3], data[4], data[5]);

		misc->param.mpa_ctrl.tx_enable = data[0];
		break;
	default:
		PRINTM(MERROR, "Default case error\n");
		ret = -EINVAL;
		goto done;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif

/**
 * @brief               Configure sleep parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_sleep_params_ioctl(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_pm_cfg *pm = NULL;
	mlan_ds_sleep_params *psleep_params = NULL;
	int data[6] = {0}, i;
	int user_data_len = 0, header_len = 0;
#ifdef DEBUG_LEVEL1
	char err_str[][36] = {{"sleep clock error in ppm"},
			      {"wakeup offset in usec"},
			      {"clock stabilization time in usec"},
			      {"control periodic calibration(0-2)"},
			      {"control of external sleepClock(0-2)"},
			      {"value of reserved for debug"}};
#endif
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	memset(data, 0, sizeof(data));
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	pm = (mlan_ds_pm_cfg *)req->pbuf;
	pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
	req->req_id = MLAN_IOCTL_PM_CFG;
	psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEP_PARAMS);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != 6) {
			PRINTM(MERROR, "Invalid number of parameters\n");
			ret = -EINVAL;
			goto done;
		}
#define MIN_VAL 0x0000
#define MAX_VAL 0xFFFF
		for (i = 0; i < 6; i++) {
			if ((i == 3) || (i == 4)) {
				/* These two cases are handled below the loop */
				continue;
			}
			if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
				PRINTM(MERROR, "Invalid %s (0-65535)!\n",
				       err_str[i]);
				ret = -EINVAL;
				goto done;
			}
		}
		if (data[3] < 0 || data[3] > 2) {
			PRINTM(MERROR,
			       "Invalid control periodic calibration (0-2)!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[4] < 0 || data[4] > 2) {
			PRINTM(MERROR,
			       "Invalid control of external sleep clock (0-2)!\n");
			ret = -EINVAL;
			goto done;
		}
		req->action = MLAN_ACT_SET;
		psleep_params->error = data[0];
		psleep_params->offset = data[1];
		psleep_params->stable_time = data[2];
		psleep_params->cal_control = data[3];
		psleep_params->ext_sleep_clk = data[4];
		psleep_params->reserved = data[5];
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = psleep_params->error;
	data[1] = psleep_params->offset;
	data[2] = psleep_params->stable_time;
	data[3] = psleep_params->cal_control;
	data[4] = psleep_params->ext_sleep_clk;
	data[5] = psleep_params->reserved;

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

#ifdef UAP_SUPPORT
/**
 * @brief               Set/Get network monitor configurations
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_net_monitor_ioctl(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	int user_data_len = 0, header_len = 0;
	int data_length = 0;
	int data[5] = {0};
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ds_misc_net_monitor *net_mon = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	moal_handle *handle = priv->phandle;
	monitor_iface *mon_if = NULL;
	struct net_device *ndev = NULL;
#endif

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_NET_MON);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		LEAVE();
		return -ENOMEM;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	net_mon = (mlan_ds_misc_net_monitor *)&misc->param.net_mon;
	misc->sub_command = MLAN_OID_MISC_NET_MONITOR;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len == 1 || user_data_len == 2 ||
		    user_data_len == 4 || user_data_len == 5) {
			if (data[0] != MTRUE && data[0] != MFALSE) {
				PRINTM(MERROR,
				       "NET_MON: Activity should be enable(=1)/"
				       "disable(=0)\n");
				ret = -EINVAL;
				goto done;
			}
			net_mon->enable_net_mon = data[0];
			if (data[0] == MTRUE) {
				int i;
				if (user_data_len != 2 && user_data_len != 4 &&
				    user_data_len != 5) {
					PRINTM(MERROR,
					       "NET_MON: Invalid number of args!\n");
					ret = -EINVAL;
					goto done;
				}
				/* Supported filter flags */
				if (!data[1] ||
				    data[1] & ~(MLAN_NETMON_DATA |
						MLAN_NETMON_MANAGEMENT |
						MLAN_NETMON_CONTROL |
						MLAN_NETMON_NOPROM |
						MLAN_NETMON_NON_BSS_BCN |
						MLAN_NETMON_TX)) {
					PRINTM(MERROR,
					       "NET_MON: Invalid filter flag\n");
					ret = -EINVAL;
					goto done;
				}

				if (user_data_len > 2) {
					/* Supported bands */

					for (i = 0;
					     i <
					     (int)(sizeof(SupportedInfraBand) /
						   sizeof(SupportedInfraBand[0]));
					     i++)
						if (data[2] ==
						    SupportedInfraBand[i])
							break;
					if (i == sizeof(SupportedInfraBand)) {
						PRINTM(MERROR,
						       "NET_MON: Invalid band\n");
						ret = -EINVAL;
						goto done;
					}
				}
				/* Supported channel */
				if (user_data_len > 3 &&
				    (data[3] < 1 ||
				     data[3] > MLAN_MAX_CHANNEL)) {
					PRINTM(MERROR,
					       "NET_MON: Invalid channel number\n");
					ret = -EINVAL;
					goto done;
				}
				if (user_data_len == 5) {
					/* Secondary channel offset */
					if (!(data[2] & (BAND_GN | BAND_AN))) {
						PRINTM(MERROR,
						       "No 11n in band, can not set "
						       "secondary channel offset\n");
						ret = -EINVAL;
						goto done;
					}
					if ((data[4] != CHANNEL_BW_20MHZ) &&
					    (data[4] !=
					     CHANNEL_BW_40MHZ_ABOVE) &&
					    (data[4] !=
					     CHANNEL_BW_40MHZ_BELOW) &&
					    (data[4] != CHANNEL_BW_80MHZ)) {
						PRINTM(MERROR,
						       "Invalid secondary channel bandwidth, "
						       "only allowed 0, 1, 3 or 4\n");
						ret = -EINVAL;
						goto done;
					}
					net_mon->chan_bandwidth = data[4];
				}

				net_mon->filter_flag = data[1];
				net_mon->band = data[2];
				net_mon->channel = data[3];
			}
			req->action = MLAN_ACT_SET;
		} else {
			PRINTM(MERROR, "NET_MON: Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "NET_MON: woal_request_ioctl fail\n");
		ret = -EFAULT;
		goto done;
	}

#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	if (req->action == MLAN_ACT_SET) {
		if (data[0]) { /** Enable sniffer mode: 1/2 */
			if (!handle->mon_if) {
				mon_if = woal_prepare_mon_if(priv, "rtap", 0);
				if (!mon_if) {
					PRINTM(MFATAL,
					       "Prepare mon_if fail.\n");
					ret = -EFAULT;
					goto done;
				}
				ndev = mon_if->mon_ndev;
				ret = register_netdevice(ndev);
				if (ret) {
					PRINTM(MFATAL,
					       "register net_device failed, ret=%d\n",
					       ret);
					free_netdev(ndev);
					ret = -EFAULT;
					goto done;
				}
				handle->mon_if = mon_if;
			}
			/* Save band channel config */
			handle->mon_if->band_chan_cfg.band = net_mon->band;
			handle->mon_if->band_chan_cfg.channel =
				net_mon->channel;
			handle->mon_if->band_chan_cfg.chan_bandwidth =
				net_mon->chan_bandwidth;
			handle->mon_if->flag = net_mon->filter_flag;
		} else { /** Disable sniffer mode: 0 */
			if (handle->mon_if) {
				ndev = handle->mon_if->mon_ndev;
				handle->mon_if = NULL;
				unregister_netdevice(ndev);
			}
		}
	}
#endif

	data[0] = net_mon->enable_net_mon;
	data[1] = net_mon->filter_flag;
	data[2] = net_mon->band;
	data[3] = net_mon->channel;
	data[4] = net_mon->chan_bandwidth;
	data_length = 5;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
			sizeof(int) * data_length, respbuflen);
	ret = sizeof(int) * data_length;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}
#endif

/**
 *  @brief This function get nop list.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_nop_list(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_cfg *ds_11hcfg = NULL;

	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11H_CFG;
	req->action = MLAN_ACT_GET;

	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
	ds_11hcfg->sub_command = MLAN_OID_11H_NOP_CHAN_LIST;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status == MLAN_STATUS_FAILURE) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf,
			(t_u8 *)&ds_11hcfg->param.nop_chan_list,
			sizeof(mlan_ds_11h_nop_chan_list), respbuflen);
	ret = sizeof(mlan_ds_11h_nop_chan_list);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief clear NOP list
 *
 *  @param priv             A pointer to moal_private structure
 *  @return                 0 --success, otherwise fail
 */
static int woal_uap_clear_nop(moal_private *priv)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_cfg *ds_11hcfg = NULL;

	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11H_CFG;
	req->action = MLAN_ACT_CLEAR;

	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
	ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_NOP_INFO;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status == MLAN_STATUS_FAILURE) {
		ret = -EFAULT;
		goto done;
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief This function clear nop flags.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_clear_nop(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret = 0;
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	struct wiphy *wiphy = priv->phandle->wiphy;
#endif

	ENTER();
	PRINTM(MCMND, "clear nop\n");
	ret = woal_uap_clear_nop(priv);
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext)) {
		if (wiphy)
			woal_clear_wiphy_dfs_state(wiphy);
	}
#endif
	ret = sizeof(int);
	LEAVE();
	return ret;
}

/**
 *  @brief This function detects fake RADAR.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             positive for success, negative for failure.
 */
static int woal_priv_fake_radar(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_snmp_mib *snmp = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;
	ENTER();
#ifdef UAP_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
	if (priv && priv->chan.chan &&
	    !(priv->chan.chan->flags & IEEE80211_CHAN_RADAR)) {
		PRINTM(MERROR, "Current op channel NOT DFS\n");
		LEAVE();
		return -EINVAL;
	}
#endif
#endif
	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
	if (ioctl_req == NULL) {
		LEAVE();
		return -ENOMEM;
	}
	snmp = (mlan_ds_snmp_mib *)ioctl_req->pbuf;
	ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
	snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H_FAKERADAR;
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);
	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get DFS Testing settings
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_dfs_testing(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_cfg *ds_11hcfg = NULL;
	int ret = 0;
	int data[5] = {0};
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_TESTING);
	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
	req->req_id = MLAN_IOCTL_11H_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != 5) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if ((unsigned)data[0] > 1800) {
			PRINTM(MERROR,
			       "The maximum user CAC is 1800 seconds (30 mins).\n");
			ret = -EINVAL;
			goto done;
		}
		if ((unsigned)data[1] > 0xFFFF) {
			PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
			ret = -EINVAL;
			goto done;
		}
		if ((unsigned)data[3] > 0xFF) {
			PRINTM(MERROR,
			       "The maximum user fixed channel is 255.\n");
			ret = -EINVAL;
			goto done;
		}
		if ((unsigned)data[4] != 0 && ((unsigned)data[4] != 1)) {
			PRINTM(MERROR, "CAC restart should be 0/1\n");
			ret = -EINVAL;
			goto done;
		}

		ds_11hcfg->param.dfs_testing.usr_cac_period_msec =
			(t_u32)data[0] * 1000;
		ds_11hcfg->param.dfs_testing.usr_nop_period_sec =
			(t_u16)data[1];
		ds_11hcfg->param.dfs_testing.usr_no_chan_change =
			data[2] ? 1 : 0;
		ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3];
		ds_11hcfg->param.dfs_testing.usr_cac_restart = (t_u8)data[4];
		priv->phandle->cac_restart = (t_u8)data[4];
		priv->phandle->cac_period_jiffies = (t_u32)data[0] * HZ;
		priv->phandle->usr_nop_period_sec = (t_u16)data[1];
		req->action = MLAN_ACT_SET;
#ifdef UAP_SUPPORT
		priv->user_cac_period_msec =
			ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
#endif
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		data[0] =
			ds_11hcfg->param.dfs_testing.usr_cac_period_msec / 1000;
		data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
		data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
		data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
		data[4] = ds_11hcfg->param.dfs_testing.usr_cac_restart;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get DFS W53 settings
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_dfs53cfg(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_cfg *ds_11hcfg = NULL;
	int ret = 0;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS53_CFG);
	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_W53_CFG;
	req->req_id = MLAN_IOCTL_11H_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args !\n");
			ret = -EINVAL;
			goto done;
		}
		if (data > DFS_W53_OLD) {
			PRINTM(MERROR, "Invalid config !\n");
			ret = -EINVAL;
			goto done;
		}

		ds_11hcfg->param.dfs_w53_cfg.dfs53cfg = (t_u8)data;
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf,
				(t_u8 *)&ds_11hcfg->param.dfs_w53_cfg.dfs53cfg,
				sizeof(ds_11hcfg->param.dfs_w53_cfg.dfs53cfg),
				respbuflen);
		ret = sizeof(t_u8);
	}

	PRINTM(MIOCTL, "dfs w53 cfg %d\n",
	       ds_11hcfg->param.dfs_w53_cfg.dfs53cfg);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get DFS mode settings
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_dfs_mode(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_cfg *ds_11hcfg = NULL;
	int ret = 0;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_MODE);
	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_MODE;
	req->req_id = MLAN_IOCTL_11H_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args !\n");
			ret = -EINVAL;
			goto done;
		}
		if (data > DFS_MODE_ENH) {
			PRINTM(MERROR, "Invalid config for dfs_mode!\n");
			ret = -EINVAL;
			goto done;
		}

		ds_11hcfg->param.dfs_mode = (t_u8)data;
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf,
				(t_u8 *)&ds_11hcfg->param.dfs_mode,
				sizeof(ds_11hcfg->param.dfs_mode), respbuflen);
		ret = sizeof(t_u8);
	}

	PRINTM(MIOCTL, "dfs_mode %d\n", ds_11hcfg->param.dfs_mode);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

#ifdef UAP_SUPPORT

/**
 *  @brief determine the center frequency center index for bandwidth
 *         of 40/80/160 MHz
 *
 ** @param priv         Pointer to moal_private structure
 *  @param band         band
 *  @param pri_chan     primary channel
 *  @param chan_bw      channel bandwidth
 *
 *  @return             channel center frequency center, if found; O, otherwise
 */
static t_u8 woal_get_center_freq_idx(moal_private *priv, t_u16 band,
				     t_u32 pri_chan, t_u8 chan_bw)
{
	struct center_freq_desc {
		t_u8 pri_chan;
		t_u8 ch_40;
		t_u8 ch_80;
		t_u8 ch_160;
	};

	static const struct center_freq_desc center_freq_idx_map_5g[] = {
		{.pri_chan = 36, .ch_40 = 38, .ch_80 = 42, .ch_160 = 50},
		{.pri_chan = 40, .ch_40 = 38, .ch_80 = 42, .ch_160 = 50},
		{.pri_chan = 44, .ch_40 = 46, .ch_80 = 42, .ch_160 = 50},
		{.pri_chan = 48, .ch_40 = 46, .ch_80 = 42, .ch_160 = 50},
		{.pri_chan = 52, .ch_40 = 54, .ch_80 = 58, .ch_160 = 50},
		{.pri_chan = 56, .ch_40 = 54, .ch_80 = 58, .ch_160 = 50},
		{.pri_chan = 60, .ch_40 = 62, .ch_80 = 58, .ch_160 = 50},
		{.pri_chan = 64, .ch_40 = 62, .ch_80 = 58, .ch_160 = 50},
		{.pri_chan = 68, .ch_40 = 70, .ch_80 = 74, .ch_160 = 0},
		{.pri_chan = 72, .ch_40 = 70, .ch_80 = 74, .ch_160 = 0},
		{.pri_chan = 76, .ch_40 = 78, .ch_80 = 74, .ch_160 = 0},
		{.pri_chan = 80, .ch_40 = 78, .ch_80 = 74, .ch_160 = 0},
		{.pri_chan = 84, .ch_40 = 86, .ch_80 = 90, .ch_160 = 0},
		{.pri_chan = 88, .ch_40 = 86, .ch_80 = 90, .ch_160 = 0},
		{.pri_chan = 92, .ch_40 = 94, .ch_80 = 90, .ch_160 = 0},
		{.pri_chan = 96, .ch_40 = 94, .ch_80 = 90, .ch_160 = 0},
		{.pri_chan = 100, .ch_40 = 102, .ch_80 = 106, .ch_160 = 114},
		{.pri_chan = 104, .ch_40 = 102, .ch_80 = 106, .ch_160 = 114},
		{.pri_chan = 108, .ch_40 = 110, .ch_80 = 106, .ch_160 = 114},
		{.pri_chan = 112, .ch_40 = 110, .ch_80 = 106, .ch_160 = 114},
		{.pri_chan = 116, .ch_40 = 118, .ch_80 = 122, .ch_160 = 114},
		{.pri_chan = 120, .ch_40 = 118, .ch_80 = 122, .ch_160 = 114},
		{.pri_chan = 124, .ch_40 = 126, .ch_80 = 122, .ch_160 = 114},
		{.pri_chan = 128, .ch_40 = 126, .ch_80 = 122, .ch_160 = 114},
		{.pri_chan = 132, .ch_40 = 134, .ch_80 = 138, .ch_160 = 0},
		{.pri_chan = 136, .ch_40 = 134, .ch_80 = 138, .ch_160 = 0},
		{.pri_chan = 140, .ch_40 = 142, .ch_80 = 138, .ch_160 = 0},
		{.pri_chan = 144, .ch_40 = 142, .ch_80 = 138, .ch_160 = 0},
		{.pri_chan = 149, .ch_40 = 151, .ch_80 = 155, .ch_160 = 163},
		{.pri_chan = 153, .ch_40 = 151, .ch_80 = 155, .ch_160 = 163},
		{.pri_chan = 157, .ch_40 = 159, .ch_80 = 155, .ch_160 = 163},
		{.pri_chan = 161, .ch_40 = 159, .ch_80 = 155, .ch_160 = 163},
		{.pri_chan = 165, .ch_40 = 167, .ch_80 = 171, .ch_160 = 163},
		{.pri_chan = 169, .ch_40 = 167, .ch_80 = 171, .ch_160 = 163},
		{.pri_chan = 173, .ch_40 = 175, .ch_80 = 171, .ch_160 = 163},
		{.pri_chan = 177, .ch_40 = 175, .ch_80 = 171, .ch_160 = 163},
		{.pri_chan = 184, .ch_40 = 186, .ch_80 = 190, .ch_160 = 0},
		{.pri_chan = 188, .ch_40 = 186, .ch_80 = 190, .ch_160 = 0},
		{.pri_chan = 192, .ch_40 = 194, .ch_80 = 190, .ch_160 = 0},
		{.pri_chan = 196, .ch_40 = 194, .ch_80 = 190, .ch_160 = 0},
		{.pri_chan = 0,
		 .ch_40 = 42 /* terminator with default cfreq */}};

	const struct center_freq_desc *map = NULL;

	if (band == BAND_5GHZ)
		map = center_freq_idx_map_5g;

	for (; map != NULL; map++) {
		/* reached end of map, return default value for that map */
		if (map->pri_chan == 0)
			return map->ch_40;

		if (map->pri_chan == pri_chan) {
			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
			    chan_bw == CHANNEL_BW_40MHZ_BELOW)
				return map->ch_40;

			if (chan_bw == CHANNEL_BW_80MHZ)
				return map->ch_80;

			if (chan_bw == CHANNEL_BW_160MHZ)
				return map->ch_160;
		}
	}

	return 0;
}

#endif

#if defined(UAP_SUPPORT)
/**
 *  @brief This function handles channel switch with CSA/ECSA IE.
 *
 ** @param priv          Pointer to moal_private structure
 *  @param block_tx      0-no need block traffic 1- need block traffic
 *  @param oper_class    oper_class
 *  @param channel       channel
 *  @param switch count  how many csa/ecsa beacon will send out
 *  @param band          see BAND_5GHZ/BAND_6GHZ enum
 *  @param band_width    1-40Mhz above, 3-40Mhz below, 4-80Mhz, 5-160Mhz
 *  @param ecsa          MTRUE/MFALSE;
 *
 *  @return             channel center frequency center, if found; O, otherwise
 */
static int woal_channel_switch(moal_private *priv, t_u8 block_tx,
			       t_u8 oper_class, t_u8 channel, t_u8 switch_count,
			       t_u8 band, t_u8 band_width, t_u8 ecsa)
{
	IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
	IEEEtypes_ChanSwitchAnn_t *chan_switch = NULL;
	custom_ie *pcust_chansw_ie = NULL;
	t_u8 center_freq_idx = 0;
	IEEEtypes_Header_t *pChanSwWrap_ie = NULL;
	IEEEtypes_WideBWChanSwitch_t *pbwchansw_ie = NULL;
	IEEEtypes_VhtTpcEnvelope_t *pvhttpcEnv_ie = NULL;
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	t_u8 bw;
	t_u8 new_oper_class = oper_class;
	int ret = 0;

	ENTER();

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
	ioctl_req->action = MLAN_ACT_SET;
	misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
	misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);

	pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
	pcust_chansw_ie->ie_length = 0;
	pcust_chansw_ie->mgmt_subtype_mask =
		MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
							    BEACON/probe resp*/
	pcust_chansw_ie->mgmt_subtype_mask |= MLAN_CUSTOM_IE_NEW_MASK;

	if (band == BAND_2GHZ || band == BAND_5GHZ) {
		pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
		chan_switch =
			(IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
		chan_switch->element_id = CHANNEL_SWITCH_ANN;
		chan_switch->len = 3;
		chan_switch->chan_switch_mode = block_tx;
		chan_switch->new_channel_num = channel;
		chan_switch->chan_switch_count = switch_count;
		DBG_HEXDUMP(MCMD_D, "CSA IE",
			    (t_u8 *)pcust_chansw_ie->ie_buffer,
			    pcust_chansw_ie->ie_length);
	}
	switch (band_width) {
	case CHANNEL_BW_40MHZ_ABOVE:
	case CHANNEL_BW_40MHZ_BELOW:
		bw = 40;
		break;
	case CHANNEL_BW_80MHZ:
		bw = 80;
		break;
	case CHANNEL_BW_160MHZ:
		bw = 160;
		break;
	default:
		bw = 20;
		break;
	}
	if (!new_oper_class && ecsa)
		woal_priv_get_nonglobal_operclass_by_bw_channel(
			priv, bw, channel, &new_oper_class);
	if (new_oper_class) {
		ext_chan_switch = (IEEEtypes_ExtChanSwitchAnn_t
					   *)(pcust_chansw_ie->ie_buffer +
					      pcust_chansw_ie->ie_length);
		ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
		ext_chan_switch->len = 4;
		ext_chan_switch->chan_switch_mode = block_tx;
		ext_chan_switch->new_oper_class = new_oper_class;
		ext_chan_switch->new_channel_num = channel;
		ext_chan_switch->chan_switch_count = switch_count;
		pcust_chansw_ie->ie_length +=
			sizeof(IEEEtypes_ExtChanSwitchAnn_t);
		DBG_HEXDUMP(MCMD_D, "ECSA IE", (t_u8 *)ext_chan_switch,
			    sizeof(IEEEtypes_ExtChanSwitchAnn_t));
	}
	/* bandwidth 40/80/160 should set channel switch wrapper ie for 11ac 5G
	 * channel*/
	if (band_width && (band == BAND_5GHZ)) {
		pChanSwWrap_ie =
			(IEEEtypes_Header_t *)(pcust_chansw_ie->ie_buffer +
					       pcust_chansw_ie->ie_length);
		pChanSwWrap_ie->element_id = EXT_POWER_CONSTR;
		pChanSwWrap_ie->len = sizeof(IEEEtypes_WideBWChanSwitch_t);

		pbwchansw_ie = (IEEEtypes_WideBWChanSwitch_t
					*)((t_u8 *)pChanSwWrap_ie +
					   sizeof(IEEEtypes_Header_t));
		pbwchansw_ie->ieee_hdr.element_id = BW_CHANNEL_SWITCH;
		pbwchansw_ie->ieee_hdr.len =
			sizeof(IEEEtypes_WideBWChanSwitch_t) -
			sizeof(IEEEtypes_Header_t);

		center_freq_idx = woal_get_center_freq_idx(priv, band, channel,
							   band_width);
		if (band_width == CHANNEL_BW_40MHZ_ABOVE ||
		    band_width == CHANNEL_BW_40MHZ_BELOW) {
			pbwchansw_ie->new_channel_width = 0;
			pbwchansw_ie->new_channel_center_freq0 =
				center_freq_idx;
		} else if (band_width == CHANNEL_BW_80MHZ) {
			pbwchansw_ie->new_channel_width = 1;
			pbwchansw_ie->new_channel_center_freq0 =
				center_freq_idx - 4;
			pbwchansw_ie->new_channel_center_freq1 =
				center_freq_idx + 4;
		} else if (band_width == CHANNEL_BW_160MHZ) {
			pbwchansw_ie->new_channel_width = 2;
			pbwchansw_ie->new_channel_center_freq0 =
				center_freq_idx - 8;
			pbwchansw_ie->new_channel_center_freq1 =
				center_freq_idx + 8;
		} else
			PRINTM(MERROR,
			       "Invalid bandwidth.Support value 1/3/4/5 for 40+/40-/80/160MHZ\n");

		/*prepare the VHT Transmit Power Envelope IE*/
		pvhttpcEnv_ie =
			(IEEEtypes_VhtTpcEnvelope_t
				 *)((t_u8 *)pChanSwWrap_ie +
				    sizeof(IEEEtypes_Header_t) +
				    sizeof(IEEEtypes_WideBWChanSwitch_t));
		pvhttpcEnv_ie->ieee_hdr.element_id = VHT_TX_POWER_ENV;
		pvhttpcEnv_ie->ieee_hdr.len =
			sizeof(IEEEtypes_VhtTpcEnvelope_t) -
			sizeof(IEEEtypes_Header_t);
		/* Local Max TX Power Count= 3,
		 * Local TX Power Unit Inter=EIP(0) */
		pvhttpcEnv_ie->tpc_info = 3;
		pvhttpcEnv_ie->local_max_tp_20mhz = 0xff;
		pvhttpcEnv_ie->local_max_tp_40mhz = 0xff;
		pvhttpcEnv_ie->local_max_tp_80mhz = 0xff;
		pvhttpcEnv_ie->local_max_tp_160mhz_80_80mhz = 0xff;
		pChanSwWrap_ie->len += sizeof(IEEEtypes_VhtTpcEnvelope_t);
		pcust_chansw_ie->ie_length +=
			pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t);
		DBG_HEXDUMP(MCMD_D, "Channel switch wrapper IE",
			    (t_u8 *)pChanSwWrap_ie,
			    pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t));
	}
	if (block_tx) {
		if (netif_carrier_ok(priv->netdev))
			netif_carrier_off(priv->netdev);
		woal_stop_queue(priv->netdev);
		priv->uap_tx_blocked = MTRUE;
	}

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "Failed to set ECSA IE\n");
		ret = -EFAULT;
		goto done;
	}

	priv->phandle->chsw_wait_q_woken = MFALSE;
	/* wait for channel switch to complete  */
	wait_event_interruptible_timeout(
		priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
		(u32)HZ * (switch_count + 2) * 110 / 1000);

	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
	pcust_chansw_ie->mgmt_subtype_mask = 0;
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "Failed to clear ECSA IE\n");
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}
#endif

#ifdef UAP_SUPPORT
/**
 * @brief Given bandwidth and channel, create Band_Config
 *
 * @param priv         A pointer to moal_private
 * @param bandcfg         A pointer to Band_Config_t structure
 * @param channel         A pointer to cfg80211_chan_def structure
 * @param bandwidth       0/1/3/4
 *
 * @return                N/A
 */
static void woal_convert_chanbw_to_bandconfig(moal_private *priv,
					      Band_Config_t *bandcfg,
					      t_u8 channel, t_u8 bandwidth)
{
	ENTER();

	if (channel <= MAX_BG_CHANNEL)
		bandcfg->chanBand = BAND_2GHZ;
	else
		bandcfg->chanBand = BAND_5GHZ;
	switch (bandwidth) {
	case CHANNEL_BW_40MHZ_ABOVE:
		bandcfg->chanWidth = CHAN_BW_40MHZ;
		bandcfg->chan2Offset = SEC_CHAN_ABOVE;
		break;
	case CHANNEL_BW_40MHZ_BELOW:
		bandcfg->chanWidth = CHAN_BW_40MHZ;
		bandcfg->chan2Offset = SEC_CHAN_BELOW;
		break;
	case CHANNEL_BW_80MHZ:
		bandcfg->chanWidth = CHAN_BW_80MHZ;
		bandcfg->chan2Offset =
			woal_get_second_channel_offset(priv, channel);
		break;
	case CHANNEL_BW_20MHZ:
	default:
		bandcfg->chanWidth = CHAN_BW_20MHZ;
		break;
	}
	LEAVE();
	return;
}

/**
 * @brief Get DFS channel list
 *
 * @param priv         A pointer to moal_private
 *
 * @return                N/A
 */
static void woal_get_dfs_chan_list(moal_private *priv)
{
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	struct wiphy *wiphy = priv->phandle->wiphy;
	struct ieee80211_supported_band *sband;
#endif
	int i;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfp_misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext) &&
	    wiphy) {
		sband = wiphy->bands[NL80211_BAND_5GHZ];
		if (sband) {
			for (i = 0; i < sband->n_channels; i++) {
				if ((sband->channels[i].flags &
				     IEEE80211_CHAN_RADAR) &&
				    (priv->auto_dfs_cfg.num_of_chan <= 0xFF)) {
					priv->auto_dfs_cfg.dfs_chan_list
						[priv->auto_dfs_cfg.num_of_chan] =
						sband->channels[i].hw_value;
					priv->auto_dfs_cfg.num_of_chan++;
				}
			}
			return;
		}
	}
#endif
	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL)
		goto done;

	/* Fill request buffer */
	cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
	cfp_misc->sub_command = MLAN_OID_MISC_CFP_TABLE;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;
	cfp_misc->param.cfp.band = BAND_A;

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS)
		goto done;

	for (i = 0; i < cfp_misc->param.cfp.num_chan; i++) {
		if (cfp_misc->param.cfp.cfp_tbl[i].dynamic.flags &
		    NXP_CHANNEL_DISABLED)
			continue;
		if (cfp_misc->param.cfp.cfp_tbl[i].passive_scan_or_radar_detect) {
			priv->auto_dfs_cfg
				.dfs_chan_list[priv->auto_dfs_cfg.num_of_chan] =
				cfp_misc->param.cfp.cfp_tbl[i].channel;
			priv->auto_dfs_cfg.num_of_chan++;
		}
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return;
}

/**
 * @brief               Process dfs cac command
 *
 * @param priv          a pointer to moal_private structure
 * @param ch_rpt_req    a pointer to mlan_ds_11h_chan_rep_req structure
 *
 * @return              MLAN_STATUS_FAILRUE or MLAN_STATUS_SUCCESS
 */
mlan_status woal_do_dfs_cac(moal_private *priv,
			    mlan_ds_11h_chan_rep_req *ch_rpt_req)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_cfg *p11h_cfg = NULL;
	mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (NULL == req) {
		LEAVE();
		return MLAN_STATUS_FAILURE;
	}
	p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
	pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;

	moal_memcpy_ext(priv->phandle, pchan_rpt_req, ch_rpt_req,
			sizeof(mlan_ds_11h_chan_rep_req),
			sizeof(mlan_ds_11h_chan_rep_req));

	if (priv->bss_type == MLAN_BSS_TYPE_DFS)
		p11h_cfg->sub_command = MLAN_OID_11H_CHAN_REPORT_REQUEST;
	else
		p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;

	req->req_id = MLAN_IOCTL_11H_CFG;

	req->action = MLAN_ACT_SET;
	/* Send Channel Check command and wait until the report is ready */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return status;
}

/**
 * @brief               Get Next DFS channel from dfs_chan_list
 *
 * @param priv          a pointer to moal_private structure
 *
 * @return              N/A
 *
 */
static t_u8 woal_get_next_dfs_chan(moal_private *priv)
{
	int i;
	int idx = priv->curr_cac_idx;
	mlan_ds_11h_chan_dfs_state ch_dfs_state;
	t_u8 chan = 0;
	ENTER();
	idx++;
	if (idx >= priv->auto_dfs_cfg.num_of_chan)
		idx = 0;
	for (i = 0; i < priv->auto_dfs_cfg.num_of_chan; i++) {
		if (priv->chan_rpt_req.chanNum !=
		    priv->auto_dfs_cfg.dfs_chan_list[idx]) {
			memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
			ch_dfs_state.channel =
				priv->auto_dfs_cfg.dfs_chan_list[idx];
			if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
						    &ch_dfs_state)) {
				PRINTM(MERROR,
				       "%s: woal_11h_chan_dfs_state failed \n",
				       __func__);
				continue;
			}
			if (ch_dfs_state.dfs_state != DFS_UNAVAILABLE) {
				chan = priv->auto_dfs_cfg.dfs_chan_list[idx];
				priv->curr_cac_idx = idx;
				break;
			}
		}
		idx++;
		if (idx >= priv->auto_dfs_cfg.num_of_chan)
			idx = 0;
	}
	LEAVE();
	return chan;
}

/**
 * @brief               Process auto dfs cac
 *
 * @param priv          a pointer to moal_private structure
 *
 * @return              N/A
 *
 */
static void woal_do_auto_dfs(moal_private *priv)
{
	mlan_ds_11h_chan_rep_req chan_rpt_req;
	ENTER();
	if (priv->auto_dfs_cfg.multi_chan_dfs &&
	    priv->auto_dfs_cfg.num_of_chan) {
		memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
		chan_rpt_req.startFreq = START_FREQ_11A_BAND;
		chan_rpt_req.chanNum = woal_get_next_dfs_chan(priv);
		if (priv->chan_rpt_req.chanNum) {
			if (woal_11h_cancel_chan_report_ioctl(priv,
							      MOAL_IOCTL_WAIT))
				PRINTM(MERROR,
				       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
				       __func__);
			memset(&priv->chan_rpt_req, 0,
			       sizeof(mlan_ds_11h_chan_rep_req));
		}
		if (chan_rpt_req.chanNum) {
			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
			chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
			chan_rpt_req.millisec_dwell_time =
				priv->auto_dfs_cfg.cac_timer;
			moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
					&chan_rpt_req,
					sizeof(mlan_ds_11h_chan_rep_req),
					sizeof(mlan_ds_11h_chan_rep_req));
			PRINTM(MCMND,
			       "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
			       chan_rpt_req.chanNum,
			       (int)(chan_rpt_req.bandcfg.chanWidth),
			       chan_rpt_req.millisec_dwell_time);
			if (MLAN_STATUS_SUCCESS !=
			    woal_do_dfs_cac(priv, &chan_rpt_req))
				PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
				       __func__);
		}
	}
	LEAVE();
	return;
}

/*
 * @brief  prepare and send WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
 *
 * @param priv           A pointer moal_private structure
 * @param type 			 WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
 * @param channel 		 channel
 * @param radar          MTRUE/MFALSE
 *
 * @return          N/A
 */
void woal_chan_event(moal_private *priv, t_u8 type, t_u8 channel, t_u8 radar)
{
	struct woal_event *evt;
	unsigned long flags;
	moal_handle *handle = priv->phandle;

	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
	if (!evt) {
		PRINTM(MERROR, "Fail to alloc memory for deauth event\n");
		LEAVE();
		return;
	}
	evt->priv = priv;
	evt->type = type;
	evt->radar_info.channel = channel;
	evt->radar_info.radar = radar;
	INIT_LIST_HEAD(&evt->link);
	spin_lock_irqsave(&handle->evt_lock, flags);
	list_add_tail(&evt->link, &handle->evt_queue);
	spin_unlock_irqrestore(&handle->evt_lock, flags);
	queue_work(handle->evt_workqueue, &handle->evt_work);
}

/**
 * @brief               Get active UAP handler
 *
 * @param handle        a pointer to moal_handle structure
 *
 * @return              N/A
 *
 */
static moal_private *woal_get_active_uap_interface(moal_handle *handle)
{
	int i;
	moal_private *priv = NULL;
	for (i = 0; i < handle->priv_num; i++) {
		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
			if (handle->priv[i]->bss_started == MTRUE) {
				priv = handle->priv[i];
				break;
			}
		}
	}
	return priv;
}

/**
 * @brief               handle auto uap channel switch
 *
 * @param priv          a pointer to moal_private structure
 * @param channel       channel
 *
 * @return              N/A
 *
 */
static void woal_auto_uap_channel_switch(moal_private *priv, t_u8 channel)
{
	moal_private *pmpriv = NULL;
	chan_band_info chaninfo;
	t_u8 band = BAND_2GHZ;
	moal_handle *ref_handle;
	t_u8 band_width = CHANNEL_BW_20MHZ;

	memset(&chaninfo, 0, sizeof(chaninfo));

	pmpriv = woal_get_active_uap_interface(priv->phandle);
	if (!pmpriv) {
		ref_handle = (moal_handle *)priv->phandle->pref_mac;
		pmpriv = woal_get_active_uap_interface(ref_handle);
	}
	if (pmpriv) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_get_ap_channel(pmpriv, MLAN_ACT_GET,
					    MOAL_IOCTL_WAIT, &chaninfo)) {
			PRINTM(MERROR, "Fail to get ap channel \n");
			return;
		}
		if (chaninfo.channel != channel) {
			switch (chaninfo.bandcfg.chanWidth) {
			case CHAN_BW_40MHZ:
				if (chaninfo.bandcfg.chan2Offset ==
				    SEC_CHAN_BELOW)
					band_width = CHANNEL_BW_40MHZ_BELOW;
				else if (chaninfo.bandcfg.chan2Offset ==
					 SEC_CHAN_ABOVE)
					band_width = CHANNEL_BW_40MHZ_ABOVE;
				break;
			case CHAN_BW_80MHZ:
				band_width = CHANNEL_BW_80MHZ;
				break;
			default:
				band_width = CHANNEL_BW_20MHZ;
				break;
			}
			if (channel > MAX_BG_CHANNEL)
				band = BAND_5GHZ;
#define DEF_SWITCH_COUNT 10
			woal_channel_switch(pmpriv, MTRUE, 0, channel,
					    DEF_SWITCH_COUNT, band, band_width,
					    MTRUE);
		}
	}
}

/**
 * @brief               Process channel event
 *
 * @param priv          a pointer to moal_private structure
 * @param type 			WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
 * @param channel       channel
 * @param radar         radar
 *
 * @return              N/A
 *
 */
void woal_process_chan_event(moal_private *priv, t_u8 type, t_u8 channel,
			     t_u8 radar)
{
	mlan_ds_11h_chan_rep_req chan_rpt_req;

	if (!priv->auto_dfs_cfg.start_auto_zero_dfs)
		return;
	if (type == WOAL_EVENT_CHAN_RPT) {
		if (priv->auto_dfs_cfg.uap_chan_switch && !radar) {
			priv->auto_dfs_cfg.uap_chan_switch = MFALSE;
			PRINTM(MCMND, "Trying uap_chan_switch to %d\n",
			       channel);
			woal_auto_uap_channel_switch(priv, channel);
		}
		woal_do_auto_dfs(priv);
	} else if (type == WOAL_EVENT_RADAR) {
		memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
		chan_rpt_req.startFreq = START_FREQ_11A_BAND;
		chan_rpt_req.chanNum = woal_get_next_dfs_chan(priv);
		if (priv->chan_rpt_req.chanNum) {
			if (woal_11h_cancel_chan_report_ioctl(priv,
							      MOAL_IOCTL_WAIT))
				PRINTM(MERROR,
				       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
				       __func__);
			memset(&priv->chan_rpt_req, 0,
			       sizeof(mlan_ds_11h_chan_rep_req));
		}
		if (chan_rpt_req.chanNum) {
			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
			chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
			chan_rpt_req.millisec_dwell_time =
				priv->auto_dfs_cfg.cac_timer;
			moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
					&chan_rpt_req,
					sizeof(mlan_ds_11h_chan_rep_req),
					sizeof(mlan_ds_11h_chan_rep_req));
			PRINTM(MCMND,
			       "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
			       chan_rpt_req.chanNum,
			       (int)(chan_rpt_req.bandcfg.chanWidth),
			       chan_rpt_req.millisec_dwell_time);
			if (MLAN_STATUS_SUCCESS !=
			    woal_do_dfs_cac(priv, &chan_rpt_req))
				PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
				       __func__);
		}
	}
}

/**
 * @brief               check if channel under nop
 *
 * @param priv          a pointer to moal_private structure
 * @param channel       WIFI channel
 *
 * @return              length
 */
static t_u8 woal_is_channel_under_nop(moal_private *priv, t_u8 channel)
{
	mlan_ds_11h_chan_nop_info chan_nop_info;
	t_u8 ret = MFALSE;
	ENTER();
	memset(&chan_nop_info, 0, sizeof(chan_nop_info));
	chan_nop_info.curr_chan = channel;
	woal_uap_get_channel_nop_info(priv, MOAL_IOCTL_WAIT, &chan_nop_info);
	if (chan_nop_info.chan_under_nop)
		ret = MTRUE;
	LEAVE();
	return ret;
}

/**
 * @brief               Process dfs cac command
 *
 * @param priv          a pointer to moal_private structure
 * @param respbuf       respbuf buffer
 * @param respbuflen    respbuf length
 *
 * @return              length
 */
static int woal_priv_do_dfs_cac(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0;
	int data[3] = {0};
	int user_data_len = 0, header_len = 0;
	mlan_ds_11h_chan_rep_req chan_rpt_req;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_11h_chan_dfs_state ch_dfs_state;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_CAC);

	if ((int)strlen(respbuf) >= header_len) {
		memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len >= 1) {
			if (!data[0] ||
			    (priv->chan_rpt_req.chanNum &&
			     (priv->chan_rpt_req.chanNum != data[0]))) {
				if (priv->chan_rpt_pending ||
				    (priv->bss_type == MLAN_BSS_TYPE_DFS)) {
					if (woal_11h_cancel_chan_report_ioctl(
						    priv, MOAL_IOCTL_WAIT)) {
						PRINTM(MERROR,
						       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
						       __func__);
						LEAVE();
						return -EFAULT;
					}
					priv->chan_rpt_pending = MFALSE;
				}
#ifdef UAP_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
				if (!data[0] && priv->chan_rpt_req.chanNum) {
					memset(&ch_dfs_state, 0,
					       sizeof(ch_dfs_state));
					ch_dfs_state.channel =
						priv->chan_rpt_req.chanNum;
					if (!woal_11h_chan_dfs_state(
						    priv, MLAN_ACT_GET,
						    &ch_dfs_state)) {
						if (ch_dfs_state.dfs_state ==
						    DFS_AVAILABLE)
							woal_update_channels_dfs_state(
								priv,
								priv->chan_rpt_req
									.chanNum,
								priv->chan_rpt_req
									.bandcfg
									.chanWidth,
								DFS_USABLE);
					}
				}
#endif
#endif
				memset(&priv->chan_rpt_req, 0,
				       sizeof(mlan_ds_11h_chan_rep_req));
				PRINTM(MCMND, "DFS: Stop Radar detect\n");
				if (!data[0]) {
					if (priv->bss_type == MLAN_BSS_TYPE_UAP)
						woal_uap_11h_ctrl(priv, MFALSE);
					LEAVE();
					return ret;
				}
			}
			if (data[0] == priv->chan_rpt_req.chanNum &&
			    priv->bss_type == MLAN_BSS_TYPE_UAP)
				woal_uap_11h_ctrl(priv, MFALSE);
			memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
			ch_dfs_state.channel = data[0];
			if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
						    &ch_dfs_state)) {
				PRINTM(MERROR,
				       "%s: woal_11h_chan_dfs_state failed \n",
				       __func__);
				LEAVE();
				return -EFAULT;
			}
			if (!ch_dfs_state.dfs_required ||
			    ch_dfs_state.dfs_state == DFS_UNAVAILABLE) {
				PRINTM(MCMND,
				       "DFS: This channel=%d under NOP or not DFS channel\n",
				       data[0]);
				LEAVE();
				return -EINVAL;
			}
			if (woal_is_channel_under_nop(priv, data[0])) {
				PRINTM(MCMND,
				       "DFS: This channel=%d under NOP\n",
				       data[0]);
				LEAVE();
				return -EINVAL;
			}
			chan_rpt_req.startFreq = START_FREQ_11A_BAND;
			chan_rpt_req.chanNum = data[0];
			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
			chan_rpt_req.bandcfg.chanWidth = CHAN_BW_20MHZ;
			chan_rpt_req.millisec_dwell_time = DEF_CAC_DWELL_TIME;
			chan_rpt_req.host_based = MTRUE;
		}
		if (user_data_len >= 2) {
			if (data[1] < 0 || data[1] > CHANNEL_BW_80MHZ) {
				PRINTM(MERROR, "Inavalid bandwidth %d\n",
				       data[1]);
				LEAVE();
				return -EINVAL;
			}
			woal_convert_chanbw_to_bandconfig(priv,
							  &chan_rpt_req.bandcfg,
							  chan_rpt_req.chanNum,
							  data[1]);
		}
		if (user_data_len >= 3)
			chan_rpt_req.millisec_dwell_time =
				MIN(MAX_CAC_DWELL_TIME, data[2] * 1000);
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
		else {
			if ((woal_is_etsi_country(
				     priv->phandle->country_code) == MTRUE)) {
				if (chan_rpt_req.chanNum == 120 ||
				    chan_rpt_req.chanNum == 124 ||
				    chan_rpt_req.chanNum == 128) {
					chan_rpt_req.millisec_dwell_time =
						DEF_CAC_DWELL_TIME * 10;
				}
				if (chan_rpt_req.chanNum == 116 &&
				    user_data_len >= 2 && data[1] > 0)
					chan_rpt_req.millisec_dwell_time =
						DEF_CAC_DWELL_TIME * 10;
			}
		}
#endif
		moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
				&chan_rpt_req, sizeof(mlan_ds_11h_chan_rep_req),
				sizeof(mlan_ds_11h_chan_rep_req));
		PRINTM(MCMND,
		       "DFS: Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
		       chan_rpt_req.chanNum,
		       (int)(chan_rpt_req.bandcfg.chanWidth),
		       chan_rpt_req.millisec_dwell_time);
		status = woal_do_dfs_cac(priv, &chan_rpt_req);
		if (status != MLAN_STATUS_SUCCESS)
			ret = -EFAULT;
		else
			priv->chan_rpt_pending = MTRUE;
	}
	LEAVE();
	return ret;
}

/**
 * @brief               Set Auto Zero DFS configure
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 --success, otherwise fail
 */
static int woal_priv_auto_dfs_cfg(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	int ret = 0;
	int header_len = 0;
	auto_zero_dfs_cfg *auto_dfs_cfg = NULL;
	int i;
	int idx = 0;
	mlan_ds_11h_chan_dfs_state ch_dfs_state;
	mlan_ds_11h_chan_rep_req chan_rpt_req;

	ENTER();
	if (priv->bss_type != MLAN_BSS_TYPE_DFS) {
		PRINTM(MWARN, "Invalid BSS type\n");
		ret = -EINVAL;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTODFS);
	auto_dfs_cfg = (auto_zero_dfs_cfg *)(respbuf + header_len);
	/** Auto DFS is enabled and save config to moal_private structure */
	if (auto_dfs_cfg->start_auto_zero_dfs) {
		if (priv->auto_dfs_cfg.start_auto_zero_dfs ||
		    priv->chan_rpt_req.chanNum) {
			if (woal_11h_cancel_chan_report_ioctl(
				    priv, MOAL_IOCTL_WAIT)) {
				PRINTM(MERROR,
				       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
				       __func__);
				ret = -EFAULT;
				goto done;
			}
			memset(&priv->chan_rpt_req, 0,
			       sizeof(mlan_ds_11h_chan_rep_req));
		}
		memset(&priv->auto_dfs_cfg, 0, sizeof(auto_zero_dfs_cfg));
		if (auto_dfs_cfg->cac_start_chan) {
			memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
			ch_dfs_state.channel = auto_dfs_cfg->cac_start_chan;
			if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
						    &ch_dfs_state)) {
				PRINTM(MERROR,
				       "%s: woal_11h_chan_dfs_state failed \n",
				       __func__);
				ret = -EFAULT;
				goto done;
			}
			if (!ch_dfs_state.dfs_required ||
			    ch_dfs_state.dfs_state == DFS_UNAVAILABLE) {
				PRINTM(MCMND,
				       "ZeroDFS: This channel=%d under NOP or not DFS channel\n",
				       auto_dfs_cfg->cac_start_chan);
				LEAVE();
				return -EINVAL;
			}
		}
		priv->auto_dfs_cfg.cac_start_chan =
			auto_dfs_cfg->cac_start_chan;
		if (auto_dfs_cfg->cac_timer)
			priv->auto_dfs_cfg.cac_timer =
				MIN(MAX_CAC_DWELL_TIME,
				    auto_dfs_cfg->cac_timer * 1000);
		else
			priv->auto_dfs_cfg.cac_timer = DEF_CAC_DWELL_TIME;
		if ((auto_dfs_cfg->bw != CHANNEL_BW_20MHZ) &&
		    (auto_dfs_cfg->bw != CHANNEL_BW_40MHZ_ABOVE) &&
		    (auto_dfs_cfg->bw != CHANNEL_BW_40MHZ_BELOW) &&
		    (auto_dfs_cfg->bw != CHANNEL_BW_80MHZ)) {
			PRINTM(MERROR, "ZeroDFS: Invalid bw = %d\n",
			       auto_dfs_cfg->bw);
			LEAVE();
			return -EINVAL;
		}
		priv->auto_dfs_cfg.bw = auto_dfs_cfg->bw;
		priv->auto_dfs_cfg.uap_chan_switch =
			auto_dfs_cfg->uap_chan_switch;
		priv->auto_dfs_cfg.multi_chan_dfs =
			auto_dfs_cfg->multi_chan_dfs;
		if (auto_dfs_cfg->num_of_chan) {
			for (i = 0; i < auto_dfs_cfg->num_of_chan; i++) {
				memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
				ch_dfs_state.channel =
					auto_dfs_cfg->dfs_chan_list[i];
				if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
							    &ch_dfs_state)) {
					PRINTM(MERROR,
					       "%s: woal_11h_chan_dfs_state failed \n",
					       __func__);
					ret = -EFAULT;
					goto done;
				}
				if (!ch_dfs_state.dfs_required)
					continue;
				priv->auto_dfs_cfg.dfs_chan_list[idx] =
					auto_dfs_cfg->dfs_chan_list[i];
				idx++;
			}
			priv->auto_dfs_cfg.num_of_chan = idx;
		}
		if (!priv->auto_dfs_cfg.num_of_chan)
			woal_get_dfs_chan_list(priv);
		priv->curr_cac_idx = -1;
		if (!priv->auto_dfs_cfg.cac_start_chan)
			priv->auto_dfs_cfg.cac_start_chan =
				woal_get_next_dfs_chan(priv);
		PRINTM(MCMND, "Start Auto ZeroDFS\n");
		PRINTM(MCMND, "cac_start_chan=%d\n",
		       priv->auto_dfs_cfg.cac_start_chan);
		PRINTM(MCMND, "cac_timer=%d\n", priv->auto_dfs_cfg.cac_timer);
		PRINTM(MCMND, "bw=%d\n", priv->auto_dfs_cfg.bw);
		PRINTM(MCMND, "uap_chan_switch=%d\n",
		       priv->auto_dfs_cfg.uap_chan_switch);
		PRINTM(MCMND, "multi_chan_dfs=%d\n",
		       priv->auto_dfs_cfg.multi_chan_dfs);
		PRINTM(MCMND, "num of chan=%d\n",
		       priv->auto_dfs_cfg.num_of_chan);
		DBG_HEXDUMP(MCMD_D, "dfs chan list",
			    priv->auto_dfs_cfg.dfs_chan_list,
			    priv->auto_dfs_cfg.num_of_chan);
		if (priv->auto_dfs_cfg.cac_start_chan) {
			priv->auto_dfs_cfg.start_auto_zero_dfs = MTRUE;
			memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
			chan_rpt_req.startFreq = START_FREQ_11A_BAND;
			chan_rpt_req.chanNum =
				priv->auto_dfs_cfg.cac_start_chan;
			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
			chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
			chan_rpt_req.millisec_dwell_time =
				priv->auto_dfs_cfg.cac_timer;
			moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
					&chan_rpt_req,
					sizeof(mlan_ds_11h_chan_rep_req),
					sizeof(mlan_ds_11h_chan_rep_req));
			PRINTM(MCMND,
			       "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
			       chan_rpt_req.chanNum,
			       (int)(chan_rpt_req.bandcfg.chanWidth),
			       chan_rpt_req.millisec_dwell_time);
			if (MLAN_STATUS_SUCCESS !=
			    woal_do_dfs_cac(priv, &chan_rpt_req)) {
				PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
				       __func__);
				ret = -EFAULT;
			}
		}
	} else {
		PRINTM(MCMND, "Stop Auto ZeroDFS\n");
		if (woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT))
			PRINTM(MERROR,
			       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
			       __func__);
		memset(&priv->chan_rpt_req, 0,
		       sizeof(mlan_ds_11h_chan_rep_req));
		memset(&priv->auto_dfs_cfg, 0, sizeof(auto_zero_dfs_cfg));
	}
done:
	LEAVE();
	return ret;
}
#endif

/**
 * @brief               Set/Get CFP table codes
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cfp_code(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	int data[2] = {0};
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_ds_misc_cfp_code *cfp_code = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFP_CODE);

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfp_code = &misc_cfg->param.cfp_code;
	misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 2) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		cfp_code->cfp_code_bg = data[0];
		if (user_data_len == 2)
			cfp_code->cfp_code_a = data[1];
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		data[0] = cfp_code->cfp_code_bg;
		data[1] = cfp_code->cfp_code_a;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               mcast aggr group configure
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 --success, otherwise fail
 */
static int woal_priv_mcast_aggr_group_cfg(moal_private *priv, t_u8 *respbuf,
					  t_u32 respbuflen)
{
	int ret = 0;
	int header_len = 0;
	mcast_aggr_group *mcast_cfg = NULL;
	int index = 0;
	struct mcast_node *node = NULL;
	unsigned long flags;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MCAST_AGGR_GROUP);
	mcast_cfg = (mcast_aggr_group *)(respbuf + header_len);
	if (mcast_cfg->action == ACTION_ADD) {
		if (priv->num_mcast_addr >= MLAN_MAX_MULTICAST_LIST_SIZE) {
			PRINTM(MERROR, "mcast_aggr_group already full!\n");
			ret = -EINVAL;
			goto done;
		}
		woal_add_mcast_node(priv, mcast_cfg->mcast_addr);
	} else if (mcast_cfg->action == ACTION_REMOVE) {
		woal_remove_mcast_node(priv, mcast_cfg->mcast_addr);
	}
	memset(mcast_cfg, 0, sizeof(mcast_aggr_group));

	spin_lock_irqsave(&priv->mcast_lock, flags);
	list_for_each_entry (node, &priv->mcast_list, link) {
		moal_memcpy_ext(priv->phandle, &mcast_cfg->mac_list[index],
				node->mcast_addr, ETH_ALEN, ETH_ALEN);
		index++;
	}
	spin_unlock_irqrestore(&priv->mcast_lock, flags);
	mcast_cfg->num_mcast_addr = index;
	priv->num_mcast_addr = index;
	ret = header_len + sizeof(mcast_aggr_group);
done:
	LEAVE();
	return ret;
}

/**
 * @brief               mcast aggr configure
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 --success, otherwise fail
 */
static int woal_priv_mc_aggr_cfg(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_mc_aggr_cfg *mc_cfg;
	int ret = 0;
	int header_len = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_MC_AGGR_CFG;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MC_AGGR_CFG);
	mc_cfg = (mlan_ds_mc_aggr_cfg *)(respbuf + header_len);
	ioctl_req->action = mc_cfg->action;
	misc->param.mc_aggr_cfg.enable_bitmap = mc_cfg->enable_bitmap;
	misc->param.mc_aggr_cfg.mask_bitmap = mc_cfg->mask_bitmap;
	misc->param.mc_aggr_cfg.cts2self_offset = mc_cfg->cts2self_offset;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	mc_cfg->enable_bitmap = misc->param.mc_aggr_cfg.enable_bitmap;
	mc_cfg->mask_bitmap = misc->param.mc_aggr_cfg.mask_bitmap;
	mc_cfg->cts2self_offset = misc->param.mc_aggr_cfg.cts2self_offset;
	ret = header_len + sizeof(misc->param.mc_aggr_cfg);

	if (mc_cfg->mask_bitmap & MC_AGGR_CTRL) {
		if (mc_cfg->enable_bitmap & MC_AGGR_CTRL)
			priv->enable_mc_aggr = MTRUE;
		else
			priv->enable_mc_aggr = MFALSE;
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               per peer stats configure
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 --success, otherwise fail
 */
static int woal_priv_stats(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ds_stats *stats;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0;
	int header_len = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_STATS;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_STATS);
	stats = (mlan_ds_stats *)(respbuf + header_len);
	ioctl_req->action = stats->action;

	moal_memcpy_ext(priv->phandle, &misc->param.stats, stats,
			sizeof(mlan_ds_stats) + stats->tlv_len - 1,
			sizeof(mlan_ds_stats) + stats->tlv_len - 1);

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf + header_len,
			(mlan_ds_stats *)&misc->param.stats, ioctl_req->buf_len,
			respbuflen - header_len);
	ret = header_len + ioctl_req->buf_len;

done:
	LEAVE();
	return ret;
}
/**
 * @brief               get channel load results
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 --success, otherwise fail
 */
static int woal_priv_get_ch_load_results(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_ch_load *cl_cfg;
	int ret = 0;
	int header_len = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CH_LOAD_RESULTS;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CH_LOAD_RESULTS);
	cl_cfg = (mlan_ds_ch_load *)(respbuf + header_len);
	ioctl_req->action = cl_cfg->action;
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EAGAIN;
		goto done;
	}

	cl_cfg->ch_load_param = misc->param.ch_load.ch_load_param;
	cl_cfg->noise = misc->param.ch_load.noise;
	cl_cfg->rx_quality = misc->param.ch_load.rx_quality;
	ret = header_len + sizeof(misc->param.ch_load);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               get channel load
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              0 --success, otherwise fail
 */
static int woal_priv_get_ch_load(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_ch_load *cl_cfg;
	int ret = 0;
	int header_len = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CH_LOAD;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CH_LOAD);
	cl_cfg = (mlan_ds_ch_load *)(respbuf + header_len);
	ioctl_req->action = cl_cfg->action;
	misc->param.ch_load.ch_load_param = cl_cfg->ch_load_param;
	misc->param.ch_load.noise = cl_cfg->noise;
	misc->param.ch_load.rx_quality = cl_cfg->rx_quality;
	misc->param.ch_load.duration = cl_cfg->duration;
	status = woal_request_ioctl(priv, ioctl_req, MOAL_NO_WAIT);
	if (status != MLAN_STATUS_SUCCESS && status != MLAN_STATUS_PENDING) {
		ret = -EFAULT;
		goto done;
	}

	ret = header_len + sizeof(misc->param.ch_load);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get Tx/Rx antenna
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_ds_radio_cfg *radio = NULL;
	mlan_ioctl_req *req = NULL;
	int data[3] = {0};
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ANT_CFG);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	radio = (mlan_ds_radio_cfg *)req->pbuf;
	radio->sub_command = MLAN_OID_ANT_CFG;
	req->req_id = MLAN_IOCTL_RADIO_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 2) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
			radio->param.ant_cfg.tx_antenna = data[0];
			radio->param.ant_cfg.rx_antenna = data[0];
			if (user_data_len == 2)
				radio->param.ant_cfg.rx_antenna = data[1];
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
			if (IS_CARD9098(priv->phandle->card_type) ||
			    IS_CARD9097(priv->phandle->card_type) ||
			    IS_CARDIW624(priv->phandle->card_type)) {
				woal_cfg80211_notify_antcfg(
					priv, priv->phandle->wiphy, radio);
			}
#endif
		} else {
			radio->param.ant_cfg_1x1.antenna = data[0];
			if (user_data_len == 2)
				radio->param.ant_cfg_1x1.evaluate_time =
					data[1];
		}
		req->action = MLAN_ACT_SET;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (!user_data_len) {
		if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
			data[0] = radio->param.ant_cfg.tx_antenna;
			data[1] = radio->param.ant_cfg.rx_antenna;
			if (data[0] && data[1])
				ret = sizeof(int) * 2;
			else
				ret = sizeof(int) * 1;
			moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
					sizeof(data), respbuflen);
		} else {
			data[0] = (int)radio->param.ant_cfg_1x1.antenna;
			data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time;
			data[2] = (int)radio->param.ant_cfg_1x1.current_antenna;
			moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
					sizeof(data), respbuflen);
			ret = sizeof(data);
		}
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/*
 * @brief               Set/Get CWMode
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_cwmode(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_cw_mode_ctrl *cwmode;
	int ret = 0;
	int header_len = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CWMODE_CTRL;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CWMODE);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		ioctl_req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		ioctl_req->action = MLAN_ACT_SET;

		cwmode = (mlan_ds_cw_mode_ctrl *)(respbuf + header_len +
						  sizeof(t_u8));
		misc->param.cwmode.mode = cwmode->mode;
		misc->param.cwmode.txPower = cwmode->txPower;
		misc->param.cwmode.rateInfo = cwmode->rateInfo;
		misc->param.cwmode.channel = cwmode->channel;
		misc->param.cwmode.chanInfo = cwmode->chanInfo;
		misc->param.cwmode.pktLength = cwmode->pktLength;
	}

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.cwmode,
			sizeof(misc->param.cwmode), respbuflen);
	ret = sizeof(misc->param.cwmode);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get out band independent reset
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_ind_rst_cfg(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ioctl_req *req = NULL;
	int data[2] = {0};
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_IND_RST_CFG);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	memset(misc, 0, sizeof(mlan_ds_misc_cfg));
	misc->sub_command = MLAN_OID_MISC_IND_RST_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 2) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}

		if ((user_data_len == 1) || (user_data_len == 2)) {
			req->action = MLAN_ACT_SET;

			/* ir_mode */
			if (data[0] < 0 || data[0] > 2) {
				PRINTM(MERROR, "Invalid ir mode parameter!\n");
				ret = -EINVAL;
				goto done;
			}
			misc->param.ind_rst_cfg.ir_mode = data[0];

			/* gpio_pin */
			if (user_data_len == 2) {
				if ((data[1] != 0xFF) && (data[1] < 0)) {
					PRINTM(MERROR,
					       "Invalid gpio pin no!\n");
					ret = -EINVAL;
					goto done;
				}
				misc->param.ind_rst_cfg.gpio_pin = data[1];
			}
		}
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = (int)misc->param.ind_rst_cfg.ir_mode;
	data[1] = (int)misc->param.ind_rst_cfg.gpio_pin;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Get/Set system clock
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_sysclock(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int data[65];
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	int ret = 0, i = 0;
	int user_data_len = 0, header_len = 0;
	int data_length = 0, length_index = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SYSCLOCK);
	memset(data, 0, sizeof(data));
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
	}

	if (user_data_len > MLAN_MAX_CLK_NUM) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	if (user_data_len) {
		/* SET operation */
		req->action = MLAN_ACT_SET;

		/* Set configurable clocks */
		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
		cfg->param.sys_clock.sys_clk_num =
			MIN(MLAN_MAX_CLK_NUM, user_data_len);
		for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++)
			cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i];

		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
	} else {
		/* GET operation */
		req->action = MLAN_ACT_GET;

		/* Get configurable clocks */
		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}

		/* Current system clock */
		data[1] = (int)cfg->param.sys_clock.cur_sys_clk;
		data_length = 1;

		length_index =
			MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);

		/* Configurable clocks */
		for (i = 1; i <= length_index; i++)
			data[i + data_length] =
				(int)cfg->param.sys_clock.sys_clk[i - 1];

		data_length += length_index;

		/* Get supported clocks */
		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}

		length_index =
			MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);

		/* Supported clocks */
		for (i = 1; i <= length_index; i++)
			data[i + data_length] =
				(int)cfg->param.sys_clock.sys_clk[i - 1];

		data_length += length_index;

		/* Send length as first element */
		data[0] = data_length;
		data_length++;

		moal_memcpy_ext(priv->phandle, respbuf, data,
				sizeof(int) * data_length, respbuflen);
		ret = data_length * sizeof(int);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Get GTK/PTK
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_get_key(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int ret = 0, copy_len = 0;
	int header_len = 0;
	unsigned int i;
	t_u8 key_ascii[256];
	t_u8 *tmp;
	mlan_ds_sec_cfg *sec = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_KEY);
	if ((int)strlen(respbuf) != header_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}
	memset(key_ascii, 0x00, sizeof(key_ascii));
	tmp = key_ascii;

	if (priv->media_connected == MFALSE) {
		PRINTM(MERROR, "Can't get key in un-associated state\n");
		ret = -EFAULT;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Get Unicast Key */
	req->req_id = MLAN_IOCTL_SEC_CFG;
	req->action = MLAN_ACT_GET;
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
	sec->param.encrypt_key.key_index = 0;
	sec->param.encrypt_key.key_flags = 0;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (sec->param.encrypt_key.key_len) {
		snprintf((char *)tmp, CMD_BUF_LEN, "\n%s", "PTK: ");
		tmp += 5;
		for (i = 0; i < sec->param.encrypt_key.key_len; i++)
			tmp += snprintf((char *)tmp, CMD_BUF_LEN, "%02x",
					sec->param.encrypt_key.key_material[i]);
	}

	/* Get Multicase Key */
	req->req_id = MLAN_IOCTL_SEC_CFG;
	req->action = MLAN_ACT_GET;
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
	sec->param.encrypt_key.key_index = 0;
	sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
	memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (sec->param.encrypt_key.key_len) {
		snprintf((char *)tmp, CMD_BUF_LEN, "\n%s", "GTK: ");
		tmp += 5;
		for (i = 0; i < sec->param.encrypt_key.key_len; i++)
			tmp += snprintf((char *)tmp, CMD_BUF_LEN, "%02x",
					sec->param.encrypt_key.key_material[i]);
	}

	/* Get IGTK Key */
	req->req_id = MLAN_IOCTL_SEC_CFG;
	req->action = MLAN_ACT_GET;
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
	sec->param.encrypt_key.key_index = 0;
	sec->param.encrypt_key.key_flags = KEY_FLAG_AES_MCAST_IGTK;
	memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (sec->param.encrypt_key.key_len) {
		snprintf((char *)tmp, CMD_BUF_LEN, "\n%s", "IGTK: ");
		tmp += 6;
		for (i = 0; i < sec->param.encrypt_key.key_len; i++)
			tmp += snprintf((char *)tmp, CMD_BUF_LEN, "%02x",
					sec->param.encrypt_key.key_material[i]);
	}

	copy_len = tmp - key_ascii;
	moal_memcpy_ext(priv->phandle, respbuf, &key_ascii, copy_len,
			respbuflen);
	ret = copy_len;
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Associate to a specific indexed entry in the ScanTable
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_associate_ssid_bssid(moal_private *priv, t_u8 *respbuf,
					  t_u32 respbuflen)
{
	int ret = 0, copy_len = 0;
	int header_len = 0;
	mlan_ssid_bssid ssid_bssid;
#ifdef REASSOCIATION
	mlan_bss_info bss_info;
#endif
	char buf[64];
	t_u8 buflen;
	t_u8 mac_idx;
	t_u8 i;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCIATE);
	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}
	copy_len = strlen(respbuf) - header_len;
	mac_idx = 0;
	buflen = MIN(copy_len, (int)(sizeof(buf) - 1));
	memset(buf, 0, sizeof(buf));
	memset(&ssid_bssid, 0, sizeof(ssid_bssid));

	if (buflen < (3 * ETH_ALEN) + 2) {
		PRINTM(MERROR,
		       "Associate: Insufficient length in IOCTL input\n");

		/* buffer should be at least 3 characters per BSSID octet "00:"
		**   plus a space separater and at least 1 char in the SSID
		*/
		ret = -EINVAL;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, buf, respbuf + header_len, buflen,
			sizeof(buf));

	/* Skip white space */
	for (i = 0; (i < buflen) && (buf[i] == ' '); i++)
		;

	/* Copy/Convert the BSSID */
	for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) {
		if (buf[i] == ':') {
			mac_idx++;
		} else {
			ssid_bssid.bssid[mac_idx] = (t_u8)woal_atox(buf + i);

			while (((i < buflen) && isxdigit(buf[i + 1])))
				/* Skip entire hex value */
				i++;
		}
	}

	/* Skip one space between the BSSID and start of the SSID */
	i++;

	/* Copy the SSID */
	ssid_bssid.ssid.ssid_len = buflen - i;
	moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, buf + i,
			sizeof(ssid_bssid.ssid.ssid),
			sizeof(ssid_bssid.ssid.ssid));

	PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n",
	       MAC2STR(ssid_bssid.bssid), (int)ssid_bssid.ssid.ssid_len,
	       ssid_bssid.ssid.ssid);

	if (MLAN_STATUS_SUCCESS !=
	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
		ret = -EFAULT;
		goto done;
	}

#ifdef REASSOCIATION
	memset(&bss_info, 0x00, sizeof(bss_info));
	if (MLAN_STATUS_SUCCESS ==
	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
		moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
				&bss_info.ssid, sizeof(mlan_802_11_ssid),
				sizeof(mlan_802_11_ssid));
		moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
				&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
				sizeof(mlan_802_11_mac_addr));
	}
#endif /* REASSOCIATION */

done:
	LEAVE();
	return ret;
}

/* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
#define MAX_IN_OUT_CHAR 256
/** Tx BF Global conf argument index */
#define BF_ENABLE_PARAM 1
#define SOUND_ENABLE_PARAM 2
#define FB_TYPE_PARAM 3
#define SNR_THRESHOLD_PARAM 4
#define SOUND_INTVL_PARAM 5
#define BF_MODE_PARAM 6
#define BF_CFG_ACT_GET 0
#define BF_CFG_ACT_SET 1

/**
 * @brief               Set/Get Transmit beamforming configuration
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_tx_bf_cfg(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int header_len = 0;
	int ret = 0, copy_len = 0;
	int bf_action = 0, interval = 0;
	int snr = 0, i, tmp_val = 0;
	t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
	t_u8 *str, *token, *pos;
	t_u16 action = 0;

	mlan_ds_11n_tx_bf_cfg bf_cfg;
	mlan_trigger_sound_args *bf_sound = NULL;
	mlan_tx_bf_peer_args *tx_bf_peer = NULL;
	mlan_snr_thr_args *bf_snr = NULL;
	mlan_bf_periodicity_args *bf_periodicity = NULL;
	mlan_bf_global_cfg_args *bf_global = NULL;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CFG);
	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}
	memset(&bf_cfg, 0, sizeof(bf_cfg));
	/* Pointer to corresponding buffer */
	bf_sound = bf_cfg.body.bf_sound;
	tx_bf_peer = bf_cfg.body.tx_bf_peer;
	bf_snr = bf_cfg.body.bf_snr;
	bf_periodicity = bf_cfg.body.bf_periodicity;
	bf_global = &bf_cfg.body.bf_global_cfg;

	/* Total characters in buffer */
	char_count = strlen(respbuf) - header_len;
	copy_len = char_count;
	memset(buf, 0, sizeof(buf));
	if (char_count) {
		if (copy_len > (int)sizeof(buf)) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
		moal_memcpy_ext(priv->phandle, buf, respbuf + header_len,
				copy_len, sizeof(buf));

		if (char_count > 1 && buf[1] != ';') {
			PRINTM(MERROR,
			       "No action argument. Separate with ';'\n");
			ret = -EINVAL;
			goto done;
		}
		/* Replace ';' with NULL in the string to separate args */
		for (i = 0; i < char_count; i++) {
			if (buf[i] == ';')
				buf[i] = '\0';
		}
		/* The first byte represents the beamforming action */
		if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
			ret = -EINVAL;
			goto done;
		}
		switch (bf_action) {
		case BF_GLOBAL_CONFIGURATION:
			if (char_count == 1) {
				action = MLAN_ACT_GET;
				bf_cfg.action = BF_CFG_ACT_GET;
			} else {
				action = MLAN_ACT_SET;
				bf_cfg.action = BF_CFG_ACT_SET;
				/* Eliminate action field */
				token = &buf[2];
				for (i = 1, str = &buf[2]; token != NULL; i++) {
					token = strstr(str, " ");
					pos = str;
					if (token != NULL) {
						*token = '\0';
						str = token + 1;
					}
					(void)woal_atoi(&tmp_val, pos);
					switch (i) {
					case BF_ENABLE_PARAM:
						bf_global->bf_enbl =
							(t_u8)tmp_val;
						break;
					case SOUND_ENABLE_PARAM:
						bf_global->sounding_enbl =
							(t_u8)tmp_val;
						break;
					case FB_TYPE_PARAM:
						bf_global->fb_type =
							(t_u8)tmp_val;
						break;
					case SNR_THRESHOLD_PARAM:
						bf_global->snr_threshold =
							(t_u8)tmp_val;
						break;
					case SOUND_INTVL_PARAM:
						bf_global->sounding_interval =
							(t_u16)tmp_val;
						break;
					case BF_MODE_PARAM:
						bf_global->bf_mode =
							(t_u8)tmp_val;
						break;
					default:
						PRINTM(MERROR,
						       "Invalid Argument\n");
						ret = -EINVAL;
						goto done;
					}
				}
			}
			break;
		case TRIGGER_SOUNDING_FOR_PEER:
			/* First arg  = 2   BfAction
			 * Second arg = 17  MAC "00:50:43:20:BF:64" */
			if (char_count != 19) {
				PRINTM(MERROR, "Invalid argument\n");
				ret = -EINVAL;
				goto done;
			}
			woal_mac2u8(bf_sound->peer_mac, &buf[2]);
			action = MLAN_ACT_SET;
			bf_cfg.action = BF_CFG_ACT_SET;
			break;
		case SET_GET_BF_PERIODICITY:
			/* First arg  = 2   BfAction
			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
			 * Third arg =  1  (min char)  TX BF interval
			 *              10 (max char)  u32 maximum value
			 * 4294967295 */
			if (char_count < 19 || char_count > 30) {
				PRINTM(MERROR, "Invalid argument\n");
				ret = -EINVAL;
				goto done;
			}

			woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
			if (char_count == 19) {
				action = MLAN_ACT_GET;
				bf_cfg.action = BF_CFG_ACT_GET;
			} else {
				action = MLAN_ACT_SET;
				bf_cfg.action = BF_CFG_ACT_SET;
				if (woal_atoi(&interval, &buf[20]) !=
				    MLAN_STATUS_SUCCESS) {
					ret = -EINVAL;
					goto done;
				}
				bf_periodicity->interval = interval;
			}
			break;
		case TX_BF_FOR_PEER_ENBL:
			/* Handle only SET operation here
			 * First arg  = 2   BfAction
			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
			 * Third arg  = 2   enable/disable bf
			 * Fourth arg = 2   enable/disable sounding
			 * Fifth arg  = 1   FB Type */
			if (char_count != 25 && char_count != 1) {
				PRINTM(MERROR, "Invalid argument\n");
				ret = -EINVAL;
				goto done;
			}
			if (char_count == 1) {
				action = MLAN_ACT_GET;
				bf_cfg.action = BF_CFG_ACT_GET;
			} else {
				woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
				(void)woal_atoi(&tmp_val, &buf[20]);
				tx_bf_peer->bf_enbl = (t_u8)tmp_val;
				(void)woal_atoi(&tmp_val, &buf[22]);
				tx_bf_peer->sounding_enbl = (t_u8)tmp_val;
				(void)woal_atoi(&tmp_val, &buf[24]);
				tx_bf_peer->fb_type = (t_u8)tmp_val;
				action = MLAN_ACT_SET;
				bf_cfg.action = BF_CFG_ACT_SET;
			}
			break;
		case SET_SNR_THR_PEER:
			/* First arg  = 2   BfAction
			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
			 * Third arg  = 1/2 SNR u8 - can be 1/2 charerters */
			if (char_count != 1 &&
			    !(char_count == 21 || char_count == 22)) {
				PRINTM(MERROR, "Invalid argument\n");
				ret = -EINVAL;
				goto done;
			}
			if (char_count == 1) {
				action = MLAN_ACT_GET;
				bf_cfg.action = BF_CFG_ACT_GET;
			} else {
				woal_mac2u8(bf_snr->peer_mac, &buf[2]);
				if (woal_atoi(&snr, &buf[20]) !=
				    MLAN_STATUS_SUCCESS) {
					ret = -EINVAL;
					goto done;
				}
				bf_snr->snr = snr;
				action = MLAN_ACT_SET;
				bf_cfg.action = BF_CFG_ACT_SET;
			}
			break;
		default:
			ret = -EINVAL;
			goto done;
		}

		/* Save the value */
		bf_cfg.bf_action = bf_action;
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
			ret = -EFAULT;
			goto done;
		}
	} else {
		ret = -EINVAL;
		goto done;
	}

	switch (bf_action) {
	case BF_GLOBAL_CONFIGURATION:
		moal_memcpy_ext(priv->phandle, respbuf, bf_global,
				sizeof(mlan_bf_global_cfg_args), respbuflen);
		ret = sizeof(mlan_bf_global_cfg_args);
		break;
	case TRIGGER_SOUNDING_FOR_PEER:
		moal_memcpy_ext(priv->phandle, respbuf, bf_sound,
				sizeof(mlan_bf_global_cfg_args), respbuflen);
		ret = sizeof(mlan_bf_global_cfg_args);
		break;
	case SET_GET_BF_PERIODICITY:
		moal_memcpy_ext(priv->phandle, respbuf, bf_periodicity,
				sizeof(mlan_bf_periodicity_args), respbuflen);
		ret = sizeof(mlan_bf_periodicity_args);
		break;
	case TX_BF_FOR_PEER_ENBL:
		moal_memcpy_ext(priv->phandle, respbuf, tx_bf_peer,
				sizeof(mlan_tx_bf_peer_args), respbuflen);
		ret = sizeof(mlan_tx_bf_peer_args);
		break;
	case SET_SNR_THR_PEER:
		moal_memcpy_ext(priv->phandle, respbuf, bf_snr,
				sizeof(mlan_snr_thr_args), respbuflen);
		ret = sizeof(mlan_snr_thr_args);
		break;
		/** Default case not required as bf_action value already
		 * sanitized */
	}

done:
	LEAVE();
	return ret;
}

#ifdef SDIO
/**
 * @brief               Cmd53 read/write register
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cmd53rdwr(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int header_len = 0;
	int ret = 0;
	t_u8 *buf = NULL;
	t_u8 *data = NULL;
	t_u8 rw, mode;
	t_u16 blklen = 0, blknum = 0;
	int reg = 0;
	t_u32 pattern_len = 0, total_len = 0;
	t_u16 cmd_len;
	gfp_t flag;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SD_CMD53_RW);

	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
	data = kzalloc(WOAL_2K_BYTES, flag);
	if (!data) {
		PRINTM(MERROR, "Cannot allocate buffer for command!\n");
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, &cmd_len, respbuf + header_len,
			sizeof(cmd_len), sizeof(cmd_len));
	buf = respbuf + header_len + sizeof(cmd_len);

	rw = buf[0]; /* read/write (0/1) */
	reg = buf[5]; /* address */
	reg = (reg << 8) | buf[4];
	reg = (reg << 8) | buf[3];
	reg = (reg << 8) | buf[2];
	mode = buf[6]; /* byte mode/block mode (0/1) */
	blklen = buf[8]; /* block size */
	blklen = (blklen << 8) | buf[7];
	blknum = buf[10]; /* block number or byte number */
	blknum = (blknum << 8) | buf[9];

	if (mode == BYTE_MODE)
		blklen = 1;
	else
		mode = BLOCK_MODE;

	total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
	if (total_len > WOAL_2K_BYTES) {
		PRINTM(MERROR, "Total data length is too large!\n");
		ret = -EINVAL;
		goto done;
	}
	PRINTM(MINFO,
	       "CMD53 read/write, addr = %#x, mode = %d, "
	       "block size = %d, block(byte) number = %d\n",
	       reg, mode, blklen, blknum);

	if (!rw) {
		sdio_claim_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		if (sdio_readsb(
			    ((struct sdio_mmc_card *)priv->phandle->card)->func,
			    respbuf, reg, total_len)) {
			PRINTM(MERROR,
			       "sdio_readsb: reading memory 0x%x failed\n",
			       reg);
			goto done;
		}
		sdio_release_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		ret = total_len;
	} else {
		int pos = 0;
		pattern_len = cmd_len - 11;
		if (pattern_len > total_len)
			pattern_len = total_len;

		/* Copy/duplicate the pattern to data buffer */
		for (pos = 0; pos < (int)total_len; pos++)
			data[pos] = buf[11 + (pos % pattern_len)];
		sdio_claim_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
		if (sdio_writesb(
			    ((struct sdio_mmc_card *)priv->phandle->card)->func,
			    reg, data, total_len))
			PRINTM(MERROR,
			       "sdio_writesb: writing memory 0x%x failed\n",
			       reg);
		sdio_release_host(
			((struct sdio_mmc_card *)priv->phandle->card)->func);
	}

done:
	kfree(data);
	LEAVE();
	return ret;
}
#endif /* SDIO */

/**
 * @brief               Set/Get Port Control mode
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_port_ctrl(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_sec_cfg *sec = NULL;
	int ret = 0, data = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;
	ENTER();

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
	req->req_id = MLAN_IOCTL_SEC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PORT_CTRL);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len == 1) {
			sec->param.port_ctrl_enabled = data;
			req->action = MLAN_ACT_SET;
		} else {
			PRINTM(MERROR, "Invalid number of parameters\n");
			ret = -EINVAL;
			goto done;
		}
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf,
				&sec->param.port_ctrl_enabled, sizeof(int),
				respbuflen);
		ret = sizeof(int);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Private IOCTL entry to get the By-passed TX packet from
 * upper layer
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_bypassed_packet(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	int header_len = 0;
	int ret = 0;
	struct sk_buff *skb = NULL;
	struct ethhdr *eth;
	t_u16 moreLen = 0, copyLen = 0;
	ENTER();

#define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PB_BYPASS);
	copyLen = strlen(respbuf) - header_len;
	moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET +
		  sizeof(mlan_buffer);

	skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
	if (skb == NULL) {
		PRINTM(MERROR, "kmalloc no memory !!\n");
		LEAVE();
		return -ENOMEM;
	}

	skb_reserve(skb, moreLen);

	moal_memcpy_ext(priv->phandle, skb_put(skb, copyLen),
			respbuf + header_len, copyLen, copyLen);

	eth = (struct ethhdr *)skb->data;
	eth->h_proto = __constant_htons(eth->h_proto);
	skb->dev = priv->netdev;

	HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));

	woal_hard_start_xmit(skb, priv->netdev);

	LEAVE();
	return ret;
}

/**
 * @brief               Set Robustcoex gpiocfg
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_robustcoex(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[3] = {0};
	mlan_ds_misc_cfg *robust_coex_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	robust_coex_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	while (respbuf[0] == ' ') {
		/** skip space */
		respbuf = (t_u8 *)(respbuf + 1);
	}

	if (strncmp(respbuf, "gpiocfg", strlen("gpiocfg")) == 0) {
		header_len = strlen("gpiocfg") + 1;
		parse_arguments(respbuf + header_len, data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len > 3) {
			PRINTM(MERROR, "Invalid parameter number\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] != ROBUSTCOEX_GPIOCFG_ENABLE &&
		    data[0] != ROBUSTCOEX_GPIOCFG_DISABLE) {
			PRINTM(MERROR, "Invalid parameter number\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == ROBUSTCOEX_GPIOCFG_ENABLE) {
			if (user_data_len != 3) {
				PRINTM(MMSG,
				       "Please provide gpio num and gpio polarity for ROBUSTCOEX_GPIOCFG_ENABLE\n");
				ret = -EINVAL;
				goto done;
			}
			robust_coex_cfg->param.robustcoexparams.method =
				ROBUSTCOEX_GPIO_CFG;
			robust_coex_cfg->param.robustcoexparams.enable =
				ROBUSTCOEX_GPIOCFG_ENABLE;
			robust_coex_cfg->param.robustcoexparams.gpio_num =
				data[1];
			robust_coex_cfg->param.robustcoexparams.gpio_polarity =
				data[2];
		} else {
			robust_coex_cfg->param.robustcoexparams.method =
				ROBUSTCOEX_GPIO_CFG;
			robust_coex_cfg->param.robustcoexparams.enable =
				ROBUSTCOEX_GPIOCFG_DISABLE;
			robust_coex_cfg->param.robustcoexparams.gpio_num = 0;
			robust_coex_cfg->param.robustcoexparams.gpio_polarity =
				0;
		}
		req->action = MLAN_ACT_SET;
		req->req_id = MLAN_IOCTL_MISC_CFG;
		robust_coex_cfg->sub_command = MLAN_OID_MISC_ROBUSTCOEX;
	} else {
		PRINTM(MERROR, "Invalid parameter\n");
		ret = -EFAULT;
		goto done;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Set DMCS mapping policy or get DMCS status
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_dmcs(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[2] = {0};
	mlan_ds_misc_cfg *dmcs_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DMCS);
	dmcs_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);
	if (user_data_len > 2) {
		PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
		ret = -EINVAL;
		goto done;
	}
	req->req_id = MLAN_IOCTL_MISC_CFG;
	dmcs_cfg->sub_command = MLAN_OID_MISC_DMCS_CONFIG;
	dmcs_cfg->param.dmcs_policy.subcmd = data[0];
	switch (data[0]) {
	case 0:
		if (user_data_len != 2) {
			PRINTM(MERROR, "Please provide mapping policy\n");
			ret = -EINVAL;
			goto done;
		}
		req->action = MLAN_ACT_SET;
		dmcs_cfg->param.dmcs_policy.mapping_policy = data[1];
		break;
	case 1:
		req->action = MLAN_ACT_GET;
		break;
	default:
		break;
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (req->action == MLAN_ACT_GET) {
		moal_memcpy_ext(priv->phandle, respbuf,
				&dmcs_cfg->param.dmcs_status,
				sizeof(mlan_ds_misc_dmcs_status), respbuflen);
	}
	ret = sizeof(mlan_ds_misc_dmcs_status);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Set and get boot sleep configure
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_bootsleep(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret = MLAN_STATUS_SUCCESS;
	int user_data_len = 0;
	int header_len = 0;
	int allowed = 1;
	int data[1] = {0};
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		LEAVE();
		return -ENOMEM;
	}

	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_BOOT_SLEEP;
	req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BOOTSLEEP);

	if ((int)strlen(respbuf) == header_len) {
		req->action = MLAN_ACT_GET;
	} else {
		req->action = MLAN_ACT_SET;
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != allowed) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		misc->param.boot_sleep = data[0] ? 1 : 0;
		PRINTM(MIOCTL, "boot sleep cfg:%u\n", misc->param.boot_sleep);
	}

	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT);
	if (ret != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, &misc->param.boot_sleep,
			sizeof(misc->param.boot_sleep), respbuflen);
	ret = sizeof(misc->param.boot_sleep);

	PRINTM(MIOCTL, "boot sleep cfg: %u\n", misc->param.boot_sleep);

done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  * @brief               Set and get txwatchdog check
 *   * @param priv          Pointer to moal_private structure
 *    * @param respbuf       Pointer to response buffer
 *     * @param resplen       Response buffer length
 *      *
 *       *  @return             Number of bytes written, negative for failure.
 *        */
static int woal_priv_txwatchdog(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0;
	int header_len = 0;
	int user_data_len = 0;
	int data[1] = {0};
	int allowed = 1;
	t_u32 action;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXWATCHDOG);

	if (strlen(respbuf) == header_len) {
		action = MLAN_ACT_GET;
		ret = sizeof(t_u32);
	} else {
		action = MLAN_ACT_SET;
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != allowed) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
	}

	if (action == MLAN_ACT_SET) {
		priv->txwatchdog_disable = ((*data == 0) ? MTRUE : MFALSE);
	} else {
		*data = ((priv->txwatchdog_disable == MTRUE) ? 0 : 1);
	}
	memcpy(respbuf, data, sizeof(t_u32));
	PRINTM(MINFO, "priv->txwatchdog_disable:%u, action:%u, data[0]=%d\n",
	       priv->txwatchdog_disable, action, data[0]);

done:
	LEAVE();
	return ret;
}

#if defined(PCIE)
/**
 * @brief               Enable SSU support
 * @param priv          Pointer to moal_private structure
 * @param used_len 		used length
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_ssu_cmd(moal_private *priv, t_u8 used_len, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int ret = 0;
	mlan_ds_misc_cfg *ssu_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	ssu_params_cfg *ssu_params;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	ssu_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	memset(&ssu_cfg->param.ssu_params, 0, sizeof(mlan_ds_ssu_params));
	if (!used_len) {
		req->action = MLAN_ACT_SET;
		ssu_cfg->param.ssu_params.nskip = 0;
		ssu_cfg->param.ssu_params.nsel = 1;
		ssu_cfg->param.ssu_params.adcdownsample = 3;
		ssu_cfg->param.ssu_params.mask_adc_pkt = 0;
		ssu_cfg->param.ssu_params.out_16bits = 1;
	} else {
		ssu_params = (ssu_params_cfg *)respbuf;
		DBG_HEXDUMP(MCMD_D, "User SSU params:", respbuf,
			    sizeof(mlan_ds_ssu_params));
		if (ssu_params->ssu_mode == 2)
			req->action = MLAN_ACT_DEFAULT;
		else {
			req->action = MLAN_ACT_SET;
			ssu_cfg->param.ssu_params.nskip = ssu_params->nskip;
			ssu_cfg->param.ssu_params.nsel = ssu_params->nsel;
			ssu_cfg->param.ssu_params.adcdownsample =
				ssu_params->adcdownsample;
			ssu_cfg->param.ssu_params.mask_adc_pkt =
				ssu_params->mask_adc_pkt;
			ssu_cfg->param.ssu_params.out_16bits =
				ssu_params->out_16bits;
			ssu_cfg->param.ssu_params.spec_pwr_enable =
				ssu_params->spec_pwr_enable;
			ssu_cfg->param.ssu_params.rate_deduction =
				ssu_params->rate_deduction;
			ssu_cfg->param.ssu_params.n_pkt_avg =
				ssu_params->n_pkt_avg;
		}
	}
	req->req_id = MLAN_IOCTL_MISC_CFG;
	ssu_cfg->sub_command = MLAN_OID_MISC_SSU;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
#endif

/**
 * @brief               Configure the hal/phy cfg params
 *
 *  The command structure contains the following parameters
 *      dot11b_psd_mask: 1: enable, 0: disable
 *      Reserved : reserved 7 params for future such use
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_hal_phy_cfg_cmd(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	int ret = 0;
	mlan_ds_hal_phy_cfg_params *data_ptr;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = (mlan_ds_hal_phy_cfg_params *)respbuf;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_MISC_CFG;
	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_HAL_PHY_CFG;

	cfg->param.hal_phy_cfg_params.dot11b_psd_mask_cfg =
		data_ptr->dot11b_psd_mask_cfg;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Enable/disable CSI support
 *
 *  The command structure contains the following parameters
 *      csi_enable: 1: enable, 0: diable
 *      csi_filter_cnt: Number of CSI filters
 *      csi_filter: CSI filters
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_csi_cmd(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *cfg = NULL;
	int ret = 0;
	mlan_ds_csi_params *data_ptr;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	data_ptr = (mlan_ds_csi_params *)respbuf;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_MISC_CFG;
	cfg = (mlan_ds_misc_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_MISC_CSI;

	cfg->param.csi_params.csi_enable = data_ptr->csi_enable;
	if (data_ptr->csi_enable == 1) {
		cfg->param.csi_params.head_id = data_ptr->head_id;
		cfg->param.csi_params.tail_id = data_ptr->tail_id;
		cfg->param.csi_params.csi_filter_cnt = data_ptr->csi_filter_cnt;
		cfg->param.csi_params.chip_id = data_ptr->chip_id;
		if (cfg->param.csi_params.csi_filter_cnt > CSI_FILTER_MAX)
			cfg->param.csi_params.csi_filter_cnt = CSI_FILTER_MAX;
		moal_memcpy_ext(priv->phandle, cfg->param.csi_params.csi_filter,
				data_ptr->csi_filter,
				sizeof(mlan_csi_filter_t) *
					cfg->param.csi_params.csi_filter_cnt,
				sizeof(mlan_csi_filter_t) * CSI_FILTER_MAX);
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               configure 11ax HE capability or HE operation
 *
 *
 *  @param priv    Pointer to the mlan_private driver data struct
 *  @param respbuf      A pointer to response buffer
 *  @param len          length used
 *  @param respbuflen   Available length of response buffer
 *
 *  @return         Number of bytes written if successful else negative value
 */
static int woal_priv_11axcfg_cmd(moal_private *priv, t_u8 *respbuf, t_u8 len,
				 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11ax_cfg *cfg = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11AX_CFG;
	req->action = MLAN_ACT_SET;
	cfg = (mlan_ds_11ax_cfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_11AX_HE_CFG;
	if (len)
		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.he_cfg,
				respbuf, len, sizeof(mlan_ds_11ax_he_cfg));
	else
		req->action = MLAN_ACT_GET;
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.he_cfg,
			sizeof(mlan_ds_11ax_he_cfg), respbuflen);
	ret = sizeof(mlan_ds_11ax_he_cfg);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}
/**
 * @brief               Configure TWT Setup parameters
 *
 * @param priv          Pointer to the mlan_private driver data struct
 * @param respbuf       A pointer to response buffer
 * @param len           Length used
 * @param respbuflen    Available length of response buffer
 *
 * @return              Number of bytes written if successful else negative
 * value
 */
static int woal_priv_twt_setup(moal_private *priv, t_u8 *respbuf, t_u8 len,
			       t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_twtcfg *cfg = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
	if (req == NULL) {
		PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11AX_CFG;
	req->action = MLAN_ACT_SET;
	cfg = (mlan_ds_twtcfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
	cfg->sub_id = MLAN_11AX_TWT_SETUP_SUBID;

	if (len) {
		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_setup,
				respbuf, len, sizeof(mlan_ds_twt_setup));
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "woal_request_ioctl failed!\n");
		ret = -EFAULT;
		goto done;
	}

	ret = sizeof(mlan_ds_twt_setup);
done:
	if (status != MLAN_STATUS_PENDING) {
		kfree(req);
	}
	LEAVE();
	return ret;
}

/**
 * @brief               Configure TWT Tear down parameters
 *
 * @param priv          Pointer to the mlan_private driver data struct
 * @param respbuf       A pointer to response buffer
 * @param len           Length used
 * @param respbuflen    Available length of response buffer
 *
 * @return              Number of bytes written if successful else negative
 * value
 */
static int woal_priv_twt_teardown(moal_private *priv, t_u8 *respbuf, t_u8 len,
				  t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_twtcfg *cfg = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
	if (req == NULL) {
		PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11AX_CFG;
	req->action = MLAN_ACT_SET;
	cfg = (mlan_ds_twtcfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
	cfg->sub_id = MLAN_11AX_TWT_TEARDOWN_SUBID;

	if (len) {
		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_teardown,
				respbuf, len, sizeof(mlan_ds_twt_teardown));
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "woal_request_ioctl failed!\n");
		ret = -EFAULT;
		goto done;
	}

	ret = sizeof(mlan_ds_twt_teardown);
done:
	if (status != MLAN_STATUS_PENDING) {
		kfree(req);
	}
	LEAVE();
	return ret;
}

/**
* @brief               Configure TWT Report parameters

 *@param priv          Pointer to the mlan_private driver data struct
 *@param respbuf       A pointer to response buffer
 *@param len           Length used
 *@param respbuflen    Available length of response buffer

 *@return              Number of bytes written if successful else negative value
*/
static int woal_priv_twt_report(moal_private *priv, t_u8 *respbuf, t_u8 len,
				t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_twtcfg *cfg = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
	if (req == NULL) {
		PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_11AX_CFG;
	req->action = MLAN_ACT_GET;
	cfg = (mlan_ds_twtcfg *)req->pbuf;
	cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
	cfg->sub_id = MLAN_11AX_TWT_REPORT_SUBID;

	if (len) {
		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_report,
				respbuf, len, sizeof(mlan_ds_twt_report));
	}

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "woal_request_ioctl failed!\n");
		ret = -EFAULT;
		goto done;
	}

	ret = sizeof(mlan_ds_twt_report);
done:
	if (status != MLAN_STATUS_PENDING) {
		kfree(req);
	}
	LEAVE();
	return ret;
}

#ifdef WIFI_DIRECT_SUPPORT
#if defined(UAP_CFG80211)
/**
 * @brief               Set/Get P2P NoA (Notice of Absence) parameters
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cfg_noa(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[7];
	mlan_ds_wifi_direct_config noa_cfg;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_NOA);
	memset(&noa_cfg, 0, sizeof(noa_cfg));

	memset(data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len > 5) {
		PRINTM(MERROR, "invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}

	noa_cfg.flags |= WIFI_DIRECT_NOA;

	if (woal_p2p_config(priv, MLAN_ACT_GET, &noa_cfg) !=
	    MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "Could not get P2P noa config\n");
		ret = -EINVAL;
		goto done;
	}

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		moal_memcpy_ext(priv->phandle, respbuf, &noa_cfg,
				sizeof(noa_cfg), respbuflen);
		ret = sizeof(noa_cfg);
	} else {
		switch (user_data_len) {
		case 5:
			noa_cfg.noa_interval = (t_u32)data[4];
			/* fall through */
		case 4:
			noa_cfg.noa_duration = (t_u32)data[3];
			/* fall through */
		case 3:
			if (data[2] < 1 || data[2] > 255) {
				PRINTM(MERROR,
				       "Invalid number of absence intervals\n");
				ret = -EINVAL;
				goto done;
			}
			noa_cfg.noa_count = (t_u8)data[2];
			/* fall through */
		case 2:
			if (data[1] < 0 || data[1] > 255) {
				PRINTM(MERROR, "Invalid Index\n");
				ret = -EINVAL;
				goto done;
			}
			noa_cfg.index = (t_u16)data[1];
			/* fall through */
		case 1:
			if (data[0] < 0 || data[0] > 1) {
				PRINTM(MERROR, "Invalid noa enable\n");
				ret = -EINVAL;
				goto done;
			}
			noa_cfg.noa_enable = (t_u8)data[0];
			noa_cfg.flags |= WIFI_DIRECT_NOA;
			break;
		default:
			break;
		}
		if (woal_p2p_config(priv, MLAN_ACT_SET, &noa_cfg) !=
		    MLAN_STATUS_SUCCESS) {
			PRINTM(MERROR, "woal_p2p_config fail\n");
			ret = -EFAULT;
		}
	}

done:

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get P2P OPP-PS parameters
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cfg_opp_ps(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[7];
	mlan_ds_wifi_direct_config opp_ps_cfg;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_OPP_PS);
	memset(&opp_ps_cfg, 0, sizeof(opp_ps_cfg));

	memset(data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len > 2) {
		PRINTM(MERROR, "invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}

	opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;

	if (woal_p2p_config(priv, MLAN_ACT_GET, &opp_ps_cfg) !=
	    MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "Could not get P2P opp ps config\n");
		ret = -EINVAL;
		goto done;
	}

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		moal_memcpy_ext(priv->phandle, respbuf, &opp_ps_cfg,
				sizeof(opp_ps_cfg), respbuflen);
		ret = sizeof(opp_ps_cfg);
	} else {
		switch (user_data_len) {
		case 2:
			opp_ps_cfg.ct_window = (t_u8)data[1];
			/* fall through */
		case 1:
			if (data[0] < 0 || data[0] > 1) {
				PRINTM(MERROR, "Invalid ps enable\n");
				ret = -EINVAL;
				goto done;
			}
			opp_ps_cfg.opp_ps_enable = (t_u8)data[0];
			opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
			/* fall through */
		default:
			break;
		}
		if (woal_p2p_config(priv, MLAN_ACT_SET, &opp_ps_cfg) !=
		    MLAN_STATUS_SUCCESS) {
			PRINTM(MERROR, "woal_p2p_config fail\n");
			ret = -EINVAL;
		}
	}

done:
	LEAVE();
	return ret;
}
#endif
#endif

/**
 * @brief               Set/Get GPIO TSF latch clock sync config parameters
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cfg_clock_sync(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[5];
	mlan_ds_gpio_tsf_latch *clock_sync_cfg = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_CLOCK_SYNC);

	memset(data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len > 5) {
		PRINTM(MERROR, "invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	req->req_id = MLAN_IOCTL_MISC_CFG;
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	misc_cfg->sub_command = MLAN_OID_MISC_GPIO_TSF_LATCH;
	clock_sync_cfg = &misc_cfg->param.gpio_tsf_latch_config;
	memset(clock_sync_cfg, 0, sizeof(mlan_ds_gpio_tsf_latch));

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		req->action = MLAN_ACT_SET;
		switch (user_data_len) {
		case 5:
			clock_sync_cfg->clock_sync_gpio_pulse_width =
				(t_u16)data[4];
			/* fall through */
		case 4:
			if (data[3] < 0 || data[3] > 1) {
				PRINTM(MERROR, "Invalid Level/Trigger\n");
				ret = -EINVAL;
				goto done;
			}
			clock_sync_cfg->clock_sync_gpio_level_toggle =
				(t_u8)data[3];
			/* fall through */
		case 3:
			if (data[2] < 1 || data[2] > 255) {
				PRINTM(MERROR,
				       "Invalid number of GPIO Pin Number\n");
				ret = -EINVAL;
				goto done;
			}
			clock_sync_cfg->clock_sync_gpio_pin_number =
				(t_u8)data[2];
			/* fall through */
		case 2:
			if (data[1] < 0 || data[1] > 2) {
				PRINTM(MERROR, "Invalid Role\n");
				ret = -EINVAL;
				goto done;
			}
			clock_sync_cfg->clock_sync_Role = (t_u8)data[1];
			/* fall through */
		case 1:
			if (data[0] < 0 || data[0] > 2) {
				PRINTM(MERROR, "Invalid Mode\n");
				ret = -EINVAL;
				goto done;
			}
			clock_sync_cfg->clock_sync_mode = (t_u8)data[0];
			break;
		default:
			break;
		}
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)clock_sync_cfg,
				sizeof(mlan_ds_gpio_tsf_latch), respbuflen);
		ret = sizeof(mlan_ds_gpio_tsf_latch);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get GPIO TSF latch get tsf info config parameters
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cfg_get_tsf_info(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[1];
	mlan_ds_tsf_info *tsf_info;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_GET_TSF_INFO);

	memset(data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len > 1) {
		PRINTM(MERROR, "invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}
	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	misc_cfg->sub_command = MLAN_OID_MISC_GET_TSF_INFO;
	tsf_info = &misc_cfg->param.tsf_info;
	memset(tsf_info, 0, sizeof(mlan_ds_tsf_info));
	if (user_data_len == 1) {
		if (data[0] < 0 || data[0] > 1) {
			PRINTM(MERROR, "Invalid tsf Format\n");
			ret = -EINVAL;
			goto done;
		}
		tsf_info->tsf_format = data[0];
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)tsf_info,
			sizeof(mlan_ds_tsf_info), respbuflen);
	ret = sizeof(mlan_ds_tsf_info);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get cross chip sync config parameters
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cross_chip_synch(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	mlan_ds_cross_chip_synch *cross_chip_sync = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int data[5] = {0};
	int header_len = 0;
	int user_data_len = 0;
	int ret = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CROSS_CHIP_SYNCH);

	memset(data, 0, sizeof(data));
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len > 5) {
		PRINTM(MERROR, "invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	req->req_id = MLAN_IOCTL_MISC_CFG;
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	misc_cfg->sub_command = MLAN_OID_MISC_CROSS_CHIP_SYNCH;
	cross_chip_sync = &misc_cfg->param.cross_chip_synch;
	memset(cross_chip_sync, 0, sizeof(mlan_ds_cross_chip_synch));

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		req->action = MLAN_ACT_GET;
		user_data_len = 0;
	} else {
		req->action = MLAN_ACT_SET;

		if (data[0] < 0 || data[0] > 1) {
			PRINTM(MERROR, "Invalid start_stop value\n");
			ret = -EINVAL;
			goto done;
		} else if (data[1] < 1 || data[1] > 2) {
			PRINTM(MERROR, "Invalid role value\n");
			ret = -EINVAL;
			goto done;
		} else {
			cross_chip_sync->start_stop = (t_u8)data[0];
			cross_chip_sync->role = (t_u8)data[1];
			cross_chip_sync->period = (t_u32)data[2];
			cross_chip_sync->init_tsf_low = (t_u32)data[3];
			cross_chip_sync->init_tsf_high = (t_u32)data[4];
		}
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		/* Copy back to userspace call */
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)cross_chip_sync,
				sizeof(mlan_ds_cross_chip_synch), respbuflen);
		ret = sizeof(mlan_ds_cross_chip_synch);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

#ifdef UAP_SUPPORT
/**
 * @brief               Set/Get target channel
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_target_channel(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[1];

	ENTER();
	if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) {
		PRINTM(MERROR, "priv is null or interface is not AP");
		ret = -EFAULT;
		LEAVE();
		return ret;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TARGET_CHANNEL);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len > 1) {
			PRINTM(MERROR, "Invalid parameter number\n");
			ret = -EINVAL;
			goto done;
		}
		if (user_data_len)
			priv->target_chan = data[0];
	}
	data[0] = priv->target_chan;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(int);
done:

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get backup channel
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_backup_channel(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	int header_len = 0, user_data_len = 0;
	int ret = 0, data[1];

	ENTER();
	if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) {
		PRINTM(MERROR, "priv is null or interface is not AP");
		ret = -EFAULT;
		LEAVE();
		return ret;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BACKUP_CHANNEL);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len > 1) {
			PRINTM(MERROR, "Invalid parameter number\n");
			ret = -EINVAL;
			goto done;
		}
		if (user_data_len)
			priv->backup_chan = data[0];
	}
	data[0] = priv->backup_chan;
	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
			respbuflen);
	ret = sizeof(int);
done:

	LEAVE();
	return ret;
}
#endif

#if defined(STA_CFG80211) || defined(UAP_CFG80211)
#ifdef WIFI_DIRECT_SUPPORT
#define DEF_NOA_INTERVAL 100
/**
 ** @brief               Set/Get P2P NoA (Notice of Absence) parameters
 ** @param priv          Pointer to moal_private structure
 ** @param respbuf       Pointer to response buffer
 ** @param resplen       Response buffer length
 **
 **  @return             Number of bytes written, negative for failure.
 **/
static int woal_p2p_ps_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	int user_data_len = 0;
	int ret = 0, data[2];
	u32 duration = priv->phandle->noa_duration;
	u32 interval = 0;

	ENTER();
	if (strlen(respbuf) > strlen("P2P_PERIODIC_SLEEP")) {
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen("P2P_PERIODIC_SLEEP") + 1,
				data, ARRAY_SIZE(data), &user_data_len);
	}
	if ((user_data_len != 1) && (user_data_len != 2)) {
		PRINTM(MERROR,
		       " Invalid parameter number for P2P_PERIODIC_SLEEP");
		ret = -EINVAL;
		goto done;
	}
	if (data[0] < DEF_NOA_INTERVAL)
		interval = DEF_NOA_INTERVAL;
	else
		interval = (data[0] + DEF_NOA_INTERVAL - 1) / DEF_NOA_INTERVAL *
			   DEF_NOA_INTERVAL;

	if (user_data_len == 2)
		duration = data[1];
	if (duration >= interval) {
		PRINTM(MERROR,
		       " Invalid noa duration/interval! duration=%d interval=%d\n",
		       duration, interval);
		ret = -EINVAL;
		goto done;
	}
	priv->phandle->noa_interval = interval;
	priv->phandle->noa_duration = duration;
	PRINTM(MIOCTL, "configure noa interval=%d, duration=%d\n",
	       priv->phandle->noa_interval, priv->phandle->noa_duration);
done:
	LEAVE();
	return ret;
}
#endif
#endif

/**
 * @brief               Set/Get DFS repeater mode
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_dfs_repeater_cfg(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0, data[1] = {0};
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc_cfg = NULL;
	mlan_ds_misc_dfs_repeater *dfs_repeater = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_REPEATER_CFG);

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	req->req_id = MLAN_IOCTL_MISC_CFG;
	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
	misc_cfg->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE;
	dfs_repeater =
		(mlan_ds_misc_dfs_repeater *)&misc_cfg->param.dfs_repeater;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
			PRINTM(MERROR, "Invalid DFS repeater mode %d\n",
			       data[0]);
			ret = -EINVAL;
			goto done;
		}
		dfs_repeater->mode = (t_u16)data[0];

		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)dfs_repeater,
				sizeof(mlan_ds_misc_dfs_repeater), respbuflen);
		ret = sizeof(mlan_ds_misc_dfs_repeater);
	}

	/* Store current value of DFS repeater mode for futher references. eg.,
	 * for avoiding CAC timers
	 */
	priv->phandle->dfs_repeater_mode = dfs_repeater->mode;

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
/**
 * @brief               Set/Get MIRACAST configuration parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_miracast_cfg(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0, data[3] = {0, 0, 0};

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIRACAST_CFG);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		data[0] = priv->phandle->miracast_mode;
		data[1] = priv->phandle->miracast_scan_time;
		data[2] = priv->phandle->scan_chan_gap;

		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	} else {
		/* SET operation */
		memset(data, 0, sizeof(data));
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);

		if (user_data_len > 3) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] < 0 || data[0] > 2 || data[1] < 0 || data[2] < 0) {
			PRINTM(MERROR, "Invalid argument\n");
			ret = -EINVAL;
			goto done;
		}
	}

	if (user_data_len >= 1)
		priv->phandle->miracast_mode = (t_u8)data[0];
	if (user_data_len >= 2)
		priv->phandle->miracast_scan_time = (t_u16)data[1];
	if (user_data_len == 3)
		priv->phandle->scan_chan_gap = (t_u16)data[2];

done:
	LEAVE();
	return ret;
}

/**
 *   @brief Configuring scan gap for miracast mode
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             0 --success, otherwise failure
 */
static int woal_set_scan_chan_gap(moal_private *priv, t_u8 *respbuf,
				  int respbuflen)
{
	t_u32 data[2];
	int ret = 0;
	int user_data_len = 0;

	ENTER();

	if (strlen(respbuf) > strlen("SCAN_TIMING")) {
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen("SCAN_TIMING") + 1, data,
				ARRAY_SIZE(data), &user_data_len);
	}

	if (user_data_len != 2) {
		PRINTM(MERROR, "Invalid arguments for scan timing\n");
		ret = -EINVAL;
		goto done;
	}
	priv->phandle->miracast_scan_time = (t_u16)data[0];
	priv->phandle->scan_chan_gap = (t_u16)data[1];
done:
	LEAVE();
	return ret;
}
#endif
#endif

/**
 * @brief               Set/Get control to coex RX window size configuration
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_coex_rx_winsize(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0, data = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_COEX_RX_WINSIZE);

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	req->req_id = MLAN_IOCTL_11N_CFG;
	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_COEX_RX_WINSIZE;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		if ((data != MTRUE) && (data != MFALSE)) {
			PRINTM(MERROR,
			       "Invalid coex RX window size parameter %d\n",
			       data);
			ret = -EINVAL;
			goto done;
		}
		cfg_11n->param.coex_rx_winsize = data;
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf,
				(t_u8 *)&cfg_11n->param.coex_rx_winsize,
				sizeof(t_u32), respbuflen);
		ret = sizeof(t_u32);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get control to TX AMPDU configuration on infra link
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_txaggrctrl(moal_private *priv, t_u8 *respbuf,
				t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0, data = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_11n_cfg *cfg_11n = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AGGR_CTRL);

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	req->req_id = MLAN_IOCTL_11N_CFG;
	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX_AGGR_CTRL;

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		if ((data != MTRUE) && (data != MFALSE)) {
			PRINTM(MERROR, "Invalid txaggrctrl parameter %d\n",
			       data);
			ret = -EINVAL;
			goto done;
		}
		cfg_11n->param.txaggrctrl = data;
		req->action = MLAN_ACT_SET;
	}

	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!user_data_len) {
		moal_memcpy_ext(priv->phandle, respbuf,
				(t_u8 *)&cfg_11n->param.txaggrctrl,
				sizeof(t_u32), respbuflen);
		ret = sizeof(t_u32);
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get control to enable/disable auto TDLS
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_auto_tdls(moal_private *priv, t_u8 *respbuf,
			       t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0, data = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_TDLS);

	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		data = priv->enable_auto_tdls;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		if ((data != MTRUE) && (data != MFALSE)) {
			PRINTM(MERROR, "Invalid autotdls parameter %d\n", data);
			ret = -EINVAL;
			goto done;
		}
		priv->enable_auto_tdls = (t_u8)data;
	}

done:
	LEAVE();
	return ret;
}

#ifdef PCIE
/**
 * @brief               Read/Write PCIE register
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              Number of bytes written, negative for failure.
 */
static int woal_priv_pcie_reg_rw(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	moal_handle *handle = priv->phandle;
	int data[3];
	t_u32 reg;
	t_u32 value;
	int ret = MLAN_STATUS_SUCCESS;
	int user_data_len = 0, header_len = 0;

	ENTER();

	memset(data, 0, sizeof(data));
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_REG_RW);
	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}

	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);
	if ((user_data_len != 1) && (user_data_len != 2)) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}

	reg = (t_u32)data[0];
	if (user_data_len == 1) {
		if (moal_read_reg(handle, reg, &value)) {
			ret = -EFAULT;
			goto done;
		}
		data[1] = value;
	} else {
		value = data[1];
		if (moal_write_reg(handle, reg, value)) {
			ret = -EFAULT;
			goto done;
		}
	}
	moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	LEAVE();
	return ret;
}

/**
 * @brief               Read/Write PCIE register/memory from BAR0
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              Number of bytes written, negative for failure.
 */
static int woal_priv_pcie_bar0_reg_rw(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	moal_handle *handle = priv->phandle;
	pcie_service_card *card = (pcie_service_card *)handle->card;
	int data[3];
	t_u32 reg;
	t_u32 value;
	int ret = MLAN_STATUS_SUCCESS;
	int user_data_len = 0, header_len = 0;

	ENTER();

	memset(data, 0, sizeof(data));
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_BAR0_REG_RW);
	if ((int)strlen(respbuf) == header_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}

	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);
	if ((user_data_len != 1) && (user_data_len != 2)) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}

	reg = (t_u32)data[0];
	if (user_data_len == 1) {
		value = ioread32(card->pci_mmap + reg);
		if (value == MLAN_STATUS_FAILURE) {
			ret = -EFAULT;
			goto done;
		}
		data[1] = value;
	} else {
		value = data[1];
		iowrite32(value, card->pci_mmap + reg);
	}
	moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	LEAVE();
	return ret;
}
#endif

/**
 * @brief               Get SOC temperature
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              Number of bytes written, negative for failure.
 */
static int woal_priv_get_sensor_temp(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *pcfg = NULL;
	int ret = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	pcfg = (mlan_ds_misc_cfg *)req->pbuf;
	pcfg->sub_command = MLAN_OID_MISC_GET_SENSOR_TEMP;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	req->action = MLAN_ACT_GET;

	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	memset(respbuf, 0, respbuflen);
	moal_memcpy_ext(priv->phandle, respbuf,
			&pcfg->param.sensor_temp.temperature, sizeof(t_u32),
			respbuflen);

	ret = sizeof(t_u32);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
/**
 * @brief               Enable/disable DFS offload
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return              Number of bytes written, negative for failure.
 */
static int woal_priv_dfs_offload_enable(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	int ret = 0, dfs_offload_en = 0, user_data_len = 0, header_len = 0,
	    dfs_offload;

	ENTER();

	if (!priv) {
		PRINTM(MERROR, "priv is NULL\n");
		ret = -EFAULT;
		goto done;
	}

	dfs_offload = moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD);
	if (woal_is_any_interface_active(priv->phandle)) {
		PRINTM(MERROR,
		       "DFS offload enable/disable do not allowed after BSS started!\n");
		ret = -EFAULT;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_OFFLOAD);
	parse_arguments(respbuf + header_len, &dfs_offload_en,
			sizeof(dfs_offload_en) / sizeof(int), &user_data_len);
	if (user_data_len != 1) {
		PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
		ret = -EINVAL;
		goto done;
	}

	if (dfs_offload_en != 0 && dfs_offload_en != 1) {
		PRINTM(MERROR, "Invalid args!\n");
		ret = -EINVAL;
		goto done;
	}
	if (dfs_offload != dfs_offload_en) {
		dfs_offload = dfs_offload_en;
		if (dfs_offload)
			moal_extflg_set(priv->phandle, EXT_DFS_OFFLOAD);
		else
			moal_extflg_clear(priv->phandle, EXT_DFS_OFFLOAD);
	}
done:
	LEAVE();
	return ret;
}
#endif
#endif

/**
 * @brief               Set/Get TDLS CS off channel value
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_tdls_cs_chan(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0;
	int user_data_len = 0, header_len = 0, data = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_TDLS_CS_CHANNEL;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen("TDLS_CS_CHAN");
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		ioctl_req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len + 1, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		ioctl_req->action = MLAN_ACT_SET;
		misc->param.tdls_cs_channel = (t_u8)data;
	}

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	ret = snprintf(respbuf, CMD_BUF_LEN, "off channel %d\n",
		       misc->param.tdls_cs_channel) +
	      1;

	PRINTM(MIOCTL, "tdls CS channel %d\n", misc->param.tdls_cs_channel);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}
/**
 * @brief               Set/Get TDLS idle timeout value
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_tdls_idle_time(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0;
	int user_data_len = 0, header_len = 0, data = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_TDLS_IDLE_TIME;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TDLS_IDLE_TIME);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		ioctl_req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		ioctl_req->action = MLAN_ACT_SET;
		misc->param.tdls_idle_time = (t_u16)data;
	}

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf,
			(t_u8 *)&misc->param.tdls_idle_time, sizeof(t_u16),
			respbuflen);
	ret = sizeof(t_u16);

	PRINTM(MIOCTL, "tdls idle time %d\n", misc->param.tdls_idle_time);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Set/Get dynamic bandwidth
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_config_dyn_bw(moal_private *priv, t_u8 *respbuf,
				   t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0;
	int user_data_len = 0, header_len = 0, data = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_DYN_BW;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DYN_BW);
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		ioctl_req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, &data,
				sizeof(data) / sizeof(int), &user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid number of args! %d\n",
			       user_data_len);
			ret = -EINVAL;
			goto done;
		}
		ioctl_req->action = MLAN_ACT_SET;
		misc->param.dyn_bw = (t_u16)data;
	}

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.dyn_bw,
			sizeof(t_u16), respbuflen);
	ret = sizeof(t_u16);

	PRINTM(MIOCTL, "Dynamic bandwidth %d\n", misc->param.dyn_bw);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

#if defined(UAP_SUPPORT)
/**
 * @brief               Check validation of channel and oper class
 *
 * @param priv          Pointer to moal_private structure
 * @param channel       channel
 * @param oper_class    oper_class
 * @param bandwidth     band width
 *
 *  @return             SUCCESS/FAIL
 */
static int woal_check_valid_channel_operclass(moal_private *priv, int channel,
					      int oper_class, t_u8 bandwidth)
{
	int ret = 0;
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	t_u8 bw;

	ENTER();

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	switch (bandwidth) {
	case CHANNEL_BW_40MHZ_ABOVE:
	case CHANNEL_BW_40MHZ_BELOW:
		bw = CHAN_BW_40MHZ;
		break;
	case CHANNEL_BW_80MHZ:
		bw = CHAN_BW_80MHZ;
		break;
	default:
		bw = CHAN_BW_20MHZ;
		break;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_OPER_CLASS_CHECK;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
	ioctl_req->action = MLAN_ACT_GET;
	misc->param.bw_chan_oper.oper_class = (t_u8)oper_class;
	misc->param.bw_chan_oper.channel = (t_u8)channel;
	misc->param.bw_chan_oper.bandwidth = (t_u8)bw;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief Enable radar detect for DFS channel
 *
 * @param priv            A pointer to moal private structure
 * @param chan            channel
 * @return                N/A
 */
static void woal_enable_dfs(moal_private *priv, t_u8 channel, t_u8 wait_option)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
	mlan_ds_11h_cfg *p11h_cfg = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	ENTER();
	PRINTM(MCMND, "Enable Radar detect, chan %d\n", channel);
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
	if (NULL == req) {
		PRINTM(MIOCTL, "No Memory to allocate ioctl buffer\n");
		LEAVE();
		return;
	}
	p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
	pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
	pchan_rpt_req->startFreq = 5000;
	pchan_rpt_req->chanNum = channel;
	pchan_rpt_req->host_based = MTRUE;
	pchan_rpt_req->millisec_dwell_time = 0;

	p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
	req->req_id = MLAN_IOCTL_11H_CFG;
	req->action = MLAN_ACT_SET;
	/* Send Channel Check command and wait until the report is ready */
	status = woal_request_ioctl(priv, req, wait_option);
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return;
}

/**
 *  @brief send CSA/ECSA action frame
 *
 ** @param priv          Pointer to moal_private structure
 *  @param block_tx      0-no need block traffic 1- need block traffic
 *  @param oper_class    oper_class
 *  @param channel       channel
 *  @param switch count  how many csa/ecsa beacon will send out
 *  @param wait_option
 *
 *  @return             channel center frequency center, if found; O, otherwise
 */
static int woal_action_channel_switch(moal_private *priv, t_u8 block_tx,
				      t_u8 oper_class, t_u8 channel,
				      t_u8 switch_count, t_u8 mode,
				      t_u8 wait_option)
{
	mlan_status ret = MLAN_STATUS_SUCCESS;
	mlan_ds_bss *bss = NULL;
	mlan_ioctl_req *req = NULL;

	ENTER();

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
	if (req == NULL) {
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}

	bss = (mlan_ds_bss *)req->pbuf;
	bss->sub_command = MLAN_OID_ACTION_CHAN_SWITCH;
	req->req_id = MLAN_IOCTL_BSS;
	req->action = MLAN_ACT_SET;
	bss->param.chanswitch.mode = mode;
	bss->param.chanswitch.chan_switch_mode = block_tx;
	bss->param.chanswitch.new_channel_num = channel;
	if (!switch_count)
		bss->param.chanswitch.chan_switch_count = DEF_NUM_PKTS;
	else if (!mode) /* bcast action frame */
		bss->param.chanswitch.chan_switch_count =
			MIN(switch_count, MAX_NUM_PKTS);
	else /* ucast action frame */
		bss->param.chanswitch.chan_switch_count = switch_count;
	bss->param.chanswitch.new_oper_class = oper_class;
	ret = woal_request_ioctl(priv, req, wait_option);
done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

#ifdef UAP_SUPPORT
/**
 *  @brief move the uAP to transition channel
 *
 *  @param priv          Pointer to moal_private structure
 *
 *  @return              N/A
 */
void woal_move_to_next_channel(moal_private *priv)
{
	mlan_ds_11h_chan_dfs_state ch_dfs;
	t_u8 next_chan = 0;
	if (priv->target_chan) {
		next_chan = priv->target_chan;
		priv->target_chan = 0;
	} else if (priv->backup_chan) {
		next_chan = priv->backup_chan;
	}
	if (!next_chan)
		return;
	memset(&ch_dfs, 0, sizeof(ch_dfs));
	ch_dfs.channel = next_chan;
	if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET, &ch_dfs))
		PRINTM(MERROR, "%s: woal_11h_chan_dfs_state failed \n",
		       __func__);
	if (ch_dfs.dfs_required)
		woal_enable_dfs(priv, next_chan, MOAL_NO_WAIT);
	woal_action_channel_switch(priv, MTRUE, 0, next_chan,
				   priv->chan_num_pkts, priv->chan_mode,
				   MOAL_NO_WAIT);
	return;
}
#endif

/**
 * @brief               Set extended channel switch ie
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_extend_channel_switch(moal_private *priv, t_u8 *respbuf,
					   t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0;
	int data[6] = {0};
	t_u8 band = BAND_2GHZ;
	t_u8 channel;
	mlan_ds_11h_chan_dfs_state ch_dfs;

	ENTER();

	if (!priv || !priv->phandle || (priv->bss_role != MLAN_BSS_ROLE_UAP) ||
	    (priv->bss_started != MTRUE)) {
		PRINTM(MERROR,
		       "priv or handle is null or interface is not AP/GO"
		       "or AP is not started\n");
		ret = -EFAULT;
		LEAVE();
		return ret;
	}

	parse_arguments(respbuf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_EXTEND_CHAN_SWITCH),
			data, ARRAY_SIZE(data), &user_data_len);

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		LEAVE();
		return ret;
	}
	if (user_data_len < 4) {
		PRINTM(MERROR, "Too few arguments\n");
		ret = -EINVAL;
		LEAVE();
		return ret;
	}
	channel = data[2];
	if (data[1]) {
		if (woal_check_valid_channel_operclass(priv, data[2], data[1],
						       data[4])) {
			PRINTM(MERROR, "Wrong channel switch parameters!\n");
			ret = -EINVAL;
			goto done;
		}
	}

	if (channel > MAX_BG_CHANNEL)
		band = BAND_5GHZ;
	/* For 2.4G/6G channels skip the DFS checks */
	if (band == BAND_5GHZ) {
		memset(&ch_dfs, 0, sizeof(ch_dfs));
		ch_dfs.channel = data[2];

		if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET, &ch_dfs)) {
			PRINTM(MERROR, "%s: woal_11h_chan_dfs_state failed \n",
			       __func__);
			ret = -EFAULT;
			LEAVE();
			return ret;
		}

		if (ch_dfs.dfs_required &&
		    (ch_dfs.dfs_state == DFS_UNAVAILABLE ||
		     ch_dfs.dfs_state == DFS_USABLE)) {
			PRINTM(MERROR,
			       "DFS: Channel=%d is not Available, cannot switch to this channel\n",
			       data[2]);
			ret = -EFAULT;
			LEAVE();
			return ret;
		}

		if (ch_dfs.dfs_required) {
#ifdef UAP_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
			woal_update_channels_dfs_state(priv, channel, data[4],
						       DFS_AVAILABLE);
#endif
#endif
			woal_enable_dfs(priv, data[2], MOAL_IOCTL_WAIT);
		}
	}
	if (data[5] && (data[5] < 0 || data[5] > 3)) {
		PRINTM(MERROR,
		       "Wrong channel switch parameters for ucast action frame!\n");
		ret = -EINVAL;
		goto done;
	}

	if (!data[3]) {
		if (!data[5] && (data[4] < 0 || data[4] > MAX_NUM_PKTS)) {
			PRINTM(MERROR,
			       "Bcast action frame count exceeds maximum %d!\n",
			       MAX_NUM_PKTS);
			ret = -EINVAL;
			goto done;
		}
		priv->chan_mode = data[5] & DEFAULT_CHAN_MODE_MASK;
		priv->chan_num_pkts = data[4];
	}

	if (data[3])
		woal_channel_switch(priv, data[0], data[1], data[2], data[3],
				    band, data[4], MFALSE);
	else
		woal_action_channel_switch(priv, data[0], data[1], data[2],
					   data[4], data[5], MOAL_IOCTL_WAIT);
done:
	LEAVE();
	return ret;
}

/**
 * @brief               Set the new CSA parameter for target channel and backup
 * channel
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length
 *
 * @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_channel_switch_param(moal_private *priv, t_u8 *respbuf,
					      t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0;
	int data[2] = {0};

	ENTER();

	if (!priv || !priv->phandle || (priv->bss_role != MLAN_BSS_ROLE_UAP)) {
		PRINTM(MERROR,
		       "priv or handle is null or interface is not AP/GO\n");
		ret = -EFAULT;
		LEAVE();
		return ret;
	}

	if (strlen(respbuf) ==
	    (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_CHAN_SWITCH_PARAM))) {
		/* GET operation */
		respbuf[0] = priv->chan_mode;
		respbuf[1] = priv->chan_num_pkts;
		ret = 2;
		goto done;
	} else {
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_SET_CHAN_SWITCH_PARAM),
				data, ARRAY_SIZE(data), &user_data_len);
	}

	if (sizeof(int) * user_data_len > sizeof(data)) {
		PRINTM(MERROR, "Too many arguments\n");
		ret = -EINVAL;
		LEAVE();
		return ret;
	}
	if (user_data_len < 2) {
		PRINTM(MERROR, "Too few arguments\n");
		ret = -EINVAL;
		LEAVE();
		return ret;
	}

	if (data[0] && (data[0] < 0 || data[0] > 3)) {
		PRINTM(MERROR,
		       "Wrong channel switch parameter <mode> for ucast action frame!\n");
		ret = -EINVAL;
		goto done;
	}

	if (!data[0] && (data[1] < 0 || data[1] > MAX_NUM_PKTS)) {
		PRINTM(MERROR, "Bcast action frame count exceeds maximum %d!\n",
		       MAX_NUM_PKTS);
		ret = -EINVAL;
		goto done;
	}
	priv->chan_mode = data[0] & DEFAULT_CHAN_MODE_MASK;
	priv->chan_num_pkts = data[1];
done:
	LEAVE();
	return ret;
}

/**
 * @brief               P2P extended channel switch
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_p2p_ecsa(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int ret = 0;
	int user_data_len = 0, header_len = 0;
	int data[2] = {0};
	t_u8 bw = 0, oper_class = 0, channel = 0;
	IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
	custom_ie *pcust_chansw_ie = NULL;
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	if (priv->bss_role != MLAN_BSS_ROLE_UAP) {
		PRINTM(MERROR,
		       "Extended Channel Switch is only allowed for AP/GO mode\n");
		ret = -EFAULT;
		goto done;
	}

	if (priv->bss_started != MTRUE) {
		PRINTM(MERROR, "AP is not started!\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
	ioctl_req->action = MLAN_ACT_SET;
	misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
	misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);

	pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
	pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ExtChanSwitchAnn_t);
	pcust_chansw_ie->mgmt_subtype_mask =
		MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
							    BEACON/probe resp*/
	ext_chan_switch =
		(IEEEtypes_ExtChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;

	header_len = strlen("P2P_ECSA");
	parse_arguments(respbuf + header_len + 1, data, ARRAY_SIZE(data),
			&user_data_len);

	if (user_data_len != 2) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	}

	channel = data[0];
	/* bandwidth 20:20M 40:40M 80:80M*/
	bw = data[1];
	if (bw != 20 && bw != 40 && bw != 80) {
		PRINTM(MERROR, "Unsupported bandwidth\n");
		ret = -EINVAL;
		goto done;
	}
	if (channel >= 52 && channel <= 144) {
		PRINTM(MERROR, "Switch to DFS channel is not allowed!\n");
		ret = -EINVAL;
		goto done;
	}

	woal_priv_get_nonglobal_operclass_by_bw_channel(priv, bw, channel,
							&oper_class);
	if (oper_class == 0) {
		PRINTM(MERROR, "Wrong parameters!\n");
		ret = -EFAULT;
		goto done;
	}
	ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
	ext_chan_switch->len = 4;
	ext_chan_switch->chan_switch_mode = 1;
	ext_chan_switch->new_oper_class = oper_class;
	ext_chan_switch->new_channel_num = channel;
	ext_chan_switch->chan_switch_count = DEF_CHAN_SWITCH_COUNT;

	if (ext_chan_switch->chan_switch_mode) {
		if (netif_carrier_ok(priv->netdev))
			netif_carrier_off(priv->netdev);
		woal_stop_queue(priv->netdev);
		priv->uap_tx_blocked = MTRUE;
	}

	DBG_HEXDUMP(MCMD_D, "ECSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
		    pcust_chansw_ie->ie_length);

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	priv->phandle->chsw_wait_q_woken = MFALSE;
	/* wait for channel switch to complete  */
	(void)wait_event_interruptible_timeout(
		priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
		(u32)HZ * (ext_chan_switch->chan_switch_count + 2) * 110 /
			1000);

	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
	pcust_chansw_ie->mgmt_subtype_mask = 0;
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		PRINTM(MERROR, "Failed to clear ECSA IE\n");
	}
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}
#endif

/**
* @brief               Set random mac configure value (ON/OFF)
*
* @param priv          Pointer to moal_private structure
* @param respbuf       Pointer to response buffer
* @param resplen       Response buffer length

*  @return             Number of bytes written, negative for failure.
*/
static int woal_priv_config_random_mac(moal_private *priv, t_u8 *respbuf,
				       t_u32 respbuflen)
{
	int ret = 0;
	int header_len = 0, space_len = 0, i;
	t_u8 rand_data[3];
	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	header_len = strlen("FAKEMAC");
	if ((int)strlen(respbuf) >= header_len) {
		for (i = 0; i < (int)(strlen(respbuf) - header_len - 1); i++) {
			if (respbuf[header_len + 1 + i] != ' ')
				break;
		}
		space_len = i;

		if (strncmp(respbuf + header_len + 1 + space_len, "On",
			    strlen("On")) == 0) {
			if (memcmp(priv->random_mac, zero_mac,
				   MLAN_MAC_ADDR_LENGTH)) {
				ret = snprintf(respbuf, CMD_BUF_LEN,
					       "FAKEMAC has been On\n") +
				      1;
				goto done;
			}
			moal_memcpy_ext(priv->phandle, priv->random_mac,
					priv->current_addr, ETH_ALEN,
					MLAN_MAC_ADDR_LENGTH);
			get_random_bytes(rand_data, 3);
			moal_memcpy_ext(priv->phandle, priv->random_mac + 3,
					rand_data, 3, 3);
			PRINTM(MMSG, "FAKEMAC parameter is On\n");
		} else if (strncmp(respbuf + header_len + 1 + space_len, "Off",
				   strlen("Off")) == 0) {
			memset(priv->random_mac, 0, ETH_ALEN);
			PRINTM(MMSG, "FAKEMAC parameter is Off\n");
		} else {
			PRINTM(MERROR, "Invalid parameter!\n");
			ret = -EINVAL;
			goto done;
		}
	} else {
		PRINTM(MERROR, "Invalid parameter!\n");
		ret = -EINVAL;
		goto done;
	}

done:
	LEAVE();
	return ret;
}

/**
 * @brief               enable/disable roaming offload to firmware
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_roam_offload(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int user_data_len = 0, header_len = 0, ret = 0;
	int data = 0;
#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
	t_u8 enable = 0;
#endif
#endif

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
		ret = -EFAULT;
		goto done;
	}
#endif
#endif

	header_len = strlen("SETROAMOFFLOAD");
	parse_arguments(respbuf + header_len + 1, &data, 1, &user_data_len);

	if (data < 0 || data > 5) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	}

#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
	if (!data) {
		woal_cfg80211_vendor_event(priv, event_set_key_mgmt_offload,
					   &enable, sizeof(enable));
	}
#endif
#endif

	ret = woal_enable_fw_roaming(priv, data);
done:

	LEAVE();
	return ret;
}

/**
 * @brief               set roaming offload aplist to firmware
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_roam_offload_aplist(moal_private *priv, t_u8 *respbuf,
					     t_u32 respbuflen)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_ds_misc_roam_offload *roam = NULL;
	mlan_ds_misc_roam_offload_aplist *aplist = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0, i = 0;
	int user_data_len = 0, header_len = 0;
	int ap_count = 0;
	char *begin = NULL, *end = NULL;
	t_u8 mac_addr[6];

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
		ret = -EFAULT;
		goto done;
	}
#endif
#endif

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_ROAM_OFFLOAD_APLIST;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	roam = (mlan_ds_misc_roam_offload *)&misc->param.roam_offload;
	/*Set enable to invalid value(valid: 0, 1, 2)*/
	roam->enable = 3;
	aplist = &roam->aplist;

	header_len = strlen("SETROAMOFFLAPLIST");
	user_data_len = strlen(respbuf) - header_len;
	if (!user_data_len) {
		/* GET operation */
		ioctl_req->action = MLAN_ACT_GET;
	} else {
		begin = &respbuf[header_len + 1];
		end = begin;
		while (begin && *begin == ' ') {
			begin++;
			end++;
		}
		while (end && *end != ' ')
			end++;
		if (end != NULL)
			*end = '\0';
		end++;
		if (begin) {
			if (woal_atoi(&ap_count, begin) !=
			    MLAN_STATUS_SUCCESS) {
				ret = -EINVAL;
				goto done;
			}
		}
		aplist->ap_num = ap_count;
		if (ap_count > 0 && ap_count <= MAX_AP_LIST) {
			/* SET operation */
			ioctl_req->action = MLAN_ACT_SET;
			for (i = 0; i < ap_count; i++) {
				begin = end;
				while (begin && *begin == ' ') {
					begin++;
					end++;
				}
				while (end && *end != ' ' && *end != '\0')
					end++;
				if (end == begin) {
					PRINTM(MERROR,
					       "AP number %d is wrong\n",
					       ap_count);
					ret = -EINVAL;
					goto done;
				}
				if (end != NULL)
					*end = '\0';
				end++;
				woal_mac2u8(mac_addr, begin);
				moal_memcpy_ext(priv->phandle,
						aplist->ap_mac[i], mac_addr,
						MLAN_MAC_ADDR_LENGTH,
						MLAN_MAC_ADDR_LENGTH);
			}
		} else {
			PRINTM(MERROR,
			       "AP number is wrong.Support max 8 APs\n");
			ret = -EINVAL;
			goto done;
		}
	}

	DBG_HEXDUMP(MERROR, "APLIST", (t_u8 *)aplist->ap_mac,
		    aplist->ap_num * MLAN_MAC_ADDR_LENGTH);
	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}
/**
 * @brief               Configure roaming offload to firmware
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_roam_offload_cfg(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int ret = 0, user_data_len = 0, header_len = 0, data = 0;
	char *begin = NULL, *end = NULL, *pvariable_name = NULL;
	t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
	woal_roam_offload_cfg roam_offload_cfg;
	t_u8 len = 0;
	int count = 0, i = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
		ret = -EFAULT;
		goto done;
	}
#endif
#endif

	memset((char *)&roam_offload_cfg, 0, sizeof(roam_offload_cfg));
	header_len = strlen("CFGROAMOFFLOAD");
	user_data_len = strlen(respbuf) - header_len;
	if (!user_data_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}
	roam_offload_cfg.band_rssi.band_preferred = 0xff;
	roam_offload_cfg.trigger_condition = 0xff;
	end = &respbuf[header_len];
	while (((t_u8 *)end - &respbuf[header_len]) < user_data_len - 1) {
		end++;
		begin = end;
		while (begin && *begin == ' ') {
			begin++;
			end++;
		}
		while (end && *end != ' ' && *end != '\0' && *end != '=')
			end++;
		if (end == begin) {
			PRINTM(MERROR, "Invalid command specified!\n");
			ret = -EINVAL;
			goto done;
		}
		if (end)
			*end = '\0';
		pvariable_name = begin;

		if (((t_u8 *)end - &respbuf[header_len]) >= user_data_len) {
			PRINTM(MERROR, "Invalid command length!\n");
			ret = -EINVAL;
			goto done;
		}
		end++;
		begin = end;
		while (begin && (*begin == ' ' || *begin == '=')) {
			begin++;
			end++;
		}
		while (end && *end != ' ' && *end != '\0' && *end != '=')
			end++;
		if (end == begin) {
			PRINTM(MERROR, "Invalid command specified!\n");
			ret = -EINVAL;
			goto done;
		}
		if (end != NULL)
			*end = '\0';
		if (pvariable_name && begin) {
			if (strcmp(pvariable_name, "AUTO_RECONNECT") == 0) {
				(void)woal_atoi(&data, begin);
			} else if (strcmp(pvariable_name, "BSSID") == 0) {
				woal_mac2u8(mac_addr, begin);
				moal_memcpy_ext(priv->phandle,
						roam_offload_cfg.bssid,
						mac_addr, MLAN_MAC_ADDR_LENGTH,
						MLAN_MAC_ADDR_LENGTH);
			} else if (strcmp(pvariable_name, "BLACKLIST") == 0) {
				if (woal_atoi(&count, begin) !=
				    MLAN_STATUS_SUCCESS) {
					ret = -EINVAL;
					goto done;
				}
				if (count > 0 && count <= MAX_AP_LIST) {
					roam_offload_cfg.black_list.ap_num =
						count;
					for (i = 0; i < count; i++) {
						end++;
						begin = end;
						while (begin && *begin == ' ') {
							begin++;
							end++;
						}
						while (end && *end != ' ' &&
						       *end != '\0')
							end++;
						if (end == begin) {
							PRINTM(MERROR,
							       "BSSID %d is wrong\n",
							       count);
							ret = -EINVAL;
							goto done;
						}
						if (end != NULL)
							*end = '\0';
						woal_mac2u8(mac_addr, begin);
						moal_memcpy_ext(
							priv->phandle,
							roam_offload_cfg
								.black_list
								.ap_mac[i],
							mac_addr,
							MLAN_MAC_ADDR_LENGTH,
							MLAN_MAC_ADDR_LENGTH);
					}
				} else {
					PRINTM(MERROR,
					       "BSSID number is wrong.Support max %d BSSIDs\n",
					       MAX_AP_LIST);
					ret = -EINVAL;
					goto done;
				}
			} else if (strcmp(pvariable_name, "SSID") == 0) {
				if (woal_atoi(&count, begin) !=
				    MLAN_STATUS_SUCCESS) {
					ret = -EINVAL;
					goto done;
				}
				if (count > 0 && count <= MAX_SSID_NUM) {
					roam_offload_cfg.ssid_list.ssid_num =
						count;
					for (i = 0; i < count; i++) {
						end++;
						begin = end;
						while (begin && *begin == ' ') {
							begin++;
							end++;
						}
						while (end && *end != ' ' &&
						       *end != '\0') {
							end++;
							len++;
						}
						if ((end == begin) ||
						    len >= MLAN_MAX_SSID_LENGTH) {
							PRINTM(MERROR,
							       "SSID %d is wrong\n",
							       count);
							ret = -EINVAL;
							goto done;
						}
						if (end != NULL)
							*end = '\0';
						roam_offload_cfg.ssid_list
							.ssids[i]
							.ssid_len = len + 1;
						moal_memcpy_ext(
							priv->phandle,
							(t_u8 *)&roam_offload_cfg
								.ssid_list
								.ssids[i]
								.ssid,
							begin, len + 1,
							MLAN_MAX_SSID_LENGTH);
						len = 0;
					}
				} else {
					PRINTM(MERROR,
					       "SSID number is wrong.Support max %d SSIDs\n",
					       MAX_SSID_NUM);
					ret = -EINVAL;
					goto done;
				}
			} else if (strcmp(pvariable_name, "RETRY_COUNT") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.retry_count = (t_u8)data;
			} else if (strcmp(pvariable_name,
					  "TRIGGER_CONDITION") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.trigger_condition =
					(t_u16)data;
			} else if (strcmp(pvariable_name, "MAX_RSSI") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.max_rssi = (t_u8)data;
				roam_offload_cfg.rssi_param_set_flag = 1;
			} else if (strcmp(pvariable_name, "MIN_RSSI") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.min_rssi = (t_u8)data;
				roam_offload_cfg.rssi_param_set_flag = 1;
			} else if (strcmp(pvariable_name, "STEP_RSSI") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.step_rssi = (t_u8)data;
				roam_offload_cfg.rssi_param_set_flag = 1;
			} else if (strcmp(pvariable_name, "BAND_PREFER") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.band_rssi.band_preferred =
					(t_u8)data;
				roam_offload_cfg.band_rssi_flag = 1;
			} else if (strcmp(pvariable_name, "RSSI_HYSTERESIS") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.band_rssi.rssi_hysteresis =
					(t_u8)data;
				roam_offload_cfg.band_rssi_flag = 1;
			}

			else if (strcmp(pvariable_name, "BSSTYPE") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.bgscan_cfg.bss_type =
					(t_u8)data;
				roam_offload_cfg.bgscan_set_flag++;
			} else if (strcmp(pvariable_name, "CHANSPERSCAN") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.bgscan_cfg.channels_per_scan =
					(t_u8)data;
				roam_offload_cfg.bgscan_set_flag++;
			} else if (strcmp(pvariable_name, "BGRPTCONDITION") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.bgscan_cfg.bg_rpt_condition =
					(t_u32)data;
				roam_offload_cfg.bgscan_set_flag++;
			} else if (strcmp(pvariable_name, "SCANINTERVAL") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.bgscan_cfg.scan_interval =
					(t_u32)data;
				roam_offload_cfg.bgscan_set_flag++;
			}

			else if (strcmp(pvariable_name, "EESMODE") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.ees_mode = (t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "EESRPTCONDITION") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.ees_rpt_condition =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "HIGHSCANPERIOD") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.high_scan_period =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "HIGHSCANCOUNT") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.high_scan_count =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "MIDSCANPERIOD") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.mid_scan_period =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "MIDSCANCOUNT") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.mid_scan_count =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "LOWSCANPERIOD") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.low_scan_period =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			} else if (strcmp(pvariable_name, "LOWSCANCOUNT") ==
				   0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.ees_cfg.low_scan_count =
					(t_u16)data;
				roam_offload_cfg.ees_param_set_flag++;
			}

			else if (strcmp(pvariable_name, "BCNMISSTHRESHOLD") ==
				 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.bcn_miss_threshold =
					(t_u8)data;
			}

			else if (strcmp(pvariable_name,
					"PREBCNMISSTHRESHOLD") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.pre_bcn_miss_threshold =
					(t_u8)data;
			} else if (strcmp(pvariable_name, "REPEATCOUNT") == 0) {
				(void)woal_atoi(&data, begin);
				roam_offload_cfg.repeat_count = (t_u16)data;
			} else {
				PRINTM(MERROR, "Un-support parameter: %s\n",
				       pvariable_name);
				ret = -EINVAL;
				goto done;
			}
		}
	}
	if (priv->phandle->fw_roam_enable == AUTO_RECONNECT) {
		moal_memcpy_ext(priv->phandle,
				priv->phandle->auto_reconnect_bssid,
				roam_offload_cfg.bssid, MLAN_MAC_ADDR_LENGTH,
				sizeof(mlan_802_11_mac_addr));
		moal_memcpy_ext(priv->phandle,
				&priv->phandle->auto_reconnect_ssid,
				&roam_offload_cfg.ssid_list.ssids[0],
				sizeof(mlan_802_11_ssid),
				sizeof(mlan_802_11_ssid));
		priv->phandle->auto_reconnect_retry_count = (t_u8)data;
	} else {
		if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS))
			moal_memcpy_ext(priv->phandle,
					(void *)&priv->phandle->fw_roam_params,
					(void *)&roam_offload_cfg,
					sizeof(roam_offload_cfg),
					sizeof(priv->phandle->fw_roam_params));
		else {
			if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_PARAM_CFG,
						   &roam_offload_cfg)) {
				PRINTM(MERROR,
				       "%s: config fw roaming failed \n",
				       __func__);
				ret = -EFAULT;
			}
		}
	}
done:
	LEAVE();
	return ret;
}

/**
 * @brief               Configure roaming SSID passphrase
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_roam_passphrase(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_sec_cfg *sec = NULL;
	int ret = 0, action = -1;
	int user_data_len = 0, header_len = 0;
	char *begin, *end, *opt, *item;
	mlan_status status = MLAN_STATUS_SUCCESS;
	woal_roam_offload_cfg roam_offload_cfg;
	mlan_ds_passphrase *ssid_passphrase = NULL;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
		ret = -EFAULT;
		goto done;
	}
#endif
#endif

	memset((char *)&roam_offload_cfg, 0, sizeof(roam_offload_cfg));
	header_len = strlen("SETROAMPASSPHRASE");
	user_data_len = strlen(respbuf) - header_len;
	if (!user_data_len) {
		PRINTM(MERROR, "Invalid number of parameters\n");
		ret = -EINVAL;
		goto done;
	}

	/* Parse the buf to get the cmd_action */
	begin = respbuf + header_len;
	while (begin && *begin == ' ')
		begin++;
	end = woal_strsep(&begin, ';', '/');
	if (end)
		action = woal_atox(end);
	PRINTM(MMSG, "action= %d\n", action);
	if (action != 1 || end[1] != '\0') {
		PRINTM(MERROR, "Invalid action argument %s\n", end);
		ret = -EINVAL;
		goto done;
	}

	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	req->req_id = MLAN_IOCTL_SEC_CFG;
	sec = (mlan_ds_sec_cfg *)req->pbuf;
	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
	sec->multi_passphrase = 1;
	req->action = MLAN_ACT_SET;

	/*Parse the buffer like "ssid=xxx passphrase=xxxx;ssid=xxx
	 * passphrase=xxx"*/
	while (begin) {
		while (begin && *begin == ' ')
			begin++;
		end = woal_strsep(&begin, ';', '/');
		item = woal_strsep(&end, ' ', '/');
		opt = woal_strsep(&item, '=', '/');
		while (opt) {
			if (roam_offload_cfg.userset_passphrase >=
			    MAX_SEC_SSID_NUM - 1) {
				PRINTM(MERROR,
				       "Support max %d security SSIDs!\n",
				       MAX_SEC_SSID_NUM);
				break;
			}
			ssid_passphrase =
				&sec->param.roam_passphrase
					 [roam_offload_cfg.userset_passphrase];
			if (!opt || !item || !end) {
				PRINTM(MERROR, "Invalid option\n");
				ret = -EINVAL;
				goto done;
			} else if (!strnicmp(opt, "ssid", strlen(opt))) {
				if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
					PRINTM(MERROR,
					       "SSID length exceeds max length\n");
					ret = -EFAULT;
					goto done;
				}
				ssid_passphrase->ssid.ssid_len = strlen(item);
				strncpy((char *)ssid_passphrase->ssid.ssid,
					item,
					MIN(strlen(item),
					    MLAN_MAX_SSID_LENGTH));
				PRINTM(MINFO, "ssid=%s, len=%d\n",
				       ssid_passphrase->ssid.ssid,
				       (int)ssid_passphrase->ssid.ssid_len);
			} else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
				   req->action == MLAN_ACT_SET) {
				if (strlen(item) < MLAN_MIN_PASSPHRASE_LENGTH ||
				    strlen(item) > MLAN_MAX_PASSPHRASE_LENGTH) {
					PRINTM(MERROR,
					       "Invalid length for passphrase\n");
					ret = -EINVAL;
					goto done;
				}
				ssid_passphrase->psk_type = MLAN_PSK_PASSPHRASE;
				moal_memcpy_ext(priv->phandle,
						ssid_passphrase->psk.passphrase
							.passphrase,
						item, strlen(item),
						MLAN_MAX_PASSPHRASE_LENGTH);
				ssid_passphrase->psk.passphrase.passphrase_len =
					strlen(item);
				PRINTM(MINFO, "passphrase=%s, len=%d\n",
				       ssid_passphrase->psk.passphrase
					       .passphrase,
				       (int)ssid_passphrase->psk.passphrase
					       .passphrase_len);
			} else {
				PRINTM(MERROR, "Invalid option %s\n", opt);
				ret = -EINVAL;
				goto done;
			}
			if (!end || *end == '\0')
				break;
			while (end && *end == ' ')
				end++;
			item = woal_strsep(&end, ' ', '/');
			opt = woal_strsep(&item, '=', '/');
		}
		roam_offload_cfg.userset_passphrase++;
	}

	if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS)) {
		moal_memcpy_ext(priv->phandle,
				(char *)priv->phandle->ssid_passphrase,
				(char *)sec->param.roam_passphrase,
				MAX_SEC_SSID_NUM * sizeof(mlan_ds_passphrase),
				MAX_SEC_SSID_NUM * sizeof(mlan_ds_passphrase));
		priv->phandle->fw_roam_params.userset_passphrase =
			roam_offload_cfg.userset_passphrase;
		goto done;
	}

	if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_ENABLE,
				   &roam_offload_cfg)) {
		PRINTM(MERROR, "%s: config fw roaming failed \n", __func__);
		ret = -EFAULT;
		goto done;
	}
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 * @brief               Download start keep alive parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param mkeep_alive_id       keep alive ID number
 * @param ip_pke        IP packet from host
 * @param ip_pke_len    IP packet length from host
 * @param src_mac       Source MAC address
 * @param dst_mac       Destination MAC address
 * @param period_msec   Send keep alive packet interval

 * @return      0: success  fail otherwise
 */
int woal_start_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id,
			   t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac,
			   t_u8 *dst_mac, t_u32 period_msec,
			   t_u32 retry_interval, t_u8 retry_cnt)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	}

	/* SET operation */
	ioctl_req->action = MLAN_ACT_SET;
	misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
	misc->param.keep_alive.enable = true;
	misc->param.keep_alive.send_interval = period_msec;
	misc->param.keep_alive.retry_interval = retry_interval;
	misc->param.keep_alive.retry_count = retry_cnt;
	moal_memcpy_ext(priv->phandle, misc->param.keep_alive.dst_mac, dst_mac,
			MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
	moal_memcpy_ext(priv->phandle, misc->param.keep_alive.src_mac, src_mac,
			MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
	misc->param.keep_alive.pkt_len =
		MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
	moal_memcpy_ext(priv->phandle, misc->param.keep_alive.packet, ip_pkt,
			ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Download stop keep alive parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param mkeep_alive_id       keep alive ID number
 * @param ip_pkt        Last packet
 * @param ip_pkt_len    Last packet length

 * @return      0: success  fail otherwise
 */
int woal_stop_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, t_u8 reset,
			  t_u8 *ip_pkt, t_u8 *pkt_len)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_misc_keep_alive *misc_keep_alive = NULL;
	int ret = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
	misc_keep_alive = &misc->param.keep_alive;

	if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	}

	/* GET operation */
	ioctl_req->action = MLAN_ACT_GET;
	misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
	misc_keep_alive->enable = false;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!misc_keep_alive->enable) {
		PRINTM(MERROR, "ID %d is already stop\n", mkeep_alive_id);
		goto done;
	}

	if (reset)
		ioctl_req->action = MLAN_ACT_RESET;
	else
		/* SET operation */
		ioctl_req->action = MLAN_ACT_SET;
	misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
	misc_keep_alive->enable = false;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
	if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
		ret = woal_mkeep_alive_vendor_event(priv,
						    &misc->param.keep_alive);
		if (ret)
			PRINTM(MERROR,
			       "Keep alive vendor event upload failed\n");
	}
#endif
#endif
	if (pkt_len) {
		*pkt_len = MIN(misc_keep_alive->pkt_len,
			       (MKEEP_ALIVE_IP_PKT_MAX - 1));
		PRINTM(MINFO, "keep alive stop pkt_len is %d\n", *pkt_len);
	}
	if (*pkt_len && ip_pkt)
		moal_memcpy_ext(priv->phandle, ip_pkt, misc_keep_alive->packet,
				*pkt_len, *pkt_len);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Save cloud keep alive params in driver handle
 *
 * @param priv          Pointer to moal_private structure
 * @params              Other params for keep alive

 *  @return             Number of bytes written, negative for failure.
 */
int woal_priv_save_cloud_keep_alive_params(moal_private *priv,
					   t_u8 mkeep_alive_id, t_u8 enable,
					   t_u16 ether_type, t_u8 *ip_pkt,
					   t_u16 ip_pkt_len, t_u8 *src_mac,
					   t_u8 *dst_mac, t_u32 period_msec,
					   t_u32 retry_interval, t_u8 retry_cnt)

{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	mlan_ds_misc_keep_alive *keep_alive = NULL;
	moal_handle *phandle = NULL;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}
	phandle = priv->phandle;

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}

	/* GET operation */
	ioctl_req->action = MLAN_ACT_GET;
	misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
	misc->param.keep_alive.enable = true;

	ret = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (ret != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (misc->param.keep_alive.enable) {
		PRINTM(MERROR, "ID %d is in use\n", mkeep_alive_id);
		ret = -EINVAL;
		goto done;
	}

	keep_alive = &phandle->keep_alive[mkeep_alive_id];
	keep_alive->mkeep_alive_id = mkeep_alive_id;
	keep_alive->enable = enable;
	if (enable) {
		keep_alive->cached = true;
		keep_alive->send_interval = period_msec;
		keep_alive->retry_interval = retry_interval;
		keep_alive->retry_count = retry_cnt;
		moal_memcpy_ext(phandle, keep_alive->dst_mac, dst_mac,
				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
		moal_memcpy_ext(phandle, keep_alive->src_mac, src_mac,
				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
		keep_alive->pkt_len = MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
		moal_memcpy_ext(phandle, keep_alive->packet, ip_pkt, ip_pkt_len,
				MKEEP_ALIVE_IP_PKT_MAX);
		if (ether_type)
			keep_alive->ether_type = ether_type;
		else
			keep_alive->ether_type = 0;
	}

done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Cloud keep alive feature
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cloud_keep_alive(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	int ret = 0;
	cloud_keep_alive *keep_alive = NULL;
	int header_len = 0;

	ENTER();

	header_len = strlen(PRIV_CMD_CLOUD_KEEP_ALIVE);

	keep_alive = (cloud_keep_alive *)(respbuf + header_len);

	if (keep_alive->enable) {
		ret = woal_priv_save_cloud_keep_alive_params(
			priv, keep_alive->mkeep_alive_id, keep_alive->enable, 0,
			keep_alive->pkt, keep_alive->pkt_len,
			keep_alive->src_mac, keep_alive->dst_mac,
			keep_alive->sendInterval, keep_alive->retryInterval,
			keep_alive->retryCount);
	} else {
		if (0 != woal_stop_mkeep_alive(priv, keep_alive->mkeep_alive_id,
					       keep_alive->reset,
					       keep_alive->pkt,
					       &keep_alive->pkt_len)) {
			ret = -EFAULT;
			return ret;
		}
		ret = respbuflen;
	}

	LEAVE();
	return ret;
}

/**
 * @brief               Download start keep alive rx parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param mkeep_alive_id       keep alive ID number
 * @param ip_pke        IP packet from host
 * @param ip_pke_len    IP packet length from host
 * @param src_mac       Source MAC address
 * @param dst_mac       Destination MAC address

 * @return      0: success  fail otherwise
 */
int woal_start_mkeep_alive_rx(moal_private *priv, t_u8 mkeep_alive_id,
			      t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac,
			      t_u8 *dst_mac)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	int ret = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE_RX;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	if (mkeep_alive_id >= MAX_KEEP_ALIVE_RX_ID) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	}

	/* SET operation */
	ioctl_req->action = MLAN_ACT_SET;
	misc->param.keep_alive_rx.mkeep_alive_id = mkeep_alive_id;
	misc->param.keep_alive_rx.enable = true;
	moal_memcpy_ext(priv->phandle, misc->param.keep_alive_rx.dst_mac,
			dst_mac, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
	moal_memcpy_ext(priv->phandle, misc->param.keep_alive_rx.src_mac,
			src_mac, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
	misc->param.keep_alive_rx.pkt_len =
		MIN(ip_pkt_len, MKEEP_ALIVE_ACK_PKT_MAX);
	moal_memcpy_ext(priv->phandle, misc->param.keep_alive_rx.packet, ip_pkt,
			ip_pkt_len, MKEEP_ALIVE_ACK_PKT_MAX);

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Download stop keep alive rx parameters
 *
 * @param priv          Pointer to moal_private structure
 * @param mkeep_alive_id       keep alive ID number
 * @param ip_pkt        Last packet
 * @param ip_pkt_len    Last packet length

 * @return      0: success  fail otherwise
 */
int woal_stop_mkeep_alive_rx(moal_private *priv, t_u8 mkeep_alive_id,
			     t_u8 reset, t_u8 *ip_pkt, t_u8 *pkt_len)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	mlan_status status = MLAN_STATUS_SUCCESS;
	mlan_ds_misc_keep_alive_rx *misc_keep_alive_rx = NULL;
	int ret = 0;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE_RX;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
	misc_keep_alive_rx = &misc->param.keep_alive_rx;

	if (mkeep_alive_id >= MAX_KEEP_ALIVE_RX_ID) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EFAULT;
		goto done;
	}

	/* GET operation */
	ioctl_req->action = MLAN_ACT_GET;
	misc_keep_alive_rx->mkeep_alive_id = mkeep_alive_id;
	misc_keep_alive_rx->enable = false;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (!misc_keep_alive_rx->enable) {
		PRINTM(MERROR, "ID %d is already stop\n", mkeep_alive_id);
		goto done;
	}

	if (reset)
		ioctl_req->action = MLAN_ACT_RESET;
	else
		/* SET operation */
		ioctl_req->action = MLAN_ACT_SET;
	misc_keep_alive_rx->mkeep_alive_id = mkeep_alive_id;
	misc_keep_alive_rx->enable = false;

	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	if (pkt_len) {
		*pkt_len = MIN(misc_keep_alive_rx->pkt_len,
			       (MKEEP_ALIVE_ACK_PKT_MAX - 1));
		PRINTM(MINFO, "keep alive rx stop pkt_len is %d\n", *pkt_len);
	}
	if (*pkt_len && ip_pkt)
		moal_memcpy_ext(priv->phandle, ip_pkt,
				misc_keep_alive_rx->packet, *pkt_len, *pkt_len);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Save cloud keep alive params in driver handle
 *
 * @param priv          Pointer to moal_private structure
 * @params              Other params for keep alive

 *  @return             Number of bytes written, negative for failure.
 */
int woal_priv_save_cloud_keep_alive_params_rx(moal_private *priv,
					      t_u8 mkeep_alive_id, t_u8 enable,
					      t_u16 ether_type, t_u8 *ip_pkt,
					      t_u16 ip_pkt_len, t_u8 *src_mac,
					      t_u8 *dst_mac)
{
	mlan_ioctl_req *ioctl_req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	mlan_ds_misc_keep_alive_rx *keep_alive_rx = NULL;
	moal_handle *phandle = NULL;

	ENTER();

	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is null\n");
		ret = -EFAULT;
		goto done;
	}
	phandle = priv->phandle;

	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (ioctl_req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE_RX;
	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

	if (mkeep_alive_id >= MAX_KEEP_ALIVE_RX_ID) {
		PRINTM(MERROR, "Invalid parameters\n");
		ret = -EINVAL;
		goto done;
	}

	/* GET operation */
	ioctl_req->action = MLAN_ACT_GET;
	misc->param.keep_alive_rx.mkeep_alive_id = mkeep_alive_id;
	misc->param.keep_alive_rx.enable = true;

	ret = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
	if (ret != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (misc->param.keep_alive_rx.enable) {
		PRINTM(MERROR, "ID %d is in use\n", mkeep_alive_id);
		ret = -EINVAL;
		goto done;
	}

	keep_alive_rx = &phandle->keep_alive_rx[mkeep_alive_id];
	keep_alive_rx->mkeep_alive_id = mkeep_alive_id;
	keep_alive_rx->enable = enable;
	if (enable) {
		keep_alive_rx->cached = true;
		moal_memcpy_ext(phandle, keep_alive_rx->dst_mac, dst_mac,
				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
		moal_memcpy_ext(phandle, keep_alive_rx->src_mac, src_mac,
				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
		keep_alive_rx->pkt_len =
			MIN(ip_pkt_len, MKEEP_ALIVE_ACK_PKT_MAX);
		moal_memcpy_ext(phandle, keep_alive_rx->packet, ip_pkt,
				ip_pkt_len, MKEEP_ALIVE_ACK_PKT_MAX);
		if (ether_type)
			keep_alive_rx->ether_type = ether_type;
		else
			keep_alive_rx->ether_type = 0;
	}

done:
	if (ret != MLAN_STATUS_PENDING)
		kfree(ioctl_req);

	LEAVE();
	return ret;
}

/**
 * @brief               Cloud keep alive rx feature
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cloud_keep_alive_rx(moal_private *priv, t_u8 *respbuf,
					 t_u32 respbuflen)
{
	int ret = 0;
	cloud_keep_alive_rx *keep_alive_rx = NULL;
	int header_len = 0;

	ENTER();

	header_len = strlen(PRIV_CMD_CLOUD_KEEP_ALIVE_RX);

	keep_alive_rx = (cloud_keep_alive_rx *)(respbuf + header_len);

	if (keep_alive_rx->enable) {
		ret = woal_priv_save_cloud_keep_alive_params_rx(
			priv, keep_alive_rx->mkeep_alive_id,
			keep_alive_rx->enable, 0, keep_alive_rx->pkt,
			keep_alive_rx->pkt_len, keep_alive_rx->src_mac,
			keep_alive_rx->dst_mac);
	} else {
		if (0 != woal_stop_mkeep_alive_rx(
				 priv, keep_alive_rx->mkeep_alive_id,
				 keep_alive_rx->reset, keep_alive_rx->pkt,
				 &keep_alive_rx->pkt_len)) {
			ret = -EFAULT;
			return ret;
		}
		ret = respbuflen;
	}

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get static rx abort config
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_rx_abort_cfg(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[2] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 2 ||
		    (data[0] == MTRUE && user_data_len != 2)) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == MTRUE && data[1] > 0x7f) {
			PRINTM(MERROR, "Invalid threshold value\n");
			ret = -EINVAL;
			goto done;
		}
		misc->param.rx_abort_cfg.enable = (t_u8)data[0];
		if (user_data_len == 2)
			misc->param.rx_abort_cfg.rssi_threshold = (t_s8)data[1];
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.rx_abort_cfg.enable;
	data[1] = misc->param.rx_abort_cfg.rssi_threshold;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}
/**
 *  @brief Set/Get static OFDM DESENSE CFG
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_ofdm_desense_cfg(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[2] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_OFDM_DESENSE_CFG);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_OFDM_DESENSE_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 2 ||
		    (data[0] == MTRUE && user_data_len != 2)) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == MTRUE && data[1] > 0x7f) {
			PRINTM(MERROR, "Invalid threshold value\n");
			ret = -EINVAL;
			goto done;
		}
		misc->param.ofdm_desense_cfg.enable = (t_u8)data[0];
		if (user_data_len == 2)
			misc->param.ofdm_desense_cfg.cca_threshold =
				(t_s8)data[1];
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.ofdm_desense_cfg.enable;
	data[1] = misc->param.ofdm_desense_cfg.cca_threshold;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get dynamic rx abort config
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_rx_abort_cfg_ext(moal_private *priv, t_u8 *respbuf,
				      t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[7] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG_EXT);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG_EXT;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 4 ||
		    ((data[0] == MTRUE && user_data_len != 3) &&
		     (data[0] == MTRUE && user_data_len != 4))) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == MTRUE) {
			if (data[1] > 0x7f) {
				PRINTM(MERROR, "Invalid margin value\n");
				ret = -EINVAL;
				goto done;
			}
			if (data[2] > 0x7f && data[2] != 0xff) {
				PRINTM(MERROR,
				       "Invalid ceil threshold value\n");
				ret = -EINVAL;
				goto done;
			}
			if (data[3] > 0x7f) {
				PRINTM(MERROR,
				       "Invalid floor threshold value\n");
				ret = -EINVAL;
				goto done;
			}
		}
		misc->param.rx_abort_cfg_ext.enable = (t_u8)data[0];
		if (user_data_len > 1) {
			misc->param.rx_abort_cfg_ext.rssi_margin =
				(t_s8)data[1];
			misc->param.rx_abort_cfg_ext.ceil_rssi_threshold =
				(t_s8)data[2];
			/** not to update floor_rssi_threshold if not included
			 * in coammnd */
			if (user_data_len == 3)
				misc->param.rx_abort_cfg_ext
					.floor_rssi_threshold = 0xff;
			else
				misc->param.rx_abort_cfg_ext
					.floor_rssi_threshold = (t_s8)data[3];

			misc->param.rx_abort_cfg_ext
				.current_dynamic_rssi_threshold = 0;
			misc->param.rx_abort_cfg_ext.rssi_default_config = 0;
			misc->param.rx_abort_cfg_ext.edmac_enable = 0;
		}
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.rx_abort_cfg_ext.enable;
	data[1] = misc->param.rx_abort_cfg_ext.rssi_margin;
	data[2] = misc->param.rx_abort_cfg_ext.ceil_rssi_threshold;
	data[3] = misc->param.rx_abort_cfg_ext.floor_rssi_threshold;
	data[4] = misc->param.rx_abort_cfg_ext.current_dynamic_rssi_threshold;
	data[5] = misc->param.rx_abort_cfg_ext.rssi_default_config;
	data[6] = misc->param.rx_abort_cfg_ext.edmac_enable;

	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get NAV mitigation config parameters
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_nav_mitigation(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[4] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_NAV_MITIGATION);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_NAV_MITIGATION;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 2 ||
		    (user_data_len == 1 && data[0] != MFALSE)) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}

		misc->param.nav_mitigation.start_nav_mitigation = data[0];
		if (data[0] == MTRUE)
			misc->param.nav_mitigation.threshold = data[1];
		else
			misc->param.nav_mitigation.threshold = 0;

		// Not used for MLAN_ACT_SET, Set to 0
		misc->param.nav_mitigation.detect_cnt = 0;
		misc->param.nav_mitigation.stop_cnt = 0;
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	if (req->action == MLAN_ACT_GET) {
		data[0] = misc->param.nav_mitigation.start_nav_mitigation;
		data[1] = misc->param.nav_mitigation.threshold;
		data[2] = misc->param.nav_mitigation.detect_cnt;
		data[3] = misc->param.nav_mitigation.stop_cnt;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
	}
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Enable/Disable Un-associated Dot11mc FTM Frame exchanges
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_dot11mc_unassoc_ftm_cfg(moal_private *priv, t_u8 *respbuf,
					     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[1] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 1) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
			PRINTM(MERROR, "Invalid state for unassoc ftm\n");
			ret = -EINVAL;
			goto done;
		}
		misc->param.dot11mc_unassoc_ftm_cfg.state = (t_u16)data[0];
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.dot11mc_unassoc_ftm_cfg.state;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get Tx  AMPDU protection mode
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_tx_ampdu_prot_mode(moal_private *priv, t_u8 *respbuf,
					t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[1] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AMPDU_PROT_MODE);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_TX_AMPDU_PROT_MODE;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 1) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] > TX_AMPDU_DYNAMIC_RTS_CTS) {
			PRINTM(MERROR, "Invalid protection mode\n");
			ret = -EINVAL;
			goto done;
		}
		misc->param.tx_ampdu_prot_mode.mode = (t_u16)data[0];
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.tx_ampdu_prot_mode.mode;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get Tx rate adapt config
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_rate_adapt_cfg(moal_private *priv, t_u8 *respbuf,
				    t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[4] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RATE_ADAPT_CFG);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_RATE_ADAPT_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len < 1) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] > RATEADAPT_ALGO_SR) {
			PRINTM(MERROR, "Invalid Rateadapt Algorithm\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
			if ((data[1] & data[2]) == 0xff) {
				/* dynamic CCA noise based rate adapation enable
				 * request nothing to do here
				 */
			} else if (data[1] > 100 || data[2] > 100) {
				PRINTM(MERROR,
				       "Invalid success rate threshold value\n");
				ret = -EINVAL;
				goto done;
			}
			if (data[3] < 10 || data[3] > 0xffff) {
				PRINTM(MERROR, "Invalid interval value\n");
				ret = -EINVAL;
				goto done;
			}
		}
		misc->param.rate_adapt_cfg.sr_rateadapt = (t_u8)data[0];
		if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
			misc->param.rate_adapt_cfg.ra_low_thresh =
				(t_u8)data[1];
			misc->param.rate_adapt_cfg.ra_high_thresh =
				(t_u8)data[2];
			misc->param.rate_adapt_cfg.ra_interval = (t_u16)data[3];
		}
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}
	data[0] = misc->param.rate_adapt_cfg.sr_rateadapt;
	data[1] = misc->param.rate_adapt_cfg.ra_low_thresh;
	data[2] = misc->param.rate_adapt_cfg.ra_high_thresh;
	data[3] = misc->param.rate_adapt_cfg.ra_interval;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get global cck desense config
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_cck_desense_cfg(moal_private *priv, t_u8 *respbuf,
				     t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[5] = {0};
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CCK_DESENSE_CFG);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_CCK_DESENSE_CFG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len > 5) {
			PRINTM(MERROR, "Invalid number of args!\n");
			ret = -EINVAL;
			goto done;
		}
		if (data[0] > CCK_DESENSE_MODE_DYN_ENH) {
			PRINTM(MERROR, "Invalid cck desense mode\n");
			ret = -EINVAL;
			goto done;
		}
		if ((data[0] == CCK_DESENSE_MODE_DISABLED &&
		     user_data_len > 1) ||
		    (data[0] == CCK_DESENSE_MODE_DYNAMIC &&
		     user_data_len != 3) ||
		    (data[0] == CCK_DESENSE_MODE_DYN_ENH &&
		     (user_data_len < 3 || user_data_len == 4))) {
			PRINTM(MERROR,
			       "Invalid number of args for requested mode\n");
			ret = -EINVAL;
			goto done;
		}
		if (user_data_len > 1) {
			if (data[1] > 0x7f) {
				PRINTM(MERROR, "Invalid margin value\n");
				ret = -EINVAL;
				goto done;
			}
			if (data[2] > 0x7f) {
				PRINTM(MERROR,
				       "Invalid ceil threshold value\n");
				ret = -EINVAL;
				goto done;
			}
		}
		if (user_data_len > 3) {
			if (data[3] > 0xff || data[4] > 0xff) {
				PRINTM(MERROR,
				       "Invalid ON/OFF intervals value\n");
				ret = -EINVAL;
				goto done;
			}
		}
		misc->param.cck_desense_cfg.mode = (t_u8)data[0];
		if (user_data_len > 1) {
			misc->param.cck_desense_cfg.margin = (t_s8)data[1];
			misc->param.cck_desense_cfg.ceil_thresh = (t_s8)data[2];
		}
		if (data[0] == CCK_DESENSE_MODE_DYN_ENH) {
			if (user_data_len > 3) {
				misc->param.cck_desense_cfg.num_on_intervals =
					(t_u8)data[3];
				misc->param.cck_desense_cfg.num_off_intervals =
					(t_u8)data[4];
			} else {
				/* set these to 0xff. This will indicate the FW
				 * to use previously set values.
				 */
				misc->param.cck_desense_cfg.num_on_intervals =
					0xff;
				misc->param.cck_desense_cfg.num_off_intervals =
					0xff;
			}
		}
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.cck_desense_cfg.mode;
	data[1] = misc->param.cck_desense_cfg.margin;
	data[2] = misc->param.cck_desense_cfg.ceil_thresh;
	data[3] = misc->param.cck_desense_cfg.num_on_intervals;
	data[4] = misc->param.cck_desense_cfg.num_off_intervals;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 * @brief               set/get low power mode
 *
 * @param priv          Pointer to moal_private structure
 * @param respbuf       Pointer to response buffer
 * @param resplen       Response buffer length

 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_get_lpm(moal_private *priv, t_u8 *respbuf,
				 t_u32 respbuflen)
{
	int ret = 0;
	mlan_ioctl_req *req = NULL;
	mlan_ds_power_cfg *cfg = NULL;
	int data = 0;
	int user_data_len = 0, header_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (IS_CARD9098(priv->phandle->card_type) ||
	    IS_CARD9097(priv->phandle->card_type)) {
		header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_LPM);
		if ((int)strlen(respbuf) == header_len) {
			/* GET operation */
			user_data_len = 0;
		} else {
			/* SET operation */
			parse_arguments(respbuf + header_len, &data, 1,
					&user_data_len);
		}
		if (user_data_len >= 2) {
			PRINTM(MERROR, "Too many arguments\n");
			ret = -EINVAL;
			goto done;
		} else {
			req = woal_alloc_mlan_ioctl_req(
				sizeof(mlan_ds_power_cfg));
			if (req == NULL) {
				ret = -ENOMEM;
				goto done;
			}

			cfg = (mlan_ds_power_cfg *)req->pbuf;
			if (user_data_len == 0) {
				req->action = MLAN_ACT_GET;
			} else {
				cfg->param.lpm = data;
				req->action = MLAN_ACT_SET;
			}
		}
		cfg->sub_command = MLAN_OID_POWER_LOW_POWER_MODE;
		req->req_id = MLAN_IOCTL_POWER_CFG;

		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}

		data = cfg->param.lpm;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
				sizeof(data), respbuflen);
		ret = sizeof(data);
	} else
		PRINTM(MERROR, "Low power mode command is not supported!\n");

done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

/**
 *  @brief Set/Get HW ARB config
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_arbcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	int ret = 0;
	int data[1];
	int header_len = 0, user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ARB_CFG);
	user_data_len = strlen(respbuf) - header_len;

	/* Allocate an IOCTL request buffer */
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL) {
		ret = -ENOMEM;
		goto done;
	}
	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_ARB_CONFIG;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	if ((int)strlen(respbuf) == header_len) {
		/* GET operation */
		user_data_len = 0;
		req->action = MLAN_ACT_GET;
	} else {
		/* SET operation */
		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
				&user_data_len);
		if (user_data_len != 1) {
			PRINTM(MERROR, "Invalid Parameter\n");
			ret = -EFAULT;
			goto done;
		}
		if (data[0] < 0 || data[0] > 4) {
			PRINTM(MERROR, "Invalid Parameter: arb mode 0-4\n");
			ret = -EFAULT;
			goto done;
		}
		misc->param.arb_cfg.arb_mode = (t_u32)data[0];
		req->action = MLAN_ACT_SET;
	}
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_SUCCESS) {
		ret = -EFAULT;
		goto done;
	}

	data[0] = misc->param.arb_cfg.arb_mode;
	moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
			respbuflen);
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);

	LEAVE();
	return ret;
}

/**
 *  @brief      Timer function for TP state command.
 *
 *  @param data pointer to a buffer
 *
 *  @return     N/A
 */
void woal_tp_acnt_timer_func(void *context)
{
	moal_handle *phandle = (moal_handle *)context;
	int i = 0;

	if (phandle == NULL)
		return;
	PRINTM(MDATA, "####### CPU%d: tp acnt timer\n", smp_processor_id());
	/* Tx TP accounting */
	for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
		phandle->tp_acnt.tx_bytes_rate[i] =
			phandle->tp_acnt.tx_bytes[i] -
			phandle->tp_acnt.tx_bytes_last[i];
		phandle->tp_acnt.tx_bytes_last[i] =
			phandle->tp_acnt.tx_bytes[i];
		phandle->tp_acnt.tx_packets_rate[i] =
			phandle->tp_acnt.tx_packets[i] -
			phandle->tp_acnt.tx_packets_last[i];
		phandle->tp_acnt.tx_packets_last[i] =
			phandle->tp_acnt.tx_packets[i];
	}
	phandle->tp_acnt.tx_pending = atomic_read(&phandle->tx_pending);
	/* Tx Interrupt accounting */
	phandle->tp_acnt.tx_intr_rate =
		phandle->tp_acnt.tx_intr_cnt - phandle->tp_acnt.tx_intr_last;
	phandle->tp_acnt.tx_intr_last = phandle->tp_acnt.tx_intr_cnt;

	/* Rx TP accounting */
	for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
		phandle->tp_acnt.rx_bytes_rate[i] =
			phandle->tp_acnt.rx_bytes[i] -
			phandle->tp_acnt.rx_bytes_last[i];
		phandle->tp_acnt.rx_bytes_last[i] =
			phandle->tp_acnt.rx_bytes[i];
		phandle->tp_acnt.rx_packets_rate[i] =
			phandle->tp_acnt.rx_packets[i] -
			phandle->tp_acnt.rx_packets_last[i];
		phandle->tp_acnt.rx_packets_last[i] =
			phandle->tp_acnt.rx_packets[i];
	}
	phandle->tp_acnt.rx_pending = atomic_read(&phandle->rx_pending);
	// Interrupt accounting, RX
	phandle->tp_acnt.rx_intr_rate =
		phandle->tp_acnt.rx_intr_cnt - phandle->tp_acnt.rx_intr_last;
	phandle->tp_acnt.rx_intr_last = phandle->tp_acnt.rx_intr_cnt;
	phandle->tp_acnt.rx_amsdu_cnt_rate = phandle->tp_acnt.rx_amsdu_cnt -
					     phandle->tp_acnt.rx_amsdu_cnt_last;
	phandle->tp_acnt.rx_amsdu_cnt_last = phandle->tp_acnt.rx_amsdu_cnt;

	phandle->tp_acnt.rx_amsdu_pkt_cnt_rate =
		phandle->tp_acnt.rx_amsdu_pkt_cnt -
		phandle->tp_acnt.rx_amsdu_pkt_cnt_last;
	phandle->tp_acnt.rx_amsdu_pkt_cnt_last =
		phandle->tp_acnt.rx_amsdu_pkt_cnt;

	phandle->tp_acnt.tx_amsdu_cnt_rate = phandle->tp_acnt.tx_amsdu_cnt -
					     phandle->tp_acnt.tx_amsdu_cnt_last;
	phandle->tp_acnt.tx_amsdu_cnt_last = phandle->tp_acnt.tx_amsdu_cnt;

	phandle->tp_acnt.tx_amsdu_pkt_cnt_rate =
		phandle->tp_acnt.tx_amsdu_pkt_cnt -
		phandle->tp_acnt.tx_amsdu_pkt_cnt_last;
	phandle->tp_acnt.tx_amsdu_pkt_cnt_last =
		phandle->tp_acnt.tx_amsdu_pkt_cnt;

	/* re-arm timer */
	woal_mod_timer(&phandle->tp_acnt.timer, 1000);
}

/**
 *  @brief      set tp state to mlan
 *
 *  @param priv  pointer to moal_private
 *
 *  @return     N/A
 */
void woal_set_tp_state(moal_private *priv)
{
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	moal_handle *handle = priv->phandle;
	mlan_status status = MLAN_STATUS_SUCCESS;
	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
	if (req == NULL)
		return;
	/* Fill request buffer */
	misc = (mlan_ds_misc_cfg *)req->pbuf;
	misc->sub_command = MLAN_OID_MISC_TP_STATE;
	req->req_id = MLAN_IOCTL_MISC_CFG;
	misc->param.tp_state.on = handle->tp_acnt.on;
	misc->param.tp_state.drop_point = handle->tp_acnt.drop_point;
	req->action = MLAN_ACT_SET;
	/* Send IOCTL request to MLAN */
	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	return;
}

/**
 *  @brief Set/Get TP statistics.
 *
 *  @param priv         A pointer to moal_private structure
 *  @param respbuf      A pointer to response buffer
 *  @param respbuflen   Available length of response buffer
 *
 *  @return             Number of bytes written, negative for failure.
 */
static int woal_priv_set_tp_state(moal_private *priv, t_u8 *respbuf,
				  t_u32 respbuflen)
{
	moal_handle *handle = priv->phandle;
	int ret = 0;
	int data[2];
	int header_len = 0, user_data_len = 0;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -EINVAL;
		goto done;
	}
	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TP_STATE);
	user_data_len = strlen(respbuf) - header_len;
	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
			&user_data_len);
	if (user_data_len > 2) {
		PRINTM(MERROR, "Invalid number of args!\n");
		ret = -EINVAL;
		goto done;
	}
	if (user_data_len) {
		handle->tp_acnt.on = data[0];
		/* Enable TP statistics collection */
		if (data[0] == 1) {
			handle->tp_acnt.drop_point = data[1];
			if (handle->is_tp_acnt_timer_set == MFALSE) {
				woal_initialize_timer(&handle->tp_acnt.timer,
						      woal_tp_acnt_timer_func,
						      handle);
				handle->is_tp_acnt_timer_set = MTRUE;
				woal_mod_timer(&handle->tp_acnt.timer, 1000);
			}
		} else {
			if (handle->is_tp_acnt_timer_set) {
				woal_cancel_timer(&handle->tp_acnt.timer);
				handle->is_tp_acnt_timer_set = MFALSE;
			}
			memset((void *)&handle->tp_acnt, 0,
			       sizeof(moal_tp_acnt_t));
		}
		woal_set_tp_state(priv);
	}
	/* Get command results */
	if (user_data_len == 0) {
		moal_memcpy_ext(handle, respbuf, (t_u8 *)(&handle->tp_acnt),
				sizeof(handle->tp_acnt), respbuflen);
		ret = sizeof(handle->tp_acnt);
	}

done:
	LEAVE();
	return ret;
}

static int woal_priv_ips_cfg(moal_private *priv, t_u8 *respbuf,
			     t_u32 respbuflen)
{
	moal_handle *handle = priv->phandle;
	mlan_ioctl_req *req = NULL;
	mlan_ds_misc_cfg *misc = NULL;
	t_u32 data[1];
	int ret = 0;
	int user_data_len = 0;
	mlan_status status = MLAN_STATUS_SUCCESS;

	ENTER();
	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_IPS_CFG))) {
		/* GET operation */
		user_data_len = 0;
	} else {
		/* SET operation */
		memset((char *)data, 0, sizeof(data));
		parse_arguments(respbuf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_IPS_CFG),
				data, ARRAY_SIZE(data), &user_data_len);
	}
	if (user_data_len) {
		/* Allocate an IOCTL request buffer */
		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
		if (req == NULL) {
			ret = -ENOMEM;
			goto done;
		}
		/* Fill request buffer */
		misc = (mlan_ds_misc_cfg *)req->pbuf;
		misc->sub_command = MLAN_OID_MISC_IPS_CFG;
		req->req_id = MLAN_IOCTL_MISC_CFG;
		misc->param.ips_ctrl = data[0];
		req->action = MLAN_ACT_SET;
		/* Send IOCTL request to MLAN */
		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
		if (status != MLAN_STATUS_SUCCESS) {
			ret = -EFAULT;
			goto done;
		}
		handle->ips_ctrl = data[0];
	} else {
		data[0] = handle->ips_ctrl;
		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
				sizeof(data), respbuflen);
	}
	ret = sizeof(data);
done:
	if (status != MLAN_STATUS_PENDING)
		kfree(req);
	LEAVE();
	return ret;
}

static int woal_priv_get_uuid(moal_private *priv, t_u8 *respbuf,
			      t_u32 respbuflen)
{
	int ret = -1;
	mlan_fw_info fw_info;

	ENTER();

	if (!respbuf) {
		PRINTM(MERROR, "response buffer is not available!\n");
		ret = -1;
	} else {
		fw_info.uuid_lo = fw_info.uuid_hi = 0x0ULL;

		woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
		snprintf(respbuf, MLAN_MAX_UUID_LEN + 1, "%016llx%016llx",
			 fw_info.uuid_lo, fw_info.uuid_hi);
		ret = strlen(respbuf);
	}

	LEAVE();
	return ret;
}

/**
 *  @brief Set priv command for Android
 *  @param dev          A pointer to net_device structure
 *  @param req          A pointer to ifreq structure
 *
 *  @return             0 --success, otherwise fail
 */
int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
{
	int ret = 0;
	android_wifi_priv_cmd priv_cmd;
	moal_private *priv = (moal_private *)netdev_priv(dev);
	char *buf = NULL;
	char *pdata;
#ifdef STA_SUPPORT
	int power_mode = 0;
	int band = 0;
	char *pband = NULL;
	mlan_bss_info bss_info;
	mlan_ds_get_signal signal;
	mlan_rate_cfg_t rate;
	t_u8 country_code[COUNTRY_CODE_LEN];
	int copy_len = 0;
#endif
	int len = 0;
	gfp_t flag;
	char *cmd_buf = NULL;
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	int cfg80211_wext;
#endif

	ENTER();
	if (!priv || !priv->phandle) {
		PRINTM(MERROR, "priv or handle is NULL\n");
		ret = -EFAULT;
		goto done;
	}
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
	cfg80211_wext = priv->phandle->params.cfg80211_wext;
#endif
	if (copy_from_user(&priv_cmd, req->ifr_data,
			   sizeof(android_wifi_priv_cmd))) {
		ret = -EFAULT;
		goto done;
	}
	if (priv_cmd.used_len < 0 || priv_cmd.total_len <= 0 ||
	    priv_cmd.used_len > priv_cmd.total_len) {
		PRINTM(MERROR,
		       "Invalid Android priv cmd len. used_len: %d, total_len: %d\n",
		       priv_cmd.used_len, priv_cmd.total_len);
		ret = -EINVAL;
		goto done;
	}
	if (priv_cmd.total_len + 1 > CMD_BUF_LEN)
		priv_cmd.total_len = CMD_BUF_LEN - 1;

	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
	buf = kzalloc(CMD_BUF_LEN, flag);
	if (!buf) {
		PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__);
		ret = -ENOMEM;
		goto done;
	}
#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
	moal_memcpy_ext(priv->phandle, &cmd_buf, &priv_cmd.buf, sizeof(cmd_buf),
			sizeof(cmd_buf));
#else
	cmd_buf = priv_cmd.buf;
#endif
	if (copy_from_user(buf, (const void __user *)cmd_buf,
			   priv_cmd.total_len)) {
		ret = -EFAULT;
		goto done;
	}
	buf[CMD_BUF_LEN - 1] = '\0';

	PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name);

	if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) &&
	    woal_check_driver_status(priv->phandle)) {
		PRINTM(MERROR, "%s fail when driver hang\n", buf);
		ret = -EFAULT;
		goto done;
	}

	if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) == 0) {
		/* This command has come from mlanutl app */

		/* Check command */
		if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VERSION,
			     strlen(PRIV_CMD_VERSION)) == 0) {
			/* Get version */
			len = woal_get_priv_driver_version(priv, buf,
							   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BANDCFG,
				    strlen(PRIV_CMD_BANDCFG)) == 0) {
			/* Set/Get band configuration */
			len = woal_setget_priv_bandcfg(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOSTCMD,
				    strlen(PRIV_CMD_HOSTCMD)) == 0) {
			/* hostcmd configuration */
			len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len,
						MOAL_IOCTL_WAIT);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCMDCFG,
				    strlen(PRIV_CMD_11AXCMDCFG)) == 0) {
			/* 11ax command */
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_11AXCMDCFG);
			len = priv_cmd.total_len - strlen(CMD_NXP) +
			      strlen(PRIV_CMD_11AXCMDCFG);
			len = woal_setget_priv_11axcmdcfg(priv, pdata, len,
							  MOAL_IOCTL_WAIT);
			len += strlen(CMD_NXP) + strlen(PRIV_CMD_11AXCMDCFG);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RANGE_EXT,
				    strlen(PRIV_CMD_RANGE_EXT)) == 0) {
			len = woal_setget_priv_range_ext(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTTXCFG,
				    strlen(PRIV_CMD_HTTXCFG)) == 0) {
			/* Set/Get HT Tx configuration */
			len = woal_setget_priv_httxcfg(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTCAPINFO,
				    strlen(PRIV_CMD_HTCAPINFO)) == 0) {
			/* Set/Get HT Capability information */
			len = woal_setget_priv_htcapinfo(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAPARA,
				    strlen(PRIV_CMD_ADDBAPARA)) == 0) {
			/* Set/Get Add BA parameters */
			len = woal_setget_priv_addbapara(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRPRIOTBL,
				    strlen(PRIV_CMD_AGGRPRIOTBL)) == 0) {
			/* Set/Get Aggregation priority table parameters */
			len = woal_setget_priv_aggrpriotbl(priv, buf,
							   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAREJECT,
				    strlen(PRIV_CMD_ADDBAREJECT)) == 0) {
			/* Set/Get Add BA reject parameters */
			len = woal_setget_priv_addbareject(priv, buf,
							   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELBA,
				    strlen(PRIV_CMD_DELBA)) == 0) {
			/* Delete selective BA based on parameters */
			len = woal_priv_delba(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_REJECTADDBAREQ,
				    strlen(PRIV_CMD_REJECTADDBAREQ)) == 0) {
			/* Set/Get the reject addba requst conditions*/
			len = woal_priv_rejectaddbareq(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VHTCFG,
				    strlen(PRIV_CMD_VHTCFG)) == 0) {
			/* Set/Get 11AC configuration */
			len = woal_setget_priv_vhtcfg(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OPERMODECFG,
				    strlen(PRIV_CMD_OPERMODECFG)) == 0) {
			/* Set/Get 11AC configuration */
			len = woal_setget_priv_opermodecfg(priv, buf,
							   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DATARATE,
				    strlen(PRIV_CMD_DATARATE)) == 0) {
			/* Get data rate */
			len = woal_get_priv_datarate(priv, buf,
						     priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXRATECFG,
				    strlen(PRIV_CMD_TXRATECFG)) == 0) {
			/* Set/Get tx rate cfg */
			len = woal_setget_priv_txratecfg(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETLOG,
				    strlen(PRIV_CMD_GETLOG)) == 0) {
			/* Get wireless stats information */
			len = woal_get_priv_getlog(priv, buf,
						   priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CUSTOMIE,
				    strlen(PRIV_CMD_CUSTOMIE)) == 0) {
			/* Custom IE configuration */
			len = woal_priv_customie(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ESUPPMODE,
				    strlen(PRIV_CMD_ESUPPMODE)) == 0) {
			/* Esupplicant mode configuration */
			len = woal_setget_priv_esuppmode(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PASSPHRASE,
				    strlen(PRIV_CMD_PASSPHRASE)) == 0) {
			/* Esupplicant passphrase configuration */
			len = woal_setget_priv_passphrase(priv, buf,
							  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH,
				    strlen(PRIV_CMD_DEAUTH)) == 0) {
			/* Deauth */
			len = woal_priv_deauth(priv, buf, priv_cmd.total_len);
			goto handled;
#ifdef UAP_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AP_DEAUTH,
				    strlen(PRIV_CMD_AP_DEAUTH)) == 0) {
			/* AP Deauth */
			len = woal_priv_ap_deauth(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GET_STA_LIST,
				    strlen(PRIV_CMD_GET_STA_LIST)) == 0) {
			/* Get STA list */
			len = woal_priv_get_sta_list(priv, buf,
						     priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSS_CONFIG,
				    strlen(PRIV_CMD_BSS_CONFIG)) == 0) {
			/* BSS config */
			len = woal_priv_bss_config(priv, buf,
						   priv_cmd.total_len);
			goto handled;
#endif
#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSSROLE,
				    strlen(PRIV_CMD_BSSROLE)) == 0) {
			/* BSS Role */
			len = woal_priv_bssrole(priv, buf,
						(t_u32)priv_cmd.total_len);
			goto handled;
#endif
#endif
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SETUSERSCAN,
				    strlen(PRIV_CMD_SETUSERSCAN)) == 0) {
			/* Set user scan */
			len = woal_priv_setuserscan(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GETSCANTABLE,
				    strlen(PRIV_CMD_GETSCANTABLE)) == 0) {
			/* Get scan table */
			len = woal_priv_getscantable(priv, buf,
						     priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GETCHANSTATS,
				    strlen(PRIV_CMD_GETCHANSTATS)) == 0) {
			/* Get channel statistics */
			len = woal_priv_get_chanstats(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_EXTCAPCFG,
				    strlen(PRIV_CMD_EXTCAPCFG)) == 0) {
			/* Extended capabilities configure */
			len = woal_priv_extcapcfg(priv, buf,
						  (t_u32)priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CANCELSCAN,
				    strlen(PRIV_CMD_CANCELSCAN)) == 0) {
			/* Cancel scan */
			len = woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEEPSLEEP,
				    strlen(PRIV_CMD_DEEPSLEEP)) == 0) {
			/* Deep sleep */
			len = woal_priv_setgetdeepsleep(priv, buf,
							priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_REORDER_FLUSH_TIME,
				    strlen(PRIV_CMD_REORDER_FLUSH_TIME)) == 0) {
			/* reorder flush time */
			len = woal_priv_set_get_reorder_flush_time(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPADDR,
				    strlen(PRIV_CMD_IPADDR)) == 0) {
			/* IP address */
			len = woal_priv_setgetipaddr(priv, buf,
						     (t_u32)priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WPSSESSION,
				    strlen(PRIV_CMD_WPSSESSION)) == 0) {
			/* WPS Session */
			len = woal_priv_setwpssession(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OTPUSERDATA,
				    strlen(PRIV_CMD_OTPUSERDATA)) == 0) {
			/* OTP user data */
			len = woal_priv_otpuserdata(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_COUNTRYCODE,
				    strlen(PRIV_CMD_COUNTRYCODE)) == 0) {
			/* Country code */
			len = woal_priv_set_get_countrycode(priv, buf,
							    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFPINFO,
				    strlen(PRIV_CMD_CFPINFO)) == 0) {
			/* CFP info */
			len = woal_priv_get_cfpinfo(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TCPACKENH,
				    strlen(PRIV_CMD_TCPACKENH)) == 0) {
			/* TCP ack enhancement */
			len = woal_priv_setgettcpackenh(priv, buf,
							priv_cmd.total_len);
			goto handled;
#ifdef REASSOCIATION
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCBSSID,
				    strlen(PRIV_CMD_ASSOCBSSID)) == 0) {
			/* Associate to essid */
			len = woal_priv_assocessid(priv, buf,
						   priv_cmd.total_len, 1);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCESSID,
				    strlen(PRIV_CMD_ASSOCESSID)) == 0) {
			/* Associate to essid */
			len = woal_priv_assocessid(priv, buf,
						   priv_cmd.total_len, 0);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTOASSOC,
				    strlen(PRIV_CMD_AUTOASSOC)) == 0) {
			/* Auto assoc */
			len = woal_priv_setgetautoassoc(priv, buf,
							priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_WAKEUPREASON,
				    strlen(PRIV_CMD_WAKEUPREASON)) == 0) {
			/* wakeup reason */
			len = woal_priv_getwakeupreason(priv, buf,
							priv_cmd.total_len);
			goto handled;
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_LISTENINTERVAL,
				    strlen(PRIV_CMD_LISTENINTERVAL)) == 0) {
			/* Listen Interval */
			len = woal_priv_set_get_listeninterval(
				priv, buf, priv_cmd.total_len);
			goto handled;
#endif
#ifdef DEBUG_LEVEL1
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DRVDBG,
				    strlen(PRIV_CMD_DRVDBG)) == 0) {
			/* Driver debug bit mask */
			len = woal_priv_set_get_drvdbg(priv, buf,
						       priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSCFG,
				    strlen(PRIV_CMD_HSCFG)) == 0) {
			/* HS configuration */
			len = woal_priv_hscfg(priv, buf, priv_cmd.total_len,
					      MTRUE);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSSETPARA,
				    strlen(PRIV_CMD_HSSETPARA)) == 0) {
			/* Set HS parameter */
			len = woal_priv_hssetpara(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MGMT_FILTER,
				    strlen(PRIV_CMD_MGMT_FILTER)) == 0) {
			/* Management frame filter wakeup */
			len = woal_priv_mgmt_filter(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SCANCFG,
				    strlen(PRIV_CMD_SCANCFG)) == 0) {
			/* Scan configuration */
			len = woal_priv_set_get_scancfg(priv, buf,
							priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETNLNUM,
				    strlen(PRIV_CMD_GETNLNUM)) == 0) {
			/* Scan configuration */
			len = woal_priv_getnlnum(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRCTRL,
				    strlen(PRIV_CMD_AGGRCTRL)) == 0) {
			/* aggregation control */
			len = woal_priv_set_get_aggrctrl(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#ifdef USB
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USBAGGRCTRL,
				    strlen(PRIV_CMD_USBAGGRCTRL)) == 0) {
			/* USB aggregation control */
			len = woal_priv_set_get_usbaggrctrl(priv, buf,
							    priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_SET_BSS_MODE,
				    strlen(PRIV_CMD_SET_BSS_MODE)) == 0) {
			/* Set bss mode */
			len = woal_priv_set_bss_mode(priv, buf,
						     priv_cmd.total_len);
			goto handled;
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AP,
				    strlen(PRIV_CMD_SET_AP)) == 0) {
			/* Set AP */
			len = woal_priv_set_ap(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_POWER,
				    strlen(PRIV_CMD_SET_POWER)) == 0) {
			/* Set power management parameters */
			len = woal_priv_set_power(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_ESSID,
				    strlen(PRIV_CMD_SET_ESSID)) == 0) {
			/* Set essid */
			len = woal_priv_set_essid(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AUTH,
				    strlen(PRIV_CMD_SET_AUTH)) == 0) {
			/* Set authentication mode parameters */
			len = woal_priv_set_auth(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_AP,
				    strlen(PRIV_CMD_GET_AP)) == 0) {
			/* Get AP */
			len = woal_priv_get_ap(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_POWER,
				    strlen(PRIV_CMD_GET_POWER)) == 0) {
			/* Get power management parameters */
			len = woal_priv_get_power(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSMODE,
				    strlen(PRIV_CMD_PSMODE)) == 0) {
			/* Set/Get PS mode */
			len = woal_priv_set_get_psmode(priv, buf,
						       priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WARMRESET,
				    strlen(PRIV_CMD_WARMRESET)) == 0) {
			/* Performs warm reset */
			len = woal_priv_warmreset(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXPOWERCFG,
				    strlen(PRIV_CMD_TXPOWERCFG)) == 0) {
			/* TX power configurations */
			len = woal_priv_txpowercfg(priv, buf,
						   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_RX_ABORT_CFG_EXT,
				    strlen(PRIV_CMD_RX_ABORT_CFG_EXT)) == 0) {
			/* dynamic Rx Abort config */
			len = woal_priv_rx_abort_cfg_ext(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_NAV_MITIGATION,
				    strlen(PRIV_CMD_NAV_MITIGATION)) == 0) {
			/* dconfigure nav mitigate */
			len = woal_priv_nav_mitigation(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_RX_ABORT_CFG,
				    strlen(PRIV_CMD_RX_ABORT_CFG)) == 0) {
			/* static Rx Abort config */
			len = woal_priv_rx_abort_cfg(priv, buf,
						     priv_cmd.total_len);
			goto handled;

		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_OFDM_DESENSE_CFG,
				    strlen(PRIV_CMD_OFDM_DESENSE_CFG)) == 0) {
			/* OFDM DESENSE config */
			len = woal_priv_ofdm_desense_cfg(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_TX_AMPDU_PROT_MODE,
				    strlen(PRIV_CMD_TX_AMPDU_PROT_MODE)) == 0) {
			/* tx ampdu protection mode setting */
			len = woal_priv_tx_ampdu_prot_mode(priv, buf,
							   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG,
				    strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG)) ==
			   0) {
			/* setting for dot11mc un-associated case FTM frame
			 * exchange */
			len = woal_priv_dot11mc_unassoc_ftm_cfg(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_RATE_ADAPT_CFG,
				    strlen(PRIV_CMD_RATE_ADAPT_CFG)) == 0) {
			/* rate adapt config */
			len = woal_priv_rate_adapt_cfg(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_CCK_DESENSE_CFG,
				    strlen(PRIV_CMD_CCK_DESENSE_CFG)) == 0) {
			/* cck desense config */
			len = woal_priv_cck_desense_cfg(priv, buf,
							priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSCFG,
				    strlen(PRIV_CMD_PSCFG)) == 0) {
			/* PS configurations */
			len = woal_priv_pscfg(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_BCNTIMEOUTCFG,
				    strlen(PRIV_CMD_BCNTIMEOUTCFG)) == 0) {
			/* Beacon timeout configurations */
			len = woal_priv_bcntimeoutcfg(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SLEEPPD,
				    strlen(PRIV_CMD_SLEEPPD)) == 0) {
			/* Sleep period */
			len = woal_priv_sleeppd(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXCONTROL,
				    strlen(PRIV_CMD_TXCONTROL)) == 0) {
			/* Tx control */
			len = woal_priv_txcontrol(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGRDWR,
				    strlen(PRIV_CMD_REGRDWR)) == 0) {
			/* Register Read/Write */
			len = woal_priv_regrdwr(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RDEEPROM,
				    strlen(PRIV_CMD_RDEEPROM)) == 0) {
			/* Read the EEPROM contents of the card */
			len = woal_priv_rdeeprom(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MEMRDWR,
				    strlen(PRIV_CMD_MEMRDWR)) == 0) {
			/* Memory Read/Write */
			len = woal_priv_memrdwr(priv, buf, priv_cmd.total_len);
			goto handled;
#ifdef SDIO
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDCMD52RW,
				    strlen(PRIV_CMD_SDCMD52RW)) == 0) {
			/* Cmd52 read/write register */
			len = woal_priv_sdcmd52rw(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDIO_CLOCK,
				    strlen(PRIV_CMD_SDIO_CLOCK)) == 0) {
			/* Turn on/off the sdio clock */
			len = woal_priv_sdio_clock_ioctl(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MPA_CTRL,
				    strlen(PRIV_CMD_MPA_CTRL)) == 0) {
			/* Set SDIO Multi-point aggregation
			 * control parameters */
			len = woal_priv_sdio_mpa_ctrl(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SD_CMD53_RW,
				    strlen(PRIV_CMD_SD_CMD53_RW)) == 0) {
			/* Cmd53 read/write register */
			len = woal_priv_cmd53rdwr(priv, buf,
						  priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ROBUSTCOEX,
				    strlen(PRIV_CMD_ROBUSTCOEX)) == 0) {
			/* Set Robustcoex GPIOcfg */
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_ROBUSTCOEX);
			len = priv_cmd.total_len - strlen(PRIV_CMD_ROBUSTCOEX) -
			      strlen(CMD_NXP);
			len = woal_priv_robustcoex(priv, pdata, len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DMCS,
				    strlen(PRIV_CMD_DMCS)) == 0) {
			/* Set/Get DMCS config */
			len = woal_priv_dmcs(priv, buf, priv_cmd.total_len);
			goto handled;
#if defined(PCIE)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SSU,
				    strlen(PRIV_CMD_SSU)) == 0) {
			/* Set SSU config */
			pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_SSU);
			len = priv_cmd.used_len - strlen(PRIV_CMD_SSU) -
			      strlen(CMD_NXP);
			len = woal_priv_ssu_cmd(priv, len, pdata,
						priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HAL_PHY_CFG,
				    strlen(PRIV_CMD_HAL_PHY_CFG)) == 0) {
			/* Set hal_phy config */
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_HAL_PHY_CFG);
			len = priv_cmd.total_len -
			      strlen(PRIV_CMD_HAL_PHY_CFG) - strlen(CMD_NXP);
			len = woal_priv_hal_phy_cfg_cmd(priv, pdata, len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CSI,
				    strlen(PRIV_CMD_CSI)) == 0) {
			/* Set CSI config */
			pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_CSI);
			len = priv_cmd.total_len - strlen(PRIV_CMD_CSI) -
			      strlen(CMD_NXP);
			priv->csi_seq = 0;
			len = woal_priv_csi_cmd(priv, pdata, len);
			goto handled;
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARPFILTER,
				    strlen(PRIV_CMD_ARPFILTER)) == 0) {
			/* ARPFilter Configuration */
			len = woal_priv_arpfilter(priv, buf,
						  priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_ARP,
				    strlen(PRIV_CMD_AUTO_ARP)) == 0) {
			/* Auto ARP enable/disable */
			len = woal_priv_set_get_auto_arp(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOTSPOTCFG,
				    strlen(PRIV_CMD_HOTSPOTCFG)) == 0) {
			/* Hotspot CFG */
			len = woal_priv_hotspotcfg(priv, buf,
						   priv_cmd.total_len);
			goto handled;

		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_MGMT_FRAME_CTRL,
				    strlen(PRIV_CMD_MGMT_FRAME_CTRL)) == 0) {
			/* Mgmt Frame Passthrough Ctrl */
			len = woal_priv_mgmt_frame_passthru_ctrl(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QCONFIG,
				    strlen(PRIV_CMD_QCONFIG)) == 0) {
			/* Queue config */
			len = woal_priv_qconfig(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDTS,
				    strlen(PRIV_CMD_ADDTS)) == 0) {
			/* Send an ADDTS TSPEC */
			len = woal_priv_wmm_addts_req_ioctl(priv, buf,
							    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELTS,
				    strlen(PRIV_CMD_DELTS)) == 0) {
			/* Send a DELTS TSPE */
			len = woal_priv_wmm_delts_req_ioctl(priv, buf,
							    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QSTATUS,
				    strlen(PRIV_CMD_QSTATUS)) == 0) {
			/* Get the status of the WMM queues */
			len = woal_priv_wmm_queue_status_ioctl(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TS_STATUS,
				    strlen(PRIV_CMD_TS_STATUS)) == 0) {
			/* Get the status of the WMM Traffic Streams */
			len = woal_priv_wmm_ts_status_ioctl(priv, buf,
							    priv_cmd.total_len);
			goto handled;
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QOS_CFG,
				    strlen(PRIV_CMD_QOS_CFG)) == 0) {
			t_u32 action = MLAN_ACT_GET;
			if (strlen(buf) ==
			    strlen(CMD_NXP) + strlen(PRIV_CMD_QOS_CFG)) {
				pdata = buf; /* GET operation */
			} else {
				pdata = buf + strlen(CMD_NXP) +
					strlen(PRIV_CMD_QOS_CFG);
				action = MLAN_ACT_SET; /* SET operation */
			}
			if (MLAN_STATUS_SUCCESS !=
			    woal_priv_qos_cfg(priv, action, pdata)) {
				ret = -EFAULT;
				goto done;
			}
			if (action == MLAN_ACT_GET)
				len = sizeof(t_u8);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MAC_CTRL,
				    strlen(PRIV_CMD_MAC_CTRL)) == 0) {
			/* MAC CTRL */
			len = woal_priv_macctrl(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETWAP,
				    strlen(PRIV_CMD_GETWAP)) == 0) {
			/* Get WAP */
			len = woal_priv_getwap(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGION_CODE,
				    strlen(PRIV_CMD_REGION_CODE)) == 0) {
			/* Region Code */
			len = woal_priv_region_code(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DRCS_CFG,
				    strlen(PRIV_CMD_DRCS_CFG)) == 0) {
			/* DRCS configuration for mc_cfg_ext*/
			len = woal_priv_drcs_time_slicing_cfg(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_MULTI_CHAN_CFG,
				    strlen(PRIV_CMD_MULTI_CHAN_CFG)) == 0) {
			/* Channel time and buffer weight configuration */
			len = woal_priv_multi_chan_config(priv, buf,
							  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_MULTI_CHAN_POLICY,
				    strlen(PRIV_CMD_MULTI_CHAN_POLICY)) == 0) {
			/* Multi-channel Policy enable/disable */
			len = woal_priv_multi_chan_policy(priv, buf,
							  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FWMACADDR,
				    strlen(PRIV_CMD_FWMACADDR)) == 0) {
			/* Set FW MAC address */
			len = woal_priv_fwmacaddr(priv, buf,
						  priv_cmd.total_len);
			goto handled;
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OFFCHANNEL,
				    strlen(PRIV_CMD_OFFCHANNEL)) == 0) {
			if (IS_STA_CFG80211(cfg80211_wext)) {
				/* Set offchannel */
				len = woal_priv_offchannel(priv, buf,
							   priv_cmd.total_len);
			} else
				len = snprintf(buf, CMD_BUF_LEN,
					       "CFG80211 is not enabled\n") +
				      1;
			goto handled;
#endif
#endif

		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DSCP_MAP,
				    strlen(PRIV_CMD_DSCP_MAP)) == 0) {
			/* Set/Get DSCP Map */
			len = woal_priv_set_get_dscp_map(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VEREXT,
				    strlen(PRIV_CMD_VEREXT)) == 0) {
			/* Get Extended version */
			len = woal_priv_get_driver_verext(priv, buf,
							  priv_cmd.total_len);
			goto handled;
#ifdef USB
#ifdef CONFIG_USB_SUSPEND
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_SUSPEND,
				    strlen(PRIV_CMD_USB_SUSPEND)) == 0) {
			/* Makes USB device to suspend */
			len = woal_priv_enter_usb_suspend(priv, buf,
							  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_RESUME,
				    strlen(PRIV_CMD_USB_RESUME)) == 0) {
			/* Makes USB device to resume */
			len = woal_priv_exit_usb_suspend(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#endif /* CONFIG_USB_SUSPEND */
#endif
#if defined(STA_SUPPORT) && defined(STA_WEXT)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RADIO_CTRL,
				    strlen(PRIV_CMD_RADIO_CTRL)) == 0) {
			/* Set/Get radio */
			len = woal_priv_radio_ctrl(priv, buf,
						   priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WMM_CFG,
				    strlen(PRIV_CMD_WMM_CFG)) == 0) {
			/* Implement WMM enable command */
			len = woal_priv_wmm_cfg(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_MIN_BA_THRESH_CFG,
				    strlen(PRIV_CMD_MIN_BA_THRESH_CFG)) == 0) {
			/* Implement Minimum BA threshold configuration command
			 */
			len = woal_priv_min_ba_threshold_cfg(
				priv, buf, priv_cmd.total_len);
			goto handled;
#if defined(STA_SUPPORT)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CFG,
				    strlen(PRIV_CMD_11D_CFG)) == 0) {
			/* Implement 802.11D enable command */
			len = woal_priv_11d_cfg(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CLR_TBL,
				    strlen(PRIV_CMD_11D_CLR_TBL)) == 0) {
			/* Implement 802.11D clear chan table command */
			len = woal_priv_11d_clr_chan_tbl(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#endif
#ifndef OPCHAN
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WWS_CFG,
				    strlen(PRIV_CMD_WWS_CFG)) == 0) {
			/* Set/Get WWS configuration */
			len = woal_priv_wws_cfg(priv, buf, priv_cmd.total_len);
			goto handled;
#endif
#if defined(REASSOCIATION)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REASSOCTRL,
				    strlen(PRIV_CMD_REASSOCTRL)) == 0) {
			/* Set/Get reassociation settings */
			len = woal_priv_set_get_reassoc(priv, buf,
							priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXBUF_CFG,
				    strlen(PRIV_CMD_TXBUF_CFG)) == 0) {
			/* Get Transmit buffer size */
			len = woal_priv_txbuf_cfg(priv, buf,
						  priv_cmd.total_len);
			goto handled;
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTH_TYPE,
				    strlen(PRIV_CMD_AUTH_TYPE)) == 0) {
			/* Set/Get auth type */
			len = woal_priv_auth_type(priv, buf,
						  priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_POWER_CONS,
				    strlen(PRIV_CMD_POWER_CONS)) == 0) {
			/* Set/get user provisioned local power constraint */
			len = woal_priv_11h_local_pwr_constraint(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_HT_STREAM_CFG,
				    strlen(PRIV_CMD_HT_STREAM_CFG)) == 0) {
			/* Set/get HT stream configurations */
			len = woal_priv_ht_stream_cfg(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MIMO_SWITCH,
				    strlen(PRIV_CMD_MIMO_SWITCH)) == 0) {
			/* Set mimo switch configurations */
			len = woal_priv_mimo_switch(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_THERMAL,
				    strlen(PRIV_CMD_THERMAL)) == 0) {
			/* Get thermal reading */
			len = woal_priv_thermal(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_BCN_INTERVAL,
				    strlen(PRIV_CMD_BCN_INTERVAL)) == 0) {
			/* Set/Get beacon interval */
			len = woal_priv_beacon_interval(priv, buf,
							priv_cmd.total_len);
			goto handled;
#ifdef STA_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_SIGNALEXT_CFG,
				    strlen(PRIV_CMD_SIGNALEXT_CFG)) == 0) {
			/* Set signalext flag */
			len = woal_priv_signalext_cfg(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GET_SIGNAL_EXT_V2,
				    strlen(PRIV_CMD_GET_SIGNAL_EXT_V2)) == 0) {
			/* Get signal info */
			len = woal_priv_get_signal_ext_v2(priv, buf,
							  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GET_SIGNAL_EXT,
				    strlen(PRIV_CMD_GET_SIGNAL_EXT)) == 0) {
			/* Get signal info */
			len = woal_priv_get_signal_ext(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SIGNAL,
				    strlen(PRIV_CMD_GET_SIGNAL)) == 0) {
			/* Get signal */
			len = woal_priv_get_signal(priv, buf,
						   priv_cmd.total_len);
			goto handled;
#endif
#if defined(STA_SUPPORT)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PMFCFG,
				    strlen(PRIV_CMD_PMFCFG)) == 0) {
			/* Configure PMF */
			len = woal_priv_set_get_pmfcfg(priv, buf,
						       priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_INACTIVITYTO,
				    strlen(PRIV_CMD_INACTIVITYTO)) == 0) {
			/* Get/Set inactivity timeout extend */
			len = woal_priv_inactivity_timeout_ext(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_AMSDU_AGGR_CTRL,
				    strlen(PRIV_CMD_AMSDU_AGGR_CTRL)) == 0) {
			/* Enable/Disable amsdu_aggr_ctrl */
			len = woal_priv_11n_amsdu_aggr_ctrl(priv, buf,
							    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_MCAST_AGGR_GROUP,
				    strlen(PRIV_CMD_MCAST_AGGR_GROUP)) == 0) {
			/* mcast_aggr_group cfg*/
			len = woal_priv_mcast_aggr_group_cfg(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MC_AGGR_CFG,
				    strlen(PRIV_CMD_MC_AGGR_CFG)) == 0) {
			/* mc_aggr_cfg*/
			len = woal_priv_mc_aggr_cfg(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_STATS,
				    strlen(PRIV_CMD_STATS)) == 0) {
			/* stats */
			len = woal_priv_stats(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CH_LOAD,
				    strlen(PRIV_CMD_CH_LOAD)) == 0) {
			/* mc_aggr_cfg*/
			len = woal_priv_get_ch_load(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_CROSS_CHIP_SYNCH,
				    strlen(PRIV_CMD_CROSS_CHIP_SYNCH)) == 0) {
			len = woal_priv_cross_chip_synch(priv, buf,
							 priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_CH_LOAD_RESULTS,
				    strlen(PRIV_CMD_CH_LOAD_RESULTS)) == 0) {
			/* mc_aggr_cfg*/
			len = woal_priv_get_ch_load_results(priv, buf,
							    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CAP,
				    strlen(PRIV_CMD_TX_BF_CAP)) == 0) {
			/* Set/Get Transmit beamforming capabilities */
			len = woal_priv_tx_bf_cap_ioctl(priv, buf,
							priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_SLEEP_PARAMS,
				    strlen(PRIV_CMD_SLEEP_PARAMS)) == 0) {
			/* Configure sleep parameters */
			len = woal_priv_sleep_params_ioctl(priv, buf,
							   priv_cmd.total_len);
			goto handled;
#ifdef UAP_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_NET_MON,
				    strlen(PRIV_CMD_NET_MON)) == 0) {
			/* Set/Get network monitor configurations */
			len = woal_priv_net_monitor_ioctl(priv, buf,
							  priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_TESTING,
				    strlen(PRIV_CMD_DFS_TESTING)) == 0) {
			/* Set/Get DFS Testing settings */
			len = woal_priv_dfs_testing(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CLEAR_NOP,
				    strlen(PRIV_CMD_CLEAR_NOP)) == 0) {
			/* Set/Get DFS Testing settings */
			len = woal_priv_clear_nop(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_NOP_LIST,
				    strlen(PRIV_CMD_NOP_LIST)) == 0) {
			/* Set/Get DFS Testing settings */
			len = woal_priv_nop_list(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FAKE_RADAR,
				    strlen(PRIV_CMD_FAKE_RADAR)) == 0) {
			/* mcast_aggr_group cfg*/
			len = woal_priv_fake_radar(priv, buf,
						   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS53_CFG,
				    strlen(PRIV_CMD_DFS53_CFG)) == 0) {
			/* Set/Get DFS W53 settings */
			len = woal_priv_dfs53cfg(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_MODE,
				    strlen(PRIV_CMD_DFS_MODE)) == 0) {
			/* Set/Get DFS mode settings */
			len = woal_priv_dfs_mode(priv, buf, priv_cmd.total_len);
			goto handled;
#ifdef UAP_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_CAC,
				    strlen(PRIV_CMD_DFS_CAC)) == 0) {
			/* perform CAC */
			len = woal_priv_do_dfs_cac(priv, buf,
						   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTODFS,
				    strlen(PRIV_CMD_AUTODFS)) == 0) {
			len = woal_priv_auto_dfs_cfg(priv, buf,
						     priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARB_CFG,
				    strlen(PRIV_CMD_ARB_CFG)) == 0) {
			/* Set/Get CFP table codes */
			len = woal_priv_arbcfg(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFP_CODE,
				    strlen(PRIV_CMD_CFP_CODE)) == 0) {
			/* Set/Get CFP table codes */
			len = woal_priv_cfp_code(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CWMODE,
				    strlen(PRIV_CMD_CWMODE)) == 0) {
			/* Set/Get Tx CWMode */
			len = woal_priv_set_get_cwmode(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ANT_CFG,
				    strlen(PRIV_CMD_ANT_CFG)) == 0) {
			/* Set/Get Tx/Rx antenna */
			len = woal_priv_set_get_tx_rx_ant(priv, buf,
							  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SYSCLOCK,
				    strlen(PRIV_CMD_SYSCLOCK)) == 0) {
			/* Get/Set system clock */
			len = woal_priv_sysclock(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_KEY,
				    strlen(PRIV_CMD_GET_KEY)) == 0) {
			/* Get GTK/PTK */
			len = woal_priv_get_key(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCIATE,
				    strlen(PRIV_CMD_ASSOCIATE)) == 0) {
			/* Associate to a specific indexed entry in the
			 * ScanTable */
			len = woal_priv_associate_ssid_bssid(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CFG,
				    strlen(PRIV_CMD_TX_BF_CFG)) == 0) {
			/* Set/Get Transmit beamforming configuration */
			len = woal_priv_tx_bf_cfg(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BOOTSLEEP,
				    strlen(PRIV_CMD_BOOTSLEEP)) == 0) {
			len = woal_priv_bootsleep(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PORT_CTRL,
				    strlen(PRIV_CMD_PORT_CTRL)) == 0) {
			/* Set/Get Port Control mode */
			len = woal_priv_port_ctrl(priv, buf,
						  priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXWATCHDOG,
				    strlen(PRIV_CMD_TXWATCHDOG)) == 0) {
			len = woal_priv_txwatchdog(priv, buf,
						   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PB_BYPASS,
				    strlen(PRIV_CMD_PB_BYPASS)) == 0) {
			/* Private IOCTL entry to get the By-passed TX packet
			 * from upper layer */
			len = woal_priv_bypassed_packet(priv, buf,
							priv_cmd.total_len);
			goto handled;
#ifdef WIFI_DIRECT_SUPPORT
#if defined(UAP_CFG80211)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_NOA,
				    strlen(PRIV_CMD_CFG_NOA)) == 0) {
			/* Set/Get P2P NoA (Notice of Absence) parameters */
			len = woal_priv_cfg_noa(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_OPP_PS,
				    strlen(PRIV_CMD_CFG_OPP_PS)) == 0) {
			/* Set/Get P2P OPP-PS parameters */
			len = woal_priv_cfg_opp_ps(priv, buf,
						   priv_cmd.total_len);
			goto handled;
#endif
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_CFG_CLOCK_SYNC,
				    strlen(PRIV_CMD_CFG_CLOCK_SYNC)) == 0) {
			/* Set/Get P2P NoA (Notice of Absence) parameters */
			len = woal_priv_cfg_clock_sync(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_CFG_GET_TSF_INFO,
				    strlen(PRIV_CMD_CFG_GET_TSF_INFO)) == 0) {
			/* Get TSF info */
			len = woal_priv_cfg_get_tsf_info(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#ifdef UAP_SUPPORT
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_TARGET_CHANNEL,
				    strlen(PRIV_CMD_TARGET_CHANNEL)) == 0) {
			/* Get/Set Target channel*/
			len = woal_priv_target_channel(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_BACKUP_CHANNEL,
				    strlen(PRIV_CMD_BACKUP_CHANNEL)) == 0) {
			/* Get/Set Backup channel*/
			len = woal_priv_backup_channel(priv, buf,
						       priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_DFS_REPEATER_CFG,
				    strlen(PRIV_CMD_DFS_REPEATER_CFG)) == 0) {
			/* Set/Get DFS_REPEATER mode */
			len = woal_priv_dfs_repeater_cfg(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_MIRACAST_CFG,
				    strlen(PRIV_CMD_MIRACAST_CFG)) == 0) {
			/* Set/Get MIRACAST configuration parameters */
			len = woal_priv_miracast_cfg(priv, buf,
						     priv_cmd.total_len);
			goto handled;
#endif
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_COEX_RX_WINSIZE,
				    strlen(PRIV_CMD_COEX_RX_WINSIZE)) == 0) {
			/* Set/Get control to coex RX window size */
			len = woal_priv_coex_rx_winsize(priv, buf,
							priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_TX_AGGR_CTRL,
				    strlen(PRIV_CMD_TX_AGGR_CTRL)) == 0) {
			/* Set/Get control to TX AMPDU on infra link */
			len = woal_priv_txaggrctrl(priv, buf,
						   priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_TDLS,
				    strlen(PRIV_CMD_AUTO_TDLS)) == 0) {
			/* Set/Get control to enable/disable auto TDLS */
			len = woal_priv_auto_tdls(priv, buf,
						  priv_cmd.total_len);
			goto handled;
#ifdef PCIE
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PCIE_REG_RW,
				    strlen(PRIV_CMD_PCIE_REG_RW)) == 0) {
			/* Read/Write PCIE register */
			len = woal_priv_pcie_reg_rw(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_PCIE_BAR0_REG_RW,
				    strlen(PRIV_CMD_PCIE_BAR0_REG_RW)) == 0) {
			/* Read/Write PCIE register/memory from BAR0 */
			len = woal_priv_pcie_bar0_reg_rw(priv, buf,
							 priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_TDLS_IDLE_TIME,
				    strlen(PRIV_CMD_TDLS_IDLE_TIME)) == 0) {
			/* Set/Get TDLS idle timeout value */
			len = woal_priv_tdls_idle_time(priv, buf,
						       priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GET_SENSOR_TEMP,
				    strlen(PRIV_CMD_GET_SENSOR_TEMP)) == 0) {
			/* Get SOC temperature */
			len = woal_priv_get_sensor_temp(priv, buf,
							priv_cmd.total_len);
			goto handled;
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_OFFLOAD,
				    strlen(PRIV_CMD_DFS_OFFLOAD)) == 0) {
			/* Enable/disable DFS offload */
			if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
				len = woal_priv_dfs_offload_enable(
					priv, buf, priv_cmd.total_len);
			else
				len = snprintf(buf, CMD_BUF_LEN,
					       "CFG80211 is not enabled\n") +
				      1;
			goto handled;
#endif
#endif
#if defined(UAP_SUPPORT)
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_EXTEND_CHAN_SWITCH,
				    strlen(PRIV_CMD_EXTEND_CHAN_SWITCH)) == 0) {
			/* Extended channel switch */
			len = woal_priv_extend_channel_switch(
				priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_SET_CHAN_SWITCH_PARAM,
				    strlen(PRIV_CMD_SET_CHAN_SWITCH_PARAM)) ==
			   0) {
			/* set CSA/ECSA parameters */
			len = woal_priv_set_channel_switch_param(
				priv, buf, priv_cmd.total_len);
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DYN_BW,
				    strlen(PRIV_CMD_DYN_BW)) == 0) {
			/* Set/Get dynamic bandwidth */
			len = woal_priv_config_dyn_bw(priv, buf,
						      priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IND_RST_CFG,
				    strlen(PRIV_CMD_IND_RST_CFG)) == 0) {
			/* Set/Get out band independent reset */
			len = woal_priv_ind_rst_cfg(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PER_PKT_CFG,
				    strlen(PRIV_CMD_PER_PKT_CFG)) == 0) {
			/* Get/Set per packet Txctl and Rxinfo configuration */
			len = woal_priv_per_pkt_cfg(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH_CTRL,
				    strlen(PRIV_CMD_DEAUTH_CTRL)) == 0) {
			len = woal_priv_deauth_ctrl(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCFG,
				    strlen(PRIV_CMD_11AXCFG)) == 0) {
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_11AXCFG);
			len = priv_cmd.used_len - strlen(PRIV_CMD_11AXCFG) -
			      strlen(CMD_NXP);
			len = woal_priv_11axcfg_cmd(priv, pdata, len,
						    priv_cmd.total_len);
			len += strlen(PRIV_CMD_11AXCFG) + strlen(CMD_NXP);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TWT_SETUP,
				    strlen(PRIV_CMD_TWT_SETUP)) == 0) {
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_TWT_SETUP);
			len = priv_cmd.used_len - strlen(PRIV_CMD_TWT_SETUP) -
			      strlen(CMD_NXP);
			len = woal_priv_twt_setup(priv, pdata, len,
						  priv_cmd.total_len);
			len += strlen(PRIV_CMD_TWT_SETUP) + strlen(CMD_NXP);
			goto handled;

		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_TWT_TEARDOWN,
				    strlen(PRIV_CMD_TWT_TEARDOWN)) == 0) {
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_TWT_TEARDOWN);
			len = priv_cmd.used_len -
			      strlen(PRIV_CMD_TWT_TEARDOWN) - strlen(CMD_NXP);
			len = woal_priv_twt_teardown(priv, pdata, len,
						     priv_cmd.total_len);
			len += strlen(PRIV_CMD_TWT_TEARDOWN) + strlen(CMD_NXP);
			goto handled;

		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TWT_REPORT,
				    strlen(PRIV_CMD_TWT_REPORT)) == 0) {
			pdata = buf + strlen(CMD_NXP) +
				strlen(PRIV_CMD_TWT_REPORT);
			len = priv_cmd.used_len - strlen(PRIV_CMD_TWT_REPORT) -
			      strlen(CMD_NXP);
			len = woal_priv_twt_report(priv, pdata, len,
						   priv_cmd.total_len);
			len += strlen(PRIV_CMD_TWT_REPORT) + strlen(CMD_NXP);
			goto handled;
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
		} else if (strnicmp(buf + strlen(CMD_NXP),
				    PRIV_CMD_GET_CFG_CHAN_LIST,
				    strlen(PRIV_CMD_GET_CFG_CHAN_LIST)) == 0) {
			/* Get txpwrlimit */
			if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
				len = woal_priv_getcfgchanlist(
					priv, buf, priv_cmd.total_len);
			else
				len = snprintf(buf, CMD_BUF_LEN,
					       "CFG80211 is not enabled\n") +
				      1;
			goto handled;
#endif
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_LPM,
				    strlen(PRIV_CMD_LPM)) == 0) {
			/* Set/Get low power mode */
			len = woal_priv_set_get_lpm(priv, buf,
						    priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TP_STATE,
				    strlen(PRIV_CMD_TP_STATE)) == 0) {
			/* Set/Get TP accounting state */
			len = woal_priv_set_tp_state(priv, buf,
						     priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPS_CFG,
				    strlen(PRIV_CMD_IPS_CFG)) == 0) {
			len = woal_priv_ips_cfg(priv, buf, priv_cmd.total_len);
			goto handled;
		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SB_UUID,
				    strlen(PRIV_CMD_GET_SB_UUID)) == 0) {
			len = woal_priv_get_uuid(priv, buf, priv_cmd.total_len);
			goto handled;
		} else {
			PRINTM(MERROR,
			       "Unknown NXP PRIVATE command %s, ignored\n",
			       buf);
			ret = -EFAULT;
			goto done;
		}
	}
#ifdef STA_SUPPORT
	if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) ==
	    0) {
		pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_rssi_low_threshold(priv, pdata, MOAL_IOCTL_WAIT)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "SCAN-CFG", strlen("SCAN-CFG")) == 0) {
		PRINTM(MIOCTL, "Set SCAN CFG\n");
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_scan_cfg(priv, buf, priv_cmd.total_len)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
			ret = -EFAULT;
			goto done;
		}
		if (bss_info.media_connected) {
			if (MLAN_STATUS_SUCCESS !=
			    woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
						 &signal)) {
				ret = -EFAULT;
				goto done;
			}
			len = snprintf(buf, CMD_BUF_LEN, "%.32s rssi %d\n",
				       bss_info.ssid.ssid,
				       signal.bcn_rssi_avg) +
			      1;
		} else {
			len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
		}
	} else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
			ret = -EFAULT;
			goto done;
		}
		PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
		len = snprintf(buf, CMD_BUF_LEN, "LinkSpeed %d\n",
			       (int)(rate.rate * 500000 / 1000000)) +
		      1;
	} else
#endif
		if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN,
			       "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
			       priv->current_addr[0], priv->current_addr[1],
			       priv->current_addr[2], priv->current_addr[3],
			       priv->current_addr[4], priv->current_addr[5]) +
		      1;
	}
#ifdef STA_SUPPORT
	else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_get_powermode(priv, &power_mode)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "powermode = %d\n",
			       power_mode) +
		      1;
	} else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
			ret = -EFAULT;
			goto done;
		}
		priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
		PRINTM(MIOCTL, "Set Active Scan\n");
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
			ret = -EFAULT;
			goto done;
		}
		priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
		PRINTM(MIOCTL, "Set Passive Scan\n");
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
		pdata = buf + strlen("POWERMODE") + 1;
		if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
			if (MLAN_STATUS_SUCCESS !=
			    woal_set_powermode(priv, pdata)) {
				ret = -EFAULT;
				goto done;
			}
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "SETROAMING", strlen("SETROAMING")) == 0) {
		pdata = buf + strlen("SETROAMING") + 1;
#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
		if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
			goto done;
#endif
#endif
#ifdef STA_CFG80211
		if (*pdata == '1') {
			priv->roaming_enabled = MTRUE;
			PRINTM(MIOCTL, "Roaming enabled\n");
		} else if (*pdata == '0') {
			priv->roaming_enabled = MFALSE;
			PRINTM(MIOCTL, "Roaming disabled\n");
		}
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "ROAM", strlen("ROAM")) == 0) {
		pdata = buf + strlen("ROAM") + 1;
#ifdef STA_CFG80211
#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
		if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
			goto done;
#endif
#endif
#ifdef STA_CFG80211
		if (*pdata == '1') {
			priv->roaming_enabled = MTRUE;
			PRINTM(MIOCTL, "Roaming enabled\n");
		} else if (*pdata == '0') {
			priv->roaming_enabled = MFALSE;
			PRINTM(MIOCTL, "Roaming disabled\n");
		}
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "COUNTRYCODE", strlen("COUNTRYCODE")) == 0) {
		memset(country_code, 0, sizeof(country_code));
		if (MLAN_STATUS_SUCCESS !=
		    woal_get_countrycode(priv, country_code)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "%s\n", country_code) + 1;
	} else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
		copy_len = strlen(buf) - strlen("COUNTRY") - 1;
		if (copy_len > COUNTRY_CODE_LEN || copy_len <= 0) {
			PRINTM(MERROR, "Invalid country length\n");
			ret = -EFAULT;
			goto done;
		}
		memset(country_code, 0, sizeof(country_code));
		moal_memcpy_ext(priv->phandle, country_code,
				buf + strlen("COUNTRY") + 1, copy_len,
				COUNTRY_CODE_LEN);
		PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
		if (priv->phandle->params.cntry_txpwr) {
			if (MLAN_STATUS_SUCCESS !=
			    woal_request_country_power_table(priv,
							     country_code)) {
				ret = -EFAULT;
				goto done;
			}
		}
#ifdef STA_CFG80211
		if (IS_STA_CFG80211(cfg80211_wext)) {
			if (!moal_extflg_isset(priv->phandle,
					       EXT_DISABLE_REGD_BY_DRIVER)) {
				PRINTM(MIOCTL, "Notify country code=%s\n",
				       country_code);

				regulatory_hint(priv->wdev->wiphy,
						country_code);
				len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
				goto done;
			}
		}
#endif
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_region_code(priv, country_code)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) ==
		   0) {
		PRINTM(MIOCTL, "Set Combo Scan\n");
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_combo_scan(priv, buf, priv_cmd.total_len)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
		if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "Band %d\n", band) + 1;
	} else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
		pband = buf + strlen("SETBAND") + 1;
		if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#endif
	else if (strncmp(buf, "START", strlen("START")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#ifdef UAP_SUPPORT
	else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
		ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
		if (ret)
			goto done;
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
		ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
		if (ret)
			goto done;
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) {
		if (priv_cmd.total_len <= (int)strlen("AP_SET_CFG") + 1)
			goto done;
		pdata = buf + strlen("AP_SET_CFG") + 1;
		ret = woal_uap_set_ap_cfg(priv, pdata,
					  priv_cmd.total_len -
						  strlen("AP_SET_CFG") - 1);
		if (ret)
			goto done;
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) ==
		   0) {
		/* TODO Add STA list support */
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#endif
	else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
		/* it will be done by GUI */
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "SETSUSPENDMODE", strlen("SETSUSPENDMODE")) ==
		   0) {
		/* it will be done by GUI */
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "BTCOEXSCAN-START",
			   strlen("BTCOEXSCAN-START")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
		   0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#ifdef STA_SUPPORT
	else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) ==
		   0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_bg_scan(priv, buf, priv_cmd.total_len)) {
			ret = -EFAULT;
			goto done;
		}
		priv->bg_scan_start = MTRUE;
		priv->bg_scan_reported = MFALSE;
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
		if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
			if (MLAN_STATUS_FAILURE ==
			    woal_stop_bg_scan(priv, MOAL_NO_WAIT)) {
				ret = -EFAULT;
				goto done;
			}
			priv->bg_scan_start = MFALSE;
			priv->bg_scan_reported = MFALSE;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
		   0) {
#ifdef MEF_CFG_RX_FILTER
		ret = woal_set_rxfilter(priv, MTRUE);
		if (ret)
			goto done;
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) ==
		   0) {
#ifdef MEF_CFG_RX_FILTER
		ret = woal_set_rxfilter(priv, MFALSE);
		if (ret)
			goto done;
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#ifdef STA_CFG80211
	else if (strncmp(buf, "GET_EVENT", strlen("GET_EVENT")) == 0) {
		if (IS_STA_CFG80211(cfg80211_wext)) {
			if (priv->last_event & EVENT_BG_SCAN_REPORT)
				woal_inform_bss_from_scan_result(
					priv, NULL, MOAL_IOCTL_WAIT);
		}
		len = snprintf(buf, CMD_BUF_LEN, "EVENT=%d\n",
			       priv->last_event) +
		      1;
		priv->last_event = 0;
	} else if (strncmp(buf, "GET_802_11W", strlen("GET_802_11W")) == 0) {
		len = snprintf(buf, CMD_BUF_LEN, "802_11W=ENABLED\n") + 1;
	}
#endif /* STA_CFG80211 */
	else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
		pdata = buf + strlen("RXFILTER-ADD") + 1;
		if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
		   0) {
		pdata = buf + strlen("RXFILTER-REMOVE") + 1;
		if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
		pdata = buf + strlen("QOSINFO") + 1;
#ifdef STA_SUPPORT
		if (MLAN_STATUS_SUCCESS !=
		    woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
			ret = -EFAULT;
			goto done;
		}
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
		pdata = buf + strlen("SLEEPPD") + 1;
		if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "SET_AP_WPS_P2P_IE",
			   strlen("SET_AP_WPS_P2P_IE")) == 0) {
		pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1;
		/* Android cmd format:
		 * "SET_AP_WPS_P2P_IE 1"  -- beacon IE
		 * "SET_AP_WPS_P2P_IE 2"  -- proberesp IE
		 * "SET_AP_WPS_P2P_IE 4"  -- assocresp IE
		 */
#if defined(STA_CFG80211) && defined(UAP_CFG80211)
#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_ap_wps_p2p_ie(priv, (t_u8 *)pdata,
					   priv_cmd.used_len -
						   strlen("SET_AP_WPS_P2P_IE") -
						   1)) {
			ret = -EFAULT;
			goto done;
		}
#endif
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#endif
	else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) {
		memset(buf, 0x0, (size_t)priv_cmd.total_len);
		moal_memcpy_ext(priv->phandle, buf, priv->current_addr,
				ETH_ALEN, (t_u32)priv_cmd.total_len);
		len = ETH_ALEN;
	} else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) {
		/* TODO
		 * Just return '\0'
		 */
		memset(buf, 0x0, (size_t)priv_cmd.total_len);
		*buf = 0;
		len = 1;
	} else if (strnicmp(buf, "MIRACAST", strlen("MIRACAST")) == 0) {
		pdata = buf + strlen("MIRACAST");
		/* Android cmd format:
		 * "MIRACAST 0"  -- disabled
		 * "MIRACAST 1"  -- operating as source
		 * "MIRACAST 2"  -- operating as sink
		 */
#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_miracast_mode(priv, (t_u8 *)pdata,
					   priv_cmd.used_len -
						   strlen("MIRACAST"))) {
			ret = -EFAULT;
			goto done;
		}
#endif
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strnicmp(buf, "SCAN_TIMING", strlen("SCAN_TIMING")) == 0) {
#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_scan_chan_gap(priv, buf, priv_cmd.total_len)) {
			ret = -EFAULT;
			goto done;
		}
#endif
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strnicmp(buf, "BA_WSIZE_RX", strlen("BA_WSIZE_RX")) == 0) {
		pdata = buf + strlen("BA_WSIZE_RX") + 1;
		len = priv_cmd.total_len - strlen("BA_WSIZE_RX") - 1;
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_rx_ba_winsize(priv, pdata, len)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strnicmp(buf, "BA_WSIZE_TX", strlen("BA_WSIZE_TX")) == 0) {
		pdata = buf + strlen("BA_WSIZE_TX") + 1;
		len = priv_cmd.total_len - strlen("BA_WSIZE_TX") - 1;
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_tx_ba_winsize(priv, pdata, len)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "FAKE_SCAN_COMPLETE",
			   strlen("FAKE_SCAN_COMPLETE")) == 0) {
		pdata = buf + strlen("FAKE_SCAN_COMPLETE") + 1;
#ifdef STA_CFG80211
		if (*pdata == '1') {
			priv->fake_scan_complete = MTRUE;
			PRINTM(MIOCTL, "fake scan complete enabled\n");
		} else if (*pdata == '0') {
			priv->fake_scan_complete = MFALSE;
			PRINTM(MIOCTL, "fake scan complete disabled\n");
		}
#endif
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
#ifdef WIFI_DIRECT_SUPPORT
	else if (strncmp(buf, "P2P_PERIODIC_SLEEP",
			 strlen("P2P_PERIODIC_SLEEP")) == 0) {
		if (MLAN_STATUS_SUCCESS !=
		    woal_p2p_ps_cfg(priv, buf, priv_cmd.total_len)) {
			ret = -EFAULT;
			goto done;
		}
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	}
#endif
#endif
	else if (strncmp(buf, "WLS_BATCHING", strlen("WLS_BATCHING")) == 0) {
		/* TODO */
		len = snprintf(buf, CMD_BUF_LEN, "OK\n") + 1;
	} else if (strncmp(buf, "TDLS_CS_CHAN", strlen("TDLS_CS_CHAN")) == 0) {
		len = woal_priv_tdls_cs_chan(priv, buf, priv_cmd.total_len);
	}
#if defined(UAP_SUPPORT)
	else if (strncmp(buf, "P2P_ECSA", strlen("P2P_ECSA")) == 0) {
		len = woal_priv_p2p_ecsa(priv, buf, priv_cmd.total_len);
	}
#endif
	else if (strncmp(buf, "FAKEMAC", strlen("FAKEMAC")) == 0) {
		len = woal_priv_config_random_mac(priv, buf,
						  priv_cmd.total_len);
	} else if (strncmp(buf, "SETROAMOFFLOAD", strlen("SETROAMOFFLOAD")) ==
		   0) {
		len = woal_priv_set_roam_offload(priv, buf, priv_cmd.total_len);
	} else if (strncmp(buf, "SETROAMOFFLAPLIST",
			   strlen("SETROAMOFFLAPLIST")) == 0) {
		len = woal_priv_set_roam_offload_aplist(priv, buf,
							priv_cmd.total_len);
	} else if (strncmp(buf, "CFGROAMOFFLOAD", strlen("CFGROAMOFFLOAD")) ==
		   0) {
		len = woal_priv_roam_offload_cfg(priv, buf, priv_cmd.total_len);
	} else if (strncmp(buf, "SETROAMPASSPHRASE",
			   strlen("SETROAMPASSPHRASE")) == 0) {
		len = woal_priv_set_roam_passphrase(priv, buf,
						    priv_cmd.total_len);
	} else if (strncmp(buf, PRIV_CMD_CLOUD_KEEP_ALIVE_RX,
			   strlen(PRIV_CMD_CLOUD_KEEP_ALIVE_RX)) == 0) {
		len = woal_priv_cloud_keep_alive_rx(priv, buf,
						    priv_cmd.total_len);
	} else if (strncmp(buf, PRIV_CMD_CLOUD_KEEP_ALIVE,
			   strlen(PRIV_CMD_CLOUD_KEEP_ALIVE)) == 0) {
		len = woal_priv_cloud_keep_alive(priv, buf, priv_cmd.total_len);
	} else if (strnicmp(buf, PRIV_CMD_TX_RX_HISTOGRAM,
			    strlen(PRIV_CMD_TX_RX_HISTOGRAM)) == 0) {
		/* Get TX/RX histogram statistic */
		len = woal_priv_get_rx_tx_histogram(priv, buf,
						    priv_cmd.total_len);
		goto handled;
	} else if (strnicmp(buf, PRIV_CMD_GET_CHNRGPWR,
			    strlen(PRIV_CMD_GET_CHNRGPWR)) == 0) {
		/* Get chnrgpwr */
		len = woal_priv_get_chnrgpwr(priv, buf, priv_cmd.total_len);
		goto handled;
	} else if (strnicmp(buf, PRIV_CMD_GET_TXPWR_LIMIT,
			    strlen(PRIV_CMD_GET_TXPWR_LIMIT)) == 0) {
		/* Get txpwrlimit */
		len = woal_priv_get_txpwrlimit(priv, buf, priv_cmd.total_len);
		goto handled;
	} else {
		PRINTM(MIOCTL, "Unknown PRIVATE command: %s, ignored\n", buf);
		ret = -EFAULT;
		goto done;
	}

handled:
	PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);

	if (len > 0) {
		priv_cmd.used_len = len;
		if (priv_cmd.used_len <= priv_cmd.total_len) {
			memset(buf + priv_cmd.used_len, 0,
			       (size_t)(CMD_BUF_LEN - priv_cmd.used_len));
			if (copy_to_user((void __user *)cmd_buf, buf,
					 priv_cmd.total_len)) {
				PRINTM(MERROR,
				       "%s: failed to copy data to user buffer\n",
				       __FUNCTION__);
				ret = -EFAULT;
				goto done;
			}
			if (copy_to_user(req->ifr_data, &priv_cmd,
					 sizeof(android_wifi_priv_cmd))) {
				PRINTM(MERROR,
				       "%s: failed to copy command header to user buffer\n",
				       __FUNCTION__);
				ret = -EFAULT;
			}
		} else {
			PRINTM(MERROR,
			       "%s: the buffer supplied by appl is too small (supplied: %d, used: %d)\n",
			       __FUNCTION__, priv_cmd.total_len,
			       priv_cmd.used_len);
			ret = -EFAULT;
		}
	} else {
		ret = len;
	}

done:
	kfree(buf);
	LEAVE();
	return ret;
}

/********************************************************
			Global Functions
********************************************************/
/**
 *  @brief Create a brief scan resp to relay basic BSS info to the app layer
 *
 *  When the beacon/probe response has not been buffered, use the saved BSS
 *    information available to provide a minimum response for the application
 *    ioctl retrieval routines.  Include:
 *        - Timestamp
 *        - Beacon Period
 *        - Capabilities (including WMM Element if available)
 *        - SSID
 *
 *  @param ppbuffer  Output parameter: Buffer used to create basic scan rsp
 *  @param pbss_desc Pointer to a BSS entry in the scan table to create
 *                   scan response from for delivery to the application layer
 *
 *  @return          N/A
 */
void wlan_scan_create_brief_table_entry(t_u8 **ppbuffer,
					BSSDescriptor_t *pbss_desc)
{
	t_u8 *ptmp_buf = *ppbuffer;
	t_u8 tmp_ssid_hdr[2];
	t_u8 ie_len = 0;

	ENTER();

	moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->time_stamp,
			sizeof(pbss_desc->time_stamp),
			sizeof(pbss_desc->time_stamp));
	ptmp_buf += sizeof(pbss_desc->time_stamp);

	moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->beacon_period,
			sizeof(pbss_desc->beacon_period),
			sizeof(pbss_desc->beacon_period));
	ptmp_buf += sizeof(pbss_desc->beacon_period);

	moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->cap_info,
			sizeof(pbss_desc->cap_info),
			sizeof(pbss_desc->cap_info));
	ptmp_buf += sizeof(pbss_desc->cap_info);

	tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
	tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
	moal_memcpy_ext(NULL, ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr),
			sizeof(tmp_ssid_hdr));
	ptmp_buf += sizeof(tmp_ssid_hdr);

	moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->ssid.ssid,
			pbss_desc->ssid.ssid_len, pbss_desc->ssid.ssid_len);
	ptmp_buf += pbss_desc->ssid.ssid_len;

	if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
		ie_len = sizeof(IEEEtypes_Header_t) +
			 pbss_desc->wmm_ie.vend_hdr.len;
		moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->wmm_ie, ie_len,
				ie_len);
		ptmp_buf += ie_len;
	}

	if (pbss_desc->pwpa_ie) {
		if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
			ie_len = sizeof(IEEEtypes_Header_t) +
				 (*(pbss_desc->pwpa_ie)).vend_hdr.len;
			moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->pwpa_ie,
					ie_len, ie_len);
		}

		ptmp_buf += ie_len;
	}
	if (pbss_desc->prsn_ie) {
		if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
			ie_len = sizeof(IEEEtypes_Header_t) +
				 (*(pbss_desc->prsn_ie)).ieee_hdr.len;
			moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->prsn_ie,
					ie_len, ie_len);
		}

		ptmp_buf += ie_len;
	}
	*ppbuffer = ptmp_buf;
	LEAVE();
}

/**
 *  @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
 *         Descriptor for inclusion in the ioctl response to the user space
 *         application.
 *
 *
 *  @param pbss_desc   Pointer to a BSS entry in the scan table to form
 *                     scan response from for delivery to the application layer
 *  @param ppbuffer    Output parameter: Buffer used to output scan return
 * struct
 *  @param pspace_left Output parameter: Number of bytes available in the
 *                     response buffer.
 *
 *  @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
 */
int wlan_get_scan_table_ret_entry(BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer,
				  int *pspace_left)
{
	wlan_ioctl_get_scan_table_entry *prsp_entry;
	wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
	int space_needed;
	t_u8 *pcurrent;
	int variable_size;

	const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry);

	ENTER();

	pcurrent = *ppbuffer;

	/* The variable size returned is the stored beacon size */
	variable_size = pbss_desc->beacon_buf_size;

	/* If we stored a beacon and its size was zero, set the variable
	 *  size return value to the size of the brief scan response
	 *  wlan_scan_create_brief_table_entry creates.  Also used if
	 *  we are not configured to store beacons in the first place
	 */
	if (!variable_size) {
		variable_size = pbss_desc->ssid.ssid_len + 2;
		variable_size += (sizeof(pbss_desc->beacon_period) +
				  sizeof(pbss_desc->time_stamp) +
				  sizeof(pbss_desc->cap_info));
		if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
			variable_size += (sizeof(IEEEtypes_Header_t) +
					  pbss_desc->wmm_ie.vend_hdr.len);
		}

		if (pbss_desc->pwpa_ie) {
			if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
			    WPA_IE) {
				variable_size +=
					(sizeof(IEEEtypes_Header_t) +
					 (*(pbss_desc->pwpa_ie)).vend_hdr.len);
			}
		}

		if (pbss_desc->prsn_ie) {
			if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
			    RSN_IE) {
				variable_size +=
					(sizeof(IEEEtypes_Header_t) +
					 (*(pbss_desc->prsn_ie)).ieee_hdr.len);
			}
		}
	}

	space_needed = fixed_size + variable_size;

	PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n", space_needed,
	       *pspace_left);

	if (space_needed >= *pspace_left) {
		*pspace_left = 0;
		LEAVE();
		return -E2BIG;
	}

	*pspace_left -= space_needed;

	tmp_rsp_entry.fixed_field_length =
		(sizeof(tmp_rsp_entry) -
		 sizeof(tmp_rsp_entry.fixed_field_length) -
		 sizeof(tmp_rsp_entry.bss_info_length));

	moal_memcpy_ext(NULL, tmp_rsp_entry.fixed_fields.bssid,
			pbss_desc->mac_address,
			sizeof(prsp_entry->fixed_fields.bssid),
			sizeof(prsp_entry->fixed_fields.bssid));

	tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
	tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
	tmp_rsp_entry.fixed_fields.chan_load = pbss_desc->chan_load;
	tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
	tmp_rsp_entry.bss_info_length = variable_size;

	/*
	 *  Copy fixed fields to user space
	 */
	moal_memcpy_ext(NULL, pcurrent, &tmp_rsp_entry, fixed_size, fixed_size);
	pcurrent += fixed_size;

	if (pbss_desc->pbeacon_buf) {
		/*
		 *  Copy variable length elements to user space
		 */
		moal_memcpy_ext(NULL, pcurrent, pbss_desc->pbeacon_buf,
				pbss_desc->beacon_buf_size,
				pbss_desc->beacon_buf_size);

		pcurrent += pbss_desc->beacon_buf_size;
	} else {
		wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
	}

	*ppbuffer = pcurrent;

	LEAVE();

	return MLAN_STATUS_SUCCESS;
}

/**
 *  @brief ioctl function - entry point
 *
 *  @param dev      A pointer to net_device structure
 *  @param req      A pointer to ifreq structure
 *  @param cmd      Command
 *
 *  @return          0 --success, otherwise fail
 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
int woal_do_ioctl(struct net_device *dev, struct ifreq *req, void __user *data,
		  int cmd)
#else
int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
#endif

{
	int ret = 0;

	ENTER();

#ifdef CONFIG_COMPAT
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
	if (in_compat_syscall()) /* not implemented yet */
		return -EOPNOTSUPP;
#endif
#endif

	PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
	switch (cmd) {
	case WOAL_ANDROID_DEF_CMD:
		/** android default ioctl ID is SIOCDEVPRIVATE + 1 */
		ret = woal_android_priv_cmd(dev, req);
		break;
	case WOAL_CUSTOM_IE_CFG:
		ret = woal_custom_ie_ioctl(dev, req);
		break;
	case WOAL_MGMT_FRAME_TX:
		ret = woal_send_host_packet(dev, req);
		break;
	case WOAL_TDLS_CONFIG:
		ret = woal_tdls_config_ioctl(dev, req);
		break;
	case WOAL_ANDROID_PRIV_CMD:
		ret = woal_android_priv_cmd(dev, req);
		break;
	case WOAL_GET_BSS_TYPE:
		ret = woal_get_bss_type(dev, req);
		break;
	default:
#if defined(STA_WEXT)
#ifdef STA_SUPPORT
		ret = woal_wext_do_ioctl(dev, req, cmd);
#else
		ret = -EINVAL;
#endif
#else
		ret = -EINVAL;
#endif
		break;
	}

	LEAVE();
	return ret;
}
