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 ******************************************************************************/
61 /*******************************************************************************
63 ******************************************************************************/
64 #include <wl_version.h>
66 #include <linux/kernel.h>
67 // #include <linux/sched.h>
68 // #include <linux/ptrace.h>
69 #include <linux/ctype.h>
70 // #include <linux/string.h>
71 // #include <linux/timer.h>
72 // #include <linux/interrupt.h>
73 // #include <linux/in.h>
74 // #include <linux/delay.h>
75 // #include <asm/io.h>
76 // // #include <asm/bitops.h>
78 #include <linux/netdevice.h>
79 #include <linux/etherdevice.h>
80 // #include <linux/skbuff.h>
81 // #include <linux/if_arp.h>
82 // #include <linux/ioport.h>
86 // #include <hcfdef.h>
89 #include <wl_internal.h>
96 /*******************************************************************************
98 ******************************************************************************/
100 /* A matrix which maps channels to frequencies */
101 #define MAX_CHAN_FREQ_MAP_ENTRIES 50
102 static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
133 extern dbg_info_t *DbgInfo;
139 /*******************************************************************************
141 *******************************************************************************
145 * Return an energy value in dBm.
149 * value - the energy value to be converted
155 ******************************************************************************/
158 /* Truncate the value to be between min and max. */
159 if( value < HCF_MIN_SIGNAL_LEVEL )
160 value = HCF_MIN_SIGNAL_LEVEL;
162 if( value > HCF_MAX_SIGNAL_LEVEL )
163 value = HCF_MAX_SIGNAL_LEVEL;
165 /* Return the energy value in dBm. */
166 return ( value - HCF_0DBM_OFFSET );
168 /*============================================================================*/
173 /*******************************************************************************
175 *******************************************************************************
179 * Return a value as a percentage of min to max.
183 * value - the value in question
184 * min - the minimum range value
185 * max - the maximum range value
189 * the percentage value
191 ******************************************************************************/
192 int percent( int value, int min, int max )
194 /* Truncate the value to be between min and max. */
201 /* Return the value as a percentage of min to max. */
202 return ((( value - min ) * 100 ) / ( max - min ));
204 /*============================================================================*/
209 /*******************************************************************************
210 * is_valid_key_string()
211 *******************************************************************************
215 * Checks to determine if the WEP key string is valid
219 * s - the string in question
223 * non-zero if the string contains a valid key
225 ******************************************************************************/
226 int is_valid_key_string( char *s )
230 /*------------------------------------------------------------------------*/
235 /* 0x followed by 5 or 13 hexadecimal digit pairs is valid */
236 if( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X' )) {
237 if( l == 12 || l == 28 ) {
238 for( i = 2; i < l; i++ ) {
239 if( !isxdigit( s[i] ))
249 /* string with 0, 5, or 13 characters is valid */
252 return( l == 0 || l == 5 || l == 13 );
254 } // is_valid_key_string
255 /*============================================================================*/
260 /*******************************************************************************
262 *******************************************************************************
266 * Converts a key_string to a key, Assumes the key_string is validated with
267 * is_valid_key_string().
271 * ks - the valid key string
272 * key - a pointer to a KEY_STRUCT where the converted key information will
279 ******************************************************************************/
280 void key_string2key( char *ks, KEY_STRCT *key )
284 /*------------------------------------------------------------------------*/
289 /* 0x followed by hexadecimal digit pairs */
290 if( ks[0] == '0' && ( ks[1] == 'x' || ks[1] == 'X' )) {
292 p = (char *)key->key;
294 for( i = 2; i < l; i+=2 ) {
295 *p++ = (hex_to_bin(ks[i]) << 4) + hex_to_bin(ks[i+1]);
299 /* Note that endian translation of the length field is not needed here
300 because it's performed in wl_put_ltv() */
303 /* character string */
306 strcpy( (char *)key->key, ks );
312 /*============================================================================*/
317 /*******************************************************************************
319 *******************************************************************************
323 * Checks to see if the device supports WEP
327 * ifbp - the IFB pointer of the device in question
331 * 1 if WEP is known enabled, else 0
333 ******************************************************************************/
334 int wl_has_wep (IFBP ifbp)
336 CFG_PRIVACY_OPT_IMPLEMENTED_STRCT ltv;
338 /*------------------------------------------------------------------------*/
341 /* This function allows us to distiguish bronze cards from other types, to
342 know if WEP exists. Does not distinguish (because there's no way to)
343 between silver and gold cards. */
345 ltv.typ = CFG_PRIVACY_OPT_IMPLEMENTED;
347 rc = hcf_get_info( ifbp, (LTVP) <v );
349 privacy = CNV_LITTLE_TO_INT( ltv.privacy_opt_implemented );
351 //return rc ? 0 : privacy;
354 /*============================================================================*/
359 /*******************************************************************************
361 *******************************************************************************
365 * Report the type of HCF error message
373 * A descriptive string indicating the error, quiet otherwise.
375 ******************************************************************************/
376 void wl_hcf_error( struct net_device *dev, int hcfStatus )
378 char buffer[64], *pMsg;
379 /*------------------------------------------------------------------------*/
382 if( hcfStatus != HCF_SUCCESS ) {
383 switch( hcfStatus ) {
385 case HCF_ERR_TIME_OUT:
387 pMsg = "Expected adapter event did not occur in expected time";
393 pMsg = "Card not found (ejected unexpectedly)";
399 pMsg = "Command buffer size insufficient";
403 case HCF_ERR_INCOMP_PRI:
405 pMsg = "Primary functions are not compatible";
409 case HCF_ERR_INCOMP_FW:
411 pMsg = "Primary functions are compatible, "
412 "station/ap functions are not";
418 pMsg = "Inquire cmd while another Inquire in progress";
422 //case HCF_ERR_SEQ_BUG:
424 // pMsg = "Unexpected command completed";
428 case HCF_ERR_DEFUNCT_AUX:
430 pMsg = "Timeout on ack for enable/disable of AUX registers";
434 case HCF_ERR_DEFUNCT_TIMER:
435 pMsg = "Timeout on timer calibration during initialization process";
439 case HCF_ERR_DEFUNCT_TIME_OUT:
440 pMsg = "Timeout on Busy bit drop during BAP setup";
444 case HCF_ERR_DEFUNCT_CMD_SEQ:
445 pMsg = "Hermes and HCF are out of sync";
451 sprintf( buffer, "Error code %d", hcfStatus );
456 printk( KERN_INFO "%s: Wireless, HCF failure: \"%s\"\n",
460 /*============================================================================*/
465 /*******************************************************************************
466 * wl_endian_translate_event()
467 *******************************************************************************
471 * Determines what type of data is in the mailbox and performs the proper
472 * endian translation.
476 * pLtv - an LTV pointer
482 ******************************************************************************/
483 void wl_endian_translate_event( ltv_t *pLtv )
485 DBG_FUNC( "wl_endian_translate_event" );
486 DBG_ENTER( DbgInfo );
489 switch( pLtv->typ ) {
497 SCAN_RS_STRCT *pAps = (SCAN_RS_STRCT*)&pLtv->u.u8[0];
499 numAPs = (hcf_16)(( (size_t)( pLtv->len - 1 ) * 2 ) /
500 (sizeof( SCAN_RS_STRCT )));
502 while( numAPs >= 1 ) {
505 pAps[numAPs].channel_id =
506 CNV_LITTLE_TO_INT( pAps[numAPs].channel_id );
508 pAps[numAPs].noise_level =
509 CNV_LITTLE_TO_INT( pAps[numAPs].noise_level );
511 pAps[numAPs].signal_level =
512 CNV_LITTLE_TO_INT( pAps[numAPs].signal_level );
514 pAps[numAPs].beacon_interval_time =
515 CNV_LITTLE_TO_INT( pAps[numAPs].beacon_interval_time );
517 pAps[numAPs].capability =
518 CNV_LITTLE_TO_INT( pAps[numAPs].capability );
520 pAps[numAPs].ssid_len =
521 CNV_LITTLE_TO_INT( pAps[numAPs].ssid_len );
523 pAps[numAPs].ssid_val[pAps[numAPs].ssid_len] = 0;
532 PROBE_RESP *probe_resp = (PROBE_RESP *)pLtv;
534 probe_resp->frameControl = CNV_LITTLE_TO_INT( probe_resp->frameControl );
535 probe_resp->durID = CNV_LITTLE_TO_INT( probe_resp->durID );
536 probe_resp->sequence = CNV_LITTLE_TO_INT( probe_resp->sequence );
537 probe_resp->dataLength = CNV_LITTLE_TO_INT( probe_resp->dataLength );
540 probe_resp->lenType = CNV_LITTLE_TO_INT( probe_resp->lenType );
543 probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
544 probe_resp->capability = CNV_LITTLE_TO_INT( probe_resp->capability );
545 probe_resp->flags = CNV_LITTLE_TO_INT( probe_resp->flags );
551 #define ls ((LINK_STATUS_STRCT *)pLtv)
552 ls->linkStatus = CNV_LITTLE_TO_INT( ls->linkStatus );
558 ASSOC_STATUS_STRCT *pAs = (ASSOC_STATUS_STRCT *)pLtv;
560 pAs->assocStatus = CNV_LITTLE_TO_INT( pAs->assocStatus );
565 case CFG_SECURITY_STAT:
567 SECURITY_STATUS_STRCT *pSs = (SECURITY_STATUS_STRCT *)pLtv;
569 pSs->securityStatus = CNV_LITTLE_TO_INT( pSs->securityStatus );
570 pSs->reason = CNV_LITTLE_TO_INT( pSs->reason );
587 DBG_LEAVE( DbgInfo );
589 } // wl_endian_translate_event
590 /*============================================================================*/
593 /*******************************************************************************
595 *******************************************************************************
599 * Print statement used to display asserts from within the HCF. Only called
600 * when asserts in the HCF are turned on. See hcfcfg.h for more information.
604 * file_namep - the filename in which the assert occurred.
605 * line_number - the line number on which the assert occurred.
606 * trace - a comment associated with the assert.
607 * qual - return code or other value related to the assert
613 ******************************************************************************/
614 void msf_assert( unsigned int line_number, hcf_16 trace, hcf_32 qual )
616 DBG_PRINT( "HCF ASSERT: Line %d, VAL: 0x%.8x\n", line_number, /*;?*/(u32)qual );
618 /*============================================================================*/
623 /*******************************************************************************
625 *******************************************************************************
629 * This function parses the Direct Sequence Parameter Set IE, used to
630 * determine channel/frequency information.
634 * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
639 * The channel on which the BSS represented by this probe response is
642 ******************************************************************************/
643 hcf_8 wl_parse_ds_ie( PROBE_RESP *probe_rsp )
649 /*------------------------------------------------------------------------*/
652 if( probe_rsp == NULL ) {
656 buf = probe_rsp->rawData;
657 buf_size = sizeof( probe_rsp->rawData );
660 for( i = 0; i < buf_size; i++ ) {
661 if( buf[i] == DS_INFO_ELEM ) {
662 /* Increment by 1 to get the length, and test it; in a DS element,
663 length should always be 1 */
668 /* Get the channel information */
675 /* If we get here, we didn't find a DS-IE, which is strange */
680 /*******************************************************************************
682 *******************************************************************************
686 * This function parses the Probe Response for a valid WPA-IE.
690 * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
692 * length - a pointer to an hcf_16 in which the size of the WPA-IE will
693 * be stored (if found).
697 * A pointer to the location in the probe response buffer where a valid
698 * WPA-IE lives. The length of this IE is written back to the 'length'
699 * argument passed to the function.
701 ******************************************************************************/
702 hcf_8 * wl_parse_wpa_ie( PROBE_RESP *probe_rsp, hcf_16 *length )
708 hcf_8 wpa_oui[] = WPA_OUI_TYPE;
709 /*------------------------------------------------------------------------*/
712 if( probe_rsp == NULL || length == NULL ) {
716 buf = probe_rsp->rawData;
717 buf_size = sizeof( probe_rsp->rawData );
721 for( i = 0; i < buf_size; i++ ) {
722 if( buf[i] == GENERIC_INFO_ELEM ) {
723 /* Increment by one to get the IE length */
725 ie_length = probe_rsp->rawData[i];
727 /* Increment by one to point to the IE payload */
730 /* Does the IE contain a WPA OUI? If not, it's a proprietary IE */
731 if( memcmp( &buf[i], &wpa_oui, WPA_SELECTOR_LEN ) == 0 ) {
732 /* Pass back length and return a pointer to the WPA-IE */
733 /* NOTE: Length contained in the WPA-IE is only the length of
734 the payload. The entire WPA-IE, including the IE identifier
735 and the length, is 2 bytes larger */
736 *length = ie_length + 2;
738 /* Back up the pointer 2 bytes to include the IE identifier and
739 the length in the buffer returned */
744 /* Increment past this non-WPA IE and continue looking */
745 i += ( ie_length - 1 );
749 /* If we're here, we didn't find a WPA-IE in the buffer */
754 /*******************************************************************************
756 *******************************************************************************
760 * Function used to take a WPA Information Element (WPA-IE) buffer and
761 * display it in a readable format.
765 * buffer - the byte buffer containing the WPA-IE
766 * length - the length of the above buffer
770 * A pointer to the formatted WPA-IE string. Note that the format used is
771 * byte-by-byte printing as %02x hex values with no spaces. This is
772 * required for proper operation with some WPA supplicants.
774 ******************************************************************************/
775 hcf_8 * wl_print_wpa_ie( hcf_8 *buffer, int length )
782 static hcf_8 output[512];
783 /*------------------------------------------------------------------------*/
786 memset( output, 0, sizeof( output ));
787 memset( row_buf, 0, sizeof( row_buf ));
790 /* Determine how many rows will be needed, and the remainder */
791 rows = length / rowsize;
792 remainder = length % rowsize;
795 /* Format the rows */
796 for( count = 0; count < rows; count++ ) {
797 sprintf( row_buf, "%02x%02x%02x%02x",
798 buffer[count*rowsize], buffer[count*rowsize+1],
799 buffer[count*rowsize+2], buffer[count*rowsize+3]);
800 strcat( output, row_buf );
803 memset( row_buf, 0, sizeof( row_buf ));
806 /* Format the remainder */
807 for( count = 0; count < remainder; count++ ) {
808 sprintf( row_buf, "%02x", buffer[(rows*rowsize)+count]);
809 strcat( output, row_buf );
814 /*============================================================================*/
819 /*******************************************************************************
820 * wl_is_a_valid_chan()
821 *******************************************************************************
825 * Checks if a given channel is valid
829 * channel - the channel
836 ******************************************************************************/
837 int wl_is_a_valid_chan( int channel )
840 /*------------------------------------------------------------------------*/
843 /* Strip out the high bit set by the FW for 802.11a channels */
844 if( channel & 0x100 ) {
845 channel = channel & 0x0FF;
848 /* Iterate through the matrix and retrieve the frequency */
849 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
850 if( chan_freq_list[i][0] == channel ) {
856 } // wl_is_a_valid_chan
857 /*============================================================================*/
862 /*******************************************************************************
863 * wl_get_chan_from_freq()
864 *******************************************************************************
868 * Checks if a given frequency is valid
872 * freq - the frequency
879 ******************************************************************************/
880 int wl_is_a_valid_freq( long frequency )
883 /*------------------------------------------------------------------------*/
886 /* Iterate through the matrix and retrieve the channel */
887 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
888 if( chan_freq_list[i][1] == frequency ) {
894 } // wl_is_a_valid_freq
895 /*============================================================================*/
900 /*******************************************************************************
901 * wl_get_freq_from_chan()
902 *******************************************************************************
906 * Function used to look up the frequency for a given channel on which the
911 * channel - the channel
915 * The corresponding frequency
917 ******************************************************************************/
918 long wl_get_freq_from_chan( int channel )
921 /*------------------------------------------------------------------------*/
924 /* Strip out the high bit set by the FW for 802.11a channels */
925 if( channel & 0x100 ) {
926 channel = channel & 0x0FF;
929 /* Iterate through the matrix and retrieve the frequency */
930 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
931 if( chan_freq_list[i][0] == channel ) {
932 return chan_freq_list[i][1];
937 } // wl_get_freq_from_chan
938 /*============================================================================*/
943 /*******************************************************************************
944 * wl_get_chan_from_freq()
945 *******************************************************************************
949 * Function used to look up the channel for a given frequency on which the
954 * frequency - the frequency
958 * The corresponding channel
960 ******************************************************************************/
961 int wl_get_chan_from_freq( long frequency )
964 /*------------------------------------------------------------------------*/
967 /* Iterate through the matrix and retrieve the channel */
968 for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
969 if( chan_freq_list[i][1] == frequency ) {
970 return chan_freq_list[i][0];
975 } // wl_get_chan_from_freq
976 /*============================================================================*/
981 /*******************************************************************************
982 * wl_process_link_status()
983 *******************************************************************************
987 * Process the link status message signaled by the device.
991 * lp - a pointer to the device's private structure
997 ******************************************************************************/
998 void wl_process_link_status( struct wl_private *lp )
1001 /*------------------------------------------------------------------------*/
1003 DBG_FUNC( "wl_process_link_status" );
1004 DBG_ENTER( DbgInfo );
1007 //link_stat = lp->hcfCtx.IFB_DSLinkStat & CFG_LINK_STAT_FW;
1008 link_stat = lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW;
1009 switch( link_stat ) {
1011 DBG_TRACE( DbgInfo, "Link Status : Connected\n" );
1012 wl_wext_event_ap( lp->dev );
1015 DBG_TRACE( DbgInfo, "Link Status : Disconnected\n" );
1018 DBG_TRACE( DbgInfo, "Link Status : Access Point Change\n" );
1021 DBG_TRACE( DbgInfo, "Link Status : Access Point Out of Range\n" );
1024 DBG_TRACE( DbgInfo, "Link Status : Access Point In Range\n" );
1027 DBG_TRACE( DbgInfo, "Link Status : UNKNOWN (0x%04x)\n", link_stat );
1031 DBG_LEAVE( DbgInfo );
1033 } // wl_process_link_status
1034 /*============================================================================*/
1039 /*******************************************************************************
1040 * wl_process_probe_response()
1041 *******************************************************************************
1045 * Process the probe responses retunred by the device as a result of an
1050 * lp - a pointer to the device's private structure
1056 ******************************************************************************/
1057 void wl_process_probe_response( struct wl_private *lp )
1059 PROBE_RESP *probe_rsp;
1060 hcf_8 *wpa_ie = NULL;
1061 hcf_16 wpa_ie_len = 0;
1062 /*------------------------------------------------------------------------*/
1065 DBG_FUNC( "wl_process_probe_response" );
1066 DBG_ENTER( DbgInfo );
1070 probe_rsp = (PROBE_RESP *)&lp->ProbeResp;
1072 wl_endian_translate_event( (ltv_t *)probe_rsp );
1074 DBG_TRACE( DbgInfo, "(%s) =========================\n", lp->dev->name );
1075 DBG_TRACE( DbgInfo, "(%s) length : 0x%04x.\n", lp->dev->name,
1076 probe_rsp->length );
1078 if( probe_rsp->length > 1 ) {
1079 DBG_TRACE( DbgInfo, "(%s) infoType : 0x%04x.\n", lp->dev->name,
1080 probe_rsp->infoType );
1082 DBG_TRACE( DbgInfo, "(%s) signal : 0x%02x.\n", lp->dev->name,
1083 probe_rsp->signal );
1085 DBG_TRACE( DbgInfo, "(%s) silence : 0x%02x.\n", lp->dev->name,
1086 probe_rsp->silence );
1088 DBG_TRACE( DbgInfo, "(%s) rxFlow : 0x%02x.\n", lp->dev->name,
1089 probe_rsp->rxFlow );
1091 DBG_TRACE( DbgInfo, "(%s) rate : 0x%02x.\n", lp->dev->name,
1094 DBG_TRACE( DbgInfo, "(%s) frame cntl : 0x%04x.\n", lp->dev->name,
1095 probe_rsp->frameControl );
1097 DBG_TRACE( DbgInfo, "(%s) durID : 0x%04x.\n", lp->dev->name,
1100 DBG_TRACE(DbgInfo, "(%s) address1 : %pM\n", lp->dev->name,
1101 probe_rsp->address1);
1103 DBG_TRACE(DbgInfo, "(%s) address2 : %pM\n", lp->dev->name,
1104 probe_rsp->address2);
1106 DBG_TRACE(DbgInfo, "(%s) BSSID : %pM\n", lp->dev->name,
1109 DBG_TRACE( DbgInfo, "(%s) sequence : 0x%04x.\n", lp->dev->name,
1110 probe_rsp->sequence );
1112 DBG_TRACE(DbgInfo, "(%s) address4 : %pM\n", lp->dev->name,
1113 probe_rsp->address4);
1115 DBG_TRACE( DbgInfo, "(%s) datalength : 0x%04x.\n", lp->dev->name,
1116 probe_rsp->dataLength );
1118 DBG_TRACE(DbgInfo, "(%s) DA : %pM\n", lp->dev->name,
1121 DBG_TRACE(DbgInfo, "(%s) SA : %pM\n", lp->dev->name,
1126 DBG_TRACE( DbgInfo, "(%s) channel : %d\n", lp->dev->name,
1127 probe_rsp->channel );
1129 DBG_TRACE( DbgInfo, "(%s) band : %d\n", lp->dev->name,
1132 DBG_TRACE( DbgInfo, "(%s) lenType : 0x%04x.\n", lp->dev->name,
1133 probe_rsp->lenType );
1136 DBG_TRACE( DbgInfo, "(%s) timeStamp : %d.%d.%d.%d.%d.%d.%d.%d\n",
1138 probe_rsp->timeStamp[0],
1139 probe_rsp->timeStamp[1],
1140 probe_rsp->timeStamp[2],
1141 probe_rsp->timeStamp[3],
1142 probe_rsp->timeStamp[4],
1143 probe_rsp->timeStamp[5],
1144 probe_rsp->timeStamp[6],
1145 probe_rsp->timeStamp[7]);
1147 DBG_TRACE( DbgInfo, "(%s) beaconInt : 0x%04x.\n", lp->dev->name,
1148 probe_rsp->beaconInterval );
1150 DBG_TRACE( DbgInfo, "(%s) capability : 0x%04x.\n", lp->dev->name,
1151 probe_rsp->capability );
1153 DBG_TRACE( DbgInfo, "(%s) SSID len : 0x%04x.\n", lp->dev->name,
1154 probe_rsp->rawData[1] );
1157 if( probe_rsp->rawData[1] > 0 ) {
1158 char ssid[HCF_MAX_NAME_LEN];
1160 memset( ssid, 0, sizeof( ssid ));
1161 strncpy( ssid, &probe_rsp->rawData[2],
1162 probe_rsp->rawData[1] );
1164 DBG_TRACE( DbgInfo, "(%s) SSID : %s\n",
1165 lp->dev->name, ssid );
1169 /* Parse out the WPA-IE, if one exists */
1170 wpa_ie = wl_parse_wpa_ie( probe_rsp, &wpa_ie_len );
1171 if( wpa_ie != NULL ) {
1172 DBG_TRACE( DbgInfo, "(%s) WPA-IE : %s\n",
1173 lp->dev->name, wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
1176 DBG_TRACE( DbgInfo, "(%s) flags : 0x%04x.\n",
1177 lp->dev->name, probe_rsp->flags );
1180 DBG_TRACE( DbgInfo, "\n" );
1183 /* If probe response length is 1, then the scan is complete */
1184 if( probe_rsp->length == 1 ) {
1185 DBG_TRACE( DbgInfo, "SCAN COMPLETE\n" );
1186 lp->probe_results.num_aps = lp->probe_num_aps;
1187 lp->probe_results.scan_complete = TRUE;
1189 /* Reset the counter for the next scan request */
1190 lp->probe_num_aps = 0;
1192 /* Send a wireless extensions event that the scan completed */
1193 wl_wext_event_scan_complete( lp->dev );
1195 /* Only copy to the table if the entry is unique; APs sometimes
1196 respond more than once to a probe */
1197 if( lp->probe_num_aps == 0 ) {
1198 /* Copy the info to the ScanResult structure in the private
1200 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1201 probe_rsp, sizeof( PROBE_RESP ));
1203 /* Increment the number of APs detected */
1204 lp->probe_num_aps++;
1209 for( count = 0; count < lp->probe_num_aps; count++ ) {
1210 if( memcmp( &( probe_rsp->BSSID ),
1211 lp->probe_results.ProbeTable[count].BSSID,
1218 /* Copy the info to the ScanResult structure in the
1219 private adapter struct. Only copy if there's room in the
1221 if( lp->probe_num_aps < MAX_NAPS )
1223 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1224 probe_rsp, sizeof( PROBE_RESP ));
1228 DBG_WARNING( DbgInfo, "Num of scan results exceeds storage, truncating\n" );
1231 /* Increment the number of APs detected. Note I do this
1232 here even when I don't copy the probe response to the
1233 buffer in order to detect the overflow condition */
1234 lp->probe_num_aps++;
1240 DBG_LEAVE( DbgInfo );
1242 } // wl_process_probe_response
1243 /*============================================================================*/
1248 /*******************************************************************************
1249 * wl_process_updated_record()
1250 *******************************************************************************
1254 * Process the updated information record message signaled by the device.
1258 * lp - a pointer to the device's private structure
1264 ******************************************************************************/
1265 void wl_process_updated_record( struct wl_private *lp )
1267 DBG_FUNC( "wl_process_updated_record" );
1268 DBG_ENTER( DbgInfo );
1272 lp->updatedRecord.u.u16[0] = CNV_LITTLE_TO_INT( lp->updatedRecord.u.u16[0] );
1274 switch( lp->updatedRecord.u.u16[0] ) {
1275 case CFG_CUR_COUNTRY_INFO:
1276 DBG_TRACE( DbgInfo, "Updated Record: CFG_CUR_COUNTRY_INFO\n" );
1281 DBG_TRACE( DbgInfo, "Updated Record: WAIT_FOR_CONNECT (0xFD40)\n" );
1286 DBG_TRACE( DbgInfo, "UNKNOWN: 0x%04x\n",
1287 lp->updatedRecord.u.u16[0] );
1291 DBG_LEAVE( DbgInfo );
1293 } // wl_process_updated_record
1294 /*============================================================================*/
1299 /*******************************************************************************
1300 * wl_process_assoc_status()
1301 *******************************************************************************
1305 * Process the association status event signaled by the device.
1309 * lp - a pointer to the device's private structure
1315 ******************************************************************************/
1316 void wl_process_assoc_status( struct wl_private *lp )
1318 ASSOC_STATUS_STRCT *assoc_stat;
1319 /*------------------------------------------------------------------------*/
1322 DBG_FUNC( "wl_process_assoc_status" );
1323 DBG_ENTER( DbgInfo );
1327 assoc_stat = (ASSOC_STATUS_STRCT *)&lp->assoc_stat;
1329 wl_endian_translate_event( (ltv_t *)assoc_stat );
1331 switch( assoc_stat->assocStatus ) {
1333 DBG_TRACE( DbgInfo, "Association Status : STA Associated\n" );
1337 DBG_TRACE( DbgInfo, "Association Status : STA Reassociated\n" );
1341 DBG_TRACE( DbgInfo, "Association Status : STA Disassociated\n" );
1345 DBG_TRACE( DbgInfo, "Association Status : UNKNOWN (0x%04x)\n",
1346 assoc_stat->assocStatus );
1350 DBG_TRACE(DbgInfo, "STA Address : %pM\n", assoc_stat->staAddr);
1352 if(( assoc_stat->assocStatus == 2 ) && ( assoc_stat->len == 8 )) {
1353 DBG_TRACE(DbgInfo, "Old AP Address : %pM\n",
1354 assoc_stat->oldApAddr);
1358 DBG_LEAVE( DbgInfo );
1360 } // wl_process_assoc_status
1361 /*============================================================================*/
1366 /*******************************************************************************
1367 * wl_process_security_status()
1368 *******************************************************************************
1372 * Process the security status message signaled by the device.
1376 * lp - a pointer to the device's private structure
1382 ******************************************************************************/
1383 void wl_process_security_status( struct wl_private *lp )
1385 SECURITY_STATUS_STRCT *sec_stat;
1386 /*------------------------------------------------------------------------*/
1389 DBG_FUNC( "wl_process_security_status" );
1390 DBG_ENTER( DbgInfo );
1394 sec_stat = (SECURITY_STATUS_STRCT *)&lp->sec_stat;
1396 wl_endian_translate_event( (ltv_t *)sec_stat );
1398 switch( sec_stat->securityStatus ) {
1400 DBG_TRACE( DbgInfo, "Security Status : Dissassociate [AP]\n" );
1404 DBG_TRACE( DbgInfo, "Security Status : Deauthenticate [AP]\n" );
1408 DBG_TRACE( DbgInfo, "Security Status : Authenticate Fail [STA] or [AP]\n" );
1412 DBG_TRACE( DbgInfo, "Security Status : MIC Fail\n" );
1416 DBG_TRACE( DbgInfo, "Security Status : Associate Fail\n" );
1420 DBG_TRACE( DbgInfo, "Security Status : UNKNOWN (0x%04x)\n",
1421 sec_stat->securityStatus );
1425 DBG_TRACE(DbgInfo, "STA Address : %pM\n", sec_stat->staAddr);
1426 DBG_TRACE(DbgInfo, "Reason : 0x%04x\n", sec_stat->reason);
1430 DBG_LEAVE( DbgInfo );
1432 } // wl_process_security_status
1433 /*============================================================================*/
1435 int wl_get_tallies(struct wl_private *lp,
1436 CFG_HERMES_TALLIES_STRCT *tallies)
1440 CFG_HERMES_TALLIES_STRCT *pTallies;
1442 DBG_FUNC( "wl_get_tallies" );
1445 /* Get the current tallies from the adapter */
1446 lp->ltvRecord.len = 1 + HCF_TOT_TAL_CNT * sizeof(hcf_16);
1447 lp->ltvRecord.typ = CFG_TALLIES;
1449 status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));
1451 if( status == HCF_SUCCESS ) {
1452 pTallies = (CFG_HERMES_TALLIES_STRCT *)&(lp->ltvRecord.u.u32);
1453 memcpy(tallies, pTallies, sizeof(*tallies));
1454 DBG_TRACE( DbgInfo, "Get tallies okay, dixe: %d\n", sizeof(*tallies) );
1456 DBG_TRACE( DbgInfo, "Get tallies failed\n" );
1460 DBG_LEAVE( DbgInfo );