diff options
Diffstat (limited to 'drivers/staging/wlags49_h2/wl_priv.c')
-rw-r--r-- | drivers/staging/wlags49_h2/wl_priv.c | 2078 |
1 files changed, 2078 insertions, 0 deletions
diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c new file mode 100644 index 00000000000..ee610c76457 --- /dev/null +++ b/drivers/staging/wlags49_h2/wl_priv.c @@ -0,0 +1,2078 @@ +/******************************************************************************* + * 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/delay.h> +#include <asm/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: + * + * Disonnect 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; + } + + if ((data = kmalloc(urq->len, GFP_KERNEL)) != 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; + +#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 )) { + if(( pLtv = (ltv_t *)kmalloc( urq->len, GFP_KERNEL )) != 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 seperate 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 )); + memcpy( (void *)lp->StationName, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]); + 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_port( &( lp->hcfCtx ), + // HCF_PORT_ENABLE | HCF_PORT_0 ); + // //hcf_cntl( &( lp->hcfCtx ), + // // HCF_PORT_ENABLE | HCF_PORT_0 ); + //hcf_cntl( &( lp->hcfCtx ), HCF_CNTL_ENABLE ); + // //hcf_cntl( &( lp->hcfCtx ), HCF_CNTL_CONNECT ); + + hcf_cntl( &( lp->hcfCtx ), HCF_CNTL_ENABLE | HCF_PORT_0 ); + hcf_cntl( &( lp->hcfCtx ), HCF_CNTL_CONNECT ); + } else { + //hcf_cntl_port( &( lp->hcfCtx ), + // HCF_PORT_DISABLE | HCF_PORT_0 ); + // //hcf_cntl( &( lp->hcfCtx ), + // // HCF_PORT_DISABLE | HCF_PORT_0 ); + //hcf_cntl( &( lp->hcfCtx ), HCF_CNTL_DISABLE ); + // //hcf_cntl( &( lp->hcfCtx ), HCF_CNTL_DISCONNECT ); + + 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 )) { + if(( pLtv = (ltv_t *)kmalloc( urq->len, GFP_KERNEL )) != 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; + int ret = 0; + /*------------------------------------------------------------------------*/ + + + DBG_FUNC( "wvlan_set_station_nickname" ); + DBG_ENTER( DbgInfo ); + + wl_lock(lp, &flags); + + memset( lp->StationName, 0, sizeof( lp->StationName )); + + memcpy( lp->StationName, extra, wrqu->data.length); + + /* 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 */ |