1 /*******************************************************************************
3 * Wireless device driver for Linux (wlags49).
5 * Copyright (c) 1998-2003 Agere Systems Inc.
9 * Initially developed by TriplePoint, Inc.
10 * http://www.triplepoint.com
12 *------------------------------------------------------------------------------
14 * This file defines misc utility functions.
16 *------------------------------------------------------------------------------
20 * This software is provided subject to the following terms and conditions,
21 * which you should read carefully before using the software. Using this
22 * software indicates your acceptance of these terms and conditions. If you do
23 * not agree with these terms and conditions, do not use the software.
25 * Copyright © 2003 Agere Systems Inc.
26 * All rights reserved.
28 * Redistribution and use in source or binary forms, with or without
29 * modifications, are permitted provided that the following conditions are met:
31 * . Redistributions of source code must retain the above copyright notice, this
32 * list of conditions and the following Disclaimer as comments in the code as
33 * well as in the documentation and/or other materials provided with the
36 * . Redistributions in binary form must reproduce the above copyright notice,
37 * this list of conditions and the following Disclaimer in the documentation
38 * and/or other materials provided with the distribution.
40 * . Neither the name of Agere Systems Inc. nor the names of the contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED
\93AS IS
\94 AND ANY EXPRESS OR IMPLIED WARRANTIES,
47 * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
48 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
49 * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
50 * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
51 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
53 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
54 * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
56 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
59 ******************************************************************************/
64 /*******************************************************************************
65 * VERSION CONTROL INFORMATION
66 *******************************************************************************
69 * $Date: 2004/08/04 12:36:10 $
71 * $Source: /usr/local/cvs/wl_lkm/wireless/wl_util.c,v $
73 ******************************************************************************/
78 /*******************************************************************************
80 ******************************************************************************/
81 #include <wl_version.h>
83 #include <linux/kernel.h>
84 // #include <linux/sched.h>
85 // #include <linux/ptrace.h>
86 #include <linux/ctype.h>
87 // #include <linux/string.h>
88 // #include <linux/timer.h>
89 // #include <linux/interrupt.h>
90 // #include <linux/in.h>
91 // #include <linux/delay.h>
92 // #include <asm/io.h>
93 // #include <asm/system.h>
94 // #include <asm/bitops.h>
96 #include <linux/netdevice.h>
97 #include <linux/etherdevice.h>
98 // #include <linux/skbuff.h>
99 // #include <linux/if_arp.h>
100 // #include <linux/ioport.h>
104 // #include <hcfdef.h>
107 #include <wl_internal.h>
114 /*******************************************************************************
116 ******************************************************************************/
118 /* A matrix which maps channels to frequencies */
119 #define MAX_CHAN_FREQ_MAP_ENTRIES 50
120 static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
151 extern dbg_info_t *DbgInfo;
157 /*******************************************************************************
159 *******************************************************************************
163 * Return an energy value in dBm.
167 * value - the energy value to be converted
173 ******************************************************************************/
176 /* Truncate the value to be between min and max. */
177 if( value < HCF_MIN_SIGNAL_LEVEL )
178 value = HCF_MIN_SIGNAL_LEVEL;
180 if( value > HCF_MAX_SIGNAL_LEVEL )
181 value = HCF_MAX_SIGNAL_LEVEL;
183 /* Return the energy value in dBm. */
184 return ( value - HCF_0DBM_OFFSET );
186 /*============================================================================*/
191 /*******************************************************************************
193 *******************************************************************************
197 * Return a value as a percentage of min to max.
201 * value - the value in question
202 * min - the minimum range value
203 * max - the maximum range value
207 * the percentage value
209 ******************************************************************************/
210 int percent( int value, int min, int max )
212 /* Truncate the value to be between min and max. */
219 /* Return the value as a percentage of min to max. */
220 return ((( value - min ) * 100 ) / ( max - min ));
222 /*============================================================================*/
227 /*******************************************************************************
228 * is_valid_key_string()
229 *******************************************************************************
233 * Checks to determine if the WEP key string is valid
237 * s - the string in question
241 * non-zero if the string contains a valid key
243 ******************************************************************************/
244 int is_valid_key_string( char *s )
248 /*------------------------------------------------------------------------*/
253 /* 0x followed by 5 or 13 hexadecimal digit pairs is valid */
254 if( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X' )) {
255 if( l == 12 || l == 28 ) {
256 for( i = 2; i < l; i++ ) {
257 if( !isxdigit( s[i] ))
267 /* string with 0, 5, or 13 characters is valid */
270 return( l == 0 || l == 5 || l == 13 );
272 } // is_valid_key_string
273 /*============================================================================*/
278 /*******************************************************************************
280 *******************************************************************************
284 * Converts a hexadecimal digit character to an integer
288 * c - the hexadecimal digit character
292 * the converted integer
294 ******************************************************************************/
295 int hexdigit2int( char c )
297 if( c >= '0' && c <= '9' )
300 if( c >= 'A' && c <= 'F' )
303 if( c >= 'a' && c <= 'f' )
308 /*============================================================================*/
313 /*******************************************************************************
315 *******************************************************************************
319 * Converts a key_string to a key, Assumes the key_string is validated with
320 * is_valid_key_string().
324 * ks - the valid key string
325 * key - a pointer to a KEY_STRUCT where the converted key information will
332 ******************************************************************************/
333 void key_string2key( char *ks, KEY_STRCT *key )
337 /*------------------------------------------------------------------------*/
342 /* 0x followed by hexadecimal digit pairs */
343 if( ks[0] == '0' && ( ks[1] == 'x' || ks[1] == 'X' )) {
345 p = (char *)key->key;
347 for( i = 2; i < l; i+=2 ) {
348 *p++ = ( hexdigit2int( ks[i] ) << 4 ) + hexdigit2int (ks[i+1] );
352 /* Note that endian translation of the length field is not needed here
353 because it's performed in wl_put_ltv() */
356 /* character string */
359 strcpy( (char *)key->key, ks );
365 /*============================================================================*/
371 /*******************************************************************************
373 *******************************************************************************
377 * Convert a hardware ethernet address to a character string
381 * hwAddr - an ethernet address
385 * a pointer to a string representing the ethernet address
387 ******************************************************************************/
388 const char *DbgHwAddr(unsigned char *hwAddr)
390 static char buffer[18];
391 /*------------------------------------------------------------------------*/
394 sprintf( buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
395 hwAddr[0], hwAddr[1], hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5] );
399 /*============================================================================*/
406 /*******************************************************************************
408 *******************************************************************************
412 * Checks to see if the device supports WEP
416 * ifbp - the IFB pointer of the device in question
420 * 1 if WEP is known enabled, else 0
422 ******************************************************************************/
423 int wl_has_wep (IFBP ifbp)
425 CFG_PRIVACY_OPT_IMPLEMENTED_STRCT ltv;
427 /*------------------------------------------------------------------------*/
430 /* This function allows us to distiguish bronze cards from other types, to
431 know if WEP exists. Does not distinguish (because there's no way to)
432 between silver and gold cards. */
434 ltv.typ = CFG_PRIVACY_OPT_IMPLEMENTED;
436 rc = hcf_get_info( ifbp, (LTVP) <v );
438 privacy = CNV_LITTLE_TO_INT( ltv.privacy_opt_implemented );
440 //return rc ? 0 : privacy;
443 /*============================================================================*/
448 /*******************************************************************************
450 *******************************************************************************
454 * Report the type of HCF error message
462 * A descriptive string indicating the error, quiet otherwise.
464 ******************************************************************************/
465 void wl_hcf_error( struct net_device *dev, int hcfStatus )
467 char buffer[64], *pMsg;
468 /*------------------------------------------------------------------------*/
471 if( hcfStatus != HCF_SUCCESS ) {
472 switch( hcfStatus ) {
474 case HCF_ERR_TIME_OUT:
476 pMsg = "Expected adapter event did not occur in expected time";
482 pMsg = "Card not found (ejected unexpectedly)";
488 pMsg = "Command buffer size insufficient";
492 case HCF_ERR_INCOMP_PRI:
494 pMsg = "Primary functions are not compatible";
498 case HCF_ERR_INCOMP_FW:
500 pMsg = "Primary functions are compatible, "
501 "station/ap functions are not";
507 pMsg = "Inquire cmd while another Inquire in progress";
511 //case HCF_ERR_SEQ_BUG:
513 // pMsg = "Unexpected command completed";
517 case HCF_ERR_DEFUNCT_AUX:
519 pMsg = "Timeout on ack for enable/disable of AUX registers";
523 case HCF_ERR_DEFUNCT_TIMER:
524 pMsg = "Timeout on timer calibration during initialization process";
528 case HCF_ERR_DEFUNCT_TIME_OUT:
529 pMsg = "Timeout on Busy bit drop during BAP setup";
533 case HCF_ERR_DEFUNCT_CMD_SEQ:
534 pMsg = "Hermes and HCF are out of sync";
540 sprintf( buffer, "Error code %d", hcfStatus );
545 printk( KERN_INFO "%s: Wireless, HCF failure: \"%s\"\n",
549 /*============================================================================*/
554 /*******************************************************************************
555 * wl_endian_translate_event()
556 *******************************************************************************
560 * Determines what type of data is in the mailbox and performs the proper
561 * endian translation.
565 * pLtv - an LTV pointer
571 ******************************************************************************/
572 void wl_endian_translate_event( ltv_t *pLtv )
574 DBG_FUNC( "wl_endian_translate_event" );
575 DBG_ENTER( DbgInfo );
578 switch( pLtv->typ ) {
586 SCAN_RS_STRCT *pAps = (SCAN_RS_STRCT*)&pLtv->u.u8[0];
588 numAPs = (hcf_16)(( (size_t)( pLtv->len - 1 ) * 2 ) /
589 (sizeof( SCAN_RS_STRCT )));
591 while( numAPs >= 1 ) {
594 pAps[numAPs].channel_id =
595 CNV_LITTLE_TO_INT( pAps[numAPs].channel_id );
597 pAps[numAPs].noise_level =
598 CNV_LITTLE_TO_INT( pAps[numAPs].noise_level );
600 pAps[numAPs].signal_level =
601 CNV_LITTLE_TO_INT( pAps[numAPs].signal_level );
603 pAps[numAPs].beacon_interval_time =
604 CNV_LITTLE_TO_INT( pAps[numAPs].beacon_interval_time );
606 pAps[numAPs].capability =
607 CNV_LITTLE_TO_INT( pAps[numAPs].capability );
609 pAps[numAPs].ssid_len =
610 CNV_LITTLE_TO_INT( pAps[numAPs].ssid_len );
612 pAps[numAPs].ssid_val[pAps[numAPs].ssid_len] = 0;
621 PROBE_RESP *probe_resp = (PROBE_RESP *)pLtv;
623 probe_resp->frameControl = CNV_LITTLE_TO_INT( probe_resp->frameControl );
624 probe_resp->durID = CNV_LITTLE_TO_INT( probe_resp->durID );
625 probe_resp->sequence = CNV_LITTLE_TO_INT( probe_resp->sequence );
626 probe_resp->dataLength = CNV_LITTLE_TO_INT( probe_resp->dataLength );
629 probe_resp->lenType = CNV_LITTLE_TO_INT( probe_resp->lenType );
632 probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
633 probe_resp->capability = CNV_LITTLE_TO_INT( probe_resp->capability );
634 probe_resp->flags = CNV_LITTLE_TO_INT( probe_resp->flags );
640 #define ls ((LINK_STATUS_STRCT *)pLtv)
641 ls->linkStatus = CNV_LITTLE_TO_INT( ls->linkStatus );
647 ASSOC_STATUS_STRCT *pAs = (ASSOC_STATUS_STRCT *)pLtv;
649 pAs->assocStatus = CNV_LITTLE_TO_INT( pAs->assocStatus );
654 case CFG_SECURITY_STAT:
656 SECURITY_STATUS_STRCT *pSs = (SECURITY_STATUS_STRCT *)pLtv;
658 pSs->securityStatus = CNV_LITTLE_TO_INT( pSs->securityStatus );
659 pSs->reason = CNV_LITTLE_TO_INT( pSs->reason );
676 DBG_LEAVE( DbgInfo );
678 } // wl_endian_translate_event
679 /*============================================================================*/
682 /*******************************************************************************
684 *******************************************************************************
688 * Print statement used to display asserts from within the HCF. Only called
689 * when asserts in the HCF are turned on. See hcfcfg.h for more information.
693 * file_namep - the filename in which the assert occurred.
694 * line_number - the line number on which the assert occurred.
695 * trace - a comment associated with the assert.
696 * qual - return code or other value related to the assert
702 ******************************************************************************/
703 void msf_assert( unsigned int line_number, hcf_16 trace, hcf_32 qual )
705 DBG_PRINT( "HCF ASSERT: Line %d, VAL: 0x%.8x\n", line_number, /*;?*/(u32)qual );
707 /*============================================================================*/
712 /*******************************************************************************
714 *******************************************************************************
718 * This function parses the Direct Sequence Parameter Set IE, used to
719 * determine channel/frequency information.
723 * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
728 * The channel on which the BSS represented by this probe response is
731 ******************************************************************************/
732 hcf_8 wl_parse_ds_ie( PROBE_RESP *probe_rsp )
738 /*------------------------------------------------------------------------*/
741 if( probe_rsp == NULL ) {
745 buf = probe_rsp->rawData;
746 buf_size = sizeof( probe_rsp->rawData );
749 for( i = 0; i < buf_size; i++ ) {
750 if( buf[i] == DS_INFO_ELEM ) {
751 /* Increment by 1 to get the length, and test it; in a DS element,
752 length should always be 1 */
757 /* Get the channel information */
764 /* If we get here, we didn't find a DS-IE, which is strange */
769 /*******************************************************************************
771 *******************************************************************************
775 * This function parses the Probe Response for a valid WPA-IE.
779 * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
781 * length - a pointer to an hcf_16 in which the size of the WPA-IE will
782 * be stored (if found).
786 * A pointer to the location in the probe response buffer where a valid
787 * WPA-IE lives. The length of this IE is written back to the 'length'
788 * argument passed to the function.
790 ******************************************************************************/
791 hcf_8 * wl_parse_wpa_ie( PROBE_RESP *probe_rsp, hcf_16 *length )
797 hcf_8 wpa_oui[] = WPA_OUI_TYPE;
798 /*------------------------------------------------------------------------*/
801 if( probe_rsp == NULL || length == NULL ) {
805 buf = probe_rsp->rawData;
806 buf_size = sizeof( probe_rsp->rawData );
810 for( i = 0; i < buf_size; i++ ) {
811 if( buf[i] == GENERIC_INFO_ELEM ) {
812 /* Increment by one to get the IE length */
814 ie_length = probe_rsp->rawData[i];
816 /* Increment by one to point to the IE payload */
819 /* Does the IE contain a WPA OUI? If not, it's a proprietary IE */
820 if( memcmp( &buf[i], &wpa_oui, WPA_SELECTOR_LEN ) == 0 ) {
821 /* Pass back length and return a pointer to the WPA-IE */
822 /* NOTE: Length contained in the WPA-IE is only the length of
823 the payload. The entire WPA-IE, including the IE identifier
824 and the length, is 2 bytes larger */
825 *length = ie_length + 2;
827 /* Back up the pointer 2 bytes to include the IE identifier and
828 the length in the buffer returned */
833 /* Increment past this non-WPA IE and continue looking */
834 i += ( ie_length - 1 );
838 /* If we're here, we didn't find a WPA-IE in the buffer */
843 /*******************************************************************************
845 *******************************************************************************
849 * Function used to take a WPA Information Element (WPA-IE) buffer and
850 * display it in a readable format.
854 * buffer - the byte buffer containing the WPA-IE
855 * length - the length of the above buffer
859 * A pointer to the formatted WPA-IE string. Note that the format used is
860 * byte-by-byte printing as %02x hex values with no spaces. This is
861 * required for proper operation with some WPA supplicants.
863 ******************************************************************************/
864 hcf_8 * wl_print_wpa_ie( hcf_8 *buffer, int length )
871 static hcf_8 output[512];
872 /*------------------------------------------------------------------------*/
875 memset( output, 0, sizeof( output ));
876 memset( row_buf, 0, sizeof( row_buf ));
879 /* Determine how many rows will be needed, and the remainder */
880 rows = length / rowsize;
881 remainder = length % rowsize;
884 /* Format the rows */
885 for( count = 0; count < rows; count++ ) {
886 sprintf( row_buf, "%02x%02x%02x%02x",
887 buffer[count*rowsize], buffer[count*rowsize+1],
888 buffer[count*rowsize+2], buffer[count*rowsize+3]);
889 strcat( output, row_buf );
892 memset( row_buf, 0, sizeof( row_buf ));
895 /* Format the remainder */
896 for( count = 0; count < remainder; count++ ) {
897 sprintf( row_buf, "%02x", buffer[(rows*rowsize)+count]);
898 strcat( output, row_buf );
903 /*============================================================================*/
908 /*******************************************************************************
909 * wl_is_a_valid_chan()
910 *******************************************************************************
914 * Checks if a given channel is valid
918 * channel - the channel
925 ******************************************************************************/
926 int wl_is_a_valid_chan( int channel )
929 /*------------------------------------------------------------------------*/
932 /* Strip out the high bit set by the FW for 802.11a channels */
933 if( channel & 0x100 ) {
934 channel = channel & 0x0FF;
937 /* Iterate through the matrix and retrieve the frequency */
938 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
939 if( chan_freq_list[i][0] == channel ) {
945 } // wl_is_a_valid_chan
946 /*============================================================================*/
951 /*******************************************************************************
952 * wl_get_chan_from_freq()
953 *******************************************************************************
957 * Checks if a given frequency is valid
961 * freq - the frequency
968 ******************************************************************************/
969 int wl_is_a_valid_freq( long frequency )
972 /*------------------------------------------------------------------------*/
975 /* Iterate through the matrix and retrieve the channel */
976 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
977 if( chan_freq_list[i][1] == frequency ) {
983 } // wl_is_a_valid_freq
984 /*============================================================================*/
989 /*******************************************************************************
990 * wl_get_freq_from_chan()
991 *******************************************************************************
995 * Function used to look up the frequency for a given channel on which the
1000 * channel - the channel
1004 * The corresponding frequency
1006 ******************************************************************************/
1007 long wl_get_freq_from_chan( int channel )
1010 /*------------------------------------------------------------------------*/
1013 /* Strip out the high bit set by the FW for 802.11a channels */
1014 if( channel & 0x100 ) {
1015 channel = channel & 0x0FF;
1018 /* Iterate through the matrix and retrieve the frequency */
1019 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
1020 if( chan_freq_list[i][0] == channel ) {
1021 return chan_freq_list[i][1];
1026 } // wl_get_freq_from_chan
1027 /*============================================================================*/
1032 /*******************************************************************************
1033 * wl_get_chan_from_freq()
1034 *******************************************************************************
1038 * Function used to look up the channel for a given frequency on which the
1043 * frequency - the frequency
1047 * The corresponding channel
1049 ******************************************************************************/
1050 int wl_get_chan_from_freq( long frequency )
1053 /*------------------------------------------------------------------------*/
1056 /* Iterate through the matrix and retrieve the channel */
1057 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
1058 if( chan_freq_list[i][1] == frequency ) {
1059 return chan_freq_list[i][0];
1064 } // wl_get_chan_from_freq
1065 /*============================================================================*/
1070 /*******************************************************************************
1071 * wl_process_link_status()
1072 *******************************************************************************
1076 * Process the link status message signaled by the device.
1080 * lp - a pointer to the device's private structure
1086 ******************************************************************************/
1087 void wl_process_link_status( struct wl_private *lp )
1090 /*------------------------------------------------------------------------*/
1092 DBG_FUNC( "wl_process_link_status" );
1093 DBG_ENTER( DbgInfo );
1096 //link_stat = lp->hcfCtx.IFB_DSLinkStat & CFG_LINK_STAT_FW;
1097 link_stat = lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW;
1098 switch( link_stat ) {
1100 DBG_TRACE( DbgInfo, "Link Status : Connected\n" );
1101 wl_wext_event_ap( lp->dev );
1104 DBG_TRACE( DbgInfo, "Link Status : Disconnected\n" );
1107 DBG_TRACE( DbgInfo, "Link Status : Access Point Change\n" );
1110 DBG_TRACE( DbgInfo, "Link Status : Access Point Out of Range\n" );
1113 DBG_TRACE( DbgInfo, "Link Status : Access Point In Range\n" );
1116 DBG_TRACE( DbgInfo, "Link Status : UNKNOWN (0x%04x)\n", link_stat );
1120 DBG_LEAVE( DbgInfo );
1122 } // wl_process_link_status
1123 /*============================================================================*/
1128 /*******************************************************************************
1129 * wl_process_probe_response()
1130 *******************************************************************************
1134 * Process the probe responses retunred by the device as a result of an
1139 * lp - a pointer to the device's private structure
1145 ******************************************************************************/
1146 void wl_process_probe_response( struct wl_private *lp )
1148 PROBE_RESP *probe_rsp;
1149 hcf_8 *wpa_ie = NULL;
1150 hcf_16 wpa_ie_len = 0;
1151 /*------------------------------------------------------------------------*/
1154 DBG_FUNC( "wl_process_probe_response" );
1155 DBG_ENTER( DbgInfo );
1159 probe_rsp = (PROBE_RESP *)&lp->ProbeResp;
1161 wl_endian_translate_event( (ltv_t *)probe_rsp );
1163 DBG_TRACE( DbgInfo, "(%s) =========================\n", lp->dev->name );
1164 DBG_TRACE( DbgInfo, "(%s) length : 0x%04x.\n", lp->dev->name,
1165 probe_rsp->length );
1167 if( probe_rsp->length > 1 ) {
1168 DBG_TRACE( DbgInfo, "(%s) infoType : 0x%04x.\n", lp->dev->name,
1169 probe_rsp->infoType );
1171 DBG_TRACE( DbgInfo, "(%s) signal : 0x%02x.\n", lp->dev->name,
1172 probe_rsp->signal );
1174 DBG_TRACE( DbgInfo, "(%s) silence : 0x%02x.\n", lp->dev->name,
1175 probe_rsp->silence );
1177 DBG_TRACE( DbgInfo, "(%s) rxFlow : 0x%02x.\n", lp->dev->name,
1178 probe_rsp->rxFlow );
1180 DBG_TRACE( DbgInfo, "(%s) rate : 0x%02x.\n", lp->dev->name,
1183 DBG_TRACE( DbgInfo, "(%s) frame cntl : 0x%04x.\n", lp->dev->name,
1184 probe_rsp->frameControl );
1186 DBG_TRACE( DbgInfo, "(%s) durID : 0x%04x.\n", lp->dev->name,
1189 DBG_TRACE( DbgInfo, "(%s) address1 : %s\n", lp->dev->name,
1190 DbgHwAddr( probe_rsp->address1 ));
1192 DBG_TRACE( DbgInfo, "(%s) address2 : %s\n", lp->dev->name,
1193 DbgHwAddr( probe_rsp->address2 ));
1195 DBG_TRACE( DbgInfo, "(%s) BSSID : %s\n", lp->dev->name,
1196 DbgHwAddr( probe_rsp->BSSID ));
1198 DBG_TRACE( DbgInfo, "(%s) sequence : 0x%04x.\n", lp->dev->name,
1199 probe_rsp->sequence );
1201 DBG_TRACE( DbgInfo, "(%s) address4 : %s\n", lp->dev->name,
1202 DbgHwAddr( probe_rsp->address4 ));
1204 DBG_TRACE( DbgInfo, "(%s) datalength : 0x%04x.\n", lp->dev->name,
1205 probe_rsp->dataLength );
1207 DBG_TRACE( DbgInfo, "(%s) DA : %s\n", lp->dev->name,
1208 DbgHwAddr( probe_rsp->DA ));
1210 DBG_TRACE( DbgInfo, "(%s) SA : %s\n", lp->dev->name,
1211 DbgHwAddr( probe_rsp->SA ));
1215 DBG_TRACE( DbgInfo, "(%s) channel : %d\n", lp->dev->name,
1216 probe_rsp->channel );
1218 DBG_TRACE( DbgInfo, "(%s) band : %d\n", lp->dev->name,
1221 DBG_TRACE( DbgInfo, "(%s) lenType : 0x%04x.\n", lp->dev->name,
1222 probe_rsp->lenType );
1225 DBG_TRACE( DbgInfo, "(%s) timeStamp : %d.%d.%d.%d.%d.%d.%d.%d\n",
1227 probe_rsp->timeStamp[0],
1228 probe_rsp->timeStamp[1],
1229 probe_rsp->timeStamp[2],
1230 probe_rsp->timeStamp[3],
1231 probe_rsp->timeStamp[4],
1232 probe_rsp->timeStamp[5],
1233 probe_rsp->timeStamp[6],
1234 probe_rsp->timeStamp[7]);
1236 DBG_TRACE( DbgInfo, "(%s) beaconInt : 0x%04x.\n", lp->dev->name,
1237 probe_rsp->beaconInterval );
1239 DBG_TRACE( DbgInfo, "(%s) capability : 0x%04x.\n", lp->dev->name,
1240 probe_rsp->capability );
1242 DBG_TRACE( DbgInfo, "(%s) SSID len : 0x%04x.\n", lp->dev->name,
1243 probe_rsp->rawData[1] );
1246 if( probe_rsp->rawData[1] > 0 ) {
1247 char ssid[HCF_MAX_NAME_LEN];
1249 memset( ssid, 0, sizeof( ssid ));
1250 strncpy( ssid, &probe_rsp->rawData[2],
1251 probe_rsp->rawData[1] );
1253 DBG_TRACE( DbgInfo, "(%s) SSID : %s\n",
1254 lp->dev->name, ssid );
1258 /* Parse out the WPA-IE, if one exists */
1259 wpa_ie = wl_parse_wpa_ie( probe_rsp, &wpa_ie_len );
1260 if( wpa_ie != NULL ) {
1261 DBG_TRACE( DbgInfo, "(%s) WPA-IE : %s\n",
1262 lp->dev->name, wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
1265 DBG_TRACE( DbgInfo, "(%s) flags : 0x%04x.\n",
1266 lp->dev->name, probe_rsp->flags );
1269 DBG_TRACE( DbgInfo, "\n" );
1272 /* If probe response length is 1, then the scan is complete */
1273 if( probe_rsp->length == 1 ) {
1274 DBG_TRACE( DbgInfo, "SCAN COMPLETE\n" );
1275 lp->probe_results.num_aps = lp->probe_num_aps;
1276 lp->probe_results.scan_complete = TRUE;
1278 /* Reset the counter for the next scan request */
1279 lp->probe_num_aps = 0;
1281 /* Send a wireless extensions event that the scan completed */
1282 wl_wext_event_scan_complete( lp->dev );
1284 /* Only copy to the table if the entry is unique; APs sometimes
1285 respond more than once to a probe */
1286 if( lp->probe_num_aps == 0 ) {
1287 /* Copy the info to the ScanResult structure in the private
1289 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1290 probe_rsp, sizeof( PROBE_RESP ));
1292 /* Increment the number of APs detected */
1293 lp->probe_num_aps++;
1298 for( count = 0; count < lp->probe_num_aps; count++ ) {
1299 if( memcmp( &( probe_rsp->BSSID ),
1300 lp->probe_results.ProbeTable[count].BSSID,
1307 /* Copy the info to the ScanResult structure in the
1308 private adapter struct. Only copy if there's room in the
1310 if( lp->probe_num_aps < MAX_NAPS )
1312 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1313 probe_rsp, sizeof( PROBE_RESP ));
1317 DBG_WARNING( DbgInfo, "Num of scan results exceeds storage, truncating\n" );
1320 /* Increment the number of APs detected. Note I do this
1321 here even when I don't copy the probe response to the
1322 buffer in order to detect the overflow condition */
1323 lp->probe_num_aps++;
1329 DBG_LEAVE( DbgInfo );
1331 } // wl_process_probe_response
1332 /*============================================================================*/
1337 /*******************************************************************************
1338 * wl_process_updated_record()
1339 *******************************************************************************
1343 * Process the updated information record message signaled by the device.
1347 * lp - a pointer to the device's private structure
1353 ******************************************************************************/
1354 void wl_process_updated_record( struct wl_private *lp )
1356 DBG_FUNC( "wl_process_updated_record" );
1357 DBG_ENTER( DbgInfo );
1361 lp->updatedRecord.u.u16[0] = CNV_LITTLE_TO_INT( lp->updatedRecord.u.u16[0] );
1363 switch( lp->updatedRecord.u.u16[0] ) {
1364 case CFG_CUR_COUNTRY_INFO:
1365 DBG_TRACE( DbgInfo, "Updated Record: CFG_CUR_COUNTRY_INFO\n" );
1370 DBG_TRACE( DbgInfo, "Updated Record: WAIT_FOR_CONNECT (0xFD40)\n" );
1375 DBG_TRACE( DbgInfo, "UNKNOWN: 0x%04x\n",
1376 lp->updatedRecord.u.u16[0] );
1380 DBG_LEAVE( DbgInfo );
1382 } // wl_process_updated_record
1383 /*============================================================================*/
1388 /*******************************************************************************
1389 * wl_process_assoc_status()
1390 *******************************************************************************
1394 * Process the association status event signaled by the device.
1398 * lp - a pointer to the device's private structure
1404 ******************************************************************************/
1405 void wl_process_assoc_status( struct wl_private *lp )
1407 ASSOC_STATUS_STRCT *assoc_stat;
1408 /*------------------------------------------------------------------------*/
1411 DBG_FUNC( "wl_process_assoc_status" );
1412 DBG_ENTER( DbgInfo );
1416 assoc_stat = (ASSOC_STATUS_STRCT *)&lp->assoc_stat;
1418 wl_endian_translate_event( (ltv_t *)assoc_stat );
1420 switch( assoc_stat->assocStatus ) {
1422 DBG_TRACE( DbgInfo, "Association Status : STA Associated\n" );
1426 DBG_TRACE( DbgInfo, "Association Status : STA Reassociated\n" );
1430 DBG_TRACE( DbgInfo, "Association Status : STA Disassociated\n" );
1434 DBG_TRACE( DbgInfo, "Association Status : UNKNOWN (0x%04x)\n",
1435 assoc_stat->assocStatus );
1439 DBG_TRACE( DbgInfo, "STA Address : %s\n",
1440 DbgHwAddr( assoc_stat->staAddr ));
1442 if(( assoc_stat->assocStatus == 2 ) && ( assoc_stat->len == 8 )) {
1443 DBG_TRACE( DbgInfo, "Old AP Address : %s\n",
1444 DbgHwAddr( assoc_stat->oldApAddr ));
1448 DBG_LEAVE( DbgInfo );
1450 } // wl_process_assoc_status
1451 /*============================================================================*/
1456 /*******************************************************************************
1457 * wl_process_security_status()
1458 *******************************************************************************
1462 * Process the security status message signaled by the device.
1466 * lp - a pointer to the device's private structure
1472 ******************************************************************************/
1473 void wl_process_security_status( struct wl_private *lp )
1475 SECURITY_STATUS_STRCT *sec_stat;
1476 /*------------------------------------------------------------------------*/
1479 DBG_FUNC( "wl_process_security_status" );
1480 DBG_ENTER( DbgInfo );
1484 sec_stat = (SECURITY_STATUS_STRCT *)&lp->sec_stat;
1486 wl_endian_translate_event( (ltv_t *)sec_stat );
1488 switch( sec_stat->securityStatus ) {
1490 DBG_TRACE( DbgInfo, "Security Status : Dissassociate [AP]\n" );
1494 DBG_TRACE( DbgInfo, "Security Status : Deauthenticate [AP]\n" );
1498 DBG_TRACE( DbgInfo, "Security Status : Authenticate Fail [STA] or [AP]\n" );
1502 DBG_TRACE( DbgInfo, "Security Status : MIC Fail\n" );
1506 DBG_TRACE( DbgInfo, "Security Status : Associate Fail\n" );
1510 DBG_TRACE( DbgInfo, "Security Status : UNKNOWN (0x%04x)\n",
1511 sec_stat->securityStatus );
1515 DBG_TRACE( DbgInfo, "STA Address : %s\n",
1516 DbgHwAddr( sec_stat->staAddr ));
1517 DBG_TRACE( DbgInfo, "Reason : 0x%04x \n", sec_stat->reason );
1521 DBG_LEAVE( DbgInfo );
1523 } // wl_process_security_status
1524 /*============================================================================*/
1526 int wl_get_tallies(struct wl_private *lp,
1527 CFG_HERMES_TALLIES_STRCT *tallies)
1531 CFG_HERMES_TALLIES_STRCT *pTallies;
1533 DBG_FUNC( "wl_get_tallies" );
1536 /* Get the current tallies from the adapter */
1537 lp->ltvRecord.len = 1 + HCF_TOT_TAL_CNT * sizeof(hcf_16);
1538 lp->ltvRecord.typ = CFG_TALLIES;
1540 status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));
1542 if( status == HCF_SUCCESS ) {
1543 pTallies = (CFG_HERMES_TALLIES_STRCT *)&(lp->ltvRecord.u.u32);
1544 memcpy(tallies, pTallies, sizeof(*tallies));
1545 DBG_TRACE( DbgInfo, "Get tallies okay, dixe: %d\n", sizeof(*tallies) );
1547 DBG_TRACE( DbgInfo, "Get tallies failed\n" );
1551 DBG_LEAVE( DbgInfo );
1556 /*******************************************************************************
1558 *******************************************************************************
1562 * Believe it or not, we need our own implementation of atoi in the kernel.
1566 * string - the ASCII string to convert to an integer
1572 ******************************************************************************/
1573 unsigned int wl_atoi( char *string )
1575 unsigned int base = 10; //default to decimal
1576 unsigned int value = 0;
1578 int i = strlen( string );
1580 if ( i > 2 && string[0] == '0' && ( string[1] | ('X'^'x') ) == 'x' ) {
1584 while ( ( c = *string++ ) != '\0' ) {
1585 if ( value > UINT_MAX / base ) { //test for overrun
1586 DBG_FUNC( "wl_atoi" ); //don't overload the log file with good messages
1587 DBG_ENTER( DbgInfo );
1588 DBG_ERROR( DbgInfo, "string \"%s\", lenght exceeds expectations\n", string );
1589 printk( "<1>string \"%s\", lenght exceeds expectations\n", string );
1590 DBG_LEAVE( DbgInfo );
1594 if ( 0 <= c && c <= 9 ) value = base * value + c;
1595 else if ( base == 16 ) {
1599 if ( 10 <= c && c <= 15 ) value = base * value + c;