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 static const long chan_freq_list[][2] =
131 /*******************************************************************************
133 *******************************************************************************
137 * Return an energy value in dBm.
141 * value - the energy value to be converted
147 ******************************************************************************/
150 /* Truncate the value to be between min and max. */
151 if( value < HCF_MIN_SIGNAL_LEVEL )
152 value = HCF_MIN_SIGNAL_LEVEL;
154 if( value > HCF_MAX_SIGNAL_LEVEL )
155 value = HCF_MAX_SIGNAL_LEVEL;
157 /* Return the energy value in dBm. */
158 return ( value - HCF_0DBM_OFFSET );
160 /*============================================================================*/
164 /*******************************************************************************
165 * is_valid_key_string()
166 *******************************************************************************
170 * Checks to determine if the WEP key string is valid
174 * s - the string in question
178 * non-zero if the string contains a valid key
180 ******************************************************************************/
181 int is_valid_key_string( char *s )
185 /*------------------------------------------------------------------------*/
190 /* 0x followed by 5 or 13 hexadecimal digit pairs is valid */
191 if( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X' )) {
192 if( l == 12 || l == 28 ) {
193 for( i = 2; i < l; i++ ) {
194 if( !isxdigit( s[i] ))
204 /* string with 0, 5, or 13 characters is valid */
207 return( l == 0 || l == 5 || l == 13 );
209 } // is_valid_key_string
210 /*============================================================================*/
215 /*******************************************************************************
217 *******************************************************************************
221 * Converts a key_string to a key, Assumes the key_string is validated with
222 * is_valid_key_string().
226 * ks - the valid key string
227 * key - a pointer to a KEY_STRUCT where the converted key information will
234 ******************************************************************************/
235 void key_string2key( char *ks, KEY_STRCT *key )
239 /*------------------------------------------------------------------------*/
244 /* 0x followed by hexadecimal digit pairs */
245 if( ks[0] == '0' && ( ks[1] == 'x' || ks[1] == 'X' )) {
247 p = (char *)key->key;
249 for( i = 2; i < l; i+=2 ) {
250 *p++ = (hex_to_bin(ks[i]) << 4) + hex_to_bin(ks[i+1]);
254 /* Note that endian translation of the length field is not needed here
255 because it's performed in wl_put_ltv() */
258 /* character string */
261 strcpy( (char *)key->key, ks );
267 /*============================================================================*/
272 /*******************************************************************************
274 *******************************************************************************
278 * Checks to see if the device supports WEP
282 * ifbp - the IFB pointer of the device in question
286 * 1 if WEP is known enabled, else 0
288 ******************************************************************************/
289 int wl_has_wep (IFBP ifbp)
291 CFG_PRIVACY_OPT_IMPLEMENTED_STRCT ltv;
293 /*------------------------------------------------------------------------*/
296 /* This function allows us to distiguish bronze cards from other types, to
297 know if WEP exists. Does not distinguish (because there's no way to)
298 between silver and gold cards. */
300 ltv.typ = CFG_PRIVACY_OPT_IMPLEMENTED;
302 rc = hcf_get_info( ifbp, (LTVP) <v );
304 privacy = CNV_LITTLE_TO_INT( ltv.privacy_opt_implemented );
306 //return rc ? 0 : privacy;
309 /*============================================================================*/
314 /*******************************************************************************
316 *******************************************************************************
320 * Report the type of HCF error message
328 * A descriptive string indicating the error, quiet otherwise.
330 ******************************************************************************/
331 void wl_hcf_error( struct net_device *dev, int hcfStatus )
333 char buffer[64], *pMsg;
334 /*------------------------------------------------------------------------*/
337 if( hcfStatus != HCF_SUCCESS ) {
338 switch( hcfStatus ) {
340 case HCF_ERR_TIME_OUT:
342 pMsg = "Expected adapter event did not occur in expected time";
348 pMsg = "Card not found (ejected unexpectedly)";
354 pMsg = "Command buffer size insufficient";
358 case HCF_ERR_INCOMP_PRI:
360 pMsg = "Primary functions are not compatible";
364 case HCF_ERR_INCOMP_FW:
366 pMsg = "Primary functions are compatible, "
367 "station/ap functions are not";
373 pMsg = "Inquire cmd while another Inquire in progress";
377 //case HCF_ERR_SEQ_BUG:
379 // pMsg = "Unexpected command completed";
383 case HCF_ERR_DEFUNCT_AUX:
385 pMsg = "Timeout on ack for enable/disable of AUX registers";
389 case HCF_ERR_DEFUNCT_TIMER:
390 pMsg = "Timeout on timer calibration during initialization process";
394 case HCF_ERR_DEFUNCT_TIME_OUT:
395 pMsg = "Timeout on Busy bit drop during BAP setup";
399 case HCF_ERR_DEFUNCT_CMD_SEQ:
400 pMsg = "Hermes and HCF are out of sync";
406 sprintf( buffer, "Error code %d", hcfStatus );
411 printk( KERN_INFO "%s: Wireless, HCF failure: \"%s\"\n",
415 /*============================================================================*/
420 /*******************************************************************************
421 * wl_endian_translate_event()
422 *******************************************************************************
426 * Determines what type of data is in the mailbox and performs the proper
427 * endian translation.
431 * pLtv - an LTV pointer
437 ******************************************************************************/
438 void wl_endian_translate_event( ltv_t *pLtv )
440 switch( pLtv->typ ) {
448 SCAN_RS_STRCT *pAps = (SCAN_RS_STRCT*)&pLtv->u.u8[0];
450 numAPs = (hcf_16)(( (size_t)( pLtv->len - 1 ) * 2 ) /
451 (sizeof( SCAN_RS_STRCT )));
453 while( numAPs >= 1 ) {
456 pAps[numAPs].channel_id =
457 CNV_LITTLE_TO_INT( pAps[numAPs].channel_id );
459 pAps[numAPs].noise_level =
460 CNV_LITTLE_TO_INT( pAps[numAPs].noise_level );
462 pAps[numAPs].signal_level =
463 CNV_LITTLE_TO_INT( pAps[numAPs].signal_level );
465 pAps[numAPs].beacon_interval_time =
466 CNV_LITTLE_TO_INT( pAps[numAPs].beacon_interval_time );
468 pAps[numAPs].capability =
469 CNV_LITTLE_TO_INT( pAps[numAPs].capability );
471 pAps[numAPs].ssid_len =
472 CNV_LITTLE_TO_INT( pAps[numAPs].ssid_len );
474 pAps[numAPs].ssid_val[pAps[numAPs].ssid_len] = 0;
483 PROBE_RESP *probe_resp = (PROBE_RESP *)pLtv;
485 probe_resp->frameControl = CNV_LITTLE_TO_INT( probe_resp->frameControl );
486 probe_resp->durID = CNV_LITTLE_TO_INT( probe_resp->durID );
487 probe_resp->sequence = CNV_LITTLE_TO_INT( probe_resp->sequence );
488 probe_resp->dataLength = CNV_LITTLE_TO_INT( probe_resp->dataLength );
491 probe_resp->lenType = CNV_LITTLE_TO_INT( probe_resp->lenType );
494 probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
495 probe_resp->capability = CNV_LITTLE_TO_INT( probe_resp->capability );
496 probe_resp->flags = CNV_LITTLE_TO_INT( probe_resp->flags );
502 #define ls ((LINK_STATUS_STRCT *)pLtv)
503 ls->linkStatus = CNV_LITTLE_TO_INT( ls->linkStatus );
509 ASSOC_STATUS_STRCT *pAs = (ASSOC_STATUS_STRCT *)pLtv;
511 pAs->assocStatus = CNV_LITTLE_TO_INT( pAs->assocStatus );
516 case CFG_SECURITY_STAT:
518 SECURITY_STATUS_STRCT *pSs = (SECURITY_STATUS_STRCT *)pLtv;
520 pSs->securityStatus = CNV_LITTLE_TO_INT( pSs->securityStatus );
521 pSs->reason = CNV_LITTLE_TO_INT( pSs->reason );
537 } // wl_endian_translate_event
538 /*============================================================================*/
541 /*******************************************************************************
543 *******************************************************************************
547 * Print statement used to display asserts from within the HCF. Only called
548 * when asserts in the HCF are turned on. See hcfcfg.h for more information.
552 * file_namep - the filename in which the assert occurred.
553 * line_number - the line number on which the assert occurred.
554 * trace - a comment associated with the assert.
555 * qual - return code or other value related to the assert
561 ******************************************************************************/
562 void msf_assert( unsigned int line_number, hcf_16 trace, hcf_32 qual )
564 DBG_PRINT( "HCF ASSERT: Line %d, VAL: 0x%.8x\n", line_number, /*;?*/(u32)qual );
566 /*============================================================================*/
571 /*******************************************************************************
573 *******************************************************************************
577 * This function parses the Direct Sequence Parameter Set IE, used to
578 * determine channel/frequency information.
582 * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
587 * The channel on which the BSS represented by this probe response is
590 ******************************************************************************/
591 hcf_8 wl_parse_ds_ie( PROBE_RESP *probe_rsp )
597 /*------------------------------------------------------------------------*/
600 if( probe_rsp == NULL ) {
604 buf = probe_rsp->rawData;
605 buf_size = sizeof( probe_rsp->rawData );
608 for( i = 0; i < buf_size; i++ ) {
609 if( buf[i] == DS_INFO_ELEM ) {
610 /* Increment by 1 to get the length, and test it; in a DS element,
611 length should always be 1 */
616 /* Get the channel information */
623 /* If we get here, we didn't find a DS-IE, which is strange */
628 /*******************************************************************************
630 *******************************************************************************
634 * This function parses the Probe Response for a valid WPA-IE.
638 * probe_rsp - a pointer to a PROBE_RESP structure containing the probe
640 * length - a pointer to an hcf_16 in which the size of the WPA-IE will
641 * be stored (if found).
645 * A pointer to the location in the probe response buffer where a valid
646 * WPA-IE lives. The length of this IE is written back to the 'length'
647 * argument passed to the function.
649 ******************************************************************************/
650 hcf_8 * wl_parse_wpa_ie( PROBE_RESP *probe_rsp, hcf_16 *length )
656 hcf_8 wpa_oui[] = WPA_OUI_TYPE;
657 /*------------------------------------------------------------------------*/
660 if( probe_rsp == NULL || length == NULL ) {
664 buf = probe_rsp->rawData;
665 buf_size = sizeof( probe_rsp->rawData );
669 for( i = 0; i < buf_size; i++ ) {
670 if( buf[i] == GENERIC_INFO_ELEM ) {
671 /* Increment by one to get the IE length */
673 ie_length = probe_rsp->rawData[i];
675 /* Increment by one to point to the IE payload */
678 /* Does the IE contain a WPA OUI? If not, it's a proprietary IE */
679 if( memcmp( &buf[i], &wpa_oui, WPA_SELECTOR_LEN ) == 0 ) {
680 /* Pass back length and return a pointer to the WPA-IE */
681 /* NOTE: Length contained in the WPA-IE is only the length of
682 the payload. The entire WPA-IE, including the IE identifier
683 and the length, is 2 bytes larger */
684 *length = ie_length + 2;
686 /* Back up the pointer 2 bytes to include the IE identifier and
687 the length in the buffer returned */
692 /* Increment past this non-WPA IE and continue looking */
693 i += ( ie_length - 1 );
697 /* If we're here, we didn't find a WPA-IE in the buffer */
702 /*******************************************************************************
704 *******************************************************************************
708 * Function used to take a WPA Information Element (WPA-IE) buffer and
709 * display it in a readable format.
713 * buffer - the byte buffer containing the WPA-IE
714 * length - the length of the above buffer
718 * A pointer to the formatted WPA-IE string. Note that the format used is
719 * byte-by-byte printing as %02x hex values with no spaces. This is
720 * required for proper operation with some WPA supplicants.
722 ******************************************************************************/
723 hcf_8 * wl_print_wpa_ie( hcf_8 *buffer, int length )
730 static hcf_8 output[512];
731 /*------------------------------------------------------------------------*/
734 memset( output, 0, sizeof( output ));
735 memset( row_buf, 0, sizeof( row_buf ));
738 /* Determine how many rows will be needed, and the remainder */
739 rows = length / rowsize;
740 remainder = length % rowsize;
743 /* Format the rows */
744 for( count = 0; count < rows; count++ ) {
745 sprintf( row_buf, "%02x%02x%02x%02x",
746 buffer[count*rowsize], buffer[count*rowsize+1],
747 buffer[count*rowsize+2], buffer[count*rowsize+3]);
748 strcat( output, row_buf );
751 memset( row_buf, 0, sizeof( row_buf ));
754 /* Format the remainder */
755 for( count = 0; count < remainder; count++ ) {
756 sprintf( row_buf, "%02x", buffer[(rows*rowsize)+count]);
757 strcat( output, row_buf );
762 /*============================================================================*/
767 /*******************************************************************************
768 * wl_is_a_valid_chan()
769 *******************************************************************************
773 * Checks if a given channel is valid
777 * channel - the channel
784 ******************************************************************************/
785 int wl_is_a_valid_chan( int channel )
788 /*------------------------------------------------------------------------*/
791 /* Strip out the high bit set by the FW for 802.11a channels */
792 if( channel & 0x100 ) {
793 channel = channel & 0x0FF;
796 /* Iterate through the matrix and retrieve the frequency */
797 for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
798 if( chan_freq_list[i][0] == channel ) {
804 } // wl_is_a_valid_chan
805 /*============================================================================*/
810 /*******************************************************************************
811 * wl_get_chan_from_freq()
812 *******************************************************************************
816 * Checks if a given frequency is valid
820 * freq - the frequency
827 ******************************************************************************/
828 int wl_is_a_valid_freq( long frequency )
831 /*------------------------------------------------------------------------*/
834 /* Iterate through the matrix and retrieve the channel */
835 for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
836 if( chan_freq_list[i][1] == frequency ) {
842 } // wl_is_a_valid_freq
843 /*============================================================================*/
848 /*******************************************************************************
849 * wl_get_freq_from_chan()
850 *******************************************************************************
854 * Function used to look up the frequency for a given channel on which the
859 * channel - the channel
863 * The corresponding frequency
865 ******************************************************************************/
866 long wl_get_freq_from_chan( int channel )
869 /*------------------------------------------------------------------------*/
872 /* Strip out the high bit set by the FW for 802.11a channels */
873 if( channel & 0x100 ) {
874 channel = channel & 0x0FF;
877 /* Iterate through the matrix and retrieve the frequency */
878 for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
879 if( chan_freq_list[i][0] == channel ) {
880 return chan_freq_list[i][1];
885 } // wl_get_freq_from_chan
886 /*============================================================================*/
891 /*******************************************************************************
892 * wl_get_chan_from_freq()
893 *******************************************************************************
897 * Function used to look up the channel for a given frequency on which the
902 * frequency - the frequency
906 * The corresponding channel
908 ******************************************************************************/
909 int wl_get_chan_from_freq( long frequency )
912 /*------------------------------------------------------------------------*/
915 /* Iterate through the matrix and retrieve the channel */
916 for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
917 if( chan_freq_list[i][1] == frequency ) {
918 return chan_freq_list[i][0];
923 } // wl_get_chan_from_freq
924 /*============================================================================*/
929 /*******************************************************************************
930 * wl_process_link_status()
931 *******************************************************************************
935 * Process the link status message signaled by the device.
939 * lp - a pointer to the device's private structure
945 ******************************************************************************/
946 void wl_process_link_status( struct wl_private *lp )
951 //link_stat = lp->hcfCtx.IFB_DSLinkStat & CFG_LINK_STAT_FW;
952 link_stat = lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW;
953 switch( link_stat ) {
955 DBG_TRACE( DbgInfo, "Link Status : Connected\n" );
956 wl_wext_event_ap( lp->dev );
959 DBG_TRACE( DbgInfo, "Link Status : Disconnected\n" );
962 DBG_TRACE( DbgInfo, "Link Status : Access Point Change\n" );
965 DBG_TRACE( DbgInfo, "Link Status : Access Point Out of Range\n" );
968 DBG_TRACE( DbgInfo, "Link Status : Access Point In Range\n" );
971 DBG_TRACE( DbgInfo, "Link Status : UNKNOWN (0x%04x)\n", link_stat );
975 } // wl_process_link_status
976 /*============================================================================*/
981 /*******************************************************************************
982 * wl_process_probe_response()
983 *******************************************************************************
987 * Process the probe responses retunred by the device as a result of an
992 * lp - a pointer to the device's private structure
998 ******************************************************************************/
999 void wl_process_probe_response( struct wl_private *lp )
1001 PROBE_RESP *probe_rsp;
1002 hcf_8 *wpa_ie = NULL;
1003 hcf_16 wpa_ie_len = 0;
1006 probe_rsp = (PROBE_RESP *)&lp->ProbeResp;
1008 wl_endian_translate_event( (ltv_t *)probe_rsp );
1010 DBG_TRACE( DbgInfo, "(%s) =========================\n", lp->dev->name );
1011 DBG_TRACE( DbgInfo, "(%s) length : 0x%04x.\n", lp->dev->name,
1012 probe_rsp->length );
1014 if( probe_rsp->length > 1 ) {
1015 DBG_TRACE( DbgInfo, "(%s) infoType : 0x%04x.\n", lp->dev->name,
1016 probe_rsp->infoType );
1018 DBG_TRACE( DbgInfo, "(%s) signal : 0x%02x.\n", lp->dev->name,
1019 probe_rsp->signal );
1021 DBG_TRACE( DbgInfo, "(%s) silence : 0x%02x.\n", lp->dev->name,
1022 probe_rsp->silence );
1024 DBG_TRACE( DbgInfo, "(%s) rxFlow : 0x%02x.\n", lp->dev->name,
1025 probe_rsp->rxFlow );
1027 DBG_TRACE( DbgInfo, "(%s) rate : 0x%02x.\n", lp->dev->name,
1030 DBG_TRACE( DbgInfo, "(%s) frame cntl : 0x%04x.\n", lp->dev->name,
1031 probe_rsp->frameControl );
1033 DBG_TRACE( DbgInfo, "(%s) durID : 0x%04x.\n", lp->dev->name,
1036 DBG_TRACE(DbgInfo, "(%s) address1 : %pM\n", lp->dev->name,
1037 probe_rsp->address1);
1039 DBG_TRACE(DbgInfo, "(%s) address2 : %pM\n", lp->dev->name,
1040 probe_rsp->address2);
1042 DBG_TRACE(DbgInfo, "(%s) BSSID : %pM\n", lp->dev->name,
1045 DBG_TRACE( DbgInfo, "(%s) sequence : 0x%04x.\n", lp->dev->name,
1046 probe_rsp->sequence );
1048 DBG_TRACE(DbgInfo, "(%s) address4 : %pM\n", lp->dev->name,
1049 probe_rsp->address4);
1051 DBG_TRACE( DbgInfo, "(%s) datalength : 0x%04x.\n", lp->dev->name,
1052 probe_rsp->dataLength );
1054 DBG_TRACE(DbgInfo, "(%s) DA : %pM\n", lp->dev->name,
1057 DBG_TRACE(DbgInfo, "(%s) SA : %pM\n", lp->dev->name,
1062 DBG_TRACE( DbgInfo, "(%s) channel : %d\n", lp->dev->name,
1063 probe_rsp->channel );
1065 DBG_TRACE( DbgInfo, "(%s) band : %d\n", lp->dev->name,
1068 DBG_TRACE( DbgInfo, "(%s) lenType : 0x%04x.\n", lp->dev->name,
1069 probe_rsp->lenType );
1072 DBG_TRACE( DbgInfo, "(%s) timeStamp : %d.%d.%d.%d.%d.%d.%d.%d\n",
1074 probe_rsp->timeStamp[0],
1075 probe_rsp->timeStamp[1],
1076 probe_rsp->timeStamp[2],
1077 probe_rsp->timeStamp[3],
1078 probe_rsp->timeStamp[4],
1079 probe_rsp->timeStamp[5],
1080 probe_rsp->timeStamp[6],
1081 probe_rsp->timeStamp[7]);
1083 DBG_TRACE( DbgInfo, "(%s) beaconInt : 0x%04x.\n", lp->dev->name,
1084 probe_rsp->beaconInterval );
1086 DBG_TRACE( DbgInfo, "(%s) capability : 0x%04x.\n", lp->dev->name,
1087 probe_rsp->capability );
1089 DBG_TRACE( DbgInfo, "(%s) SSID len : 0x%04x.\n", lp->dev->name,
1090 probe_rsp->rawData[1] );
1093 if( probe_rsp->rawData[1] > 0 ) {
1094 char ssid[HCF_MAX_NAME_LEN];
1096 memset( ssid, 0, sizeof( ssid ));
1097 strncpy( ssid, &probe_rsp->rawData[2],
1098 probe_rsp->rawData[1] );
1100 DBG_TRACE( DbgInfo, "(%s) SSID : %s\n",
1101 lp->dev->name, ssid );
1105 /* Parse out the WPA-IE, if one exists */
1106 wpa_ie = wl_parse_wpa_ie( probe_rsp, &wpa_ie_len );
1107 if( wpa_ie != NULL ) {
1108 DBG_TRACE( DbgInfo, "(%s) WPA-IE : %s\n",
1109 lp->dev->name, wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
1112 DBG_TRACE( DbgInfo, "(%s) flags : 0x%04x.\n",
1113 lp->dev->name, probe_rsp->flags );
1116 DBG_TRACE( DbgInfo, "\n" );
1119 /* If probe response length is 1, then the scan is complete */
1120 if( probe_rsp->length == 1 ) {
1121 DBG_TRACE( DbgInfo, "SCAN COMPLETE\n" );
1122 lp->probe_results.num_aps = lp->probe_num_aps;
1123 lp->probe_results.scan_complete = TRUE;
1125 /* Reset the counter for the next scan request */
1126 lp->probe_num_aps = 0;
1128 /* Send a wireless extensions event that the scan completed */
1129 wl_wext_event_scan_complete( lp->dev );
1131 /* Only copy to the table if the entry is unique; APs sometimes
1132 respond more than once to a probe */
1133 if( lp->probe_num_aps == 0 ) {
1134 /* Copy the info to the ScanResult structure in the private
1136 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1137 probe_rsp, sizeof( PROBE_RESP ));
1139 /* Increment the number of APs detected */
1140 lp->probe_num_aps++;
1145 for( count = 0; count < lp->probe_num_aps; count++ ) {
1146 if( memcmp( &( probe_rsp->BSSID ),
1147 lp->probe_results.ProbeTable[count].BSSID,
1154 /* Copy the info to the ScanResult structure in the
1155 private adapter struct. Only copy if there's room in the
1157 if( lp->probe_num_aps < MAX_NAPS )
1159 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1160 probe_rsp, sizeof( PROBE_RESP ));
1164 DBG_WARNING( DbgInfo, "Num of scan results exceeds storage, truncating\n" );
1167 /* Increment the number of APs detected. Note I do this
1168 here even when I don't copy the probe response to the
1169 buffer in order to detect the overflow condition */
1170 lp->probe_num_aps++;
1175 } // wl_process_probe_response
1176 /*============================================================================*/
1181 /*******************************************************************************
1182 * wl_process_updated_record()
1183 *******************************************************************************
1187 * Process the updated information record message signaled by the device.
1191 * lp - a pointer to the device's private structure
1197 ******************************************************************************/
1198 void wl_process_updated_record( struct wl_private *lp )
1201 lp->updatedRecord.u.u16[0] = CNV_LITTLE_TO_INT( lp->updatedRecord.u.u16[0] );
1203 switch( lp->updatedRecord.u.u16[0] ) {
1204 case CFG_CUR_COUNTRY_INFO:
1205 DBG_TRACE( DbgInfo, "Updated Record: CFG_CUR_COUNTRY_INFO\n" );
1210 DBG_TRACE( DbgInfo, "Updated Record: WAIT_FOR_CONNECT (0xFD40)\n" );
1215 DBG_TRACE( DbgInfo, "UNKNOWN: 0x%04x\n",
1216 lp->updatedRecord.u.u16[0] );
1219 } // wl_process_updated_record
1220 /*============================================================================*/
1225 /*******************************************************************************
1226 * wl_process_assoc_status()
1227 *******************************************************************************
1231 * Process the association status event signaled by the device.
1235 * lp - a pointer to the device's private structure
1241 ******************************************************************************/
1242 void wl_process_assoc_status( struct wl_private *lp )
1244 ASSOC_STATUS_STRCT *assoc_stat;
1247 assoc_stat = (ASSOC_STATUS_STRCT *)&lp->assoc_stat;
1249 wl_endian_translate_event( (ltv_t *)assoc_stat );
1251 switch( assoc_stat->assocStatus ) {
1253 DBG_TRACE( DbgInfo, "Association Status : STA Associated\n" );
1257 DBG_TRACE( DbgInfo, "Association Status : STA Reassociated\n" );
1261 DBG_TRACE( DbgInfo, "Association Status : STA Disassociated\n" );
1265 DBG_TRACE( DbgInfo, "Association Status : UNKNOWN (0x%04x)\n",
1266 assoc_stat->assocStatus );
1270 DBG_TRACE(DbgInfo, "STA Address : %pM\n", assoc_stat->staAddr);
1272 if(( assoc_stat->assocStatus == 2 ) && ( assoc_stat->len == 8 )) {
1273 DBG_TRACE(DbgInfo, "Old AP Address : %pM\n",
1274 assoc_stat->oldApAddr);
1277 } // wl_process_assoc_status
1278 /*============================================================================*/
1283 /*******************************************************************************
1284 * wl_process_security_status()
1285 *******************************************************************************
1289 * Process the security status message signaled by the device.
1293 * lp - a pointer to the device's private structure
1299 ******************************************************************************/
1300 void wl_process_security_status( struct wl_private *lp )
1302 SECURITY_STATUS_STRCT *sec_stat;
1305 sec_stat = (SECURITY_STATUS_STRCT *)&lp->sec_stat;
1307 wl_endian_translate_event( (ltv_t *)sec_stat );
1309 switch( sec_stat->securityStatus ) {
1311 DBG_TRACE( DbgInfo, "Security Status : Dissassociate [AP]\n" );
1315 DBG_TRACE( DbgInfo, "Security Status : Deauthenticate [AP]\n" );
1319 DBG_TRACE( DbgInfo, "Security Status : Authenticate Fail [STA] or [AP]\n" );
1323 DBG_TRACE( DbgInfo, "Security Status : MIC Fail\n" );
1327 DBG_TRACE( DbgInfo, "Security Status : Associate Fail\n" );
1331 DBG_TRACE( DbgInfo, "Security Status : UNKNOWN (0x%04x)\n",
1332 sec_stat->securityStatus );
1336 DBG_TRACE(DbgInfo, "STA Address : %pM\n", sec_stat->staAddr);
1337 DBG_TRACE(DbgInfo, "Reason : 0x%04x\n", sec_stat->reason);
1340 } // wl_process_security_status
1341 /*============================================================================*/
1343 int wl_get_tallies(struct wl_private *lp,
1344 CFG_HERMES_TALLIES_STRCT *tallies)
1348 CFG_HERMES_TALLIES_STRCT *pTallies;
1350 /* Get the current tallies from the adapter */
1351 lp->ltvRecord.len = 1 + HCF_TOT_TAL_CNT * sizeof(hcf_16);
1352 lp->ltvRecord.typ = CFG_TALLIES;
1354 status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));
1356 if( status == HCF_SUCCESS ) {
1357 pTallies = (CFG_HERMES_TALLIES_STRCT *)&(lp->ltvRecord.u.u32);
1358 memcpy(tallies, pTallies, sizeof(*tallies));
1359 DBG_TRACE( DbgInfo, "Get tallies okay, dixe: %d\n", sizeof(*tallies) );
1361 DBG_TRACE( DbgInfo, "Get tallies failed\n" );