/******************************************************************************* * 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 #include // #include // #include #include // #include // #include // #include // #include // #include // #include // #include // #include #include #include // #include // #include // #include #include #include // #include #include #include #include #include #include /******************************************************************************* * 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 /*============================================================================*/ /******************************************************************************* * 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++ = (hex_to_bin(ks[i]) << 4) + hex_to_bin(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 /*============================================================================*/ /******************************************************************************* * 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) <v ); 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 : %pM\n", lp->dev->name, probe_rsp->address1); DBG_TRACE(DbgInfo, "(%s) address2 : %pM\n", lp->dev->name, probe_rsp->address2); DBG_TRACE(DbgInfo, "(%s) BSSID : %pM\n", lp->dev->name, probe_rsp->BSSID); DBG_TRACE( DbgInfo, "(%s) sequence : 0x%04x.\n", lp->dev->name, probe_rsp->sequence ); DBG_TRACE(DbgInfo, "(%s) address4 : %pM\n", lp->dev->name, probe_rsp->address4); DBG_TRACE( DbgInfo, "(%s) datalength : 0x%04x.\n", lp->dev->name, probe_rsp->dataLength ); DBG_TRACE(DbgInfo, "(%s) DA : %pM\n", lp->dev->name, probe_rsp->DA); DBG_TRACE(DbgInfo, "(%s) SA : %pM\n", lp->dev->name, 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 : %pM\n", assoc_stat->staAddr); if(( assoc_stat->assocStatus == 2 ) && ( assoc_stat->len == 8 )) { DBG_TRACE(DbgInfo, "Old AP Address : %pM\n", 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 : %pM\n", 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; }