/*******************************************************************************
 * 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 routines required to parse configuration parameters
 *   listed in a config file, if that config file exists.
 *
 *------------------------------------------------------------------------------
 *
 * 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.
 *
 ******************************************************************************/




/*******************************************************************************
 * VERSION CONTROL INFORMATION
 *******************************************************************************
 *
 * $Author: vjs $
 * $Date: 2004/03/31 14:47:45 $
 * $Revision: 1.28 $
 * $Source: /cvsroot/wifi/wl_lkm/wireless/wl_profile.c,v $
 *
 ******************************************************************************/




/* Only include this file if USE_PROFILE is defined */
#ifdef USE_PROFILE




/*******************************************************************************
 *  constant definitions
 ******************************************************************************/

/* Allow support for calling system fcns to parse config file */
#define __KERNEL_SYSCALLS__




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

#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>

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

#include <wireless/wl_if.h>
#include <wireless/wl_internal.h>
#include <wireless/wl_util.h>
#include <wireless/wl_enc.h>
#include <wireless/wl_main.h>
#include <wireless/wl_profile.h>




/*******************************************************************************
 * global variables
 ******************************************************************************/

/* Definition needed to prevent unresolved external in unistd.h */
static int errno;

#if DBG
extern dbg_info_t *DbgInfo;
#endif




/*******************************************************************************
 *	parse_config()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      This function opens the device's config file and parses the options from
 *   it, so that it can properly configure itself. If no configuration file
 *   or configuration is present, then continue to use the options already
 *   parsed from config.opts or wireless.opts.
 *
 *  PARAMETERS:
 *
 *      dev - a pointer to the device's net_device structure
 *
 *  RETURNS:
 *
 *      N/A
 *
 ******************************************************************************/
void parse_config( struct net_device *dev )
{
	int				        file_desc;
    char                    buffer[MAX_LINE_SIZE];
    char                    filename[MAX_LINE_SIZE];
    mm_segment_t	        fs;
    struct wl_private   *wvlan_config = NULL;
    ENCSTRCT                sEncryption;
    /*------------------------------------------------------------------------*/


    DBG_FUNC( "parse_config" );
    DBG_ENTER( DbgInfo );


    /* Get the wavelan specific info for this device */
    wvlan_config = (struct wl_private *)dev->priv;
    if( wvlan_config == NULL )
    {
        DBG_ERROR( DbgInfo, "Wavelan specific info struct not present?\n" );
        return;
    }

    /* setup the default encryption string */
    strcpy( wvlan_config->szEncryption, DEF_CRYPT_STR );


	/* Obtain a user-space process context, storing the original context */
	fs = get_fs( );
	set_fs( get_ds( ));

    /* Determine the filename for this device and attempt to open it */
    sprintf( filename, "%s%s", ROOT_CONFIG_FILENAME, dev->name );
    file_desc = open( filename, 0, 0 );
	if( file_desc != -1 )
	{
        DBG_TRACE( DbgInfo, "Wireless config file found. Parsing options...\n" );

		/* Read out the options */
		while( readline( file_desc, buffer ))
	    {
            translate_option( buffer, wvlan_config );
	    }
    }
    else
    {
        DBG_TRACE( DbgInfo, "No iwconfig file found for this device; "
                   "config.opts or wireless.opts will be used\n" );
    }

    /* Close the file */
    close( file_desc );

	/* Return to the original context */
	set_fs( fs );

    
    /* convert the WEP keys, if read in as key1, key2, type of data */
    if( wvlan_config->EnableEncryption )
    {
        memset( &sEncryption, 0, sizeof( sEncryption ));

        wl_wep_decode( CRYPT_CODE, &sEncryption, 
                           wvlan_config->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 */
        sEncryption.wEnabled = wvlan_config->EnableEncryption;
        sEncryption.wTxKeyID = wvlan_config->TransmitKeyID - 1;
            
        memcpy( &sEncryption.EncStr, &wvlan_config->DefaultKeys, 
                sizeof( CFG_DEFAULT_KEYS_STRCT ));
        
        memset( wvlan_config->szEncryption, 0, sizeof( wvlan_config->szEncryption ));

        wl_wep_code( CRYPT_CODE, wvlan_config->szEncryption, &sEncryption, 
                         sizeof( sEncryption ));
    }


    /* decode the encryption string for the call to wl_commit() */
    wl_wep_decode( CRYPT_CODE, &sEncryption, wvlan_config->szEncryption );

    wvlan_config->TransmitKeyID    = sEncryption.wTxKeyID + 1;
    wvlan_config->EnableEncryption = sEncryption.wEnabled;

    memcpy( &wvlan_config->DefaultKeys, &sEncryption.EncStr, 
            sizeof( CFG_DEFAULT_KEYS_STRCT ));

    DBG_LEAVE( DbgInfo );
	return;
}


/*******************************************************************************
 *	readline()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      This function reads in data from a given file one line at a time,
 *   converting the detected newline character '\n' to a null '\0'. Note that
 *   the file descriptor must be valid before calling this function.
 *
 *  PARAMETERS:
 *
 *      filedesc    - the file descriptor for the open configuration file
 *      buffer      - a buffer pointer, passed in by the caller, to which the
 *                    line will be stored.
 *
 *  RETURNS:
 *
 *      the number of bytes read
 *      -1 on error
 *
 ******************************************************************************/
int readline( int filedesc, char *buffer )
{
    int result = -1;
    int bytes_read = 0;
    /*------------------------------------------------------------------------*/

    
    /* Make sure the file descriptor is good */
    if( filedesc != -1 )
    {
        /* Read in from the file byte by byte until a newline is reached */
	    while(( result = read( filedesc, &buffer[bytes_read], 1 )) == 1 )
	    {
	        if( buffer[bytes_read] == '\n' )
	        {
                buffer[bytes_read] = '\0';
		        bytes_read++;
		        break;
	        }
	        bytes_read++;
	    }
    }

    /* Return the number of bytes read */
    if( result == -1 )
    {
        return result;
    }
    else
    {
	    return bytes_read;
    }
}
/*============================================================================*/




/*******************************************************************************
 *	translate_option()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      This function takes a line read in from the config file and parses out
 *   the key/value pairs. It then determines which key has been parsed and sets
 *   the card's configuration based on the value given.
 *
 *  PARAMETERS:
 *
 *      buffer - a buffer containing a line to translate
 *      config - a pointer to the device's private adapter structure
 *
 *  RETURNS:
 *
 *      N/A
 *
 ******************************************************************************/
void translate_option( char *buffer, struct wl_private *lp )
{
    int value_convert = 0;
    int string_length = 0;
    char *key = NULL;
    char *value = NULL;
    u_char mac_value[ETH_ALEN];
    /*------------------------------------------------------------------------*/


    DBG_FUNC( "translate_option" );


    if( buffer == NULL || lp == NULL )
    {
        DBG_ERROR( DbgInfo, "Config file buffer and/or wavelan buffer ptr NULL\n" );
        return;
    }

    ParseConfigLine( buffer, &key, &value );

    if( key == NULL || value == NULL )
    {
        return;
    }

    /* Determine which key it is and perform the appropriate action */

    /* Configuration parameters used in all scenarios */
    if(( strcmp( key, PARM_NAME_DESIRED_SSID ) == 0 ) || ( strcmp( key, PARM_NAME_OWN_SSID ) == 0 ))
    {
        DBG_TRACE( DbgInfo, "SSID, value: %s\n", value );

        memset( lp->NetworkName, 0, ( PARM_MAX_NAME_LEN + 1 ));

        /* Make sure the value isn't too long */
        string_length = strlen( value );
        if( string_length > PARM_MAX_NAME_LEN )
        {
            DBG_WARNING( DbgInfo, "SSID too long; will be truncated\n" );
            string_length = PARM_MAX_NAME_LEN;
        }

        memcpy( lp->NetworkName, value, string_length );
    }
    else if( strcmp( key, PARM_NAME_CHANNEL ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_CHANNEL, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_CHANNEL ) && ( value_convert <= PARM_MAX_CHANNEL ))
        {
            lp->Channel = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_CHANNEL );
        }
    }
    else if( strcmp( key, PARM_NAME_SYSTEM_SCALE ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_SYSTEM_SCALE, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_SYSTEM_SCALE ) && ( value_convert <= PARM_MAX_SYSTEM_SCALE ))
        {
            lp->DistanceBetweenAPs = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SYSTEM_SCALE );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->TxRateControl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE );
        }
    }
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->RTSThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD );
        }
    }
    else if( strcmp( key, PARM_NAME_MICROWAVE_ROBUSTNESS) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MICROWAVE_ROBUSTNESS, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->MicrowaveRobustness = 1;
            }
            else
            {
                lp->MicrowaveRobustness = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_MICROWAVE_ROBUSTNESS );
        }
    }
    else if( strcmp( key, PARM_NAME_OWN_NAME ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_NAME, value );

        memset( lp->StationName, 0, ( PARM_MAX_NAME_LEN + 1 ));

        /* Make sure the value isn't too long */
        string_length = strlen( value );
        if( string_length > PARM_MAX_NAME_LEN )
        {
            DBG_WARNING( DbgInfo, "%s too long; will be truncated\n", PARM_NAME_OWN_NAME );
            string_length = PARM_MAX_NAME_LEN;
        }

        memcpy( lp->StationName, value, string_length );
    }
    else if( strcmp( key, PARM_NAME_ENABLE_ENCRYPTION ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_ENABLE_ENCRYPTION, value );

        value_convert = wvlan_atoi( value );
        DBG_PRINT( "Value Convert: %d\n", value_convert );

        if(( value_convert >= PARM_MIN_ENABLE_ENCRYPTION ) && ( value_convert <= PARM_MAX_ENABLE_ENCRYPTION ))
        {
            lp->EnableEncryption = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_ENABLE_ENCRYPTION );
        }
    }
    else if( strcmp( key, PARM_NAME_KEY1 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_KEY1, value );

        if( is_valid_key_string( value ))
        {
            memset( lp->DefaultKeys.key[0].key, 0, MAX_KEY_SIZE );
            
            key_string2key( value, &lp->DefaultKeys.key[0] );
        }
        else
        {
             DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_KEY1 );
        }
    }
    else if( strcmp( key, PARM_NAME_KEY2 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_KEY2, value );

        if( is_valid_key_string( value ))
        {
            memset( lp->DefaultKeys.key[1].key, 0, MAX_KEY_SIZE );
            
            key_string2key( value, &lp->DefaultKeys.key[1] );
        }
        else
        {
             DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_KEY2 );
        }
    }
    else if( strcmp( key, PARM_NAME_KEY3 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_KEY3, value );

        if( is_valid_key_string( value ))
        {
            memset( lp->DefaultKeys.key[2].key, 0, MAX_KEY_SIZE );
            
            key_string2key( value, &lp->DefaultKeys.key[2] );
        }
        else
        {
             DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_KEY3 );
        }
    }
    else if( strcmp( key, PARM_NAME_KEY4 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_KEY4, value );

        if( is_valid_key_string( value ))
        {
            memset( lp->DefaultKeys.key[3].key, 0, MAX_KEY_SIZE );
            
            key_string2key( value, &lp->DefaultKeys.key[3] );
        }
        else
        {
             DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_KEY4 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_KEY ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_KEY, value );
        
        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_KEY ) && ( value_convert <= PARM_MAX_TX_KEY ))
        {
            lp->TransmitKeyID = wvlan_atoi( value );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_KEY );
        }
    }
    else if( strcmp( key, PARM_NAME_MULTICAST_RATE ) == 0 )
    {
        bool_t  valid = FALSE;

        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MULTICAST_RATE, value );

        value_convert = wvlan_atoi( value );

        switch( lp->DistanceBetweenAPs )
        {
        case 1:
            if(( value_convert >= PARM_MIN_MULTICAST_RATE ) && ( value_convert <= 2 ))
            {
                valid = TRUE;
            }
            break;
            
        case 2:
            if(( value_convert >= PARM_MIN_MULTICAST_RATE ) && ( value_convert <= 3 ))
            {
                valid = TRUE;
            }
            break;

        default:
            if(( value_convert >= PARM_MIN_MULTICAST_RATE ) && ( value_convert <= PARM_MAX_MULTICAST_RATE ))
            {
                valid = TRUE;
            }
        }

        if( valid == TRUE )
        {
            lp->MulticastRate = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_MULTICAST_RATE );
        }
    }
    else if( strcmp( key, PARM_NAME_DOWNLOAD_FIRMWARE ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_DOWNLOAD_FIRMWARE, value );
        
        value_convert = wvlan_atoi( value );

        if( value_convert >= 0 && value_convert <= WVLAN_DRV_MODE_MAX )
        {
            lp->DownloadFirmware = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_DOWNLOAD_FIRMWARE );
        }
    }   
    else if( strcmp( key, PARM_NAME_ENCRYPTION ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_ENCRYPTION, value );

        memset( lp->szEncryption, 0, sizeof( lp->szEncryption ));

        /* Make sure the value isn't too long */
        string_length = strlen( value );
        if( string_length > sizeof( lp->szEncryption ) )
        {
            DBG_WARNING( DbgInfo, "%s too long; will be truncated\n", PARM_NAME_ENCRYPTION );
            string_length = sizeof( lp->szEncryption );
        }

        memcpy( lp->szEncryption, value, string_length );
    }
    else if( strcmp( key, PARM_NAME_AUTH_KEY_MGMT_SUITE ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_AUTH_KEY_MGMT_SUITE, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_AUTH_KEY_MGMT_SUITE ) || ( value_convert <= PARM_MAX_AUTH_KEY_MGMT_SUITE ))
        {
            lp->AuthKeyMgmtSuite = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_AUTH_KEY_MGMT_SUITE );
        }
    }

    /* Configuration parameters specific to STA mode */
#if (HCF_TYPE) & HCF_TYPE_STA
    else if( strcmp( key, PARM_NAME_PORT_TYPE ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PORT_TYPE, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert == PARM_MIN_PORT_TYPE ) || ( value_convert == PARM_MAX_PORT_TYPE ))
        {
            lp->PortType = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_PORT_TYPE );
        }
    }
    else if( strcmp( key, PARM_NAME_PM_ENABLED ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PM_ENABLED, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->PMEnabled = 1;
            }
            else
            {
                lp->PMEnabled = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_PM_ENABLED );
        }
    }
    else if( strcmp( key, PARM_NAME_CREATE_IBSS ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_CREATE_IBSS, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->CreateIBSS = 1;
            }
            else
            {
                lp->CreateIBSS = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_CREATE_IBSS );
        }
    }
    else if( strcmp( key, PARM_NAME_RX_MULTICAST ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RX_MULTICAST, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->MulticastReceive = 1;
            }
            else
            {
                lp->MulticastReceive = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RX_MULTICAST );
        }
    }
    else if( strcmp( key, PARM_NAME_MAX_SLEEP ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MAX_SLEEP, value );
        
        value_convert = wvlan_atoi( value );
        if(( value_convert >= 0 ) && ( value_convert <= 65535 ))
        {
            lp->MaxSleepDuration = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_MAX_SLEEP );
        }
    }
    else if( strcmp( key, PARM_NAME_MAC_ADDRESS ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MAC_ADDRESS, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->MACAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_MAC_ADDRESS );
        }
    }
    else if( strcmp( key, PARM_NAME_AUTHENTICATION ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_AUTHENTICATION, value );
        
        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_AUTHENTICATION ) && ( value_convert <= PARM_MAX_AUTHENTICATION ))
        {
            lp->authentication = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_AUTHENTICATION );
        }
    }
    else if( strcmp( key, PARM_NAME_OWN_ATIM_WINDOW ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_ATIM_WINDOW, value );
        
        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_OWN_ATIM_WINDOW ) && ( value_convert <= PARM_MAX_OWN_ATIM_WINDOW ))
        {
            lp->atimWindow = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_OWN_ATIM_WINDOW );
        }
    }
    else if( strcmp( key, PARM_NAME_PM_HOLDOVER_DURATION ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PM_HOLDOVER_DURATION, value );
        
        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_PM_HOLDOVER_DURATION ) && ( value_convert <= PARM_MAX_PM_HOLDOVER_DURATION ))
        {
            lp->holdoverDuration = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_PM_HOLDOVER_DURATION );
        }
    }
    else if( strcmp( key, PARM_NAME_PROMISCUOUS_MODE ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PROMISCUOUS_MODE, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->promiscuousMode = 1;
            }
            else
            {
                lp->promiscuousMode = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_PROMISCUOUS_MODE );
        }
    }
#endif  /* (HCF_TYPE) & HCF_TYPE_STA */

    /* Configuration parameters specific to AP mode */
#if (HCF_TYPE) & HCF_TYPE_AP
    else if( strcmp( key, PARM_NAME_OWN_DTIM_PERIOD ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_DTIM_PERIOD, value );

        value_convert = wvlan_atoi( value );
        if( value_convert >= PARM_MIN_OWN_DTIM_PERIOD )
        {
            lp->DTIMPeriod = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_OWN_DTIM_PERIOD );
        }
    }
    else if( strcmp( key, PARM_NAME_REJECT_ANY ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_REJECT_ANY, value );

        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->RejectAny = 1;
            }
            else
            {
                lp->RejectAny = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_REJECT_ANY );
        }
    }
    else if( strcmp( key, PARM_NAME_EXCLUDE_UNENCRYPTED ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_EXCLUDE_UNENCRYPTED, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->ExcludeUnencrypted = 1;
            }
            else
            {
                lp->ExcludeUnencrypted = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_EXCLUDE_UNENCRYPTED );
        }
    }
    else if( strcmp( key, PARM_NAME_MULTICAST_PM_BUFFERING ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MULTICAST_PM_BUFFERING, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->ExcludeUnencrypted = 1;
            }
            else
            {
                lp->ExcludeUnencrypted = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_MULTICAST_PM_BUFFERING );
        }
    }
    else if( strcmp( key, PARM_NAME_INTRA_BSS_RELAY ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_INTRA_BSS_RELAY, value );
        
        if( strlen( value ) == 1 )
        {
            if( strchr( "Yy", value[0] ) != NULL )
            {
                lp->ExcludeUnencrypted = 1;
            }
            else
            {
                lp->ExcludeUnencrypted = 0;
            }
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_INTRA_BSS_RELAY );
        }
    }

#ifdef USE_WDS
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD1 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD1, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->wds_port[0].rtsThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD1 );
        }
    }
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD2 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD2, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->wds_port[1].rtsThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD2 );
        }
    }
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD3 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD3, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->wds_port[2].rtsThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD3 );
        }
    }
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD4 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD4, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->wds_port[3].rtsThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD4 );
        }
    }
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD5 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD5, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->wds_port[4].rtsThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD5 );
        }
    }
    else if( strcmp( key, PARM_NAME_RTS_THRESHOLD6 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD6, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD ))
        {
            lp->wds_port[5].rtsThreshold = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_RTS_THRESHOLD6 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE1 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE1, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->wds_port[0].txRateCntl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE1 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE2 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE2, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->wds_port[1].txRateCntl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE2 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE3 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE3, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->wds_port[2].txRateCntl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE3 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE4 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE4, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->wds_port[3].txRateCntl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE4 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE5 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE5, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->wds_port[4].txRateCntl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE5 );
        }
    }
    else if( strcmp( key, PARM_NAME_TX_RATE6 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE6, value );

        value_convert = wvlan_atoi( value );
        if(( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE ))
        {
            lp->wds_port[5].txRateCntl = value_convert;
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_RATE6 );
        }
    }
    else if( strcmp( key, PARM_NAME_WDS_ADDRESS1 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_WDS_ADDRESS1, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->wds_port[0].wdsAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_WDS_ADDRESS1 );
        }
    }
    else if( strcmp( key, PARM_NAME_WDS_ADDRESS2 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_WDS_ADDRESS2, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->wds_port[1].wdsAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_WDS_ADDRESS2 );
        }
    }
    else if( strcmp( key, PARM_NAME_WDS_ADDRESS3 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_WDS_ADDRESS3, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->wds_port[2].wdsAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_WDS_ADDRESS3 );
        }
    }
    else if( strcmp( key, PARM_NAME_WDS_ADDRESS4 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_WDS_ADDRESS4, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->wds_port[3].wdsAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_WDS_ADDRESS4 );
        }
    }
    else if( strcmp( key, PARM_NAME_WDS_ADDRESS5 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_WDS_ADDRESS5, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->wds_port[4].wdsAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_WDS_ADDRESS5 );
        }
    }
    else if( strcmp( key, PARM_NAME_WDS_ADDRESS6 ) == 0 )
    {
        DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_WDS_ADDRESS6, value );

        if( parse_mac_address( value, mac_value ) == ETH_ALEN )
        {
            memcpy( lp->wds_port[5].wdsAddress, mac_value, ETH_ALEN );
        }
        else
        {
            DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_WDS_ADDRESS6 );
        }
    }

#endif  /* USE_WDS */
#endif  /* (HCF_TYPE) & HCF_TYPE_AP */

    
    return;
}
/*============================================================================*/




/*******************************************************************************
 *	parse_mac_address()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      This function will parse a mac address string and convert it to a byte
 *   array.
 *
 *  PARAMETERS:
 *
 *      value       - the MAC address, represented as a string
 *      byte_array  - the MAC address, represented as a byte array of length
 *                    ETH_ALEN
 *
 *  RETURNS:
 *
 *      The number of bytes in the final MAC address, should equal to ETH_ALEN.
 *
 ******************************************************************************/
int parse_mac_address( char *value, u_char *byte_array )
{
    int     value_offset = 0;
    int     array_offset = 0;
    int     field_offset = 0;
    char    byte_field[3];
    /*------------------------------------------------------------------------*/


    memset( byte_field, '\0', 3 );

    while( value[value_offset] != '\0' )
    {
        /* Skip over the colon chars seperating the bytes, if they exist */
        if( value[value_offset] == ':' )
        {
            value_offset++;
            continue;
        }

        byte_field[field_offset] = value[value_offset];
        field_offset++;
        value_offset++;
        
        /* Once the byte_field is filled, convert it and store it */
        if( field_offset == 2 )
        {
            byte_field[field_offset] = '\0';
            byte_array[array_offset] = simple_strtoul( byte_field, NULL, 16 );
            field_offset = 0;
            array_offset++;
        }
    }

    /* Use the array_offset as a check; 6 bytes should be written to the
       byte_array */
    return array_offset;
}
/*============================================================================*/




/*******************************************************************************
 *	wvlan_atoi()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *
 *      Believe it or not, we need our own implementation of atoi in the kernel.
 *
 *  PARAMETERS:
 *
 *      string  - the ASCII string to convert to an integer
 *
 *  RETURNS:
 *
 *      an integer
 *
 ******************************************************************************/
int wvlan_atoi( char *string )
{
	int value = 0;
	
	value = 0;
	while ( *string != '\0' && *string >= '0' && *string <= '9' )
    {
		value = 10 * value + ( *string - '0' );
		string++;
	}

	return value;
}
/*============================================================================*/




/*******************************************************************************
 *	ParseConfigLine()
 *******************************************************************************
 *
 *  DESCRIPTION:
 *      
 *      Parses a line from the configuration file into an L-val and an R-val,
 *  representing a key/value pair.
 *
 *  PARAMETERS:
 *
 *      pszLine     - the line from the config file to parse
 *      ppszLVal    - the resulting L-val (Key)
 *      ppszRVal    - the resulting R-val (Value)
 *
 *  RETURNS:
 *
 *      N/A
 *
 ******************************************************************************/
void ParseConfigLine( char *pszLine, char **ppszLVal, char **ppszRVal )
{
    int i;
    int size;
    /*------------------------------------------------------------------------*/
  

    /* get a snapshot of our string size */
    size      = strlen( pszLine );
    *ppszLVal = NULL;
    *ppszRVal = NULL;


    /* skip the line if it is a comment */
    if( pszLine[0] == '#' )
    {
        return;
    }


    /* if it's an empty UNIX line, do nothing */
    if( pszLine[0] == '\n' )
    {
        return;
    }


    /* if it's an empty MS-DOS line, do nothing */
    if(( pszLine[0] == '\r' ) && ( pszLine[1] == '\n' ))
    { 
        return;
    }


    /* advance past any whitespace, and assign the L-value */
    for( i = 0; i < size; i++ )
    {
        if( pszLine[i] != ' ' )
        {
            *ppszLVal = &pszLine[i];
            break;
        }
    }


    /* advance to the end of the l-value*/
    for( i++; i < size; i++ )
    {
        if( pszLine[i] == ' ' || pszLine[i] == '=' )
        {
            pszLine[i] = '\0';
            break;
        }
    }


    /* make any whitespace and the equal sign a NULL character, and 
       advance to the R-Value */
    for( i++; i < size; i++ )
    {
        if( pszLine[i] == ' ' || pszLine[i] == '=' )
        {
            pszLine[i] = '\0';
            continue;
        }

        *ppszRVal = &pszLine[i];
        break;
    }


    /* make the line ending character(s) a NULL */
    for( i++; i < size; i++ )
    {
        if( pszLine[i] == '\n' )
        {
            pszLine[i] = '\0';
        }


        if(( pszLine[i] == '\r' ) && ( pszLine[i+1] == '\n' ))
        {
            pszLine[i] = '\0';
        }
    }

    return;
}
/*============================================================================*/

#endif  // USE_PROFILE
