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