/*******************************************************************************
 * Agere Systems Inc.
 * Wireless device driver for Linux (wlags49).
 *
 * Copyright (c) 1998-2003 Agere Systems Inc.
 * All rights reserved.
 *   http://www.agere.com
 *
 * Initially developed by TriplePoint, Inc.
 *   http://www.triplepoint.com
 *
 *------------------------------------------------------------------------------
 *
 *   This file defines handling routines for the private IOCTLs
 *
 *------------------------------------------------------------------------------
 *
 * SOFTWARE LICENSE
 *
 * This software is provided subject to the following terms and conditions,
 * which you should read carefully before using the software.  Using this
 * software indicates your acceptance of these terms and conditions.  If you do
 * not agree with these terms and conditions, do not use the software.
 *
 * Copyright © 2003 Agere Systems Inc.
 * All rights reserved.
 *
 * Redistribution and use in source or binary forms, with or without
 * modifications, are permitted provided that the following conditions are met:
 *
 * . Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following Disclaimer as comments in the code as
 *    well as in the documentation and/or other materials provided with the
 *    distribution.
 *
 * . Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following Disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * . Neither the name of Agere Systems Inc. nor the names of the contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * Disclaimer
 *
 * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  ANY
 * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
 * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 ******************************************************************************/

/*******************************************************************************
 * include files
 ******************************************************************************/
#include <wl_version.h>

#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/uaccess.h>

#include <debug.h>
#include <hcf.h>
#include <hcfdef.h>

#include <wl_if.h>
#include <wl_internal.h>
#include <wl_enc.h>
#include <wl_main.h>
#include <wl_priv.h>
#include <wl_util.h>
#include <wl_netdev.h>

int wvlan_uil_connect(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_disconnect(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_action(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_block(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_unblock(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_send_diag_msg(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_put_info(struct uilreq *urq, struct wl_private *lp);
int wvlan_uil_get_info(struct uilreq *urq, struct wl_private *lp);

int cfg_driver_info(struct uilreq *urq, struct wl_private *lp);
int cfg_driver_identity(struct uilreq *urq, struct wl_private *lp);


/*******************************************************************************
 * global variables
 ******************************************************************************/
#if DBG
extern dbg_info_t *DbgInfo;
#endif  /* DBG */




/* If USE_UIL is not defined, then none of the UIL Interface code below will
   be included in the build */
#ifdef USE_UIL

/*******************************************************************************
 *	wvlan_uil()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      The handler function for the UIL interface.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_uil(struct uilreq *urq, struct wl_private *lp)
{
	int ioctl_ret = 0;
	/*------------------------------------------------------------------------*/

	DBG_FUNC("wvlan_uil");
	DBG_ENTER(DbgInfo);

	switch (urq->command) {
	case UIL_FUN_CONNECT:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_CONNECT\n");
		ioctl_ret = wvlan_uil_connect(urq, lp);
		break;
	case UIL_FUN_DISCONNECT:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_DISCONNECT\n");
		ioctl_ret = wvlan_uil_disconnect(urq, lp);
		break;
	case UIL_FUN_ACTION:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_ACTION\n");
		ioctl_ret = wvlan_uil_action(urq, lp);
		break;
	case UIL_FUN_SEND_DIAG_MSG:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_SEND_DIAG_MSG\n");
		ioctl_ret = wvlan_uil_send_diag_msg(urq, lp);
		break;
	case UIL_FUN_GET_INFO:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_GET_INFO\n");
		ioctl_ret = wvlan_uil_get_info(urq, lp);
		break;
	case UIL_FUN_PUT_INFO:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_PUT_INFO\n");
		ioctl_ret = wvlan_uil_put_info(urq, lp);
		break;
	default:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- UNSUPPORTED UIL CODE: 0x%X", urq->command);
		ioctl_ret = -EOPNOTSUPP;
		break;
	}
	DBG_LEAVE(DbgInfo);
	return ioctl_ret;
} /* wvlan_uil */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_uil_connect()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Connect to the UIL in order to make a request.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_connect(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_connect");
	DBG_ENTER(DbgInfo);


	if (!(lp->flags & WVLAN2_UIL_CONNECTED)) {
		lp->flags |= WVLAN2_UIL_CONNECTED;
		urq->hcfCtx = &(lp->hcfCtx);
		urq->result = UIL_SUCCESS;
	} else {
		DBG_WARNING(DbgInfo, "UIL_ERR_IN_USE\n");
		urq->result = UIL_ERR_IN_USE;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_connect */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_uil_disconnect()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Disconnect from the UIL after a request has been completed.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_disconnect(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_disconnect");
	DBG_ENTER(DbgInfo);


	if (urq->hcfCtx == &(lp->hcfCtx)) {
		if (lp->flags & WVLAN2_UIL_CONNECTED) {
			lp->flags &= ~WVLAN2_UIL_CONNECTED;
			/*
			if (lp->flags & WVLAN2_UIL_BUSY) {
				lp->flags &= ~WVLAN2_UIL_BUSY;
				netif_start_queue(lp->dev);
			}
			*/
		}

		urq->hcfCtx = NULL;
		urq->result = UIL_SUCCESS;
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_disconnect */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_uil_action()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Handler for the UIL_ACT_xxx subcodes associated with UIL_FUN_ACTION
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_action(struct uilreq *urq, struct wl_private *lp)
{
	int     result = 0;
	ltv_t   *ltv;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_action");
	DBG_ENTER(DbgInfo);


	if (urq->hcfCtx == &(lp->hcfCtx)) {
		/* Make sure there's an LTV in the request buffer */
		ltv = (ltv_t *)urq->data;
		if (ltv != NULL) {
			/* Switch on the Type field of the LTV contained in the request
			   buffer */
			switch (ltv->typ) {
			case UIL_ACT_BLOCK:
				DBG_TRACE(DbgInfo, "UIL_ACT_BLOCK\n");
				result = wvlan_uil_block(urq, lp);
				break;
			case UIL_ACT_UNBLOCK:
				DBG_TRACE(DbgInfo, "UIL_ACT_UNBLOCK\n");
				result = wvlan_uil_unblock(urq, lp);
				break;
			case UIL_ACT_SCAN:
				DBG_TRACE(DbgInfo, "UIL_ACT_SCAN\n");
				urq->result = hcf_action(&(lp->hcfCtx), MDD_ACT_SCAN);
				break;
			case UIL_ACT_APPLY:
				DBG_TRACE(DbgInfo, "UIL_ACT_APPLY\n");
				urq->result = wl_apply(lp);
				break;
			case UIL_ACT_RESET:
				DBG_TRACE(DbgInfo, "UIL_ACT_RESET\n");
				urq->result = wl_go(lp);
				break;
			default:
				DBG_WARNING(DbgInfo, "Unknown action code: 0x%x\n", ltv->typ);
				break;
			}
		} else {
			DBG_ERROR(DbgInfo, "Bad LTV for this action\n");
			urq->result = UIL_ERR_LEN;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_action */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_uil_block()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Sets a block in the driver to prevent access to the card by other
 *  processes.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/

int wvlan_uil_block(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_block");
	DBG_ENTER(DbgInfo);

	if (urq->hcfCtx == &(lp->hcfCtx)) {
		if (capable(CAP_NET_ADMIN)) {
			lp->flags |= WVLAN2_UIL_BUSY;
			netif_stop_queue(lp->dev);
			WL_WDS_NETIF_STOP_QUEUE(lp);
			urq->result = UIL_SUCCESS;
		} else {
			DBG_ERROR(DbgInfo, "EPERM\n");
			urq->result = UIL_FAILURE;
			result = -EPERM;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_block */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_uil_unblock()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Unblocks the driver to restore access to the card by other processes.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_unblock(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_unblock");
	DBG_ENTER(DbgInfo);

	if (urq->hcfCtx == &(lp->hcfCtx)) {
		if (capable(CAP_NET_ADMIN)) {
			if (lp->flags & WVLAN2_UIL_BUSY) {
				lp->flags &= ~WVLAN2_UIL_BUSY;
				netif_wake_queue(lp->dev);
				WL_WDS_NETIF_WAKE_QUEUE(lp);
			}
		} else {
			DBG_ERROR(DbgInfo, "EPERM\n");
			urq->result = UIL_FAILURE;
			result = -EPERM;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_unblock */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_uil_send_diag_msg()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Sends a diagnostic message to the card.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_send_diag_msg(struct uilreq *urq, struct wl_private *lp)
{
	int         result = 0;
	DESC_STRCT  Descp[1];
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_send_diag_msg");
	DBG_ENTER(DbgInfo);

	if (urq->hcfCtx == &(lp->hcfCtx)) {
		if (capable(CAP_NET_ADMIN)) {
			if ((urq->data != NULL) && (urq->len != 0)) {
				if (lp->hcfCtx.IFB_RscInd != 0) {
					u_char *data;

					/* Verify the user buffer */
					result = verify_area(VERIFY_READ, urq->data, urq->len);
					if (result != 0) {
						DBG_ERROR(DbgInfo, "verify_area failed, result: %d\n", result);
						urq->result = UIL_FAILURE;
						DBG_LEAVE(DbgInfo);
						return result;
					}

					data = kmalloc(urq->len, GFP_KERNEL);
					if (data != NULL) {
						memset(Descp, 0, sizeof(DESC_STRCT));
						memcpy(data, urq->data, urq->len);

						Descp[0].buf_addr       = (wci_bufp)data;
						Descp[0].BUF_CNT        = urq->len;
						Descp[0].next_desc_addr = 0;    /* terminate list */

						hcf_send_msg(&(lp->hcfCtx),  &Descp[0], HCF_PORT_0);
						kfree(data);
					} else {
						DBG_ERROR(DbgInfo, "ENOMEM\n");
						urq->result = UIL_FAILURE;
						result = -ENOMEM;
						DBG_LEAVE(DbgInfo);
						return result;
					}

				} else {
					urq->result = UIL_ERR_BUSY;
				}

			} else {
				urq->result = UIL_FAILURE;
			}
		} else {
			DBG_ERROR(DbgInfo, "EPERM\n");
			urq->result = UIL_FAILURE;
			result = -EPERM;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_send_diag_msg */
/*============================================================================*/


/*******************************************************************************
 *	wvlan_uil_put_info()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Sends a specific RID directly to the driver to set configuration info.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_put_info(struct uilreq *urq, struct wl_private *lp)
{
	int                     result = 0;
	ltv_t                   *pLtv;
	bool_t                  ltvAllocated = FALSE;
	ENCSTRCT                sEncryption;
	size_t			len;

#ifdef USE_WDS
	hcf_16                  hcfPort  = HCF_PORT_0;
#endif  /* USE_WDS */
	/*------------------------------------------------------------------------*/
	DBG_FUNC("wvlan_uil_put_info");
	DBG_ENTER(DbgInfo);


	if (urq->hcfCtx == &(lp->hcfCtx)) {
		if (capable(CAP_NET_ADMIN)) {
			if ((urq->data != NULL) && (urq->len != 0)) {
				/* Make sure that we have at least a command and length to send. */
				if (urq->len < (sizeof(hcf_16) * 2)) {
					urq->len = sizeof(lp->ltvRecord);
					urq->result = UIL_ERR_LEN;
					DBG_ERROR(DbgInfo, "No Length/Type in LTV!!!\n");
					DBG_ERROR(DbgInfo, "UIL_ERR_LEN\n");
					DBG_LEAVE(DbgInfo);
					return result;
				}

				/* Verify the user buffer */
				result = verify_area(VERIFY_READ, urq->data, urq->len);
				if (result != 0) {
					urq->result = UIL_FAILURE;
					DBG_ERROR(DbgInfo, "verify_area(), VERIFY_READ FAILED\n");
					DBG_LEAVE(DbgInfo);
					return result;
				}

				/* Get only the command and length information. */
				copy_from_user(&(lp->ltvRecord), urq->data, sizeof(hcf_16) * 2);

				/* Make sure the incoming LTV record length is within the bounds of the
				   IOCTL length */
				if (((lp->ltvRecord.len + 1) * sizeof(hcf_16)) > urq->len) {
					urq->len = sizeof(lp->ltvRecord);
					urq->result = UIL_ERR_LEN;
					DBG_ERROR(DbgInfo, "UIL_ERR_LEN\n");
					DBG_LEAVE(DbgInfo);
					return result;
				}

				/* If the requested length is greater than the size of our local
				   LTV record, try to allocate it from the kernel stack.
				   Otherwise, we just use our local LTV record. */
				if (urq->len > sizeof(lp->ltvRecord)) {
					pLtv = kmalloc(urq->len, GFP_KERNEL);
					if (pLtv != NULL) {
						ltvAllocated = TRUE;
					} else {
						DBG_ERROR(DbgInfo, "Alloc FAILED\n");
						urq->len = sizeof(lp->ltvRecord);
						urq->result = UIL_ERR_LEN;
						result = -ENOMEM;
						DBG_LEAVE(DbgInfo);
						return result;
					}
				} else {
					pLtv = &(lp->ltvRecord);
				}

				/* Copy the data from the user's buffer into the local LTV
				   record data area. */
				copy_from_user(pLtv, urq->data, urq->len);


				/* We need to snoop the commands to see if there is anything we
				   need to store for the purposes of a reset or start/stop
				   sequence. Perform endian translation as needed */
				switch (pLtv->typ) {
				case CFG_CNF_PORT_TYPE:
					lp->PortType    = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_OWN_MAC_ADDR:
					/* TODO: determine if we are going to store anything based on this */
					break;
				case CFG_CNF_OWN_CHANNEL:
					lp->Channel     = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				/* CFG_CNF_OWN_SSID currently same as CNF_DESIRED_SSID. Do we
				   need separate storage for this? */
				/* case CFG_CNF_OWN_SSID: */
				case CFG_CNF_OWN_ATIM_WINDOW:
					lp->atimWindow  = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_SYSTEM_SCALE:
					lp->DistanceBetweenAPs  = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);

				case CFG_CNF_MAX_DATA_LEN:
					/* TODO: determine if we are going to store anything based
					   on this */
					break;
				case CFG_CNF_PM_ENABLED:
					lp->PMEnabled   = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_MCAST_RX:
					lp->MulticastReceive    = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_MAX_SLEEP_DURATION:
					lp->MaxSleepDuration    = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_HOLDOVER_DURATION:
					lp->holdoverDuration    = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_OWN_NAME:
					memset(lp->StationName, 0, sizeof(lp->StationName));
					len = min_t(size_t, pLtv->u.u16[0], sizeof(lp->StationName));
					strlcpy(lp->StationName, &pLtv->u.u8[2], len);
					pLtv->u.u16[0] = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_LOAD_BALANCING:
					lp->loadBalancing       = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_MEDIUM_DISTRIBUTION:
					lp->mediumDistribution  = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#ifdef WARP
				case CFG_CNF_TX_POW_LVL:
					lp->txPowLevel          = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				/* case CFG_CNF_SHORT_RETRY_LIMIT: */ /* Short Retry Limit */
				/* case 0xFC33: */   /* Long Retry Limit */
				case CFG_SUPPORTED_RATE_SET_CNTL:        /* Supported Rate Set Control */
					lp->srsc[0]             = pLtv->u.u16[0];
					lp->srsc[1]             = pLtv->u.u16[1];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					pLtv->u.u16[1]          = CNV_INT_TO_LITTLE(pLtv->u.u16[1]);
					break;
				case CFG_BASIC_RATE_SET_CNTL:        /* Basic Rate Set Control */
					lp->brsc[0]             = pLtv->u.u16[0];
					lp->brsc[1]             = pLtv->u.u16[1];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					pLtv->u.u16[1]          = CNV_INT_TO_LITTLE(pLtv->u.u16[1]);
					break;
				case CFG_CNF_CONNECTION_CNTL:
					lp->connectionControl   = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				/* case CFG_PROBE_DATA_RATE: */
#endif  /* HERMES25 */

#if 1 /* ;? (HCF_TYPE) & HCF_TYPE_AP */
		/* ;?should we restore this to allow smaller memory footprint */

				case CFG_CNF_OWN_DTIM_PERIOD:
					lp->DTIMPeriod  = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#ifdef WARP
				case CFG_CNF_OWN_BEACON_INTERVAL:        /* Own Beacon Interval */
					lp->ownBeaconInterval   = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#endif /* WARP */
				case CFG_COEXISTENSE_BEHAVIOUR:         /* Coexistence behavior */
					lp->coexistence         = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#ifdef USE_WDS
				case CFG_CNF_WDS_ADDR1:
					memcpy(&lp->wds_port[0].wdsAddress, &pLtv->u.u8[0], ETH_ALEN);
					hcfPort = HCF_PORT_1;
					break;
				case CFG_CNF_WDS_ADDR2:
					memcpy(&lp->wds_port[1].wdsAddress, &pLtv->u.u8[0], ETH_ALEN);
					hcfPort = HCF_PORT_2;
					break;
				case CFG_CNF_WDS_ADDR3:
					memcpy(&lp->wds_port[2].wdsAddress, &pLtv->u.u8[0], ETH_ALEN);
					hcfPort = HCF_PORT_3;
					break;
				case CFG_CNF_WDS_ADDR4:
					memcpy(&lp->wds_port[3].wdsAddress, &pLtv->u.u8[0], ETH_ALEN);
					hcfPort = HCF_PORT_4;
					break;
				case CFG_CNF_WDS_ADDR5:
					memcpy(&lp->wds_port[4].wdsAddress, &pLtv->u.u8[0], ETH_ALEN);
					hcfPort = HCF_PORT_5;
					break;
				case CFG_CNF_WDS_ADDR6:
					memcpy(&lp->wds_port[5].wdsAddress, &pLtv->u.u8[0], ETH_ALEN);
					hcfPort = HCF_PORT_6;
					break;
#endif  /* USE_WDS */

				case CFG_CNF_MCAST_PM_BUF:
					lp->multicastPMBuffering    = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_REJECT_ANY:
					lp->RejectAny   = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#endif

				case CFG_CNF_ENCRYPTION:
					lp->EnableEncryption    = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_CNF_AUTHENTICATION:
					lp->authentication  = pLtv->u.u16[0];
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#if 1 /* ;? (HCF_TYPE) & HCF_TYPE_AP */
		/* ;?should we restore this to allow smaller memory footprint */

				/* case CFG_CNF_EXCL_UNENCRYPTED:
					lp->ExcludeUnencrypted  = pLtv->u.u16[0];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break; */
				case CFG_CNF_MCAST_RATE:
					/* TODO: determine if we are going to store anything based on this */
					break;
				case CFG_CNF_INTRA_BSS_RELAY:
					lp->intraBSSRelay   = pLtv->u.u16[0];
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#endif

				case CFG_CNF_MICRO_WAVE:
					/* TODO: determine if we are going to store anything based on this */
					break;
				/*case CFG_CNF_LOAD_BALANCING:*/
					/* TODO: determine if we are going to store anything based on this */
					/* break; */
				/* case CFG_CNF_MEDIUM_DISTRIBUTION: */
					/* TODO: determine if we are going to store anything based on this */
					/* break; */
				/* case CFG_CNF_RX_ALL_GROUP_ADDRESS: */
					/*  TODO: determine if we are going to store anything based on this */
					/* break; */
				/* case CFG_CNF_COUNTRY_INFO: */
					/* TODO: determine if we are going to store anything based on this */
					/* break; */
				case CFG_CNF_OWN_SSID:
				/* case CNF_DESIRED_SSID: */
				case CFG_DESIRED_SSID:
					memset(lp->NetworkName, 0, sizeof(lp->NetworkName));
					memcpy((void *)lp->NetworkName, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]);
					pLtv->u.u16[0] = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);

					/* take care of the special network name "ANY" case */
					if ((strlen(&pLtv->u.u8[2]) == 0) ||
					   (strcmp(&pLtv->u.u8[2], "ANY") == 0) ||
					   (strcmp(&pLtv->u.u8[2], "any") == 0)) {
						/* set the SSID_STRCT llen field (u16[0]) to zero, and the
						effectually null the string u8[2] */
						pLtv->u.u16[0] = 0;
						pLtv->u.u8[2]  = 0;
					}
					break;
				case CFG_GROUP_ADDR:
					/* TODO: determine if we are going to store anything based on this */
					break;
				case CFG_CREATE_IBSS:
					lp->CreateIBSS  = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_RTS_THRH:
					lp->RTSThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_TX_RATE_CNTL:
					lp->TxRateControl[0]    = pLtv->u.u16[0];
					lp->TxRateControl[1]    = pLtv->u.u16[1];
					pLtv->u.u16[0]          = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					pLtv->u.u16[1]          = CNV_INT_TO_LITTLE(pLtv->u.u16[1]);
					break;
				case CFG_PROMISCUOUS_MODE:
					/* TODO: determine if we are going to store anything based on this */
					break;
				/* case CFG_WAKE_ON_LAN: */
					/* TODO: determine if we are going to store anything based on this */
					/* break; */
#if 1 /* ;? #if (HCF_TYPE) & HCF_TYPE_AP */
		/* ;?should we restore this to allow smaller memory footprint */
				case CFG_RTS_THRH0:
					lp->RTSThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_TX_RATE_CNTL0:
/*;?no idea what this should be, get going so comment it out					lp->TxRateControl   = pLtv->u.u16[0];*/
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
#ifdef USE_WDS
				case CFG_RTS_THRH1:
					lp->wds_port[0].rtsThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]                  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                         = HCF_PORT_1;
					break;
				case CFG_RTS_THRH2:
					lp->wds_port[1].rtsThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]                  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                         = HCF_PORT_2;
					break;
				case CFG_RTS_THRH3:
					lp->wds_port[2].rtsThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]                  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                         = HCF_PORT_3;
					break;
				case CFG_RTS_THRH4:
					lp->wds_port[3].rtsThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]                  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                         = HCF_PORT_4;
					break;
				case CFG_RTS_THRH5:
					lp->wds_port[4].rtsThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]                  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                         = HCF_PORT_5;
					break;
				case CFG_RTS_THRH6:
					lp->wds_port[5].rtsThreshold    = pLtv->u.u16[0];
					pLtv->u.u16[0]                  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                         = HCF_PORT_6;
					break;
				case CFG_TX_RATE_CNTL1:
					lp->wds_port[0].txRateCntl  = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                     = HCF_PORT_1;
					break;
				case CFG_TX_RATE_CNTL2:
					lp->wds_port[1].txRateCntl  = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                     = HCF_PORT_2;
					break;
				case CFG_TX_RATE_CNTL3:
					lp->wds_port[2].txRateCntl  = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                     = HCF_PORT_3;
					break;
				case CFG_TX_RATE_CNTL4:
					lp->wds_port[3].txRateCntl  = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                     = HCF_PORT_4;
					break;
				case CFG_TX_RATE_CNTL5:
					lp->wds_port[4].txRateCntl  = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                     = HCF_PORT_5;
					break;
				case CFG_TX_RATE_CNTL6:
					lp->wds_port[5].txRateCntl  = pLtv->u.u16[0];
					pLtv->u.u16[0]              = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					hcfPort                     = HCF_PORT_6;
					break;
#endif  /* USE_WDS */
#endif  /* (HCF_TYPE) & HCF_TYPE_AP */

				case CFG_DEFAULT_KEYS:
					{
						CFG_DEFAULT_KEYS_STRCT *pKeys = (CFG_DEFAULT_KEYS_STRCT *)pLtv;

						pKeys->key[0].len = CNV_INT_TO_LITTLE(pKeys->key[0].len);
						pKeys->key[1].len = CNV_INT_TO_LITTLE(pKeys->key[1].len);
						pKeys->key[2].len = CNV_INT_TO_LITTLE(pKeys->key[2].len);
						pKeys->key[3].len = CNV_INT_TO_LITTLE(pKeys->key[3].len);

						memcpy((void *)&(lp->DefaultKeys), (void *)pKeys,
								sizeof(CFG_DEFAULT_KEYS_STRCT));
					}
					break;
				case CFG_TX_KEY_ID:
					lp->TransmitKeyID   = pLtv->u.u16[0];
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_SCAN_SSID:
					/* TODO: determine if we are going to store anything based on this */
					break;
				case CFG_TICK_TIME:
					/* TODO: determine if we are going to store anything based on this */
					break;
				/* these RIDS are Info RIDs, and should they be allowed for puts??? */
				case CFG_MAX_LOAD_TIME:
				case CFG_DL_BUF:
				/* case CFG_HSI_SUP_RANGE: */
				case CFG_NIC_SERIAL_NUMBER:
				case CFG_NIC_IDENTITY:
				case CFG_NIC_MFI_SUP_RANGE:
				case CFG_NIC_CFI_SUP_RANGE:
				case CFG_NIC_TEMP_TYPE:
				case CFG_NIC_PROFILE:
				case CFG_FW_IDENTITY:
				case CFG_FW_SUP_RANGE:
				case CFG_MFI_ACT_RANGES_STA:
				case CFG_CFI_ACT_RANGES_STA:
				case CFG_PORT_STAT:
				case CFG_CUR_SSID:
				case CFG_CUR_BSSID:
				case CFG_COMMS_QUALITY:
				case CFG_CUR_TX_RATE:
				case CFG_CUR_BEACON_INTERVAL:
				case CFG_CUR_SCALE_THRH:
				case CFG_PROTOCOL_RSP_TIME:
				case CFG_CUR_SHORT_RETRY_LIMIT:
				case CFG_CUR_LONG_RETRY_LIMIT:
				case CFG_MAX_TX_LIFETIME:
				case CFG_MAX_RX_LIFETIME:
				case CFG_CF_POLLABLE:
				case CFG_AUTHENTICATION_ALGORITHMS:
				case CFG_PRIVACY_OPT_IMPLEMENTED:
				/* case CFG_CURRENT_REMOTE_RATES: */
				/* case CFG_CURRENT_USED_RATES: */
				/* case CFG_CURRENT_SYSTEM_SCALE: */
				/* case CFG_CURRENT_TX_RATE1: */
				/* case CFG_CURRENT_TX_RATE2: */
				/* case CFG_CURRENT_TX_RATE3: */
				/* case CFG_CURRENT_TX_RATE4: */
				/* case CFG_CURRENT_TX_RATE5: */
				/* case CFG_CURRENT_TX_RATE6: */
				case CFG_NIC_MAC_ADDR:
				case CFG_PCF_INFO:
				/* case CFG_CURRENT_COUNTRY_INFO: */
				case CFG_PHY_TYPE:
				case CFG_CUR_CHANNEL:
				/* case CFG_CURRENT_POWER_STATE: */
				/* case CFG_CCAMODE: */
				case CFG_SUPPORTED_DATA_RATES:
					break;
				case CFG_AP_MODE:
/*;?				lp->DownloadFirmware = (pLtv->u.u16[0]) + 1; */
					DBG_ERROR(DbgInfo, "set CFG_AP_MODE no longer supported\n");
					break;
				case CFG_ENCRYPT_STRING:
					/* TODO: ENDIAN TRANSLATION HERE??? */
					memset(lp->szEncryption, 0, sizeof(lp->szEncryption));
					memcpy((void *)lp->szEncryption,  (void *)&pLtv->u.u8[0],
							(pLtv->len * sizeof(hcf_16)));
					wl_wep_decode(CRYPT_CODE, &sEncryption,
								    lp->szEncryption);

					/* the Linux driver likes to use 1-4 for the key IDs, and then
					convert to 0-3 when sending to the card.  The Windows code
					base used 0-3 in the API DLL, which was ported to Linux.  For
					the sake of the user experience, we decided to keep 0-3 as the
					numbers used in the DLL; and will perform the +1 conversion here.
					We could have converted  the entire Linux driver, but this is
					less obtrusive.  This may be a "todo" to convert the whole driver */
					lp->TransmitKeyID    = sEncryption.wTxKeyID + 1;
					lp->EnableEncryption = sEncryption.wEnabled;

					memcpy(&lp->DefaultKeys, &sEncryption.EncStr,
							sizeof(CFG_DEFAULT_KEYS_STRCT));
					break;
				/*case CFG_COUNTRY_STRING:
					memset(lp->countryString, 0, sizeof(lp->countryString));
					memcpy((void *)lp->countryString, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]);
					break;
				*/

				case CFG_DRIVER_ENABLE:
					lp->driverEnable    = pLtv->u.u16[0];
					pLtv->u.u16[0]      = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_WOLAS_ENABLE:
					lp->wolasEnable = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_SET_WPA_AUTH_KEY_MGMT_SUITE:
					lp->AuthKeyMgmtSuite = pLtv->u.u16[0];
					pLtv->u.u16[0]  = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_DISASSOCIATE_ADDR:
					pLtv->u.u16[ETH_ALEN / 2] = CNV_INT_TO_LITTLE(pLtv->u.u16[ETH_ALEN / 2]);
					break;
				case CFG_ADD_TKIP_DEFAULT_KEY:
				case CFG_REMOVE_TKIP_DEFAULT_KEY:
					/* Endian convert the Tx Key Information */
					pLtv->u.u16[0] = CNV_INT_TO_LITTLE(pLtv->u.u16[0]);
					break;
				case CFG_ADD_TKIP_MAPPED_KEY:
					break;
				case CFG_REMOVE_TKIP_MAPPED_KEY:
					break;
				/* some RIDs just can't be put */
				case CFG_MB_INFO:
				case CFG_IFB:
				default:
					break;
				}

				/* This code will prevent Static Configuration Entities from
				   being sent to the card, as they require a call to
				   UIL_ACT_APPLY to take effect. Dynamic Entities will be sent
				   immediately */
				switch (pLtv->typ) {
				case CFG_CNF_PORT_TYPE:
				case CFG_CNF_OWN_MAC_ADDR:
				case CFG_CNF_OWN_CHANNEL:
				case CFG_CNF_OWN_SSID:
				case CFG_CNF_OWN_ATIM_WINDOW:
				case CFG_CNF_SYSTEM_SCALE:
				case CFG_CNF_MAX_DATA_LEN:
				case CFG_CNF_PM_ENABLED:
				case CFG_CNF_MCAST_RX:
				case CFG_CNF_MAX_SLEEP_DURATION:
				case CFG_CNF_HOLDOVER_DURATION:
				case CFG_CNF_OWN_NAME:
				case CFG_CNF_LOAD_BALANCING:
				case CFG_CNF_MEDIUM_DISTRIBUTION:
#ifdef WARP
				case CFG_CNF_TX_POW_LVL:
				case CFG_CNF_CONNECTION_CNTL:
				/*case CFG_PROBE_DATA_RATE: */
#endif /* HERMES25 */
#if 1 /*;? (HCF_TYPE) & HCF_TYPE_AP */
		/*;?should we restore this to allow smaller memory footprint */
				case CFG_CNF_OWN_DTIM_PERIOD:
#ifdef WARP
				case CFG_CNF_OWN_BEACON_INTERVAL:                    /* Own Beacon Interval */
#endif /* WARP */
#ifdef USE_WDS
				case CFG_CNF_WDS_ADDR1:
				case CFG_CNF_WDS_ADDR2:
				case CFG_CNF_WDS_ADDR3:
				case CFG_CNF_WDS_ADDR4:
				case CFG_CNF_WDS_ADDR5:
				case CFG_CNF_WDS_ADDR6:
#endif
				case CFG_CNF_MCAST_PM_BUF:
				case CFG_CNF_REJECT_ANY:
#endif

				case CFG_CNF_ENCRYPTION:
				case CFG_CNF_AUTHENTICATION:
#if 1 /* ;? (HCF_TYPE) & HCF_TYPE_AP */
		/* ;?should we restore this to allow smaller memory footprint */

				case CFG_CNF_EXCL_UNENCRYPTED:
				case CFG_CNF_MCAST_RATE:
				case CFG_CNF_INTRA_BSS_RELAY:
#endif

				case CFG_CNF_MICRO_WAVE:
				/* case CFG_CNF_LOAD_BALANCING: */
				/* case CFG_CNF_MEDIUM_DISTRIBUTION: */
				/* case CFG_CNF_RX_ALL_GROUP_ADDRESS: */
				/* case CFG_CNF_COUNTRY_INFO: */
				/* case CFG_COUNTRY_STRING: */
				case CFG_AP_MODE:
				case CFG_ENCRYPT_STRING:
				/* case CFG_DRIVER_ENABLE: */
				case CFG_WOLAS_ENABLE:
				case CFG_MB_INFO:
				case CFG_IFB:
					break;
				/* Deal with this dynamic MSF RID, as it's required for WPA */
				case CFG_DRIVER_ENABLE:
					if (lp->driverEnable) {
						hcf_cntl(&(lp->hcfCtx), HCF_CNTL_ENABLE | HCF_PORT_0);
						hcf_cntl(&(lp->hcfCtx), HCF_CNTL_CONNECT);
					} else {
						hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISABLE | HCF_PORT_0);
						hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISCONNECT);
					}
					break;
				default:
					wl_act_int_off(lp);
					urq->result = hcf_put_info(&(lp->hcfCtx), (LTVP) pLtv);
					wl_act_int_on(lp);
					break;
				}

				if (ltvAllocated)
					kfree(pLtv);
			} else {
				urq->result = UIL_FAILURE;
			}
		} else {
			DBG_ERROR(DbgInfo, "EPERM\n");
			urq->result = UIL_FAILURE;
			result = -EPERM;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_put_info */

/*============================================================================*/

/*******************************************************************************
 *	wvlan_uil_get_info()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Sends a specific RID directly to the driver to retrieve configuration
 *      info.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int wvlan_uil_get_info(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	int i;
	/*------------------------------------------------------------------------*/

	DBG_FUNC("wvlan_uil_get_info");
	DBG_ENTER(DbgInfo);

	if (urq->hcfCtx == &(lp->hcfCtx)) {
		if ((urq->data != NULL) && (urq->len != 0)) {
			ltv_t      *pLtv;
			bool_t      ltvAllocated = FALSE;

			/* Make sure that we have at least a command and length */
			if (urq->len < (sizeof(hcf_16) * 2)) {
				urq->len = sizeof(lp->ltvRecord);
				DBG_ERROR(DbgInfo, "No Length/Type in LTV!!!\n");
				DBG_ERROR(DbgInfo, "UIL_ERR_LEN\n");
				urq->result = UIL_ERR_LEN;
				DBG_LEAVE(DbgInfo);
				return result;
			}

			/* Verify the user's LTV record header. */
			result = verify_area(VERIFY_READ, urq->data, sizeof(hcf_16) * 2);
			if (result != 0) {
				DBG_ERROR(DbgInfo, "verify_area(), VERIFY_READ FAILED\n");
				urq->result = UIL_FAILURE;
				DBG_LEAVE(DbgInfo);
				return result;
			}

			/* Get only the command and length information. */
			result = copy_from_user(&(lp->ltvRecord), urq->data, sizeof(hcf_16) * 2);

			/* Make sure the incoming LTV record length is within the bounds of
			   the IOCTL length. */
			if (((lp->ltvRecord.len + 1) * sizeof(hcf_16)) > urq->len) {
				DBG_ERROR(DbgInfo, "Incoming LTV too big\n");
				urq->len = sizeof(lp->ltvRecord);
				urq->result = UIL_ERR_LEN;
				DBG_LEAVE(DbgInfo);
				return result;
			}

			/* Determine if hcf_get_info() is needed or not */
			switch (lp->ltvRecord.typ) {
			case CFG_NIC_IDENTITY:
				memcpy(&lp->ltvRecord.u.u8[0], &lp->NICIdentity, sizeof(lp->NICIdentity));
				break;
			case CFG_PRI_IDENTITY:
				memcpy(&lp->ltvRecord.u.u8[0], &lp->PrimaryIdentity, sizeof(lp->PrimaryIdentity));
				break;
			case CFG_AP_MODE:
				DBG_ERROR(DbgInfo, "set CFG_AP_MODE no longer supported, so is get useful ????\n");
				lp->ltvRecord.u.u16[0] =
					CNV_INT_TO_LITTLE(lp->hcfCtx.IFB_FWIdentity.comp_id) == COMP_ID_FW_AP;
				break;
			/* case CFG_DRV_INFO: */
			case CFG_ENCRYPT_STRING:
			case CFG_COUNTRY_STRING:
			case CFG_DRIVER_ENABLE:
			case CFG_WOLAS_ENABLE:
				/* TODO: determine if we're going to support these */
				urq->result = UIL_FAILURE;
				break;
			case CFG_DRV_INFO:
				DBG_TRACE(DbgInfo, "Intercept CFG_DRV_INFO\n");
				result = cfg_driver_info(urq, lp);
				break;
			case CFG_DRV_IDENTITY:
				DBG_TRACE(DbgInfo, "Intercept CFG_DRV_IDENTITY\n");
				result = cfg_driver_identity(urq, lp);
				break;
			case CFG_IFB:
				/* IFB can be a security hole */
				if (!capable(CAP_NET_ADMIN)) {
					result = -EPERM;
					break;
				}

				/* Else fall through to the default */

			case CFG_FW_IDENTITY:   /* For Hermes-1, this is cached */
			default:

				/* Verify the user buffer */
				result = verify_area(VERIFY_WRITE, urq->data, urq->len);
				if (result != 0) {
					DBG_ERROR(DbgInfo, "verify_area(), VERIFY_WRITE FAILED\n");
					urq->result = UIL_FAILURE;
					break;
				}

				/* If the requested length is greater than the size of our local
				   LTV record, try to allocate it from the kernel stack.
				   Otherwise, we just use our local LTV record. */
				if (urq->len > sizeof(lp->ltvRecord)) {
					pLtv = kmalloc(urq->len, GFP_KERNEL);
					if (pLtv != NULL) {
						ltvAllocated = TRUE;

						/* Copy the command/length information into the new buffer. */
						memcpy(pLtv, &(lp->ltvRecord), sizeof(hcf_16) * 2);
					} else {
						urq->len = sizeof(lp->ltvRecord);
						urq->result = UIL_ERR_LEN;
						DBG_ERROR(DbgInfo, "kmalloc FAILED\n");
						DBG_ERROR(DbgInfo, "UIL_ERR_LEN\n");
						result = -ENOMEM;
						break;
					}
				} else {
					pLtv = &(lp->ltvRecord);
				}

				wl_act_int_off(lp);
				urq->result = hcf_get_info(&(lp->hcfCtx), (LTVP) pLtv);
				wl_act_int_on(lp);

				/* Copy the LTV into the user's buffer. */
				/*copy_to_user(urq->data, pLtv, urq->len); */

				/*if(ltvAllocated)
				{
				    kfree(pLtv);
				}*/

				/* urq->result = UIL_SUCCESS; */
				break;
			}

			/* Handle endian conversion of special fields */
			switch (lp->ltvRecord.typ) {
			/* simple int gets just need the first hcf_16 byte flipped */
			case CFG_CNF_PORT_TYPE:
			case CFG_CNF_OWN_CHANNEL:
			case CFG_CNF_OWN_ATIM_WINDOW:
			case CFG_CNF_SYSTEM_SCALE:
			case CFG_CNF_MAX_DATA_LEN:
			case CFG_CNF_PM_ENABLED:
			case CFG_CNF_MCAST_RX:
			case CFG_CNF_MAX_SLEEP_DURATION:
			case CFG_CNF_HOLDOVER_DURATION:
			case CFG_CNF_OWN_DTIM_PERIOD:
			case CFG_CNF_MCAST_PM_BUF:
			case CFG_CNF_REJECT_ANY:
			case CFG_CNF_ENCRYPTION:
			case CFG_CNF_AUTHENTICATION:
			case CFG_CNF_EXCL_UNENCRYPTED:
			case CFG_CNF_INTRA_BSS_RELAY:
			case CFG_CNF_MICRO_WAVE:
			case CFG_CNF_LOAD_BALANCING:
			case CFG_CNF_MEDIUM_DISTRIBUTION:
#ifdef WARP
			case CFG_CNF_TX_POW_LVL:
			case CFG_CNF_CONNECTION_CNTL:
			case CFG_CNF_OWN_BEACON_INTERVAL:                          /* Own Beacon Interval */
			case CFG_COEXISTENSE_BEHAVIOUR:                            /* Coexistence Behavior */
			/*case CFG_CNF_RX_ALL_GROUP_ADDRESS: */
#endif /* HERMES25 */
			case CFG_CREATE_IBSS:
			case CFG_RTS_THRH:
			case CFG_PROMISCUOUS_MODE:
			/*case CFG_WAKE_ON_LAN: */
			case CFG_RTS_THRH0:
			case CFG_RTS_THRH1:
			case CFG_RTS_THRH2:
			case CFG_RTS_THRH3:
			case CFG_RTS_THRH4:
			case CFG_RTS_THRH5:
			case CFG_RTS_THRH6:
			case CFG_TX_RATE_CNTL0:
			case CFG_TX_RATE_CNTL1:
			case CFG_TX_RATE_CNTL2:
			case CFG_TX_RATE_CNTL3:
			case CFG_TX_RATE_CNTL4:
			case CFG_TX_RATE_CNTL5:
			case CFG_TX_RATE_CNTL6:
			case CFG_TX_KEY_ID:
			case CFG_TICK_TIME:
			case CFG_MAX_LOAD_TIME:
			case CFG_NIC_TEMP_TYPE:
			case CFG_PORT_STAT:
			case CFG_CUR_TX_RATE:
			case CFG_CUR_BEACON_INTERVAL:
			case CFG_PROTOCOL_RSP_TIME:
			case CFG_CUR_SHORT_RETRY_LIMIT:
			case CFG_CUR_LONG_RETRY_LIMIT:
			case CFG_MAX_TX_LIFETIME:
			case CFG_MAX_RX_LIFETIME:
			case CFG_CF_POLLABLE:
			case CFG_PRIVACY_OPT_IMPLEMENTED:
			/* case CFG_CURRENT_REMOTE_RATES: */
			/* case CFG_CURRENT_USED_RATES: */
			/* case CFG_CURRENT_SYSTEM_SCALE: */
			/* case CFG_CURRENT_TX_RATE1: */
			/* case CFG_CURRENT_TX_RATE2: */
			/* case CFG_CURRENT_TX_RATE3: */
			/* case CFG_CURRENT_TX_RATE4: */
			/* case CFG_CURRENT_TX_RATE5: */
			/* case CFG_CURRENT_TX_RATE6: */
			case CFG_PHY_TYPE:
			case CFG_CUR_CHANNEL:
			/* case CFG_CURRENT_POWER_STATE: */
			/* case CFG_CCAMODE: */
			/*     lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]); */
			/*     break; */
			/* name string gets just need the first hcf_16 byte flipped (length of string) */
			case CFG_CNF_OWN_SSID:
			case CFG_CNF_OWN_NAME:
			/* case CNF_DESIRED_SSID: */
			case CFG_DESIRED_SSID:
			case CFG_SCAN_SSID:
			case CFG_CUR_SSID:
				lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]);
				break;
			/* non-length counted strings need no byte flipping */
			case CFG_CNF_OWN_MAC_ADDR:
			/* this case is no longer valid: CFG_CNF_WDS_ADDR */
			case CFG_CNF_WDS_ADDR1:
			case CFG_CNF_WDS_ADDR2:
			case CFG_CNF_WDS_ADDR3:
			case CFG_CNF_WDS_ADDR4:
			case CFG_CNF_WDS_ADDR5:
			case CFG_CNF_WDS_ADDR6:
			case CFG_GROUP_ADDR:
			case CFG_NIC_SERIAL_NUMBER:
			case CFG_CUR_BSSID:
			case CFG_NIC_MAC_ADDR:
			case CFG_SUPPORTED_DATA_RATES:  /* need to ensure we can treat this as a string */
				break;
			/* case CFG_CNF_COUNTRY_INFO: */     /* special case, see page 75  of 022486, Rev C. */
			/* case CFG_CURRENT_COUNTRY_INFO: */ /* special case, see page 101 of 022486, Rev C. */
			/*
				lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]);
				lp->ltvRecord.u.u16[3] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[3]);

				for(i = 4; i < lp->ltvRecord.len; i++) {
					lp->ltvRecord.u.u16[i] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[i]);
				}
				break;
			*/

			case CFG_DEFAULT_KEYS:
				{
					CFG_DEFAULT_KEYS_STRCT *pKeys = (CFG_DEFAULT_KEYS_STRCT *)&lp->ltvRecord.u.u8[0];

					pKeys[0].len = CNV_INT_TO_LITTLE(pKeys[0].len);
					pKeys[1].len = CNV_INT_TO_LITTLE(pKeys[1].len);
					pKeys[2].len = CNV_INT_TO_LITTLE(pKeys[2].len);
					pKeys[3].len = CNV_INT_TO_LITTLE(pKeys[3].len);
				}
				break;
			case CFG_CNF_MCAST_RATE:
			case CFG_TX_RATE_CNTL:
			case CFG_SUPPORTED_RATE_SET_CNTL:    /*  Supported Rate Set Control */
			case CFG_BASIC_RATE_SET_CNTL:    /*  Basic Rate Set Control */
				lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]);
				lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[1]);
				break;
			case CFG_DL_BUF:
			case CFG_NIC_IDENTITY:
			case CFG_COMMS_QUALITY:
			case CFG_PCF_INFO:
				lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]);
				lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[1]);
				lp->ltvRecord.u.u16[2] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[2]);
				break;
			case CFG_FW_IDENTITY:
				lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]);
				lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[1]);
				lp->ltvRecord.u.u16[2] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[2]);
				lp->ltvRecord.u.u16[3] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[3]);
				break;
			/* case CFG_HSI_SUP_RANGE: */
			case CFG_NIC_MFI_SUP_RANGE:
			case CFG_NIC_CFI_SUP_RANGE:
			case CFG_NIC_PROFILE:
			case CFG_FW_SUP_RANGE:
				lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[0]);
				lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[1]);
				lp->ltvRecord.u.u16[2] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[2]);
				lp->ltvRecord.u.u16[3] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[3]);
				lp->ltvRecord.u.u16[4] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[4]);
				break;
			case CFG_MFI_ACT_RANGES_STA:
			case CFG_CFI_ACT_RANGES_STA:
			case CFG_CUR_SCALE_THRH:
			case CFG_AUTHENTICATION_ALGORITHMS:
				for (i = 0; i < (lp->ltvRecord.len - 1); i++)
					lp->ltvRecord.u.u16[i] = CNV_INT_TO_LITTLE(lp->ltvRecord.u.u16[i]);
				break;
			/* done at init time, and endian handled then */
			case CFG_PRI_IDENTITY:
				break;
			case CFG_MB_INFO:
				/* wvlanEndianTranslateMailbox(pLtv); */
				break;
			/* MSF and HCF RIDS */
			case CFG_IFB:
			case CFG_DRV_INFO:
			case CFG_AP_MODE:
			case CFG_ENCRYPT_STRING:
			case CFG_COUNTRY_STRING:
			case CFG_DRIVER_ENABLE:
			case CFG_WOLAS_ENABLE:
			default:
				break;
			}

			/* Copy the LTV into the user's buffer. */
			copy_to_user(urq->data, &(lp->ltvRecord), urq->len);

			if (ltvAllocated)
				kfree(&(lp->ltvRecord));
			urq->result = UIL_SUCCESS;
		} else {
			urq->result = UIL_FAILURE;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_get_info */
/*============================================================================*/





/*******************************************************************************
 *	cfg_driver_info()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Retrieves driver information.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int cfg_driver_info(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("cfg_driver_info");
	DBG_ENTER(DbgInfo);


	/* Make sure that user buffer can handle the driver information buffer */
	if (urq->len < sizeof(lp->driverInfo)) {
		urq->len = sizeof(lp->driverInfo);
		urq->result = UIL_ERR_LEN;
		DBG_LEAVE(DbgInfo);
		return result;
	}

	/* Verify the user buffer. */
	result = verify_area(VERIFY_WRITE, urq->data, sizeof(lp->driverInfo));
	if (result != 0) {
		urq->result = UIL_FAILURE;
		DBG_LEAVE(DbgInfo);
		return result;
	}

	lp->driverInfo.card_stat = lp->hcfCtx.IFB_CardStat;

	/* Copy the driver information into the user's buffer. */
	urq->result = UIL_SUCCESS;
	copy_to_user(urq->data, &(lp->driverInfo), sizeof(lp->driverInfo));

	DBG_LEAVE(DbgInfo);
	return result;
} /* cfg_driver_info */
/*============================================================================*/




/*******************************************************************************
 *	cfg_driver_identity()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Retrieves ID information from the card.
 *
 *  PARAMETERS:
 *
 *      urq - a pointer to the UIL request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      UIL_SUCCESS
 *      UIL_ERR_xxx value otherwise
 *
 ******************************************************************************/
int cfg_driver_identity(struct uilreq *urq, struct wl_private *lp)
{
	int result = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_driver_identity");
	DBG_ENTER(DbgInfo);


	/* Make sure that user buffer can handle the driver identity structure. */
	if (urq->len < sizeof(lp->driverIdentity)) {
		urq->len = sizeof(lp->driverIdentity);
		urq->result = UIL_ERR_LEN;
		DBG_LEAVE(DbgInfo);
		return result;
	}

	/* Verify the user buffer. */
	result = verify_area(VERIFY_WRITE, urq->data, sizeof(lp->driverIdentity));
	if (result != 0) {
		urq->result = UIL_FAILURE;
		DBG_LEAVE(DbgInfo);
		return result;
	}

	/* Copy the driver identity into the user's buffer. */
	urq->result = UIL_SUCCESS;
	copy_to_user(urq->data, &(lp->driverIdentity), sizeof(lp->driverIdentity));

	DBG_LEAVE(DbgInfo);
	return result;
} /* cfg_driver_identity */
/*============================================================================*/


#endif  /* USE_UIL */


/* If WIRELESS_EXT is not defined, then the functions that follow will not be
   included in the build. */
/* NOTE: Are these still even needed? */
#ifdef WIRELESS_EXT


/*******************************************************************************
 *	wvlan_set_netname()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Set the ESSID of the card.
 *
 *  PARAMETERS:
 *
 *      wrq - a pointer to the wireless request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_set_netname(struct net_device *dev,
		      struct iw_request_info *info,
		      union iwreq_data *wrqu,
		      char *extra)
{
	struct wl_private *lp = wl_priv(dev);
	unsigned long flags;
	int ret = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_set_netname");
	DBG_ENTER(DbgInfo);

	wl_lock(lp, &flags);

	memset(lp->NetworkName, 0, sizeof(lp->NetworkName));
	memcpy(lp->NetworkName, extra, wrqu->data.length);

	/* Commit the adapter parameters */
	wl_apply(lp);
	wl_unlock(lp, &flags);

	DBG_LEAVE(DbgInfo);
	return ret;
} /* wvlan_set_netname */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_get_netname()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Get the ESSID of the card.
 *
 *  PARAMETERS:
 *
 *      wrq - a pointer to the wireless request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_get_netname(struct net_device *dev,
		      struct iw_request_info *info,
		      union iwreq_data *wrqu,
		      char *extra)
{
	struct wl_private *lp = wl_priv(dev);
	unsigned long flags;
	int         ret = 0;
	int         status = -1;
	wvName_t   *pName;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_get_netname");
	DBG_ENTER(DbgInfo);

	wl_lock(lp, &flags);

	/* Get the current network name */
	lp->ltvRecord.len = 1 + (sizeof(*pName) / sizeof(hcf_16));
	lp->ltvRecord.typ = CFG_CUR_SSID;

	status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));

	if (status == HCF_SUCCESS) {
		pName = (wvName_t *)&(lp->ltvRecord.u.u32);

		memset(extra, '\0', HCF_MAX_NAME_LEN);
		wrqu->data.length = pName->length;

		memcpy(extra, pName->name, pName->length);
	} else {
		ret = -EFAULT;
	}

	wl_unlock(lp, &flags);

	DBG_LEAVE(DbgInfo);
	return ret;
} /* wvlan_get_netname */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_set_station_nickname()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Set the card's station nickname.
 *
 *  PARAMETERS:
 *
 *      wrq - a pointer to the wireless request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_set_station_nickname(struct net_device *dev,
		      struct iw_request_info *info,
		      union iwreq_data *wrqu,
		      char *extra)
{
	struct wl_private *lp = wl_priv(dev);
	unsigned long flags;
	size_t len;
	int         ret = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_set_station_nickname");
	DBG_ENTER(DbgInfo);

	wl_lock(lp, &flags);

	memset(lp->StationName, 0, sizeof(lp->StationName));
	len = min_t(size_t, wrqu->data.length, sizeof(lp->StationName));
	strlcpy(lp->StationName, extra, len);

	/* Commit the adapter parameters */
	wl_apply(lp);
	wl_unlock(lp, &flags);

	DBG_LEAVE(DbgInfo);
	return ret;
} /* wvlan_set_station_nickname */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_get_station_nickname()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Get the card's station nickname.
 *
 *  PARAMETERS:
 *
 *      wrq - a pointer to the wireless request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_get_station_nickname(struct net_device *dev,
		      struct iw_request_info *info,
		      union iwreq_data *wrqu,
		      char *extra)
{
	struct wl_private *lp = wl_priv(dev);
	unsigned long flags;
	int         ret = 0;
	int         status = -1;
	wvName_t   *pName;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_get_station_nickname");
	DBG_ENTER(DbgInfo);

	wl_lock(lp, &flags);

	/* Get the current station name */
	lp->ltvRecord.len = 1 + (sizeof(*pName) / sizeof(hcf_16));
	lp->ltvRecord.typ = CFG_CNF_OWN_NAME;

	status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));

	if (status == HCF_SUCCESS) {
		pName = (wvName_t *)&(lp->ltvRecord.u.u32);

		memset(extra, '\0', HCF_MAX_NAME_LEN);
		wrqu->data.length = pName->length;
		memcpy(extra, pName->name, pName->length);
	} else {
		ret = -EFAULT;
	}

	wl_unlock(lp, &flags);

/* out: */
	DBG_LEAVE(DbgInfo);
	return ret;
} /* wvlan_get_station_nickname */
/*============================================================================*/




/*******************************************************************************
 *	wvlan_set_porttype()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Set the card's porttype
 *
 *  PARAMETERS:
 *
 *      wrq - a pointer to the wireless request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_set_porttype(struct net_device *dev,
		      struct iw_request_info *info,
		      union iwreq_data *wrqu,
		      char *extra)
{
	struct wl_private *lp = wl_priv(dev);
	unsigned long flags;
	int     ret = 0;
	hcf_16  portType;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_set_porttype");
	DBG_ENTER(DbgInfo);

	wl_lock(lp, &flags);

	/* Validate the new value */
	portType = *((__u32 *)extra);

	if (!((portType == 1) || (portType == 3))) {
		ret = -EINVAL;
		goto out_unlock;
	}

	lp->PortType = portType;

	/* Commit the adapter parameters */
	wl_apply(lp);

out_unlock:
	wl_unlock(lp, &flags);

/* out: */
	DBG_LEAVE(DbgInfo);
	return ret;
}

/*============================================================================*/


/*******************************************************************************
 *	wvlan_get_porttype()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Get the card's porttype
 *
 *  PARAMETERS:
 *
 *      wrq - a pointer to the wireless request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_get_porttype(struct net_device *dev,
		      struct iw_request_info *info,
		      union iwreq_data *wrqu,
		      char *extra)
{
	struct wl_private *lp = wl_priv(dev);
	unsigned long flags;
	int     ret = 0;
	int     status = -1;
	hcf_16  *pPortType;
	__u32 *pData = (__u32 *)extra;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_get_porttype");
	DBG_ENTER(DbgInfo);

	wl_lock(lp, &flags);

	/* Get the current port type */
	lp->ltvRecord.len = 1 + (sizeof(*pPortType) / sizeof(hcf_16));
	lp->ltvRecord.typ = CFG_CNF_PORT_TYPE;

	status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));

	if (status == HCF_SUCCESS) {
		pPortType = (hcf_16 *)&(lp->ltvRecord.u.u32);

		*pData = CNV_LITTLE_TO_INT(*pPortType);
	} else {
	    ret = -EFAULT;
	}

	wl_unlock(lp, &flags);

/* out: */
	DBG_LEAVE(DbgInfo);
	return ret;
} /* wvlan_get_porttype */
/*============================================================================*/

#endif  /* WIRELESS_EXT */




#ifdef USE_RTS
/*******************************************************************************
 *	wvlan_rts()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      IOCTL handler for RTS commands
 *
 *  PARAMETERS:
 *
 *      rrq - a pointer to the rts request buffer
 *      lp  - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      0 on success
 *      errno value otherwise
 *
 ******************************************************************************/
int wvlan_rts(struct rtsreq *rrq, __u32 io_base)
{
	int ioctl_ret = 0;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_rts");
	DBG_ENTER(DbgInfo);


	DBG_PRINT("io_base: 0x%08x\n", io_base);

	switch (rrq->typ) {
	case WL_IOCTL_RTS_READ:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_RTS -- WL_IOCTL_RTS_READ\n");
		rrq->data[0] = IN_PORT_WORD(io_base + rrq->reg);
		DBG_TRACE(DbgInfo, "  reg 0x%04x ==> 0x%04x\n", rrq->reg, CNV_LITTLE_TO_SHORT(rrq->data[0]));
		break;
	case WL_IOCTL_RTS_WRITE:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_RTS -- WL_IOCTL_RTS_WRITE\n");
		OUT_PORT_WORD(io_base + rrq->reg, rrq->data[0]);
		DBG_TRACE(DbgInfo, "  reg 0x%04x <== 0x%04x\n", rrq->reg, CNV_LITTLE_TO_SHORT(rrq->data[0]));
		break;
	case WL_IOCTL_RTS_BATCH_READ:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_RTS -- WL_IOCTL_RTS_BATCH_READ\n");
		IN_PORT_STRING_16(io_base + rrq->reg, rrq->data, rrq->len);
		DBG_TRACE(DbgInfo, "  reg 0x%04x ==> %d bytes\n", rrq->reg, rrq->len * sizeof(__u16));
		break;
	case WL_IOCTL_RTS_BATCH_WRITE:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_RTS -- WL_IOCTL_RTS_BATCH_WRITE\n");
		OUT_PORT_STRING_16(io_base + rrq->reg, rrq->data, rrq->len);
		DBG_TRACE(DbgInfo, "  reg 0x%04x <== %d bytes\n", rrq->reg, rrq->len * sizeof(__u16));
		break;
	default:

		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_RTS -- UNSUPPORTED RTS CODE: 0x%X", rrq->typ);
		ioctl_ret = -EOPNOTSUPP;
		break;
	}

	DBG_LEAVE(DbgInfo);
	return ioctl_ret;
} /* wvlan_rts */
/*============================================================================*/

#endif  /* USE_RTS */
