/**
 *  @brief Set frequency/channel
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param fwrq                 A pointer to iw_freq structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_set_freq(struct net_device *dev, struct iw_request_info *info,
              struct iw_freq *fwrq, char *extra)
{
    moal_private *priv = (moal_private *) netdev_priv(dev);
    mlan_uap_bss_param sys_cfg, ap_cfg;
    int ret = 0, chan = 0, i = 0;

    ENTER();

    if (MLAN_STATUS_SUCCESS !=
        woal_set_get_sys_config(priv, MLAN_ACT_GET, &ap_cfg)) {
        PRINTM(MERROR, "Error getting AP confiruration\n");
        ret = -EFAULT;
        goto done;
    }
    i = ap_cfg.chan_list.num_of_chan;

    /* Initialize the invalid values so that the correct values below are
       downloaded to firmware */
    woal_set_sys_config_invalid_data(&sys_cfg);

    /* If setting by frequency, convert to a channel */
    if (fwrq->e == 1)
        chan = freq_to_chan(fwrq->m / 100000);
    else
        chan = fwrq->m;
    if (chan > 0 && chan < MAX_CHANNEL)
        sys_cfg.channel = chan;
    else {
        ret = -EINVAL;
        goto done;
    }
    for (i = 0; i < ap_cfg.chan_list.num_of_chan; i++)
        if (ap_cfg.chan_list.chan[i] == chan)
            break;
    if (i == ap_cfg.chan_list.num_of_chan) {
        PRINTM(MERROR, "Channel %d is not supported\n", chan);
        ret = -EINVAL;
        goto done;
    }

    if (MLAN_STATUS_SUCCESS !=
        woal_set_get_sys_config(priv, MLAN_ACT_SET, &sys_cfg)) {
        PRINTM(MERROR, "Error setting AP confiruration\n");
        ret = -EFAULT;
        goto done;
    }

  done:
    LEAVE();
    return ret;
}
/**
 *  @brief Get frequency and channel
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param fwrq                 A pointer to iw_freq structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_get_freq(struct net_device *dev, struct iw_request_info *info,
	      struct iw_freq *fwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param ap_cfg;
	t_u8 band = 0;
	int ret = 0;

	ENTER();

	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   &ap_cfg)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		LEAVE();
		return -EFAULT;
	}
	band = ap_cfg.band_cfg & BAND_CONFIG_5GHZ;
	fwrq->i = (long)ap_cfg.channel;
	fwrq->m = (long)(channel_to_frequency(ap_cfg.channel, band)) * 100000;
	fwrq->e = 1;

	LEAVE();
	return ret;
}
/**
 *  @brief Get current essid
 *
 *  @param dev      A pointer to net_device structure
 *  @param info     A pointer to iw_request_info structure
 *  @param dwrq     A pointer to iw_point structure
 *  @param extra    A pointer to extra data buf
 *
 *  @return         0--success, otherwise fail
 */
static int
woal_get_essid(struct net_device *dev, struct iw_request_info *info,
	       struct iw_point *dwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param ap_cfg;

	ENTER();

	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   &ap_cfg)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		LEAVE();
		return -EFAULT;
	}

	if (priv->bss_started) {
		dwrq->length = MIN(dwrq->length, ap_cfg.ssid.ssid_len);
		memcpy(extra, ap_cfg.ssid.ssid, dwrq->length);
	} else
		dwrq->length = 0;

	dwrq->flags = 1;

	LEAVE();
	return 0;
}
/**
 *  @brief Set AP configuration
 *
 *  @param priv     A pointer to moal_private structure
 *  @param wrq      A pointer to user data
 *
 *  @return         0 --success, otherwise fail
 */
static int
woal_uap_set_ap_cfg(moal_private * priv, struct iwreq *wrq)
{
    int ret = 0;
    static t_s8 buf[MAX_BUF_LEN];
    mlan_uap_bss_param sys_config;
    int restart = 0;

    ENTER();

#define MIN_AP_CFG_CMD_LEN   16 /* strlen("ASCII_CMD=AP_CFG") */
    if ((wrq->u.data.length - 1) <= MIN_AP_CFG_CMD_LEN) {
        PRINTM(MERROR, "Invalid length of command\n");
        ret = -EINVAL;
        goto done;
    }

    memset(buf, 0, MAX_BUF_LEN);
    memcpy(buf, wrq->u.data.pointer, wrq->u.data.length);

    /* Initialize the invalid values so that the correct values below are
       downloaded to firmware */
    woal_set_sys_config_invalid_data(&sys_config);

    /* Setting the default values */
    sys_config.channel = 6;
    sys_config.preamble_type = 0;

    if ((ret = woal_uap_ap_cfg_parse_data(&sys_config, buf)))
        goto done;

    /* If BSS already started stop it first and restart after changing the
       setting */
    if (priv->bss_started == MTRUE) {
        if ((ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)))
            goto done;
        restart = 1;
    }

    if (MLAN_STATUS_SUCCESS !=
        woal_set_get_sys_config(priv, MLAN_ACT_SET, &sys_config)) {
        ret = -EFAULT;
        goto done;
    }

    /* Start the BSS after successful configuration */
    if (restart)
        ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);

  done:
    LEAVE();
    return ret;
}
/**
 *  @brief Set essid
 *
 *  @param dev          A pointer to net_device structure
 *  @param info         A pointer to iw_request_info structure
 *  @param dwrq         A pointer to iw_point structure
 *  @param extra        A pointer to extra data buf
 *
 *  @return             0--success, otherwise fail
 */
static int
woal_set_essid(struct net_device *dev, struct iw_request_info *info,
	       struct iw_point *dwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param sys_cfg;
	int ret = 0;

	ENTER();

	/* Check the size of the string */
	if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
		ret = -E2BIG;
		goto done;
	}

	/* Initialize the invalid values so that the correct values below are
	   downloaded to firmware */
	woal_set_sys_config_invalid_data(&sys_cfg);

	/* Set the SSID */
#if WIRELESS_EXT > 20
	sys_cfg.ssid.ssid_len = dwrq->length;
#else
	sys_cfg.ssid.ssid_len = dwrq->length - 1;
#endif

	memcpy(sys_cfg.ssid.ssid, extra,
	       MIN(sys_cfg.ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
	if (!sys_cfg.ssid.ssid_len || sys_cfg.ssid.ssid[0] < 0x20) {
		PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
		ret = -EINVAL;
		goto done;
	}
	PRINTM(MINFO, "Requested new SSID = %s\n",
	       (sys_cfg.ssid.ssid_len > 0) ?
	       (char *)sys_cfg.ssid.ssid : "NULL");

	/* Set AP configuration */
	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_SET,
							   MOAL_IOCTL_WAIT,
							   &sys_cfg)) {
		PRINTM(MERROR, "Error setting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

done:
	LEAVE();
	return ret;
}
/**
 *  @brief Get frequency and channel
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param fwrq                 A pointer to iw_freq structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_get_freq(struct net_device *dev, struct iw_request_info *info,
              struct iw_freq *fwrq, char *extra)
{
    moal_private *priv = (moal_private *) netdev_priv(dev);
    mlan_uap_bss_param ap_cfg;
    int ret = 0;

    ENTER();

    if (MLAN_STATUS_SUCCESS !=
        woal_set_get_sys_config(priv, MLAN_ACT_GET, &ap_cfg)) {
        PRINTM(MERROR, "Error getting AP confiruration\n");
        LEAVE();
        return -EFAULT;
    }

    fwrq->i = (long) ap_cfg.channel;
    fwrq->m = (long) (chan_to_freq[ap_cfg.channel - 1]) * 100000;
    fwrq->e = 1;

    LEAVE();
    return ret;
}
/**
 *  @brief Get encryption key
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param dwrq                 A pointer to iw_point structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_get_encode(struct net_device *dev, struct iw_request_info *info,
		struct iw_point *dwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	int index = (dwrq->flags & IW_ENCODE_INDEX);
	wep_key *pkey = NULL;
	mlan_uap_bss_param ap_cfg;
	int ret = 0;

	ENTER();
	if (index < 0 || index > 4) {
		PRINTM(MERROR, "Key index #%d out of range\n", index);
		ret = -EINVAL;
		goto done;
	}
	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   &ap_cfg)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

	dwrq->flags = 0;
	/*
	 * Check encryption mode
	 */
	switch (ap_cfg.auth_mode) {
	case MLAN_AUTH_MODE_OPEN:
		dwrq->flags = IW_ENCODE_OPEN;
		break;
	case MLAN_AUTH_MODE_SHARED:
	case MLAN_AUTH_MODE_NETWORKEAP:
		dwrq->flags = IW_ENCODE_RESTRICTED;
		break;
	default:
		dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
		break;
	}

	switch (ap_cfg.protocol) {
	case PROTOCOL_NO_SECURITY:
		dwrq->flags |= IW_ENCODE_DISABLED;
		break;
	case PROTOCOL_STATIC_WEP:
		if (ap_cfg.wep_cfg.key0.is_default)
			pkey = &ap_cfg.wep_cfg.key0;
		else if (ap_cfg.wep_cfg.key1.is_default)
			pkey = &ap_cfg.wep_cfg.key1;
		else if (ap_cfg.wep_cfg.key2.is_default)
			pkey = &ap_cfg.wep_cfg.key2;
		else if (ap_cfg.wep_cfg.key3.is_default)
			pkey = &ap_cfg.wep_cfg.key3;
		if (pkey) {
			dwrq->flags |= (pkey->key_index + 1);
			dwrq->length = pkey->length;
			memcpy(extra, pkey->key, pkey->length);
			dwrq->flags &= ~IW_ENCODE_DISABLED;
		} else {
			ret = -EFAULT;
		}
		break;
	case PROTOCOL_WPA:
	case PROTOCOL_WPA2:
	case PROTOCOL_WPA2_MIXED:
		memcpy(extra, ap_cfg.wpa_cfg.passphrase, ap_cfg.wpa_cfg.length);
		dwrq->length = ap_cfg.wpa_cfg.length;
		dwrq->flags |= 1;
		dwrq->flags &= ~IW_ENCODE_DISABLED;
		break;
	default:
		dwrq->flags &= ~IW_ENCODE_DISABLED;
		break;
	}
	dwrq->flags |= IW_ENCODE_NOKEY;

done:
	LEAVE();
	return ret;
}
/**
 *  @brief Set encryption key
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param dwrq                 A pointer to iw_point structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_set_encode(struct net_device *dev, struct iw_request_info *info,
		struct iw_point *dwrq, char *extra)
{
	int ret = 0;
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
	wep_key *pkey = NULL;
	int key_index = 0;

	ENTER();

	/* Check index */
	key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
	if (key_index > 3) {
		PRINTM(MERROR, "Key index #%d out of range\n", key_index);
		ret = -EINVAL;
		goto done;
	}

	ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
	if (ap_cfg == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
	if (sys_cfg == NULL) {
		ret = -ENOMEM;
		goto done;
	}

	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   ap_cfg)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

	/* Initialize the invalid values so that the correct values below are
	   downloaded to firmware */
	woal_set_sys_config_invalid_data(sys_cfg);
	sys_cfg->wep_cfg.key0.key_index = 0;
	sys_cfg->wep_cfg.key1.key_index = 1;
	sys_cfg->wep_cfg.key2.key_index = 2;
	sys_cfg->wep_cfg.key3.key_index = 3;

	if (key_index >= 0 && key_index <= 3) {
		if (key_index == 0)
			pkey = &sys_cfg->wep_cfg.key0;
		else if (key_index == 1)
			pkey = &sys_cfg->wep_cfg.key1;
		else if (key_index == 2)
			pkey = &sys_cfg->wep_cfg.key2;
		else if (key_index == 3)
			pkey = &sys_cfg->wep_cfg.key3;
	}

	if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
		if (dwrq->length > MAX_WEP_KEY_SIZE) {
			PRINTM(MERROR, "Key length (%d) out of range\n",
			       dwrq->length);
			ret = -E2BIG;
			goto done;
		}
		if (key_index < 0) {
			/* Get current default key index */
			if (ap_cfg->wep_cfg.key0.is_default)
				pkey = &sys_cfg->wep_cfg.key0;
			if (ap_cfg->wep_cfg.key1.is_default)
				pkey = &sys_cfg->wep_cfg.key1;
			if (ap_cfg->wep_cfg.key2.is_default)
				pkey = &sys_cfg->wep_cfg.key2;
			if (ap_cfg->wep_cfg.key3.is_default)
				pkey = &sys_cfg->wep_cfg.key3;
		}

		sys_cfg->protocol = PROTOCOL_STATIC_WEP;
		memcpy(pkey->key, extra, dwrq->length);
		/* Set the length */
		if (dwrq->length > MIN_WEP_KEY_SIZE)
			pkey->length = MAX_WEP_KEY_SIZE;
		else
			pkey->length = MIN_WEP_KEY_SIZE;
		/* Set current key index as default */
		pkey->is_default = MTRUE;
	} else {
		/*
		 * No key provided so it is either enable key,
		 * on or off
		 */
		if (dwrq->flags & IW_ENCODE_DISABLED) {
			PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
			sys_cfg->protocol = PROTOCOL_NO_SECURITY;
		} else {
			/*
			 * iwconfig mlanX key [n]
			 * iwconfig mlanX key on
			 * Do we want to just set the transmit key index ?
			 */
			if (key_index < 0) {
				PRINTM(MINFO,
				       "*** iwconfig mlanX key on ***\n");
			} else {
				/* Get current key configuration at key_index */
				if (key_index == 0)
					memcpy(pkey, &ap_cfg->wep_cfg.key0,
					       sizeof(wep_key));
				if (key_index == 1)
					memcpy(pkey, &ap_cfg->wep_cfg.key1,
					       sizeof(wep_key));
				if (key_index == 2)
					memcpy(pkey, &ap_cfg->wep_cfg.key2,
					       sizeof(wep_key));
				if (key_index == 3)
					memcpy(pkey, &ap_cfg->wep_cfg.key3,
					       sizeof(wep_key));
				/* Set current key index as default */
				pkey->is_default = MTRUE;
			}
		}
	}
	if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
		switch (dwrq->flags & 0xf000) {
		case IW_ENCODE_RESTRICTED:
			/* iwconfig mlanX restricted key [1] */
			sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
			PRINTM(MINFO, "Auth mode restricted!\n");
			break;
		case IW_ENCODE_OPEN:
			/* iwconfig mlanX key [2] open */
			sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
			PRINTM(MINFO, "Auth mode open!\n");
			break;
		case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
		default:
			/* iwconfig mlanX key [2] open restricted */
			PRINTM(MINFO, "Auth mode auto!\n");
			break;
		}
	}

	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_SET,
							   MOAL_IOCTL_WAIT,
							   sys_cfg)) {
		PRINTM(MERROR, "Error setting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

done:
	if (sys_cfg)
		kfree(sys_cfg);
	if (ap_cfg)
		kfree(ap_cfg);
	LEAVE();
	return ret;
}
/**
 *  @brief Get Range Info
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param dwrq                 A pointer to iw_point structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_get_range(struct net_device *dev, struct iw_request_info *info,
	       struct iw_point *dwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param ap_cfg;
	struct iw_range *range = (struct iw_range *)extra;
	t_u8 band = 0;
	int i;

	ENTER();

	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   &ap_cfg)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		LEAVE();
		return -EFAULT;
	}
	dwrq->length = sizeof(struct iw_range);
	memset(range, 0, sizeof(struct iw_range));

	range->min_nwid = 0;
	range->max_nwid = 0;

	range->num_bitrates = MAX_DATA_RATES;
	for (i = 0; i < MIN(MAX_DATA_RATES, IW_MAX_BITRATES) &&
	     ap_cfg.rates[i]; i++) {
		range->bitrate[i] = (ap_cfg.rates[i] & 0x7f) * 500000;
	}
	range->num_bitrates = i;
	PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n",
	       IW_MAX_BITRATES, range->num_bitrates);

	range->num_frequency = MIN(ap_cfg.num_of_chan, IW_MAX_FREQUENCIES);

	for (i = 0; i < range->num_frequency; i++) {
		range->freq[i].i = (long)ap_cfg.chan_list[i].chan_number;
		band = ap_cfg.chan_list[i].band_config_type & BAND_CONFIG_5GHZ;
		range->freq[i].m =
			(long)channel_to_frequency(ap_cfg.chan_list[i].
						   chan_number, band) * 100000;
		range->freq[i].e = 1;
	}

	PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
	       IW_MAX_FREQUENCIES, range->num_frequency);

	range->num_channels = range->num_frequency;

	woal_sort_channels(&range->freq[0], range->num_frequency);

	/*
	 * Set an indication of the max TCP throughput in bit/s that we can
	 * expect using this interface
	 */
	if (i > 2)
		range->throughput = 5000 * 1000;
	else
		range->throughput = 1500 * 1000;

	range->min_rts = MLAN_RTS_MIN_VALUE;
	range->max_rts = MLAN_RTS_MAX_VALUE;
	range->min_frag = MLAN_FRAG_MIN_VALUE;
	range->max_frag = MLAN_FRAG_MAX_VALUE;

	range->encoding_size[0] = 5;
	range->encoding_size[1] = 13;
	range->num_encoding_sizes = 2;
	range->max_encoding_tokens = 4;

/** Minimum power period */
#define IW_POWER_PERIOD_MIN 1000000	/* 1 sec */
/** Maximum power period */
#define IW_POWER_PERIOD_MAX 120000000	/* 2 min */
/** Minimum power timeout value */
#define IW_POWER_TIMEOUT_MIN 1000	/* 1 ms */
/** Maximim power timeout value */
#define IW_POWER_TIMEOUT_MAX 1000000	/* 1 sec */

	/* Power Management duration & timeout */
	range->min_pmp = IW_POWER_PERIOD_MIN;
	range->max_pmp = IW_POWER_PERIOD_MAX;
	range->min_pmt = IW_POWER_TIMEOUT_MIN;
	range->max_pmt = IW_POWER_TIMEOUT_MAX;
	range->pmp_flags = IW_POWER_PERIOD;
	range->pmt_flags = IW_POWER_TIMEOUT;
	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;

	/*
	 * Minimum version we recommend
	 */
	range->we_version_source = 15;

	/*
	 * Version we are compiled with
	 */
	range->we_version_compiled = WIRELESS_EXT;

	range->retry_capa = IW_RETRY_LIMIT;
	range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;

	range->min_retry = MLAN_TX_RETRY_MIN;
	range->max_retry = MLAN_TX_RETRY_MAX;

#if (WIRELESS_EXT >= 18)
	if (ap_cfg.protocol & PROTOCOL_WPA)
		range->enc_capa |= IW_ENC_CAPA_WPA;
	if (ap_cfg.protocol & PROTOCOL_WPA2)
		range->enc_capa |= IW_ENC_CAPA_WPA2;
	if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
	    ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP ||
	    ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP)
		range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
	if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
	    ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP ||
	    ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP)
		range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
#endif

	LEAVE();
	return 0;
}
/** @brief Set authentication mode parameters
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param vwrq                 A pointer to iw_param structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_set_auth(struct net_device *dev, struct iw_request_info *info,
	      struct iw_param *vwrq, char *extra)
{
	int ret = 0;
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param sys_cfg;

	ENTER();

	/* Initialize the invalid values so that the correct values below are
	   downloaded to firmware */
	woal_set_sys_config_invalid_data(&sys_cfg);

	switch (vwrq->flags & IW_AUTH_INDEX) {
	case IW_AUTH_CIPHER_PAIRWISE:
		/* Rest are not supported now */
		if (vwrq->value & IW_AUTH_CIPHER_NONE) ;
		else if (vwrq->value & IW_AUTH_CIPHER_WEP40) ;
		else if (vwrq->value & IW_AUTH_CIPHER_WEP104) ;
		else if (vwrq->value == IW_AUTH_CIPHER_TKIP) {
			sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
			sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
			priv->pairwise_cipher = CIPHER_TKIP;
			if (!priv->uap_key_mgmt)
				priv->uap_key_mgmt = KEY_MGMT_PSK;
			PRINTM(MINFO, "Set Auth Cipher TKIP\n");
		} else if (vwrq->value == IW_AUTH_CIPHER_CCMP) {
			sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
			sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
			priv->pairwise_cipher = CIPHER_AES_CCMP;
			if (!priv->uap_key_mgmt)
				priv->uap_key_mgmt = KEY_MGMT_PSK;
			PRINTM(MINFO, "Set Auth Cipher CCMP\n");
		} else if (vwrq->value ==
			   (IW_AUTH_CIPHER_TKIP | IW_AUTH_CIPHER_CCMP)) {
			sys_cfg.wpa_cfg.pairwise_cipher_wpa =
				(CIPHER_TKIP | CIPHER_AES_CCMP);
			sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
				(CIPHER_TKIP | CIPHER_AES_CCMP);
			priv->pairwise_cipher = (CIPHER_TKIP | CIPHER_AES_CCMP);
			if (!priv->uap_key_mgmt)
				priv->uap_key_mgmt = KEY_MGMT_PSK;
			PRINTM(MINFO, "Set Auth Cipher TKIP + CCMP\n");
		}
		break;
	case IW_AUTH_CIPHER_GROUP:
		/* Rest are not supported now */
		if (vwrq->value & IW_AUTH_CIPHER_NONE) ;
		else if (vwrq->value & IW_AUTH_CIPHER_WEP40) ;
		else if (vwrq->value & IW_AUTH_CIPHER_WEP104) ;
		else if (vwrq->value & IW_AUTH_CIPHER_TKIP) {
			sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
			priv->group_cipher = CIPHER_TKIP;
			if (!priv->uap_key_mgmt)
				priv->uap_key_mgmt = KEY_MGMT_PSK;
			PRINTM(MINFO, "Set Auth Cipher TKIP\n");
		} else if (vwrq->value & IW_AUTH_CIPHER_CCMP) {
			sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
			priv->group_cipher = CIPHER_AES_CCMP;
			if (!priv->uap_key_mgmt)
				priv->uap_key_mgmt = KEY_MGMT_PSK;
			PRINTM(MINFO, "Set Auth Cipher CCMP\n");
		}
		break;
	case IW_AUTH_80211_AUTH_ALG:
		switch (vwrq->value) {
		case IW_AUTH_ALG_SHARED_KEY:
			PRINTM(MINFO, "Auth mode shared key!\n");
			sys_cfg.auth_mode = MLAN_AUTH_MODE_SHARED;
			break;
		case IW_AUTH_ALG_LEAP:
			break;
		case IW_AUTH_ALG_OPEN_SYSTEM:
			PRINTM(MINFO, "Auth mode open!\n");
			sys_cfg.auth_mode = MLAN_AUTH_MODE_OPEN;
			break;
		default:
			PRINTM(MINFO, "Auth mode auto!\n");
			break;
		}
		break;
	case IW_AUTH_WPA_VERSION:
		switch (vwrq->value) {
		case IW_AUTH_WPA_VERSION_DISABLED:
			sys_cfg.protocol = PROTOCOL_NO_SECURITY;
			break;
		case IW_AUTH_WPA_VERSION_WPA:
			sys_cfg.protocol = PROTOCOL_WPA;
			break;
		case IW_AUTH_WPA_VERSION_WPA2:
			sys_cfg.protocol = PROTOCOL_WPA2;
			break;
		case IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2:
			sys_cfg.protocol = PROTOCOL_WPA2_MIXED;
			break;
		default:
			break;
		}
		priv->uap_protocol = sys_cfg.protocol;
		break;
	case IW_AUTH_KEY_MGMT:
		switch (vwrq->value) {
		case IW_AUTH_KEY_MGMT_802_1X:
			sys_cfg.key_mgmt |= KEY_MGMT_EAP;
			priv->uap_key_mgmt |= KEY_MGMT_EAP;
			break;
		case IW_AUTH_KEY_MGMT_PSK:
			sys_cfg.key_mgmt |= KEY_MGMT_PSK;
			priv->uap_key_mgmt |= KEY_MGMT_PSK;
			break;
		default:
			break;
		}
		break;
	case IW_AUTH_WPA_ENABLED:
	case IW_AUTH_TKIP_COUNTERMEASURES:
	case IW_AUTH_DROP_UNENCRYPTED:
	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
	case IW_AUTH_ROAMING_CONTROL:
	case IW_AUTH_PRIVACY_INVOKED:
	default:
		LEAVE();
		return -EOPNOTSUPP;	/* No AP configuration */
	}
	if (!sys_cfg.key_mgmt)
		sys_cfg.key_mgmt = priv->uap_key_mgmt;
	if (sys_cfg.key_mgmt & KEY_MGMT_PSK)
		sys_cfg.key_mgmt_operation |= 0x01;
	if (sys_cfg.key_mgmt & KEY_MGMT_EAP)
		sys_cfg.key_mgmt_operation |= 0x03;
	if (!sys_cfg.protocol)
		sys_cfg.protocol = priv->uap_protocol;

	/* Set AP configuration */
	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_SET,
							   MOAL_IOCTL_WAIT,
							   &sys_cfg)) {
		PRINTM(MERROR, "Error setting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

done:
	LEAVE();
	return 0;
}
/** 
 *  @brief  Extended version of encoding configuration 
 *
 *  @param dev          A pointer to net_device structure
 *  @param info         A pointer to iw_request_info structure
 *  @param dwrq         A pointer to iw_point structure
 *  @param extra        A pointer to extra data buf
 *
 *  @return              0 --success, otherwise fail
 */
static int
woal_set_encode_ext(struct net_device *dev,
                    struct iw_request_info *info,
                    struct iw_point *dwrq, char *extra)
{
    struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
    moal_private *priv = (moal_private *) netdev_priv(dev);
    int key_index;
    t_u8 *pkey_material = NULL;
    mlan_ioctl_req *req = NULL;
    mlan_ds_sec_cfg *sec = NULL;
    mlan_uap_bss_param sys_cfg;
    wep_key *pwep_key = NULL;
    int ret = 0;

    ENTER();

    key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
    if (key_index < 0 || key_index > 3) {
        ret = -EINVAL;
        goto done;
    }
    if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
        ret = -EINVAL;
        goto done;
    }

    /* Initialize the invalid values so that the correct values below are
       downloaded to firmware */
    woal_set_sys_config_invalid_data(&sys_cfg);

    pkey_material = (t_u8 *) (ext + 1);
    /* Disable Key */
    if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
        sys_cfg.protocol = PROTOCOL_NO_SECURITY;
    } else if (ext->alg == IW_ENCODE_ALG_WEP) {
        sys_cfg.protocol = PROTOCOL_STATIC_WEP;
        /* Set WEP key */
        switch (key_index) {
        case 0:
            pwep_key = &sys_cfg.wep_cfg.key0;
            break;
        case 1:
            pwep_key = &sys_cfg.wep_cfg.key1;
            break;
        case 2:
            pwep_key = &sys_cfg.wep_cfg.key2;
            break;
        case 3:
            pwep_key = &sys_cfg.wep_cfg.key3;
            break;
        }
        pwep_key->key_index = key_index;
        pwep_key->is_default = MTRUE;
        pwep_key->length = ext->key_len;
        memcpy(pwep_key->key, pkey_material, ext->key_len);
    } else {
        sys_cfg.protocol = PROTOCOL_WPA2_MIXED;
        if (ext->alg == IW_ENCODE_ALG_TKIP) {
            sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
            sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
            sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
        }
        if (ext->alg == IW_ENCODE_ALG_CCMP) {
            sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
            sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
            sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
        }
        /* Set WPA key */
        req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
        if (req == NULL) {
            ret = -ENOMEM;
            goto done;
        }
        sec = (mlan_ds_sec_cfg *) req->pbuf;
        sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
        req->req_id = MLAN_IOCTL_SEC_CFG;
        req->action = MLAN_ACT_SET;
        sec->param.encrypt_key.key_len = ext->key_len;
        sec->param.encrypt_key.key_index = key_index;
        memcpy(sec->param.encrypt_key.key_material, pkey_material,
               ext->key_len);
        memcpy(sec->param.encrypt_key.mac_addr, ext->addr.sa_data, ETH_ALEN);
        if ((ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && !key_index) {
            key_index = 1;
            sec->param.encrypt_key.key_index = key_index;
            PRINTM(MWARN, "Key index changed for GTK: %ld\n",
                   sec->param.encrypt_key.key_index);
        }
        if (MLAN_STATUS_SUCCESS !=
            woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
            ret = -EFAULT;
        }
    }
    if (MLAN_STATUS_SUCCESS !=
        woal_set_get_sys_config(priv, MLAN_ACT_SET, &sys_cfg)) {
        PRINTM(MERROR, "Error setting AP confiruration\n");
        ret = -EFAULT;
        goto done;
    }

  done:
    if (req)
        kfree(req);
    LEAVE();
    return ret;
}
/**
 *  @brief Set IE
 *
 *  Pass an opaque block of data, expected to be IEEE IEs, to the driver 
 *    for eventual passthrough to the firmware in an associate/join 
 *    (and potentially start) command.
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param dwrq                 A pointer to iw_point structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
                struct iw_point *dwrq, char *extra)
{
    int ret = 0;
    moal_private *priv = (moal_private *) netdev_priv(dev);
    mlan_ds_misc_cfg *misc = NULL;
    mlan_ioctl_req *req = NULL;
    mlan_uap_bss_param sys_cfg;
    IEEEtypes_Header_t *ie_hdr = NULL;
    IEEEtypes_Header_t *ie_hdr1 = NULL;

    ENTER();

    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;
    misc = (mlan_ds_misc_cfg *) req->pbuf;
    misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
    misc->param.cust_ie.type = 0x0169;  /* TLV_TYPE_MGMT_IE */
    req->action = MLAN_ACT_SET;

    if (dwrq->length > MAX_IE_SIZE) {
        ret = -EFAULT;
        goto done;
    }
    misc->param.cust_ie.len = dwrq->length + sizeof(custom_ie) - MAX_IE_SIZE;
    misc->param.cust_ie.ie_data_list[0].ie_index = 0;
    misc->param.cust_ie.ie_data_list[0].mgmt_subtype_mask = 0xffff;
    misc->param.cust_ie.ie_data_list[0].ie_length = dwrq->length;
    memcpy(misc->param.cust_ie.ie_data_list[0].ie_buffer, extra, dwrq->length);

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

    /* Initialize the invalid values so that the correct values below are
       downloaded to firmware */
    woal_set_sys_config_invalid_data(&sys_cfg);
    ie_hdr = (IEEEtypes_Header_t *) extra;

    if (ie_hdr->element_id == WPA_IE)
        sys_cfg.protocol = PROTOCOL_WPA;
    else if (ie_hdr->element_id == RSN_IE)
        sys_cfg.protocol = PROTOCOL_WPA2;
    if (dwrq->length > (ie_hdr->len + sizeof(IEEEtypes_Header_t))) {
        ie_hdr1 = (IEEEtypes_Header_t *) ((t_u8 *) extra +
                                          ie_hdr->len +
                                          sizeof(IEEEtypes_Header_t));
        if ((ie_hdr->element_id == WPA_IE && ie_hdr1->element_id == RSN_IE) ||
            (ie_hdr->element_id == RSN_IE && ie_hdr1->element_id == WPA_IE)) {
            sys_cfg.protocol = PROTOCOL_WPA2_MIXED;
        }
    }

    if (sys_cfg.protocol) {
        if (MLAN_STATUS_SUCCESS !=
            woal_set_get_sys_config(priv, MLAN_ACT_SET, &sys_cfg)) {
            PRINTM(MERROR, "Error setting AP confiruration\n");
            ret = -EFAULT;
            goto done;
        }
    }

  done:
    if (req)
        kfree(req);

    LEAVE();
    return ret;
}
/**
 * @brief initialize AP or GO bss config
 *
 * @param priv            A pointer to moal private structure
 * @param params          A pointer to beacon_parameters structure 
 * @return                0 -- success, otherwise fail
 */
static int
woal_cfg80211_beacon_config(moal_private * priv,
                            struct beacon_parameters *params)
#endif
{
    int ret = 0;
    mlan_uap_bss_param sys_config;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
    int i = 0;
#else
    const t_u8 *ssid_ie = NULL;
    struct ieee80211_mgmt *head = NULL;
    t_u16 capab_info = 0;
#endif
    t_u8 Rates_BG[13] =
        { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
        0x60, 0x6c, 0
    };
    t_u8 Rates_A[9] = { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
    t_u8 chan2Offset = 0;
#ifdef WIFI_DIRECT_SUPPORT
    t_u8 Rates_WFD[9] = { 0x8c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 };
#endif

    ENTER();

    if (params == NULL) {
        ret = -EFAULT;
        goto done;
    }

    if (priv->bss_type != MLAN_BSS_TYPE_UAP
#ifdef WIFI_DIRECT_SUPPORT
        && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
#endif
        ) {
        ret = -EFAULT;
        goto done;
    }

    /* Initialize the uap bss values which are uploaded from firmware */
    if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
                                                       MLAN_ACT_GET,
                                                       MOAL_IOCTL_WAIT,
                                                       &sys_config)) {
        PRINTM(MERROR, "Error getting AP confiruration\n");
        ret = -EFAULT;
        goto done;
    }

    /* Setting the default values */
    sys_config.channel = 6;
    sys_config.preamble_type = 0;

    if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
        if (params->beacon_interval)
            sys_config.beacon_period = params->beacon_interval;
#else
        if (params->interval)
            sys_config.beacon_period = params->interval;
#endif
        if (params->dtim_period)
            sys_config.dtim_period = params->dtim_period;
    }
    if (priv->channel) {
        memset(sys_config.rates, 0, sizeof(sys_config.rates));
        sys_config.channel = priv->channel;
        if (priv->channel <= MAX_BG_CHANNEL) {
            sys_config.band_cfg = BAND_CONFIG_2G;
#ifdef WIFI_DIRECT_SUPPORT
            if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
                memcpy(sys_config.rates, Rates_WFD, sizeof(Rates_WFD));
            else
#endif
                memcpy(sys_config.rates, Rates_BG, sizeof(Rates_BG));
        } else {
            sys_config.band_cfg = BAND_CONFIG_5G;
            chan2Offset = woal_get_second_channel_offset(priv->channel);
            if (chan2Offset) {
                sys_config.band_cfg |= chan2Offset;
                sys_config.ht_cap_info = 0x117e;
                sys_config.ampdu_param = 3;
            }
#ifdef WIFI_DIRECT_SUPPORT
            if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
                memcpy(sys_config.rates, Rates_WFD, sizeof(Rates_WFD));
            else
#endif
                memcpy(sys_config.rates, Rates_A, sizeof(Rates_A));
        }
    }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
    if (!params->ssid || !params->ssid_len) {
        ret = -EINVAL;
        goto done;
    }
    memcpy(sys_config.ssid.ssid, params->ssid,
           MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len));
    sys_config.ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len);
    if (params->hidden_ssid)
        sys_config.bcast_ssid_ctl = 0;
    else
        sys_config.bcast_ssid_ctl = 1;
    if (params->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
        sys_config.auth_mode = MLAN_AUTH_MODE_SHARED;
    else
        sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;

    for (i = 0; i < params->crypto.n_akm_suites; i++) {
        switch (params->crypto.akm_suites[i]) {
        case WLAN_AKM_SUITE_8021X:
            sys_config.key_mgmt = KEY_MGMT_EAP;
            if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
                (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
                sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
            else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
                sys_config.protocol = PROTOCOL_WPA2;
            else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
                sys_config.protocol = PROTOCOL_WPA;
            break;
        case WLAN_AKM_SUITE_PSK:
            sys_config.key_mgmt = KEY_MGMT_PSK;
            if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
                (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
                sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
            else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
                sys_config.protocol = PROTOCOL_WPA2;
            else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
                sys_config.protocol = PROTOCOL_WPA;
            break;
        }
    }
    sys_config.wpa_cfg.pairwise_cipher_wpa = 0;
    sys_config.wpa_cfg.pairwise_cipher_wpa2 = 0;
    for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
        switch (params->crypto.ciphers_pairwise[i]) {
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
            break;
        case WLAN_CIPHER_SUITE_TKIP:
            if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
                sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP;
            if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
                sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP;
            break;
        case WLAN_CIPHER_SUITE_CCMP:
            if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
                sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP;
            if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
                sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP;
            break;
        }
    }
    switch (params->crypto.cipher_group) {
    case WLAN_CIPHER_SUITE_WEP40:
    case WLAN_CIPHER_SUITE_WEP104:
        if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
            (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
            sys_config.protocol = PROTOCOL_STATIC_WEP;
            sys_config.key_mgmt = KEY_MGMT_NONE;
            sys_config.wpa_cfg.length = 0;
            sys_config.wep_cfg.key0.key_index = priv->key_index;
            sys_config.wep_cfg.key0.is_default = 1;
            sys_config.wep_cfg.key0.length = priv->key_len;
            memcpy(sys_config.wep_cfg.key0.key, priv->key_material,
                   priv->key_len);
        }
        break;
    case WLAN_CIPHER_SUITE_TKIP:
        sys_config.wpa_cfg.group_cipher = CIPHER_TKIP;
        break;
    case WLAN_CIPHER_SUITE_CCMP:
        sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
        break;
    }
#else
    /* Since in Android ICS 4.0.1's wpa_supplicant, there is no way to set ssid
       when GO (AP) starts up, so get it from beacon head parameter TODO: right
       now use hard code 24 -- ieee80211 header lenth, 12 -- fixed element
       length for beacon */
#define BEACON_IE_OFFSET	36
    /* Find SSID in head SSID IE id: 0, right now use hard code */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
    ssid_ie = woal_parse_ie_tlv(params->beacon.head + BEACON_IE_OFFSET,
                                params->beacon.head_len - BEACON_IE_OFFSET, 0);
#else
    ssid_ie = woal_parse_ie_tlv(params->head + BEACON_IE_OFFSET,
                                params->head_len - BEACON_IE_OFFSET, 0);
#endif
    if (!ssid_ie) {
        PRINTM(MERROR, "No ssid IE found.\n");
        ret = -EFAULT;
        goto done;
    }
    if (*(ssid_ie + 1) > 32) {
        PRINTM(MERROR, "ssid len error: %d\n", *(ssid_ie + 1));
        ret = -EFAULT;
        goto done;
    }
    memcpy(sys_config.ssid.ssid, ssid_ie + 2, *(ssid_ie + 1));
    sys_config.ssid.ssid_len = *(ssid_ie + 1);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
    head = (struct ieee80211_mgmt *) params->beacon.head;
#else
    head = (struct ieee80211_mgmt *) params->head;
#endif
    capab_info = le16_to_cpu(head->u.beacon.capab_info);
    PRINTM(MIOCTL, "capab_info=0x%x\n", head->u.beacon.capab_info);
    sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
        /** For ICS, we don't support OPEN mode */
    if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
        (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
        sys_config.protocol = PROTOCOL_STATIC_WEP;
        sys_config.key_mgmt = KEY_MGMT_NONE;
        sys_config.wpa_cfg.length = 0;
        sys_config.wep_cfg.key0.key_index = priv->key_index;
        sys_config.wep_cfg.key0.is_default = 1;
        sys_config.wep_cfg.key0.length = priv->key_len;
        memcpy(sys_config.wep_cfg.key0.key, priv->key_material, priv->key_len);
    } else {
                /** Get cipher and key_mgmt from RSN/WPA IE */
        if (capab_info & WLAN_CAPABILITY_PRIVACY) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
            if (MFALSE ==
                woal_find_wpa_ies(params->beacon.tail, params->beacon.tail_len,
                                  &sys_config))
#else
            if (MFALSE ==
                woal_find_wpa_ies(params->tail, params->tail_len, &sys_config))
#endif
            {
                /* hard code setting to wpa2-psk */
                sys_config.protocol = PROTOCOL_WPA2;
                sys_config.key_mgmt = KEY_MGMT_PSK;
                sys_config.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
                sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
            }
        }
    }
#endif /* COMPAT_WIRELESS */
    /* If the security mode is configured as WEP or WPA-PSK, it will disable
       11n automatically, and if configured as open(off) or wpa2-psk, it will
       automatically enable 11n */
    if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
        (sys_config.protocol == PROTOCOL_WPA))
        woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE);
    else
        woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE);
    if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
                                                       MLAN_ACT_SET,
                                                       MOAL_IOCTL_WAIT,
                                                       &sys_config)) {
        ret = -EFAULT;
        goto done;
    }
  done:
    LEAVE();
    return ret;
}
/**
 * @brief Initialize the uAP wiphy
 *
 * @param priv            A pointer to moal_private structure
 * @param wait_option     Wait option
 *
 * @return                MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option)
{
    struct wiphy *wiphy;
    mlan_uap_bss_param ap_cfg;
    mlan_ioctl_req *req = NULL;
    mlan_ds_11n_cfg *cfg_11n = NULL;
    t_u32 hw_dev_cap;

    ENTER();

    if (priv->wdev)
        wiphy = priv->wdev->wiphy;
    else {
        PRINTM(MERROR, "Invalid parameter when init wiphy.\n");
        LEAVE();
        return MLAN_STATUS_FAILURE;
    }
    if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
                                                       MLAN_ACT_GET,
                                                       wait_option, &ap_cfg)) {
        LEAVE();
        return MLAN_STATUS_FAILURE;
    }

    /* Get 11n tx parameters from MLAN */
    req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
    if (req == NULL) {
        LEAVE();
        return MLAN_STATUS_FAILURE;
    }
    cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
    cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
    req->req_id = MLAN_IOCTL_11N_CFG;
    req->action = MLAN_ACT_GET;
    cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE;

    if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
        kfree(req);
        LEAVE();
        return MLAN_STATUS_FAILURE;
    }
    hw_dev_cap = cfg_11n->param.htcap_cfg.htcap;

    /* Get supported MCS sets */
    memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg));
    cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET;
    req->req_id = MLAN_IOCTL_11N_CFG;
    req->action = MLAN_ACT_GET;

    if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
        kfree(req);
        LEAVE();
        return MLAN_STATUS_FAILURE;
    }

    /* Initialize parameters for 2GHz and 5GHz bands */
    woal_cfg80211_setup_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
                               hw_dev_cap, cfg_11n->param.supported_mcs_set);
    /* For 2.4G band only card, this shouldn't be set */
    if (wiphy->bands[IEEE80211_BAND_5GHZ])
        woal_cfg80211_setup_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap,
                                   hw_dev_cap,
                                   cfg_11n->param.supported_mcs_set);
    if (req)
        kfree(req);

    /* Set retry limit count to wiphy */
    wiphy->retry_long = (t_u8) ap_cfg.retry_limit;
    wiphy->retry_short = (t_u8) ap_cfg.retry_limit;
    wiphy->max_scan_ie_len = MAX_IE_SIZE;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
    wiphy->mgmt_stypes = ieee80211_uap_mgmt_stypes;
#endif
    /* Set RTS threshold to wiphy */
    wiphy->rts_threshold = (t_u32) ap_cfg.rts_threshold;

    /* Set fragment threshold to wiphy */
    wiphy->frag_threshold = (t_u32) ap_cfg.frag_threshold;

    LEAVE();
    return MLAN_STATUS_SUCCESS;
}
/**
 *  @brief Set IE
 *
 *  Pass an opaque block of data, expected to be IEEE IEs, to the driver
 *    for eventual passthrough to the firmware in an associate/join
 *    (and potentially start) command.
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param dwrq                 A pointer to iw_point structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
		struct iw_point *dwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param sys_cfg;
	IEEEtypes_Header_t *tlv = NULL;
	int tlv_hdr_len = sizeof(IEEEtypes_Header_t), tlv_buf_left = 0;
	int ret = 0;

	ENTER();

	/* Initialize the invalid values so that the correct values below are
	   downloaded to firmware */
	woal_set_sys_config_invalid_data(&sys_cfg);

	tlv_buf_left = dwrq->length;
	tlv = (IEEEtypes_Header_t *) extra;
	while (tlv_buf_left >= tlv_hdr_len) {
		if (tlv->element_id == WPA_IE) {
			sys_cfg.protocol |= PROTOCOL_WPA;
			if (priv->pairwise_cipher == CIPHER_TKIP) {
				sys_cfg.wpa_cfg.pairwise_cipher_wpa =
					CIPHER_TKIP;
				PRINTM(MINFO, "Set IE Cipher TKIP\n");
			}
			if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
				sys_cfg.wpa_cfg.pairwise_cipher_wpa =
					CIPHER_AES_CCMP;
				PRINTM(MINFO, "Set IE Cipher CCMP\n");
			}
			if (priv->pairwise_cipher ==
			    (CIPHER_TKIP | CIPHER_AES_CCMP)) {
				sys_cfg.wpa_cfg.pairwise_cipher_wpa =
					CIPHER_TKIP | CIPHER_AES_CCMP;
				PRINTM(MINFO, "Set IE Cipher TKIP + CCMP\n");
			}
			memcpy(priv->bcn_ie_buf + priv->bcn_ie_len,
			       ((t_u8 *) tlv),
			       sizeof(IEEEtypes_Header_t) + tlv->len);
			priv->bcn_ie_len +=
				sizeof(IEEEtypes_Header_t) + tlv->len;
		}
		if (tlv->element_id == RSN_IE) {
			sys_cfg.protocol |= PROTOCOL_WPA2;
			if (priv->pairwise_cipher == CIPHER_TKIP) {
				sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
					CIPHER_TKIP;
			}
			if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
				sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
					CIPHER_AES_CCMP;
			}
			if (priv->pairwise_cipher ==
			    (CIPHER_TKIP | CIPHER_AES_CCMP)) {
				sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
					(CIPHER_TKIP | CIPHER_AES_CCMP);
			}
			memcpy(priv->bcn_ie_buf + priv->bcn_ie_len,
			       ((t_u8 *) tlv),
			       sizeof(IEEEtypes_Header_t) + tlv->len);
			priv->bcn_ie_len +=
				sizeof(IEEEtypes_Header_t) + tlv->len;
		}
		if (priv->group_cipher == CIPHER_TKIP)
			sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
		if (priv->group_cipher == CIPHER_AES_CCMP)
			sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
		tlv_buf_left -= (tlv_hdr_len + tlv->len);
		tlv = (IEEEtypes_Header_t *) ((t_u8 *) tlv + tlv_hdr_len +
					      tlv->len);
	}
	sys_cfg.key_mgmt = priv->uap_key_mgmt;
	if (sys_cfg.key_mgmt & KEY_MGMT_PSK)
		sys_cfg.key_mgmt_operation |= 0x01;
	if (sys_cfg.key_mgmt & KEY_MGMT_EAP)
		sys_cfg.key_mgmt_operation |= 0x03;

	if (sys_cfg.protocol) {
		if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
								   MLAN_ACT_SET,
								   MOAL_IOCTL_WAIT,
								   &sys_cfg)) {
			PRINTM(MERROR, "Error setting AP configuration\n");
			ret = -EFAULT;
			goto done;
		}
		priv->pairwise_cipher = 0;
		priv->group_cipher = 0;

		/* custom IE command to set priv->bcn_ie_buf */
		if (MLAN_STATUS_SUCCESS !=
#define UAP_RSN_MASK  (BIT(8) | BIT(5) | BIT(1) | BIT(3))
		    woal_set_get_custom_ie(priv, UAP_RSN_MASK, priv->bcn_ie_buf,
					   priv->bcn_ie_len)) {
			PRINTM(MERROR, "Error setting wpa-rsn IE\n");
			ret = -EFAULT;
		}
	} else if (dwrq->length == 0) {
		/* custom IE command to re-set priv->bcn_ie_buf */
		if (MLAN_STATUS_SUCCESS !=
		    woal_set_get_custom_ie(priv, 0, priv->bcn_ie_buf,
					   priv->bcn_ie_len)) {
			PRINTM(MERROR, "Error resetting wpa-rsn IE\n");
			ret = -EFAULT;
		}
		priv->bcn_ie_len = 0;
	}

done:
	LEAVE();
	return ret;
}
/**
 *  @brief Get authentication mode parameters
 *
 *  @param dev                  A pointer to net_device structure
 *  @param info                 A pointer to iw_request_info structure
 *  @param vwrq                 A pointer to iw_param structure
 *  @param extra                A pointer to extra data buf
 *
 *  @return                     0 --success, otherwise fail
 */
static int
woal_get_auth(struct net_device *dev, struct iw_request_info *info,
	      struct iw_param *vwrq, char *extra)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	mlan_uap_bss_param ap_cfg;

	ENTER();

	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   &ap_cfg)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		LEAVE();
		return -EFAULT;
	}
	switch (vwrq->flags & IW_AUTH_INDEX) {
	case IW_AUTH_CIPHER_PAIRWISE:
		if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
		    ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP)
			vwrq->value = IW_AUTH_CIPHER_TKIP;
		else if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP
			 || ap_cfg.wpa_cfg.pairwise_cipher_wpa2 ==
			 CIPHER_AES_CCMP)
			vwrq->value = IW_AUTH_CIPHER_CCMP;
		else
			vwrq->value = IW_AUTH_CIPHER_NONE;
		break;
	case IW_AUTH_CIPHER_GROUP:
		if (ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP)
			vwrq->value = IW_AUTH_CIPHER_TKIP;
		else if (ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP)
			vwrq->value = IW_AUTH_CIPHER_CCMP;
		else
			vwrq->value = IW_AUTH_CIPHER_NONE;
		break;
	case IW_AUTH_80211_AUTH_ALG:
		if (ap_cfg.auth_mode == MLAN_AUTH_MODE_SHARED)
			vwrq->value = IW_AUTH_ALG_SHARED_KEY;
		else if (ap_cfg.auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
			vwrq->value = IW_AUTH_ALG_LEAP;
		else
			vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
		break;
	case IW_AUTH_WPA_ENABLED:
		if (ap_cfg.protocol == PROTOCOL_WPA ||
		    ap_cfg.protocol == PROTOCOL_WPA2 ||
		    ap_cfg.protocol == PROTOCOL_WPA2_MIXED)
			vwrq->value = 1;
		else
			vwrq->value = 0;
		break;
	case IW_AUTH_KEY_MGMT:
		if (ap_cfg.key_mgmt & KEY_MGMT_EAP)
			vwrq->value |= IW_AUTH_KEY_MGMT_802_1X;
		if (ap_cfg.key_mgmt & KEY_MGMT_PSK)
			vwrq->value |= IW_AUTH_KEY_MGMT_PSK;
		break;
	case IW_AUTH_WPA_VERSION:
	case IW_AUTH_TKIP_COUNTERMEASURES:
	case IW_AUTH_DROP_UNENCRYPTED:
	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
	case IW_AUTH_ROAMING_CONTROL:
	case IW_AUTH_PRIVACY_INVOKED:
	default:
		LEAVE();
		return -EOPNOTSUPP;
	}

	LEAVE();
	return 0;
}
/**
 *  @brief  Extended version of encoding configuration
 *
 *  @param dev          A pointer to net_device structure
 *  @param info         A pointer to iw_request_info structure
 *  @param dwrq         A pointer to iw_point structure
 *  @param extra        A pointer to extra data buf
 *
 *  @return              0 --success, otherwise fail
 */
static int
woal_set_encode_ext(struct net_device *dev,
		    struct iw_request_info *info,
		    struct iw_point *dwrq, char *extra)
{
	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
	moal_private *priv = (moal_private *) netdev_priv(dev);
	int key_index;
	t_u8 *pkey_material = NULL;
	mlan_ioctl_req *req = NULL;
	mlan_ds_sec_cfg *sec = NULL;
	mlan_uap_bss_param sys_cfg;
	wep_key *pwep_key = NULL;
	int ret = 0;

	ENTER();

	key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
	if (key_index < 0 || key_index > 5) {
		ret = -EINVAL;
		goto done;
	}
	if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
		ret = -EINVAL;
		goto done;
	}

	/* Initialize the invalid values so that the correct values below are
	   downloaded to firmware */
	woal_set_sys_config_invalid_data(&sys_cfg);

	pkey_material = (t_u8 *) (ext + 1);
	/* Disable Key */
	if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
		sys_cfg.protocol = PROTOCOL_NO_SECURITY;
	} else if (ext->alg == IW_ENCODE_ALG_WEP) {
		sys_cfg.protocol = PROTOCOL_STATIC_WEP;
		/* Set WEP key */
		switch (key_index) {
		case 0:
			pwep_key = &sys_cfg.wep_cfg.key0;
			break;
		case 1:
			pwep_key = &sys_cfg.wep_cfg.key1;
			break;
		case 2:
			pwep_key = &sys_cfg.wep_cfg.key2;
			break;
		case 3:
			pwep_key = &sys_cfg.wep_cfg.key3;
			break;
		}
		if (pwep_key) {
			pwep_key->key_index = key_index;
			pwep_key->is_default = MTRUE;
			pwep_key->length = ext->key_len;
			memcpy(pwep_key->key, pkey_material, ext->key_len);
		}
	} else {
		/* Set GTK/PTK key */
		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
		if (req == NULL) {
			ret = -ENOMEM;
			goto done;
		}
		sec = (mlan_ds_sec_cfg *) req->pbuf;
		sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
		req->req_id = MLAN_IOCTL_SEC_CFG;
		req->action = MLAN_ACT_SET;
		sec->param.encrypt_key.key_len = ext->key_len;
		sec->param.encrypt_key.key_index = key_index;
		memcpy(sec->param.encrypt_key.key_material, pkey_material,
		       ext->key_len);
		memcpy(sec->param.encrypt_key.mac_addr, ext->addr.sa_data,
		       ETH_ALEN);
		sec->param.encrypt_key.key_flags = ext->ext_flags;
		if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
			memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq,
			       SEQ_MAX_SIZE);
			DBG_HEXDUMP(MCMD_D, "Uap Rx PN",
				    sec->param.encrypt_key.pn, SEQ_MAX_SIZE);
		}
		if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
			memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
			       SEQ_MAX_SIZE);
			DBG_HEXDUMP(MCMD_D, "Uap Tx PN",
				    sec->param.encrypt_key.pn, SEQ_MAX_SIZE);
		}
		PRINTM(MIOCTL,
		       "set uap wpa key key_index=%d, key_len=%d key_flags=0x%x "
		       MACSTR "\n", key_index, ext->key_len,
		       sec->param.encrypt_key.key_flags,
		       MAC2STR(sec->param.encrypt_key.mac_addr));
		DBG_HEXDUMP(MCMD_D, "uap wpa key", pkey_material, ext->key_len);
#define IW_ENCODE_ALG_AES_CMAC	5

		if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
			sec->param.encrypt_key.key_flags |=
				KEY_FLAG_AES_MCAST_IGTK;
		if (MLAN_STATUS_SUCCESS !=
		    woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
			ret = -EFAULT;
		}
		/* Cipher set will be done in set generic IE */
		priv->pairwise_cipher = ext->alg;
		priv->group_cipher = ext->alg;
		goto done;	/* No AP configuration */
	}
	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_SET,
							   MOAL_IOCTL_WAIT,
							   &sys_cfg)) {
		PRINTM(MERROR, "Error setting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

done:
	if (req)
		kfree(req);
	LEAVE();
	return ret;
}
/**
 * @brief initialize AP or GO bss config
 *
 * @param priv            A pointer to moal private structure
 * @param params          A pointer to beacon_parameters structure
 * @return                0 -- success, otherwise fail
 */
static int
woal_cfg80211_beacon_config(moal_private *priv,
			    struct beacon_parameters *params)
#endif
{
	int ret = 0;
	mlan_uap_bss_param sys_config;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) || defined(COMPAT_WIRELESS)
	int i = 0;
#else
	t_u8 wpa_ies;
	const t_u8 *ssid_ie = NULL;
	struct ieee80211_mgmt *head = NULL;
	t_u16 capab_info = 0;
#endif
	t_u8 rates_bg[13] = {
		0x82, 0x84, 0x8b, 0x96,
		0x0c, 0x12, 0x18, 0x24,
		0x30, 0x48, 0x60, 0x6c,
		0x00
	};
	t_u8 rates_a[9] = {
		0x8c, 0x12, 0x98, 0x24,
		0xb0, 0x48, 0x60, 0x6c,
		0x00
	};
#ifdef WIFI_DIRECT_SUPPORT
	t_u8 rates_wfd[9] = {
		0x8c, 0x12, 0x18, 0x24,
		0x30, 0x48, 0x60, 0x6c,
		0x00
	};
#endif
	t_u8 chan2Offset = 0;
	t_u8 enable_11n = MTRUE;
	ENTER();

	if (params == NULL) {
		ret = -EFAULT;
		goto done;
	}

	if (priv->bss_type != MLAN_BSS_TYPE_UAP
#ifdef WIFI_DIRECT_SUPPORT
	    && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
#endif
		) {
		ret = -EFAULT;
		goto done;
	}

	/* Initialize the uap bss values which are uploaded from firmware */
	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_GET,
							   MOAL_IOCTL_WAIT,
							   &sys_config)) {
		PRINTM(MERROR, "Error getting AP confiruration\n");
		ret = -EFAULT;
		goto done;
	}

	/* Setting the default values */
	sys_config.channel = 6;
	sys_config.preamble_type = 0;
	sys_config.mgmt_ie_passthru_mask = priv->mgmt_subtype_mask;
	memcpy(sys_config.mac_addr, priv->current_addr, ETH_ALEN);

	if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
		if (params->beacon_interval)
			sys_config.beacon_period = params->beacon_interval;
#else
		if (params->interval)
			sys_config.beacon_period = params->interval;
#endif
		if (params->dtim_period)
			sys_config.dtim_period = params->dtim_period;
	}
	if (priv->channel) {
		memset(sys_config.rates, 0, sizeof(sys_config.rates));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
		switch (params->chandef.width) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
		case NL80211_CHAN_WIDTH_5:
		case NL80211_CHAN_WIDTH_10:
#endif
		case NL80211_CHAN_WIDTH_20_NOHT:
			enable_11n = MFALSE;
			break;
		case NL80211_CHAN_WIDTH_20:
			break;
		case NL80211_CHAN_WIDTH_40:
		case NL80211_CHAN_WIDTH_80:
		case NL80211_CHAN_WIDTH_80P80:
		case NL80211_CHAN_WIDTH_160:
			if (params->chandef.center_freq1 <
			    params->chandef.chan->center_freq)
				chan2Offset = SECOND_CHANNEL_BELOW;
			else
				chan2Offset = SECOND_CHANNEL_ABOVE;
			break;
		default:
			PRINTM(MWARN, "Unknown channel width: %d\n",
			       params->chandef.width);
			break;
		}
#else
		switch (params->channel_type) {
		case NL80211_CHAN_NO_HT:
			enable_11n = MFALSE;
			break;
		case NL80211_CHAN_HT20:
			break;
		case NL80211_CHAN_HT40PLUS:
			chan2Offset = SECOND_CHANNEL_ABOVE;
			break;
		case NL80211_CHAN_HT40MINUS:
			chan2Offset = SECOND_CHANNEL_BELOW;
			break;
		default:
			PRINTM(MWARN, "Unknown channel type: %d\n",
			       params->channel_type);
			break;
		}
#endif
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
		sys_config.channel = priv->channel;
		if (priv->channel <= MAX_BG_CHANNEL) {
			sys_config.band_cfg = BAND_CONFIG_2G;
#ifdef WIFI_DIRECT_SUPPORT
			if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
				memcpy(sys_config.rates, rates_wfd,
				       sizeof(rates_wfd));
			else
#endif
				memcpy(sys_config.rates, rates_bg,
				       sizeof(rates_bg));
		} else {
			sys_config.band_cfg = BAND_CONFIG_5G;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
			chan2Offset =
				woal_get_second_channel_offset(priv->channel);
#else
#ifdef WIFI_DIRECT_SUPPORT
			/* Force enable 40MHZ on WFD interface */
			if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
				chan2Offset =
					woal_get_second_channel_offset(priv->
								       channel);
#endif
#endif

#ifdef WIFI_DIRECT_SUPPORT
			if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
				memcpy(sys_config.rates, rates_wfd,
				       sizeof(rates_wfd));
			else
#endif
				memcpy(sys_config.rates, rates_a,
				       sizeof(rates_a));
		}
		/* Disable GreenField by default */
		sys_config.ht_cap_info = 0x10c;
		if (enable_11n)
			sys_config.ht_cap_info |= 0x20;
		if (chan2Offset) {
			sys_config.band_cfg |= chan2Offset;
			sys_config.ht_cap_info |= 0x1042;
			sys_config.ampdu_param = 3;
		}
		PRINTM(MCMND,
		       "11n=%d, ht_cap=0x%x, channel=%d, band_cfg=0x%x\n",
		       enable_11n, sys_config.ht_cap_info, priv->channel,
		       sys_config.band_cfg);
	}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) || defined(COMPAT_WIRELESS)
	if (!params->ssid || !params->ssid_len) {
		ret = -EINVAL;
		goto done;
	}
	memcpy(sys_config.ssid.ssid, params->ssid,
	       MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len));
	sys_config.ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len);
	if (params->hidden_ssid)
		sys_config.bcast_ssid_ctl = 0;
	else
		sys_config.bcast_ssid_ctl = 1;
	if (params->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
		sys_config.auth_mode = MLAN_AUTH_MODE_SHARED;
	else
		sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
	if (params->crypto.n_akm_suites) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
		woal_find_wpa_ies(params->beacon.tail,
				  (int)params->beacon.tail_len, &sys_config);
#else
		woal_find_wpa_ies(params->tail, params->tail_len, &sys_config);
#endif
	}
	for (i = 0; i < params->crypto.n_akm_suites; i++) {
		switch (params->crypto.akm_suites[i]) {
		case WLAN_AKM_SUITE_8021X:
			sys_config.key_mgmt |= KEY_MGMT_EAP;
			if ((params->crypto.
			     wpa_versions & NL80211_WPA_VERSION_1) &&
			    (params->crypto.
			     wpa_versions & NL80211_WPA_VERSION_2))
				sys_config.protocol =
					PROTOCOL_WPA | PROTOCOL_WPA2;
			else if (params->crypto.
				 wpa_versions & NL80211_WPA_VERSION_2)
				sys_config.protocol = PROTOCOL_WPA2;
			else if (params->crypto.
				 wpa_versions & NL80211_WPA_VERSION_1)
				sys_config.protocol = PROTOCOL_WPA;
			break;
		case WLAN_AKM_SUITE_PSK:
			sys_config.key_mgmt |= KEY_MGMT_PSK;
			if ((params->crypto.
			     wpa_versions & NL80211_WPA_VERSION_1) &&
			    (params->crypto.
			     wpa_versions & NL80211_WPA_VERSION_2))
				sys_config.protocol =
					PROTOCOL_WPA | PROTOCOL_WPA2;
			else if (params->crypto.
				 wpa_versions & NL80211_WPA_VERSION_2)
				sys_config.protocol = PROTOCOL_WPA2;
			else if (params->crypto.
				 wpa_versions & NL80211_WPA_VERSION_1)
				sys_config.protocol = PROTOCOL_WPA;
			break;
		}
	}
	sys_config.wpa_cfg.pairwise_cipher_wpa = 0;
	sys_config.wpa_cfg.pairwise_cipher_wpa2 = 0;
	for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
		switch (params->crypto.ciphers_pairwise[i]) {
		case WLAN_CIPHER_SUITE_WEP40:
		case WLAN_CIPHER_SUITE_WEP104:
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
				sys_config.wpa_cfg.pairwise_cipher_wpa |=
					CIPHER_TKIP;
			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
				sys_config.wpa_cfg.pairwise_cipher_wpa2 |=
					CIPHER_TKIP;
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
				sys_config.wpa_cfg.pairwise_cipher_wpa |=
					CIPHER_AES_CCMP;
			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
				sys_config.wpa_cfg.pairwise_cipher_wpa2 |=
					CIPHER_AES_CCMP;
			break;
		}
	}
	switch (params->crypto.cipher_group) {
	case WLAN_CIPHER_SUITE_WEP40:
	case WLAN_CIPHER_SUITE_WEP104:
		if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
		    (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
			sys_config.protocol = PROTOCOL_STATIC_WEP;
			sys_config.key_mgmt = KEY_MGMT_NONE;
			sys_config.wpa_cfg.length = 0;
			memcpy(&sys_config.wep_cfg.key0, &priv->uap_wep_key[0],
			       sizeof(wep_key));
			memcpy(&sys_config.wep_cfg.key1, &priv->uap_wep_key[1],
			       sizeof(wep_key));
			memcpy(&sys_config.wep_cfg.key2, &priv->uap_wep_key[2],
			       sizeof(wep_key));
			memcpy(&sys_config.wep_cfg.key3, &priv->uap_wep_key[3],
			       sizeof(wep_key));
		}
		break;
	case WLAN_CIPHER_SUITE_TKIP:
		sys_config.wpa_cfg.group_cipher = CIPHER_TKIP;
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
		break;
	}
#else
	/* Since in Android ICS 4.0.1's wpa_supplicant, there is no way to set
	   ssid when GO (AP) starts up, so get it from beacon head parameter
	   TODO: right now use hard code 24 -- ieee80211 header lenth, 12 --
	   fixed element length for beacon */
#define BEACON_IE_OFFSET	36
	/* Find SSID in head SSID IE id: 0, right now use hard code */
	ssid_ie = woal_parse_ie_tlv(params->head + BEACON_IE_OFFSET,
				    params->head_len - BEACON_IE_OFFSET, 0);

	if (!ssid_ie) {
		PRINTM(MERROR, "No ssid IE found.\n");
		ret = -EFAULT;
		goto done;
	}
	if (*(ssid_ie + 1) > 32) {
		PRINTM(MERROR, "ssid len error: %d\n", *(ssid_ie + 1));
		ret = -EFAULT;
		goto done;
	}
	memcpy(sys_config.ssid.ssid, ssid_ie + 2, *(ssid_ie + 1));
	sys_config.ssid.ssid_len = *(ssid_ie + 1);
	head = (struct ieee80211_mgmt *)params->head;

	capab_info = le16_to_cpu(head->u.beacon.capab_info);
	PRINTM(MIOCTL, "capab_info=0x%x\n", head->u.beacon.capab_info);
	sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
	/** For ICS, we don't support OPEN mode */
	if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
	    (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
		sys_config.protocol = PROTOCOL_STATIC_WEP;
		sys_config.key_mgmt = KEY_MGMT_NONE;
		sys_config.wpa_cfg.length = 0;
		memcpy(&sys_config.wep_cfg.key0, &priv->uap_wep_key[0],
		       sizeof(wep_key));
		memcpy(&sys_config.wep_cfg.key1, &priv->uap_wep_key[1],
		       sizeof(wep_key));
		memcpy(&sys_config.wep_cfg.key2, &priv->uap_wep_key[2],
		       sizeof(wep_key));
		memcpy(&sys_config.wep_cfg.key3, &priv->uap_wep_key[3],
		       sizeof(wep_key));
	} else {
		/** Get cipher and key_mgmt from RSN/WPA IE */
		if (capab_info & WLAN_CAPABILITY_PRIVACY) {
			wpa_ies =
				woal_find_wpa_ies(params->tail,
						  params->tail_len,
						  &sys_config);
			if (wpa_ies == MFALSE) {
				/* hard code setting to wpa2-psk */
				sys_config.protocol = PROTOCOL_WPA2;
				sys_config.key_mgmt = KEY_MGMT_PSK;
				sys_config.wpa_cfg.pairwise_cipher_wpa2 =
					CIPHER_AES_CCMP;
				sys_config.wpa_cfg.group_cipher =
					CIPHER_AES_CCMP;
			}
		}
	}
#endif /* COMPAT_WIRELESS */
	/* If the security mode is configured as WEP or WPA-PSK, it will
	   disable 11n automatically, and if configured as open(off) or
	   wpa2-psk, it will automatically enable 11n */
	if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
	    (sys_config.protocol == PROTOCOL_WPA))
		enable_11n = MFALSE;
	if (!enable_11n) {
		woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE);
	} else {
		woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE);
		woal_set_get_tx_bf_cap(priv, MLAN_ACT_GET,
				       &sys_config.tx_bf_cap);
	}
	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
							   MLAN_ACT_SET,
							   MOAL_IOCTL_WAIT,
							   &sys_config)) {
		ret = -EFAULT;
		goto done;
	}
done:
	LEAVE();
	return ret;
}