aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/wlags49_h2/wl_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/wlags49_h2/wl_util.c')
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c1587
1 files changed, 1587 insertions, 0 deletions
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
new file mode 100644
index 000000000000..ac1e7f38f982
--- /dev/null
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -0,0 +1,1587 @@
+/*******************************************************************************
+ * 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 misc utility functions.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * 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/kernel.h>
+// #include <linux/sched.h>
+// #include <linux/ptrace.h>
+#include <linux/ctype.h>
+// #include <linux/string.h>
+// #include <linux/timer.h>
+// #include <linux/interrupt.h>
+// #include <linux/in.h>
+// #include <linux/delay.h>
+// #include <asm/io.h>
+// #include <asm/system.h>
+// #include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+// #include <linux/skbuff.h>
+// #include <linux/if_arp.h>
+// #include <linux/ioport.h>
+
+#include <debug.h>
+#include <hcf.h>
+// #include <hcfdef.h>
+
+#include <wl_if.h>
+#include <wl_internal.h>
+#include <wl_util.h>
+#include <wl_wext.h>
+#include <wl_main.h>
+
+
+
+/*******************************************************************************
+ * global variables
+ ******************************************************************************/
+
+/* A matrix which maps channels to frequencies */
+#define MAX_CHAN_FREQ_MAP_ENTRIES 50
+static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
+{
+ {1,2412},
+ {2,2417},
+ {3,2422},
+ {4,2427},
+ {5,2432},
+ {6,2437},
+ {7,2442},
+ {8,2447},
+ {9,2452},
+ {10,2457},
+ {11,2462},
+ {12,2467},
+ {13,2472},
+ {14,2484},
+ {36,5180},
+ {40,5200},
+ {44,5220},
+ {48,5240},
+ {52,5260},
+ {56,5280},
+ {60,5300},
+ {64,5320},
+ {149,5745},
+ {153,5765},
+ {157,5785},
+ {161,5805}
+};
+
+#if DBG
+extern dbg_info_t *DbgInfo;
+#endif /* DBG */
+
+
+
+
+/*******************************************************************************
+ * dbm()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Return an energy value in dBm.
+ *
+ * PARAMETERS:
+ *
+ * value - the energy value to be converted
+ *
+ * RETURNS:
+ *
+ * the value in dBm
+ *
+ ******************************************************************************/
+int dbm( int value )
+{
+ /* Truncate the value to be between min and max. */
+ if( value < HCF_MIN_SIGNAL_LEVEL )
+ value = HCF_MIN_SIGNAL_LEVEL;
+
+ if( value > HCF_MAX_SIGNAL_LEVEL )
+ value = HCF_MAX_SIGNAL_LEVEL;
+
+ /* Return the energy value in dBm. */
+ return ( value - HCF_0DBM_OFFSET );
+} // dbm
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * percent()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Return a value as a percentage of min to max.
+ *
+ * PARAMETERS:
+ *
+ * value - the value in question
+ * min - the minimum range value
+ * max - the maximum range value
+ *
+ * RETURNS:
+ *
+ * the percentage value
+ *
+ ******************************************************************************/
+int percent( int value, int min, int max )
+{
+ /* Truncate the value to be between min and max. */
+ if( value < min )
+ value = min;
+
+ if( value > max )
+ value = max;
+
+ /* Return the value as a percentage of min to max. */
+ return ((( value - min ) * 100 ) / ( max - min ));
+} // percent
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * is_valid_key_string()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Checks to determine if the WEP key string is valid
+ *
+ * PARAMETERS:
+ *
+ * s - the string in question
+ *
+ * RETURNS:
+ *
+ * non-zero if the string contains a valid key
+ *
+ ******************************************************************************/
+int is_valid_key_string( char *s )
+{
+ int l;
+ int i;
+ /*------------------------------------------------------------------------*/
+
+
+ l = strlen( s );
+
+ /* 0x followed by 5 or 13 hexadecimal digit pairs is valid */
+ if( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X' )) {
+ if( l == 12 || l == 28 ) {
+ for( i = 2; i < l; i++ ) {
+ if( !isxdigit( s[i] ))
+ return 0;
+ }
+
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ /* string with 0, 5, or 13 characters is valid */
+ else
+ {
+ return( l == 0 || l == 5 || l == 13 );
+ }
+} // is_valid_key_string
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * hexdigit2int()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Converts a hexadecimal digit character to an integer
+ *
+ * PARAMETERS:
+ *
+ * c - the hexadecimal digit character
+ *
+ * RETURNS:
+ *
+ * the converted integer
+ *
+ ******************************************************************************/
+int hexdigit2int( char c )
+{
+ if( c >= '0' && c <= '9' )
+ return c - '0';
+
+ if( c >= 'A' && c <= 'F' )
+ return c - 'A' + 10;
+
+ if( c >= 'a' && c <= 'f' )
+ return c - 'a' + 10;
+
+ return 0;
+} // hexdigit2int
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * key_string2key()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Converts a key_string to a key, Assumes the key_string is validated with
+ * is_valid_key_string().
+ *
+ * PARAMETERS:
+ *
+ * ks - the valid key string
+ * key - a pointer to a KEY_STRUCT where the converted key information will
+ * be stored.
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void key_string2key( char *ks, KEY_STRCT *key )
+{
+ int l,i,n;
+ char *p;
+ /*------------------------------------------------------------------------*/
+
+
+ l = strlen( ks );
+
+ /* 0x followed by hexadecimal digit pairs */
+ if( ks[0] == '0' && ( ks[1] == 'x' || ks[1] == 'X' )) {
+ n = 0;
+ p = (char *)key->key;
+
+ for( i = 2; i < l; i+=2 ) {
+ *p++ = ( hexdigit2int( ks[i] ) << 4 ) + hexdigit2int (ks[i+1] );
+ n++;
+ }
+
+ /* Note that endian translation of the length field is not needed here
+ because it's performed in wl_put_ltv() */
+ key->len = n;
+ }
+ /* character string */
+ else
+ {
+ strcpy( (char *)key->key, ks );
+ key->len = l;
+ }
+
+ return;
+} // key_string2key
+/*============================================================================*/
+
+
+
+
+#if DBG
+/*******************************************************************************
+ * DbgHwAddr()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Convert a hardware ethernet address to a character string
+ *
+ * PARAMETERS:
+ *
+ * hwAddr - an ethernet address
+ *
+ * RETURNS:
+ *
+ * a pointer to a string representing the ethernet address
+ *
+ ******************************************************************************/
+const char *DbgHwAddr(unsigned char *hwAddr)
+{
+ static char buffer[18];
+ /*------------------------------------------------------------------------*/
+
+
+ sprintf( buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
+ hwAddr[0], hwAddr[1], hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5] );
+
+ return buffer;
+} // DbgHwAddr
+/*============================================================================*/
+
+#endif /* DBG */
+
+
+
+
+/*******************************************************************************
+ * wl_has_wep()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Checks to see if the device supports WEP
+ *
+ * PARAMETERS:
+ *
+ * ifbp - the IFB pointer of the device in question
+ *
+ * RETURNS:
+ *
+ * 1 if WEP is known enabled, else 0
+ *
+ ******************************************************************************/
+int wl_has_wep (IFBP ifbp)
+{
+ CFG_PRIVACY_OPT_IMPLEMENTED_STRCT ltv;
+ int rc, privacy;
+ /*------------------------------------------------------------------------*/
+
+
+ /* This function allows us to distiguish bronze cards from other types, to
+ know if WEP exists. Does not distinguish (because there's no way to)
+ between silver and gold cards. */
+ ltv.len = 2;
+ ltv.typ = CFG_PRIVACY_OPT_IMPLEMENTED;
+
+ rc = hcf_get_info( ifbp, (LTVP) &ltv );
+
+ privacy = CNV_LITTLE_TO_INT( ltv.privacy_opt_implemented );
+
+ //return rc ? 0 : privacy;
+ return 1;
+} // wl_has_wep
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_hcf_error()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Report the type of HCF error message
+ *
+ * PARAMETERS:
+ *
+ * none
+ *
+ * RETURNS:
+ *
+ * A descriptive string indicating the error, quiet otherwise.
+ *
+ ******************************************************************************/
+void wl_hcf_error( struct net_device *dev, int hcfStatus )
+{
+ char buffer[64], *pMsg;
+ /*------------------------------------------------------------------------*/
+
+
+ if( hcfStatus != HCF_SUCCESS ) {
+ switch( hcfStatus ) {
+
+ case HCF_ERR_TIME_OUT:
+
+ pMsg = "Expected adapter event did not occur in expected time";
+ break;
+
+
+ case HCF_ERR_NO_NIC:
+
+ pMsg = "Card not found (ejected unexpectedly)";
+ break;
+
+
+ case HCF_ERR_LEN:
+
+ pMsg = "Command buffer size insufficient";
+ break;
+
+
+ case HCF_ERR_INCOMP_PRI:
+
+ pMsg = "Primary functions are not compatible";
+ break;
+
+
+ case HCF_ERR_INCOMP_FW:
+
+ pMsg = "Primary functions are compatible, "
+ "station/ap functions are not";
+ break;
+
+
+ case HCF_ERR_BUSY:
+
+ pMsg = "Inquire cmd while another Inquire in progress";
+ break;
+
+
+ //case HCF_ERR_SEQ_BUG:
+
+ // pMsg = "Unexpected command completed";
+ // break;
+
+
+ case HCF_ERR_DEFUNCT_AUX:
+
+ pMsg = "Timeout on ack for enable/disable of AUX registers";
+ break;
+
+
+ case HCF_ERR_DEFUNCT_TIMER:
+ pMsg = "Timeout on timer calibration during initialization process";
+ break;
+
+
+ case HCF_ERR_DEFUNCT_TIME_OUT:
+ pMsg = "Timeout on Busy bit drop during BAP setup";
+ break;
+
+
+ case HCF_ERR_DEFUNCT_CMD_SEQ:
+ pMsg = "Hermes and HCF are out of sync";
+ break;
+
+
+ default:
+
+ sprintf( buffer, "Error code %d", hcfStatus );
+ pMsg = buffer;
+ break;
+ }
+
+ printk( KERN_INFO "%s: Wireless, HCF failure: \"%s\"\n",
+ dev->name, pMsg );
+ }
+} // wl_hcf_error
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_endian_translate_event()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Determines what type of data is in the mailbox and performs the proper
+ * endian translation.
+ *
+ * PARAMETERS:
+ *
+ * pLtv - an LTV pointer
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_endian_translate_event( ltv_t *pLtv )
+{
+ DBG_FUNC( "wl_endian_translate_event" );
+ DBG_ENTER( DbgInfo );
+
+
+ switch( pLtv->typ ) {
+ case CFG_TALLIES:
+ break;
+
+
+ case CFG_SCAN:
+ {
+ int numAPs;
+ SCAN_RS_STRCT *pAps = (SCAN_RS_STRCT*)&pLtv->u.u8[0];
+
+ numAPs = (hcf_16)(( (size_t)( pLtv->len - 1 ) * 2 ) /
+ (sizeof( SCAN_RS_STRCT )));
+
+ while( numAPs >= 1 ) {
+ numAPs--;
+
+ pAps[numAPs].channel_id =
+ CNV_LITTLE_TO_INT( pAps[numAPs].channel_id );
+
+ pAps[numAPs].noise_level =
+ CNV_LITTLE_TO_INT( pAps[numAPs].noise_level );
+
+ pAps[numAPs].signal_level =
+ CNV_LITTLE_TO_INT( pAps[numAPs].signal_level );
+
+ pAps[numAPs].beacon_interval_time =
+ CNV_LITTLE_TO_INT( pAps[numAPs].beacon_interval_time );
+
+ pAps[numAPs].capability =
+ CNV_LITTLE_TO_INT( pAps[numAPs].capability );
+
+ pAps[numAPs].ssid_len =
+ CNV_LITTLE_TO_INT( pAps[numAPs].ssid_len );
+
+ pAps[numAPs].ssid_val[pAps[numAPs].ssid_len] = 0;
+
+ }
+ }
+ break;
+
+
+ case CFG_ACS_SCAN:
+ {
+ PROBE_RESP *probe_resp = (PROBE_RESP *)pLtv;
+
+ probe_resp->frameControl = CNV_LITTLE_TO_INT( probe_resp->frameControl );
+ probe_resp->durID = CNV_LITTLE_TO_INT( probe_resp->durID );
+ probe_resp->sequence = CNV_LITTLE_TO_INT( probe_resp->sequence );
+ probe_resp->dataLength = CNV_LITTLE_TO_INT( probe_resp->dataLength );
+
+#ifndef WARP
+ probe_resp->lenType = CNV_LITTLE_TO_INT( probe_resp->lenType );
+#endif // WARP
+
+ probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
+ probe_resp->capability = CNV_LITTLE_TO_INT( probe_resp->capability );
+ probe_resp->flags = CNV_LITTLE_TO_INT( probe_resp->flags );
+ }
+ break;
+
+
+ case CFG_LINK_STAT:
+#define ls ((LINK_STATUS_STRCT *)pLtv)
+ ls->linkStatus = CNV_LITTLE_TO_INT( ls->linkStatus );
+ break;
+#undef ls
+
+ case CFG_ASSOC_STAT:
+ {
+ ASSOC_STATUS_STRCT *pAs = (ASSOC_STATUS_STRCT *)pLtv;
+
+ pAs->assocStatus = CNV_LITTLE_TO_INT( pAs->assocStatus );
+ }
+ break;
+
+
+ case CFG_SECURITY_STAT:
+ {
+ SECURITY_STATUS_STRCT *pSs = (SECURITY_STATUS_STRCT *)pLtv;
+
+ pSs->securityStatus = CNV_LITTLE_TO_INT( pSs->securityStatus );
+ pSs->reason = CNV_LITTLE_TO_INT( pSs->reason );
+ }
+ break;
+
+
+ case CFG_WMP:
+ break;
+
+
+ case CFG_NULL:
+ break;
+
+
+ default:
+ break;
+ }
+
+ DBG_LEAVE( DbgInfo );
+ return;
+} // wl_endian_translate_event
+/*============================================================================*/
+
+
+/*******************************************************************************
+ * msf_assert()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Print statement used to display asserts from within the HCF. Only called
+ * when asserts in the HCF are turned on. See hcfcfg.h for more information.
+ *
+ * PARAMETERS:
+ *
+ * file_namep - the filename in which the assert occurred.
+ * line_number - the line number on which the assert occurred.
+ * trace - a comment associated with the assert.
+ * qual - return code or other value related to the assert
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void msf_assert( unsigned int line_number, hcf_16 trace, hcf_32 qual )
+{
+ DBG_PRINT( "HCF ASSERT: Line %d, VAL: 0x%.8x\n", line_number, /*;?*/(u32)qual );
+} // msf_assert
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_parse_ds_ie()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function parses the Direct Sequence Parameter Set IE, used to
+ * determine channel/frequency information.
+ *
+ * PARAMETERS:
+ *
+ * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
+ * response.
+ *
+ * RETURNS:
+ *
+ * The channel on which the BSS represented by this probe response is
+ * transmitting.
+ *
+ ******************************************************************************/
+hcf_8 wl_parse_ds_ie( PROBE_RESP *probe_rsp )
+{
+ int i;
+ int ie_length = 0;
+ hcf_8 *buf;
+ hcf_8 buf_size;
+ /*------------------------------------------------------------------------*/
+
+
+ if( probe_rsp == NULL ) {
+ return 0;
+ }
+
+ buf = probe_rsp->rawData;
+ buf_size = sizeof( probe_rsp->rawData );
+
+
+ for( i = 0; i < buf_size; i++ ) {
+ if( buf[i] == DS_INFO_ELEM ) {
+ /* Increment by 1 to get the length, and test it; in a DS element,
+ length should always be 1 */
+ i++;
+ ie_length = buf[i];
+
+ if( buf[i] == 1 ) {
+ /* Get the channel information */
+ i++;
+ return buf[i];
+ }
+ }
+ }
+
+ /* If we get here, we didn't find a DS-IE, which is strange */
+ return 0;
+} // wl_parse_ds_ie
+
+
+/*******************************************************************************
+ * wl_parse_wpa_ie()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function parses the Probe Response for a valid WPA-IE.
+ *
+ * PARAMETERS:
+ *
+ * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
+ * response
+ * length - a pointer to an hcf_16 in which the size of the WPA-IE will
+ * be stored (if found).
+ *
+ * RETURNS:
+ *
+ * A pointer to the location in the probe response buffer where a valid
+ * WPA-IE lives. The length of this IE is written back to the 'length'
+ * argument passed to the function.
+ *
+ ******************************************************************************/
+hcf_8 * wl_parse_wpa_ie( PROBE_RESP *probe_rsp, hcf_16 *length )
+{
+ int i;
+ int ie_length = 0;
+ hcf_8 *buf;
+ hcf_8 buf_size;
+ hcf_8 wpa_oui[] = WPA_OUI_TYPE;
+ /*------------------------------------------------------------------------*/
+
+
+ if( probe_rsp == NULL || length == NULL ) {
+ return NULL;
+ }
+
+ buf = probe_rsp->rawData;
+ buf_size = sizeof( probe_rsp->rawData );
+ *length = 0;
+
+
+ for( i = 0; i < buf_size; i++ ) {
+ if( buf[i] == GENERIC_INFO_ELEM ) {
+ /* Increment by one to get the IE length */
+ i++;
+ ie_length = probe_rsp->rawData[i];
+
+ /* Increment by one to point to the IE payload */
+ i++;
+
+ /* Does the IE contain a WPA OUI? If not, it's a proprietary IE */
+ if( memcmp( &buf[i], &wpa_oui, WPA_SELECTOR_LEN ) == 0 ) {
+ /* Pass back length and return a pointer to the WPA-IE */
+ /* NOTE: Length contained in the WPA-IE is only the length of
+ the payload. The entire WPA-IE, including the IE identifier
+ and the length, is 2 bytes larger */
+ *length = ie_length + 2;
+
+ /* Back up the pointer 2 bytes to include the IE identifier and
+ the length in the buffer returned */
+ i -= 2;
+ return &buf[i];
+ }
+
+ /* Increment past this non-WPA IE and continue looking */
+ i += ( ie_length - 1 );
+ }
+ }
+
+ /* If we're here, we didn't find a WPA-IE in the buffer */
+ return NULL;
+} // wl_parse_wpa_ie
+
+
+/*******************************************************************************
+ * wl_print_wpa_ie()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Function used to take a WPA Information Element (WPA-IE) buffer and
+ * display it in a readable format.
+ *
+ * PARAMETERS:
+ *
+ * buffer - the byte buffer containing the WPA-IE
+ * length - the length of the above buffer
+ *
+ * RETURNS:
+ *
+ * A pointer to the formatted WPA-IE string. Note that the format used is
+ * byte-by-byte printing as %02x hex values with no spaces. This is
+ * required for proper operation with some WPA supplicants.
+ *
+ ******************************************************************************/
+hcf_8 * wl_print_wpa_ie( hcf_8 *buffer, int length )
+{
+ int count;
+ int rows;
+ int remainder;
+ int rowsize = 4;
+ hcf_8 row_buf[64];
+ static hcf_8 output[512];
+ /*------------------------------------------------------------------------*/
+
+
+ memset( output, 0, sizeof( output ));
+ memset( row_buf, 0, sizeof( row_buf ));
+
+
+ /* Determine how many rows will be needed, and the remainder */
+ rows = length / rowsize;
+ remainder = length % rowsize;
+
+
+ /* Format the rows */
+ for( count = 0; count < rows; count++ ) {
+ sprintf( row_buf, "%02x%02x%02x%02x",
+ buffer[count*rowsize], buffer[count*rowsize+1],
+ buffer[count*rowsize+2], buffer[count*rowsize+3]);
+ strcat( output, row_buf );
+ }
+
+ memset( row_buf, 0, sizeof( row_buf ));
+
+
+ /* Format the remainder */
+ for( count = 0; count < remainder; count++ ) {
+ sprintf( row_buf, "%02x", buffer[(rows*rowsize)+count]);
+ strcat( output, row_buf );
+ }
+
+ return output;
+} // wl_print_wpa_ie
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_is_a_valid_chan()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Checks if a given channel is valid
+ *
+ * PARAMETERS:
+ *
+ * channel - the channel
+ *
+ * RETURNS:
+ *
+ * 1 if TRUE
+ * 0 if FALSE
+ *
+ ******************************************************************************/
+int wl_is_a_valid_chan( int channel )
+{
+ int i;
+ /*------------------------------------------------------------------------*/
+
+
+ /* Strip out the high bit set by the FW for 802.11a channels */
+ if( channel & 0x100 ) {
+ channel = channel & 0x0FF;
+ }
+
+ /* Iterate through the matrix and retrieve the frequency */
+ for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ if( chan_freq_list[i][0] == channel ) {
+ return 1;
+ }
+ }
+
+ return 0;
+} // wl_is_a_valid_chan
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_get_chan_from_freq()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Checks if a given frequency is valid
+ *
+ * PARAMETERS:
+ *
+ * freq - the frequency
+ *
+ * RETURNS:
+ *
+ * 1 if TRUE
+ * 0 if FALSE
+ *
+ ******************************************************************************/
+int wl_is_a_valid_freq( long frequency )
+{
+ int i;
+ /*------------------------------------------------------------------------*/
+
+
+ /* Iterate through the matrix and retrieve the channel */
+ for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ if( chan_freq_list[i][1] == frequency ) {
+ return 1;
+ }
+ }
+
+ return 0;
+} // wl_is_a_valid_freq
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_get_freq_from_chan()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Function used to look up the frequency for a given channel on which the
+ * adapter is Tx/Rx.
+ *
+ * PARAMETERS:
+ *
+ * channel - the channel
+ *
+ * RETURNS:
+ *
+ * The corresponding frequency
+ *
+ ******************************************************************************/
+long wl_get_freq_from_chan( int channel )
+{
+ int i;
+ /*------------------------------------------------------------------------*/
+
+
+ /* Strip out the high bit set by the FW for 802.11a channels */
+ if( channel & 0x100 ) {
+ channel = channel & 0x0FF;
+ }
+
+ /* Iterate through the matrix and retrieve the frequency */
+ for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ if( chan_freq_list[i][0] == channel ) {
+ return chan_freq_list[i][1];
+ }
+ }
+
+ return 0;
+} // wl_get_freq_from_chan
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_get_chan_from_freq()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Function used to look up the channel for a given frequency on which the
+ * adapter is Tx/Rx.
+ *
+ * PARAMETERS:
+ *
+ * frequency - the frequency
+ *
+ * RETURNS:
+ *
+ * The corresponding channel
+ *
+ ******************************************************************************/
+int wl_get_chan_from_freq( long frequency )
+{
+ int i;
+ /*------------------------------------------------------------------------*/
+
+
+ /* Iterate through the matrix and retrieve the channel */
+ for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ if( chan_freq_list[i][1] == frequency ) {
+ return chan_freq_list[i][0];
+ }
+ }
+
+ return 0;
+} // wl_get_chan_from_freq
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_process_link_status()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Process the link status message signaled by the device.
+ *
+ * PARAMETERS:
+ *
+ * lp - a pointer to the device's private structure
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_process_link_status( struct wl_private *lp )
+{
+ hcf_16 link_stat;
+ /*------------------------------------------------------------------------*/
+
+ DBG_FUNC( "wl_process_link_status" );
+ DBG_ENTER( DbgInfo );
+
+ if( lp != NULL ) {
+ //link_stat = lp->hcfCtx.IFB_DSLinkStat & CFG_LINK_STAT_FW;
+ link_stat = lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW;
+ switch( link_stat ) {
+ case 1:
+ DBG_TRACE( DbgInfo, "Link Status : Connected\n" );
+ wl_wext_event_ap( lp->dev );
+ break;
+ case 2:
+ DBG_TRACE( DbgInfo, "Link Status : Disconnected\n" );
+ break;
+ case 3:
+ DBG_TRACE( DbgInfo, "Link Status : Access Point Change\n" );
+ break;
+ case 4:
+ DBG_TRACE( DbgInfo, "Link Status : Access Point Out of Range\n" );
+ break;
+ case 5:
+ DBG_TRACE( DbgInfo, "Link Status : Access Point In Range\n" );
+ break;
+ default:
+ DBG_TRACE( DbgInfo, "Link Status : UNKNOWN (0x%04x)\n", link_stat );
+ break;
+ }
+ }
+ DBG_LEAVE( DbgInfo );
+ return;
+} // wl_process_link_status
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_process_probe_response()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Process the probe responses retunred by the device as a result of an
+ * active scan.
+ *
+ * PARAMETERS:
+ *
+ * lp - a pointer to the device's private structure
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_process_probe_response( struct wl_private *lp )
+{
+ PROBE_RESP *probe_rsp;
+ hcf_8 *wpa_ie = NULL;
+ hcf_16 wpa_ie_len = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wl_process_probe_response" );
+ DBG_ENTER( DbgInfo );
+
+
+ if( lp != NULL ) {
+ probe_rsp = (PROBE_RESP *)&lp->ProbeResp;
+
+ wl_endian_translate_event( (ltv_t *)probe_rsp );
+
+ DBG_TRACE( DbgInfo, "(%s) =========================\n", lp->dev->name );
+ DBG_TRACE( DbgInfo, "(%s) length : 0x%04x.\n", lp->dev->name,
+ probe_rsp->length );
+
+ if( probe_rsp->length > 1 ) {
+ DBG_TRACE( DbgInfo, "(%s) infoType : 0x%04x.\n", lp->dev->name,
+ probe_rsp->infoType );
+
+ DBG_TRACE( DbgInfo, "(%s) signal : 0x%02x.\n", lp->dev->name,
+ probe_rsp->signal );
+
+ DBG_TRACE( DbgInfo, "(%s) silence : 0x%02x.\n", lp->dev->name,
+ probe_rsp->silence );
+
+ DBG_TRACE( DbgInfo, "(%s) rxFlow : 0x%02x.\n", lp->dev->name,
+ probe_rsp->rxFlow );
+
+ DBG_TRACE( DbgInfo, "(%s) rate : 0x%02x.\n", lp->dev->name,
+ probe_rsp->rate );
+
+ DBG_TRACE( DbgInfo, "(%s) frame cntl : 0x%04x.\n", lp->dev->name,
+ probe_rsp->frameControl );
+
+ DBG_TRACE( DbgInfo, "(%s) durID : 0x%04x.\n", lp->dev->name,
+ probe_rsp->durID );
+
+ DBG_TRACE( DbgInfo, "(%s) address1 : %s\n", lp->dev->name,
+ DbgHwAddr( probe_rsp->address1 ));
+
+ DBG_TRACE( DbgInfo, "(%s) address2 : %s\n", lp->dev->name,
+ DbgHwAddr( probe_rsp->address2 ));
+
+ DBG_TRACE( DbgInfo, "(%s) BSSID : %s\n", lp->dev->name,
+ DbgHwAddr( probe_rsp->BSSID ));
+
+ DBG_TRACE( DbgInfo, "(%s) sequence : 0x%04x.\n", lp->dev->name,
+ probe_rsp->sequence );
+
+ DBG_TRACE( DbgInfo, "(%s) address4 : %s\n", lp->dev->name,
+ DbgHwAddr( probe_rsp->address4 ));
+
+ DBG_TRACE( DbgInfo, "(%s) datalength : 0x%04x.\n", lp->dev->name,
+ probe_rsp->dataLength );
+
+ DBG_TRACE( DbgInfo, "(%s) DA : %s\n", lp->dev->name,
+ DbgHwAddr( probe_rsp->DA ));
+
+ DBG_TRACE( DbgInfo, "(%s) SA : %s\n", lp->dev->name,
+ DbgHwAddr( probe_rsp->SA ));
+
+#ifdef WARP
+
+ DBG_TRACE( DbgInfo, "(%s) channel : %d\n", lp->dev->name,
+ probe_rsp->channel );
+
+ DBG_TRACE( DbgInfo, "(%s) band : %d\n", lp->dev->name,
+ probe_rsp->band );
+#else
+ DBG_TRACE( DbgInfo, "(%s) lenType : 0x%04x.\n", lp->dev->name,
+ probe_rsp->lenType );
+#endif // WARP
+
+ DBG_TRACE( DbgInfo, "(%s) timeStamp : %d.%d.%d.%d.%d.%d.%d.%d\n",
+ lp->dev->name,
+ probe_rsp->timeStamp[0],
+ probe_rsp->timeStamp[1],
+ probe_rsp->timeStamp[2],
+ probe_rsp->timeStamp[3],
+ probe_rsp->timeStamp[4],
+ probe_rsp->timeStamp[5],
+ probe_rsp->timeStamp[6],
+ probe_rsp->timeStamp[7]);
+
+ DBG_TRACE( DbgInfo, "(%s) beaconInt : 0x%04x.\n", lp->dev->name,
+ probe_rsp->beaconInterval );
+
+ DBG_TRACE( DbgInfo, "(%s) capability : 0x%04x.\n", lp->dev->name,
+ probe_rsp->capability );
+
+ DBG_TRACE( DbgInfo, "(%s) SSID len : 0x%04x.\n", lp->dev->name,
+ probe_rsp->rawData[1] );
+
+
+ if( probe_rsp->rawData[1] > 0 ) {
+ char ssid[HCF_MAX_NAME_LEN];
+
+ memset( ssid, 0, sizeof( ssid ));
+ strncpy( ssid, &probe_rsp->rawData[2],
+ probe_rsp->rawData[1] );
+
+ DBG_TRACE( DbgInfo, "(%s) SSID : %s\n",
+ lp->dev->name, ssid );
+ }
+
+
+ /* Parse out the WPA-IE, if one exists */
+ wpa_ie = wl_parse_wpa_ie( probe_rsp, &wpa_ie_len );
+ if( wpa_ie != NULL ) {
+ DBG_TRACE( DbgInfo, "(%s) WPA-IE : %s\n",
+ lp->dev->name, wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
+ }
+
+ DBG_TRACE( DbgInfo, "(%s) flags : 0x%04x.\n",
+ lp->dev->name, probe_rsp->flags );
+ }
+
+ DBG_TRACE( DbgInfo, "\n" );
+
+
+ /* If probe response length is 1, then the scan is complete */
+ if( probe_rsp->length == 1 ) {
+ DBG_TRACE( DbgInfo, "SCAN COMPLETE\n" );
+ lp->probe_results.num_aps = lp->probe_num_aps;
+ lp->probe_results.scan_complete = TRUE;
+
+ /* Reset the counter for the next scan request */
+ lp->probe_num_aps = 0;
+
+ /* Send a wireless extensions event that the scan completed */
+ wl_wext_event_scan_complete( lp->dev );
+ } else {
+ /* Only copy to the table if the entry is unique; APs sometimes
+ respond more than once to a probe */
+ if( lp->probe_num_aps == 0 ) {
+ /* Copy the info to the ScanResult structure in the private
+ adapter struct */
+ memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
+ probe_rsp, sizeof( PROBE_RESP ));
+
+ /* Increment the number of APs detected */
+ lp->probe_num_aps++;
+ } else {
+ int count;
+ int unique = 1;
+
+ for( count = 0; count < lp->probe_num_aps; count++ ) {
+ if( memcmp( &( probe_rsp->BSSID ),
+ lp->probe_results.ProbeTable[count].BSSID,
+ ETH_ALEN ) == 0 ) {
+ unique = 0;
+ }
+ }
+
+ if( unique ) {
+ /* Copy the info to the ScanResult structure in the
+ private adapter struct. Only copy if there's room in the
+ table */
+ if( lp->probe_num_aps < MAX_NAPS )
+ {
+ memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
+ probe_rsp, sizeof( PROBE_RESP ));
+ }
+ else
+ {
+ DBG_WARNING( DbgInfo, "Num of scan results exceeds storage, truncating\n" );
+ }
+
+ /* Increment the number of APs detected. Note I do this
+ here even when I don't copy the probe response to the
+ buffer in order to detect the overflow condition */
+ lp->probe_num_aps++;
+ }
+ }
+ }
+ }
+
+ DBG_LEAVE( DbgInfo );
+ return;
+} // wl_process_probe_response
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_process_updated_record()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Process the updated information record message signaled by the device.
+ *
+ * PARAMETERS:
+ *
+ * lp - a pointer to the device's private structure
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_process_updated_record( struct wl_private *lp )
+{
+ DBG_FUNC( "wl_process_updated_record" );
+ DBG_ENTER( DbgInfo );
+
+
+ if( lp != NULL ) {
+ lp->updatedRecord.u.u16[0] = CNV_LITTLE_TO_INT( lp->updatedRecord.u.u16[0] );
+
+ switch( lp->updatedRecord.u.u16[0] ) {
+ case CFG_CUR_COUNTRY_INFO:
+ DBG_TRACE( DbgInfo, "Updated Record: CFG_CUR_COUNTRY_INFO\n" );
+ wl_connect( lp );
+ break;
+
+ case CFG_PORT_STAT:
+ DBG_TRACE( DbgInfo, "Updated Record: WAIT_FOR_CONNECT (0xFD40)\n" );
+ //wl_connect( lp );
+ break;
+
+ default:
+ DBG_TRACE( DbgInfo, "UNKNOWN: 0x%04x\n",
+ lp->updatedRecord.u.u16[0] );
+ }
+ }
+
+ DBG_LEAVE( DbgInfo );
+ return;
+} // wl_process_updated_record
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_process_assoc_status()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Process the association status event signaled by the device.
+ *
+ * PARAMETERS:
+ *
+ * lp - a pointer to the device's private structure
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_process_assoc_status( struct wl_private *lp )
+{
+ ASSOC_STATUS_STRCT *assoc_stat;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wl_process_assoc_status" );
+ DBG_ENTER( DbgInfo );
+
+
+ if( lp != NULL ) {
+ assoc_stat = (ASSOC_STATUS_STRCT *)&lp->assoc_stat;
+
+ wl_endian_translate_event( (ltv_t *)assoc_stat );
+
+ switch( assoc_stat->assocStatus ) {
+ case 1:
+ DBG_TRACE( DbgInfo, "Association Status : STA Associated\n" );
+ break;
+
+ case 2:
+ DBG_TRACE( DbgInfo, "Association Status : STA Reassociated\n" );
+ break;
+
+ case 3:
+ DBG_TRACE( DbgInfo, "Association Status : STA Disassociated\n" );
+ break;
+
+ default:
+ DBG_TRACE( DbgInfo, "Association Status : UNKNOWN (0x%04x)\n",
+ assoc_stat->assocStatus );
+ break;
+ }
+
+ DBG_TRACE( DbgInfo, "STA Address : %s\n",
+ DbgHwAddr( assoc_stat->staAddr ));
+
+ if(( assoc_stat->assocStatus == 2 ) && ( assoc_stat->len == 8 )) {
+ DBG_TRACE( DbgInfo, "Old AP Address : %s\n",
+ DbgHwAddr( assoc_stat->oldApAddr ));
+ }
+ }
+
+ DBG_LEAVE( DbgInfo );
+ return;
+} // wl_process_assoc_status
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_process_security_status()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Process the security status message signaled by the device.
+ *
+ * PARAMETERS:
+ *
+ * lp - a pointer to the device's private structure
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_process_security_status( struct wl_private *lp )
+{
+ SECURITY_STATUS_STRCT *sec_stat;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wl_process_security_status" );
+ DBG_ENTER( DbgInfo );
+
+
+ if( lp != NULL ) {
+ sec_stat = (SECURITY_STATUS_STRCT *)&lp->sec_stat;
+
+ wl_endian_translate_event( (ltv_t *)sec_stat );
+
+ switch( sec_stat->securityStatus ) {
+ case 1:
+ DBG_TRACE( DbgInfo, "Security Status : Dissassociate [AP]\n" );
+ break;
+
+ case 2:
+ DBG_TRACE( DbgInfo, "Security Status : Deauthenticate [AP]\n" );
+ break;
+
+ case 3:
+ DBG_TRACE( DbgInfo, "Security Status : Authenticate Fail [STA] or [AP]\n" );
+ break;
+
+ case 4:
+ DBG_TRACE( DbgInfo, "Security Status : MIC Fail\n" );
+ break;
+
+ case 5:
+ DBG_TRACE( DbgInfo, "Security Status : Associate Fail\n" );
+ break;
+
+ default:
+ DBG_TRACE( DbgInfo, "Security Status : UNKNOWN (0x%04x)\n",
+ sec_stat->securityStatus );
+ break;
+ }
+
+ DBG_TRACE( DbgInfo, "STA Address : %s\n",
+ DbgHwAddr( sec_stat->staAddr ));
+ DBG_TRACE( DbgInfo, "Reason : 0x%04x \n", sec_stat->reason );
+
+ }
+
+ DBG_LEAVE( DbgInfo );
+ return;
+} // wl_process_security_status
+/*============================================================================*/
+
+int wl_get_tallies(struct wl_private *lp,
+ CFG_HERMES_TALLIES_STRCT *tallies)
+{
+ int ret = 0;
+ int status;
+ CFG_HERMES_TALLIES_STRCT *pTallies;
+
+ DBG_FUNC( "wl_get_tallies" );
+ DBG_ENTER(DbgInfo);
+
+ /* Get the current tallies from the adapter */
+ lp->ltvRecord.len = 1 + HCF_TOT_TAL_CNT * sizeof(hcf_16);
+ lp->ltvRecord.typ = CFG_TALLIES;
+
+ status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));
+
+ if( status == HCF_SUCCESS ) {
+ pTallies = (CFG_HERMES_TALLIES_STRCT *)&(lp->ltvRecord.u.u32);
+ memcpy(tallies, pTallies, sizeof(*tallies));
+ DBG_TRACE( DbgInfo, "Get tallies okay, dixe: %d\n", sizeof(*tallies) );
+ } else {
+ DBG_TRACE( DbgInfo, "Get tallies failed\n" );
+ ret = -EFAULT;
+ }
+
+ DBG_LEAVE( DbgInfo );
+
+ return ret;
+}
+
+/*******************************************************************************
+ * wl_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:
+ *
+ * unsigned integer
+ *
+ ******************************************************************************/
+unsigned int wl_atoi( char *string )
+{
+unsigned int base = 10; //default to decimal
+unsigned int value = 0;
+unsigned int c;
+int i = strlen( string );
+
+ if ( i > 2 && string[0] == '0' && ( string[1] | ('X'^'x') ) == 'x' ) {
+ base = 16;
+ string +=2;
+ }
+ while ( ( c = *string++ ) != '\0' ) {
+ if ( value > UINT_MAX / base ) { //test for overrun
+ DBG_FUNC( "wl_atoi" ); //don't overload the log file with good messages
+ DBG_ENTER( DbgInfo );
+ DBG_ERROR( DbgInfo, "string \"%s\", lenght exceeds expectations\n", string );
+ printk( "<1>string \"%s\", lenght exceeds expectations\n", string );
+ DBG_LEAVE( DbgInfo );
+ break;
+ }
+ c -= '0';
+ if ( 0 <= c && c <= 9 ) value = base * value + c;
+ else if ( base == 16 ) {
+ c += '0';
+ c |= 'A'^'a';
+ c = c - 'a'+ 10;
+ if ( 10 <= c && c <= 15 ) value = base * value + c;
+ }
+ }
+ return value;
+} // wl_atoi
+