1 /*******************************************************************************
2  * Agere Systems Inc.
3  * Wireless device driver for Linux (wlags49).
4  *
5  * Copyright (c) 1998-2003 Agere Systems Inc.
6  * All rights reserved.
7  *   http://www.agere.com
8  *
9  * Initially developed by TriplePoint, Inc.
10  *   http://www.triplepoint.com
11  *
12  *------------------------------------------------------------------------------
13  *
14  *   This file defines misc utility functions.
15  *
16  *------------------------------------------------------------------------------
17  *
18  * SOFTWARE LICENSE
19  *
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.
24  *
25  * Copyright � 2003 Agere Systems Inc.
26  * All rights reserved.
27  *
28  * Redistribution and use in source or binary forms, with or without
29  * modifications, are permitted provided that the following conditions are met:
30  *
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
34  *    distribution.
35  *
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.
39  *
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.
43  *
44  * Disclaimer
45  *
46  * THIS SOFTWARE IS PROVIDED �AS IS� 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
57  * DAMAGE.
58  *
59  ******************************************************************************/
60 
61 /*******************************************************************************
62  *  include files
63  ******************************************************************************/
64 #include <wl_version.h>
65 
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/system.h>
77 // #include <asm/bitops.h>
78 
79 #include <linux/netdevice.h>
80 #include <linux/etherdevice.h>
81 // #include <linux/skbuff.h>
82 // #include <linux/if_arp.h>
83 // #include <linux/ioport.h>
84 
85 #include <debug.h>
86 #include <hcf.h>
87 // #include <hcfdef.h>
88 
89 #include <wl_if.h>
90 #include <wl_internal.h>
91 #include <wl_util.h>
92 #include <wl_wext.h>
93 #include <wl_main.h>
94 
95 
96 
97 /*******************************************************************************
98  * global variables
99  ******************************************************************************/
100 
101 /* A matrix which maps channels to frequencies */
102 #define MAX_CHAN_FREQ_MAP_ENTRIES   50
103 static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
104 {
105     {1,2412},
106     {2,2417},
107     {3,2422},
108     {4,2427},
109     {5,2432},
110     {6,2437},
111     {7,2442},
112     {8,2447},
113     {9,2452},
114     {10,2457},
115     {11,2462},
116     {12,2467},
117     {13,2472},
118     {14,2484},
119     {36,5180},
120     {40,5200},
121     {44,5220},
122     {48,5240},
123     {52,5260},
124     {56,5280},
125     {60,5300},
126     {64,5320},
127     {149,5745},
128     {153,5765},
129     {157,5785},
130     {161,5805}
131 };
132 
133 #if DBG
134 extern dbg_info_t *DbgInfo;
135 #endif  /* DBG */
136 
137 
138 
139 
140 /*******************************************************************************
141  *	dbm()
142  *******************************************************************************
143  *
144  *  DESCRIPTION:
145  *
146  *      Return an energy value in dBm.
147  *
148  *  PARAMETERS:
149  *
150  *      value - the energy value to be converted
151  *
152  *  RETURNS:
153  *
154  *      the value in dBm
155  *
156  ******************************************************************************/
dbm(int value)157 int dbm( int value )
158 {
159     /* Truncate the value to be between min and max. */
160     if( value < HCF_MIN_SIGNAL_LEVEL )
161         value = HCF_MIN_SIGNAL_LEVEL;
162 
163     if( value > HCF_MAX_SIGNAL_LEVEL )
164         value = HCF_MAX_SIGNAL_LEVEL;
165 
166     /* Return the energy value in dBm. */
167     return ( value - HCF_0DBM_OFFSET );
168 } // dbm
169 /*============================================================================*/
170 
171 
172 
173 
174 /*******************************************************************************
175  *	percent()
176  *******************************************************************************
177  *
178  *  DESCRIPTION:
179  *
180  *      Return a value as a percentage of min to max.
181  *
182  *  PARAMETERS:
183  *
184  *      value   - the value in question
185  *      min     - the minimum range value
186  *      max     - the maximum range value
187  *
188  *  RETURNS:
189  *
190  *      the percentage value
191  *
192  ******************************************************************************/
percent(int value,int min,int max)193 int percent( int value, int min, int max )
194 {
195     /* Truncate the value to be between min and max. */
196     if( value < min )
197         value = min;
198 
199     if( value > max )
200         value = max;
201 
202     /* Return the value as a percentage of min to max. */
203     return ((( value - min ) * 100 ) / ( max - min ));
204 } // percent
205 /*============================================================================*/
206 
207 
208 
209 
210 /*******************************************************************************
211  *	is_valid_key_string()
212  *******************************************************************************
213  *
214  *  DESCRIPTION:
215  *
216  *      Checks to determine if the WEP key string is valid
217  *
218  *  PARAMETERS:
219  *
220  *      s - the string in question
221  *
222  *  RETURNS:
223  *
224  *      non-zero if the string contains a valid key
225  *
226  ******************************************************************************/
is_valid_key_string(char * s)227 int is_valid_key_string( char *s )
228 {
229     int l;
230     int i;
231     /*------------------------------------------------------------------------*/
232 
233 
234     l = strlen( s );
235 
236     /* 0x followed by 5 or 13 hexadecimal digit pairs is valid */
237     if( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X' )) {
238         if( l == 12 || l == 28 ) {
239             for( i = 2; i < l; i++ ) {
240                 if( !isxdigit( s[i] ))
241                     return 0;
242             }
243 
244             return 1;
245         } else {
246             return 0;
247         }
248     }
249 
250     /* string with 0, 5, or 13 characters is valid */
251     else
252     {
253         return( l == 0 || l == 5 || l == 13 );
254     }
255 } // is_valid_key_string
256 /*============================================================================*/
257 
258 
259 
260 
261 /*******************************************************************************
262  *	key_string2key()
263  *******************************************************************************
264  *
265  *  DESCRIPTION:
266  *
267  *      Converts a key_string to a key, Assumes the key_string is validated with
268  *  is_valid_key_string().
269  *
270  *  PARAMETERS:
271  *
272  *      ks  - the valid key string
273  *      key - a pointer to a KEY_STRUCT where the converted key information will
274  *            be stored.
275  *
276  *  RETURNS:
277  *
278  *      N/A
279  *
280  ******************************************************************************/
key_string2key(char * ks,KEY_STRCT * key)281 void key_string2key( char *ks, KEY_STRCT *key )
282 {
283     int l,i,n;
284     char *p;
285     /*------------------------------------------------------------------------*/
286 
287 
288     l = strlen( ks );
289 
290     /* 0x followed by hexadecimal digit pairs */
291     if( ks[0] == '0' && ( ks[1] == 'x' || ks[1] == 'X' )) {
292         n = 0;
293         p = (char *)key->key;
294 
295         for( i = 2; i < l; i+=2 ) {
296 			*p++ = (hex_to_bin(ks[i]) << 4) + hex_to_bin(ks[i+1]);
297            n++;
298         }
299 
300         /* Note that endian translation of the length field is not needed here
301           because it's performed in wl_put_ltv() */
302         key->len = n;
303     }
304     /* character string */
305     else
306     {
307         strcpy( (char *)key->key, ks );
308         key->len = l;
309     }
310 
311     return;
312 } // key_string2key
313 /*============================================================================*/
314 
315 
316 
317 
318 /*******************************************************************************
319  *	wl_has_wep()
320  *******************************************************************************
321  *
322  *  DESCRIPTION:
323  *
324  *      Checks to see if the device supports WEP
325  *
326  *  PARAMETERS:
327  *
328  *      ifbp    - the IFB pointer of the device in question
329  *
330  *  RETURNS:
331  *
332  *      1 if WEP is known enabled, else 0
333  *
334  ******************************************************************************/
wl_has_wep(IFBP ifbp)335 int wl_has_wep (IFBP ifbp)
336 {
337     CFG_PRIVACY_OPT_IMPLEMENTED_STRCT ltv;
338 	int rc, privacy;
339     /*------------------------------------------------------------------------*/
340 
341 
342 	/* This function allows us to distiguish bronze cards from other types, to
343        know if WEP exists. Does not distinguish (because there's no way to)
344        between silver and gold cards. */
345     ltv.len = 2;
346     ltv.typ = CFG_PRIVACY_OPT_IMPLEMENTED;
347 
348 	rc = hcf_get_info( ifbp, (LTVP) &ltv );
349 
350 	privacy = CNV_LITTLE_TO_INT( ltv.privacy_opt_implemented );
351 
352 	//return rc ? 0 : privacy;
353     return 1;
354 } // wl_has_wep
355 /*============================================================================*/
356 
357 
358 
359 
360 /*******************************************************************************
361  *	wl_hcf_error()
362  *******************************************************************************
363  *
364  *  DESCRIPTION:
365  *
366  *      Report the type of HCF error message
367  *
368  *  PARAMETERS:
369  *
370  *      none
371  *
372  *  RETURNS:
373  *
374  *      A descriptive string indicating the error, quiet otherwise.
375  *
376  ******************************************************************************/
wl_hcf_error(struct net_device * dev,int hcfStatus)377 void wl_hcf_error( struct net_device *dev, int hcfStatus )
378 {
379     char     buffer[64], *pMsg;
380     /*------------------------------------------------------------------------*/
381 
382 
383     if( hcfStatus != HCF_SUCCESS ) {
384         switch( hcfStatus ) {
385 
386         case HCF_ERR_TIME_OUT:
387 
388             pMsg = "Expected adapter event did not occur in expected time";
389             break;
390 
391 
392         case HCF_ERR_NO_NIC:
393 
394             pMsg = "Card not found (ejected unexpectedly)";
395             break;
396 
397 
398         case HCF_ERR_LEN:
399 
400             pMsg = "Command buffer size insufficient";
401             break;
402 
403 
404         case HCF_ERR_INCOMP_PRI:
405 
406             pMsg = "Primary functions are not compatible";
407             break;
408 
409 
410         case HCF_ERR_INCOMP_FW:
411 
412             pMsg = "Primary functions are compatible, "
413                 "station/ap functions are not";
414             break;
415 
416 
417         case HCF_ERR_BUSY:
418 
419             pMsg = "Inquire cmd while another Inquire in progress";
420             break;
421 
422 
423         //case HCF_ERR_SEQ_BUG:
424 
425         //    pMsg = "Unexpected command completed";
426         //    break;
427 
428 
429         case HCF_ERR_DEFUNCT_AUX:
430 
431             pMsg = "Timeout on ack for enable/disable of AUX registers";
432             break;
433 
434 
435         case HCF_ERR_DEFUNCT_TIMER:
436             pMsg = "Timeout on timer calibration during initialization process";
437             break;
438 
439 
440         case HCF_ERR_DEFUNCT_TIME_OUT:
441             pMsg = "Timeout on Busy bit drop during BAP setup";
442             break;
443 
444 
445         case HCF_ERR_DEFUNCT_CMD_SEQ:
446             pMsg = "Hermes and HCF are out of sync";
447             break;
448 
449 
450         default:
451 
452             sprintf( buffer, "Error code %d", hcfStatus );
453             pMsg = buffer;
454             break;
455         }
456 
457         printk( KERN_INFO "%s: Wireless, HCF failure: \"%s\"\n",
458                 dev->name, pMsg );
459     }
460 } // wl_hcf_error
461 /*============================================================================*/
462 
463 
464 
465 
466 /*******************************************************************************
467  *	wl_endian_translate_event()
468  *******************************************************************************
469  *
470  *  DESCRIPTION:
471  *
472  *      Determines what type of data is in the mailbox and performs the proper
473  *  endian translation.
474  *
475  *  PARAMETERS:
476  *
477  *      pLtv - an LTV pointer
478  *
479  *  RETURNS:
480  *
481  *      N/A
482  *
483  ******************************************************************************/
wl_endian_translate_event(ltv_t * pLtv)484 void wl_endian_translate_event( ltv_t *pLtv )
485 {
486     DBG_FUNC( "wl_endian_translate_event" );
487     DBG_ENTER( DbgInfo );
488 
489 
490     switch( pLtv->typ ) {
491     case CFG_TALLIES:
492         break;
493 
494 
495     case CFG_SCAN:
496         {
497             int numAPs;
498             SCAN_RS_STRCT *pAps = (SCAN_RS_STRCT*)&pLtv->u.u8[0];
499 
500             numAPs = (hcf_16)(( (size_t)( pLtv->len - 1 ) * 2 ) /
501                                 (sizeof( SCAN_RS_STRCT )));
502 
503             while( numAPs >= 1 ) {
504                 numAPs--;
505 
506                 pAps[numAPs].channel_id           =
507                     CNV_LITTLE_TO_INT( pAps[numAPs].channel_id );
508 
509                 pAps[numAPs].noise_level          =
510                     CNV_LITTLE_TO_INT( pAps[numAPs].noise_level );
511 
512                 pAps[numAPs].signal_level         =
513                     CNV_LITTLE_TO_INT( pAps[numAPs].signal_level );
514 
515                 pAps[numAPs].beacon_interval_time =
516                     CNV_LITTLE_TO_INT( pAps[numAPs].beacon_interval_time );
517 
518                 pAps[numAPs].capability           =
519                     CNV_LITTLE_TO_INT( pAps[numAPs].capability );
520 
521                 pAps[numAPs].ssid_len             =
522                     CNV_LITTLE_TO_INT( pAps[numAPs].ssid_len );
523 
524                 pAps[numAPs].ssid_val[pAps[numAPs].ssid_len] = 0;
525 
526             }
527         }
528         break;
529 
530 
531     case CFG_ACS_SCAN:
532         {
533             PROBE_RESP *probe_resp = (PROBE_RESP *)pLtv;
534 
535             probe_resp->frameControl   = CNV_LITTLE_TO_INT( probe_resp->frameControl );
536             probe_resp->durID          = CNV_LITTLE_TO_INT( probe_resp->durID );
537             probe_resp->sequence       = CNV_LITTLE_TO_INT( probe_resp->sequence );
538             probe_resp->dataLength     = CNV_LITTLE_TO_INT( probe_resp->dataLength );
539 
540 #ifndef WARP
541             probe_resp->lenType        = CNV_LITTLE_TO_INT( probe_resp->lenType );
542 #endif // WARP
543 
544             probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
545             probe_resp->capability     = CNV_LITTLE_TO_INT( probe_resp->capability );
546             probe_resp->flags          = CNV_LITTLE_TO_INT( probe_resp->flags );
547         }
548         break;
549 
550 
551     case CFG_LINK_STAT:
552 #define ls ((LINK_STATUS_STRCT *)pLtv)
553             ls->linkStatus = CNV_LITTLE_TO_INT( ls->linkStatus );
554         break;
555 #undef ls
556 
557     case CFG_ASSOC_STAT:
558         {
559             ASSOC_STATUS_STRCT *pAs = (ASSOC_STATUS_STRCT *)pLtv;
560 
561             pAs->assocStatus = CNV_LITTLE_TO_INT( pAs->assocStatus );
562         }
563         break;
564 
565 
566     case CFG_SECURITY_STAT:
567         {
568             SECURITY_STATUS_STRCT *pSs = (SECURITY_STATUS_STRCT *)pLtv;
569 
570             pSs->securityStatus = CNV_LITTLE_TO_INT( pSs->securityStatus );
571             pSs->reason         = CNV_LITTLE_TO_INT( pSs->reason );
572         }
573         break;
574 
575 
576     case CFG_WMP:
577         break;
578 
579 
580     case CFG_NULL:
581         break;
582 
583 
584     default:
585         break;
586     }
587 
588     DBG_LEAVE( DbgInfo );
589     return;
590 } // wl_endian_translate_event
591 /*============================================================================*/
592 
593 
594 /*******************************************************************************
595  *	msf_assert()
596  *******************************************************************************
597  *
598  *  DESCRIPTION:
599  *
600  *      Print statement used to display asserts from within the HCF. Only called
601  *  when asserts in the HCF are turned on. See hcfcfg.h for more information.
602  *
603  *  PARAMETERS:
604  *
605  *      file_namep  - the filename in which the assert occurred.
606  *      line_number - the line number on which the assert occurred.
607  *      trace       - a comment associated with the assert.
608  *      qual        - return code or other value related to the assert
609  *
610  *  RETURNS:
611  *
612  *      N/A
613  *
614  ******************************************************************************/
msf_assert(unsigned int line_number,hcf_16 trace,hcf_32 qual)615 void msf_assert( unsigned int line_number, hcf_16 trace, hcf_32 qual )
616 {
617     DBG_PRINT( "HCF ASSERT: Line %d, VAL: 0x%.8x\n", line_number, /*;?*/(u32)qual );
618 } // msf_assert
619 /*============================================================================*/
620 
621 
622 
623 
624 /*******************************************************************************
625  *	wl_parse_ds_ie()
626  *******************************************************************************
627  *
628  *  DESCRIPTION:
629  *
630  *      This function parses the Direct Sequence Parameter Set IE, used to
631  *      determine channel/frequency information.
632  *
633  *  PARAMETERS:
634  *
635  *      probe_rsp - a pointer to a PROBE_RESP structure containing the probe
636  *                  response.
637  *
638  *  RETURNS:
639  *
640  *      The channel on which the BSS represented by this probe response is
641  *      transmitting.
642  *
643  ******************************************************************************/
wl_parse_ds_ie(PROBE_RESP * probe_rsp)644 hcf_8 wl_parse_ds_ie( PROBE_RESP *probe_rsp )
645 {
646     int     i;
647     int     ie_length = 0;
648     hcf_8   *buf;
649     hcf_8   buf_size;
650     /*------------------------------------------------------------------------*/
651 
652 
653     if( probe_rsp == NULL ) {
654         return 0;
655     }
656 
657     buf      = probe_rsp->rawData;
658     buf_size = sizeof( probe_rsp->rawData );
659 
660 
661     for( i = 0; i < buf_size; i++ ) {
662         if( buf[i] == DS_INFO_ELEM ) {
663             /* Increment by 1 to get the length, and test it; in a DS element,
664                length should always be 1 */
665             i++;
666             ie_length = buf[i];
667 
668             if( buf[i] == 1 ) {
669                 /* Get the channel information */
670                 i++;
671                 return buf[i];
672             }
673         }
674     }
675 
676     /* If we get here, we didn't find a DS-IE, which is strange */
677     return 0;
678 } // wl_parse_ds_ie
679 
680 
681 /*******************************************************************************
682  *	wl_parse_wpa_ie()
683  *******************************************************************************
684  *
685  *  DESCRIPTION:
686  *
687  *      This function parses the Probe Response for a valid WPA-IE.
688  *
689  *  PARAMETERS:
690  *
691  *      probe_rsp - a pointer to a PROBE_RESP structure containing the probe
692  *                  response
693  *      length    - a pointer to an hcf_16 in which the size of the WPA-IE will
694  *                  be stored (if found).
695  *
696  *  RETURNS:
697  *
698  *      A pointer to the location in the probe response buffer where a valid
699  *      WPA-IE lives. The length of this IE is written back to the 'length'
700  *      argument passed to the function.
701  *
702  ******************************************************************************/
wl_parse_wpa_ie(PROBE_RESP * probe_rsp,hcf_16 * length)703 hcf_8 * wl_parse_wpa_ie( PROBE_RESP *probe_rsp, hcf_16 *length )
704 {
705     int     i;
706     int     ie_length = 0;
707     hcf_8   *buf;
708     hcf_8   buf_size;
709     hcf_8   wpa_oui[] = WPA_OUI_TYPE;
710     /*------------------------------------------------------------------------*/
711 
712 
713     if( probe_rsp == NULL || length == NULL ) {
714         return NULL;
715     }
716 
717     buf      = probe_rsp->rawData;
718     buf_size = sizeof( probe_rsp->rawData );
719     *length  = 0;
720 
721 
722     for( i = 0; i < buf_size; i++ ) {
723         if( buf[i] == GENERIC_INFO_ELEM ) {
724             /* Increment by one to get the IE length */
725             i++;
726             ie_length = probe_rsp->rawData[i];
727 
728             /* Increment by one to point to the IE payload */
729             i++;
730 
731             /* Does the IE contain a WPA OUI? If not, it's a proprietary IE */
732             if( memcmp( &buf[i], &wpa_oui, WPA_SELECTOR_LEN ) == 0 ) {
733                 /* Pass back length and return a pointer to the WPA-IE */
734                 /* NOTE: Length contained in the WPA-IE is only the length of
735                    the payload. The entire WPA-IE, including the IE identifier
736                    and the length, is 2 bytes larger */
737                 *length = ie_length + 2;
738 
739                 /* Back up the pointer 2 bytes to include the IE identifier and
740                    the length in the buffer returned */
741                 i -= 2;
742                 return &buf[i];
743             }
744 
745             /* Increment past this non-WPA IE and continue looking */
746             i += ( ie_length - 1 );
747         }
748     }
749 
750     /* If we're here, we didn't find a WPA-IE in the buffer */
751     return NULL;
752 } // wl_parse_wpa_ie
753 
754 
755 /*******************************************************************************
756  *	wl_print_wpa_ie()
757  *******************************************************************************
758  *
759  *  DESCRIPTION:
760  *
761  *      Function used to take a WPA Information Element (WPA-IE) buffer and
762  *      display it in a readable format.
763  *
764  *  PARAMETERS:
765  *
766  *      buffer - the byte buffer containing the WPA-IE
767  *      length - the length of the above buffer
768  *
769  *  RETURNS:
770  *
771  *      A pointer to the formatted WPA-IE string. Note that the format used is
772  *      byte-by-byte printing as %02x hex values with no spaces. This is
773  *      required for proper operation with some WPA supplicants.
774  *
775  ******************************************************************************/
wl_print_wpa_ie(hcf_8 * buffer,int length)776 hcf_8 * wl_print_wpa_ie( hcf_8 *buffer, int length )
777 {
778     int count;
779     int rows;
780     int remainder;
781     int rowsize = 4;
782     hcf_8 row_buf[64];
783     static hcf_8 output[512];
784     /*------------------------------------------------------------------------*/
785 
786 
787     memset( output, 0, sizeof( output ));
788     memset( row_buf, 0, sizeof( row_buf ));
789 
790 
791     /* Determine how many rows will be needed, and the remainder */
792     rows = length / rowsize;
793     remainder = length % rowsize;
794 
795 
796     /* Format the rows */
797     for( count = 0; count < rows; count++ ) {
798         sprintf( row_buf, "%02x%02x%02x%02x",
799                  buffer[count*rowsize], buffer[count*rowsize+1],
800                  buffer[count*rowsize+2], buffer[count*rowsize+3]);
801         strcat( output, row_buf );
802     }
803 
804     memset( row_buf, 0, sizeof( row_buf ));
805 
806 
807     /* Format the remainder */
808     for( count = 0; count < remainder; count++ ) {
809         sprintf( row_buf, "%02x", buffer[(rows*rowsize)+count]);
810         strcat( output, row_buf );
811     }
812 
813     return output;
814 } // wl_print_wpa_ie
815 /*============================================================================*/
816 
817 
818 
819 
820 /*******************************************************************************
821  *	wl_is_a_valid_chan()
822  *******************************************************************************
823  *
824  *  DESCRIPTION:
825  *
826  *      Checks if a given channel is valid
827  *
828  *  PARAMETERS:
829  *
830  *      channel - the channel
831  *
832  *  RETURNS:
833  *
834  *      1 if TRUE
835  *      0 if FALSE
836  *
837  ******************************************************************************/
wl_is_a_valid_chan(int channel)838 int wl_is_a_valid_chan( int channel )
839 {
840     int i;
841     /*------------------------------------------------------------------------*/
842 
843 
844     /* Strip out the high bit set by the FW for 802.11a channels */
845     if( channel & 0x100 ) {
846         channel = channel & 0x0FF;
847     }
848 
849     /* Iterate through the matrix and retrieve the frequency */
850     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
851         if( chan_freq_list[i][0] == channel ) {
852             return 1;
853         }
854     }
855 
856     return 0;
857 } // wl_is_a_valid_chan
858 /*============================================================================*/
859 
860 
861 
862 
863 /*******************************************************************************
864  *	wl_get_chan_from_freq()
865  *******************************************************************************
866  *
867  *  DESCRIPTION:
868  *
869  *      Checks if a given frequency is valid
870  *
871  *  PARAMETERS:
872  *
873  *      freq - the frequency
874  *
875  *  RETURNS:
876  *
877  *      1 if TRUE
878  *      0 if FALSE
879  *
880  ******************************************************************************/
wl_is_a_valid_freq(long frequency)881 int wl_is_a_valid_freq( long frequency )
882 {
883     int i;
884     /*------------------------------------------------------------------------*/
885 
886 
887     /* Iterate through the matrix and retrieve the channel */
888     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
889         if( chan_freq_list[i][1] == frequency ) {
890             return 1;
891         }
892     }
893 
894     return 0;
895 } // wl_is_a_valid_freq
896 /*============================================================================*/
897 
898 
899 
900 
901 /*******************************************************************************
902  *	wl_get_freq_from_chan()
903  *******************************************************************************
904  *
905  *  DESCRIPTION:
906  *
907  *      Function used to look up the frequency for a given channel on which the
908  *      adapter is Tx/Rx.
909  *
910  *  PARAMETERS:
911  *
912  *      channel - the channel
913  *
914  *  RETURNS:
915  *
916  *      The corresponding frequency
917  *
918  ******************************************************************************/
wl_get_freq_from_chan(int channel)919 long wl_get_freq_from_chan( int channel )
920 {
921     int i;
922     /*------------------------------------------------------------------------*/
923 
924 
925     /* Strip out the high bit set by the FW for 802.11a channels */
926     if( channel & 0x100 ) {
927         channel = channel & 0x0FF;
928     }
929 
930     /* Iterate through the matrix and retrieve the frequency */
931     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
932         if( chan_freq_list[i][0] == channel ) {
933             return chan_freq_list[i][1];
934         }
935     }
936 
937     return 0;
938 } // wl_get_freq_from_chan
939 /*============================================================================*/
940 
941 
942 
943 
944 /*******************************************************************************
945  *	wl_get_chan_from_freq()
946  *******************************************************************************
947  *
948  *  DESCRIPTION:
949  *
950  *      Function used to look up the channel for a given frequency on which the
951  *      adapter is Tx/Rx.
952  *
953  *  PARAMETERS:
954  *
955  *      frequency - the frequency
956  *
957  *  RETURNS:
958  *
959  *      The corresponding channel
960  *
961  ******************************************************************************/
wl_get_chan_from_freq(long frequency)962 int wl_get_chan_from_freq( long frequency )
963 {
964     int i;
965     /*------------------------------------------------------------------------*/
966 
967 
968     /* Iterate through the matrix and retrieve the channel */
969     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
970         if( chan_freq_list[i][1] == frequency ) {
971             return chan_freq_list[i][0];
972         }
973     }
974 
975     return 0;
976 } // wl_get_chan_from_freq
977 /*============================================================================*/
978 
979 
980 
981 
982 /*******************************************************************************
983  *	wl_process_link_status()
984  *******************************************************************************
985  *
986  *  DESCRIPTION:
987  *
988  *      Process the link status message signaled by the device.
989  *
990  *  PARAMETERS:
991  *
992  *      lp - a pointer to the device's private structure
993  *
994  *  RETURNS:
995  *
996  *      N/A
997  *
998  ******************************************************************************/
wl_process_link_status(struct wl_private * lp)999 void wl_process_link_status( struct wl_private *lp )
1000 {
1001     hcf_16 link_stat;
1002     /*------------------------------------------------------------------------*/
1003 
1004     DBG_FUNC( "wl_process_link_status" );
1005     DBG_ENTER( DbgInfo );
1006 
1007     if( lp != NULL ) {
1008         //link_stat = lp->hcfCtx.IFB_DSLinkStat & CFG_LINK_STAT_FW;
1009         link_stat = lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW;
1010         switch( link_stat ) {
1011         case 1:
1012             DBG_TRACE( DbgInfo, "Link Status : Connected\n" );
1013             wl_wext_event_ap( lp->dev );
1014             break;
1015         case 2:
1016             DBG_TRACE( DbgInfo, "Link Status : Disconnected\n"  );
1017             break;
1018         case 3:
1019             DBG_TRACE( DbgInfo, "Link Status : Access Point Change\n" );
1020             break;
1021         case 4:
1022             DBG_TRACE( DbgInfo, "Link Status : Access Point Out of Range\n" );
1023             break;
1024         case 5:
1025             DBG_TRACE( DbgInfo, "Link Status : Access Point In Range\n" );
1026             break;
1027         default:
1028             DBG_TRACE( DbgInfo, "Link Status : UNKNOWN (0x%04x)\n", link_stat );
1029             break;
1030         }
1031     }
1032     DBG_LEAVE( DbgInfo );
1033     return;
1034 } // wl_process_link_status
1035 /*============================================================================*/
1036 
1037 
1038 
1039 
1040 /*******************************************************************************
1041  *	wl_process_probe_response()
1042  *******************************************************************************
1043  *
1044  *  DESCRIPTION:
1045  *
1046  *      Process the probe responses retunred by the device as a result of an
1047  *      active scan.
1048  *
1049  *  PARAMETERS:
1050  *
1051  *      lp - a pointer to the device's private structure
1052  *
1053  *  RETURNS:
1054  *
1055  *      N/A
1056  *
1057  ******************************************************************************/
wl_process_probe_response(struct wl_private * lp)1058 void wl_process_probe_response( struct wl_private *lp )
1059 {
1060     PROBE_RESP  *probe_rsp;
1061     hcf_8       *wpa_ie = NULL;
1062     hcf_16      wpa_ie_len = 0;
1063     /*------------------------------------------------------------------------*/
1064 
1065 
1066     DBG_FUNC( "wl_process_probe_response" );
1067     DBG_ENTER( DbgInfo );
1068 
1069 
1070     if( lp != NULL ) {
1071         probe_rsp = (PROBE_RESP *)&lp->ProbeResp;
1072 
1073         wl_endian_translate_event( (ltv_t *)probe_rsp );
1074 
1075         DBG_TRACE( DbgInfo, "(%s) =========================\n", lp->dev->name );
1076         DBG_TRACE( DbgInfo, "(%s) length      : 0x%04x.\n",  lp->dev->name,
1077                 probe_rsp->length );
1078 
1079         if( probe_rsp->length > 1 ) {
1080             DBG_TRACE( DbgInfo, "(%s) infoType    : 0x%04x.\n", lp->dev->name,
1081                     probe_rsp->infoType );
1082 
1083             DBG_TRACE( DbgInfo, "(%s) signal      : 0x%02x.\n", lp->dev->name,
1084                     probe_rsp->signal );
1085 
1086             DBG_TRACE( DbgInfo, "(%s) silence     : 0x%02x.\n", lp->dev->name,
1087                     probe_rsp->silence );
1088 
1089             DBG_TRACE( DbgInfo, "(%s) rxFlow      : 0x%02x.\n", lp->dev->name,
1090                     probe_rsp->rxFlow );
1091 
1092             DBG_TRACE( DbgInfo, "(%s) rate        : 0x%02x.\n", lp->dev->name,
1093                     probe_rsp->rate );
1094 
1095             DBG_TRACE( DbgInfo, "(%s) frame cntl  : 0x%04x.\n", lp->dev->name,
1096                     probe_rsp->frameControl );
1097 
1098             DBG_TRACE( DbgInfo, "(%s) durID       : 0x%04x.\n", lp->dev->name,
1099                     probe_rsp->durID );
1100 
1101 		DBG_TRACE(DbgInfo, "(%s) address1    : %pM\n", lp->dev->name,
1102 			probe_rsp->address1);
1103 
1104 		DBG_TRACE(DbgInfo, "(%s) address2    : %pM\n", lp->dev->name,
1105 			probe_rsp->address2);
1106 
1107 		DBG_TRACE(DbgInfo, "(%s) BSSID       : %pM\n", lp->dev->name,
1108 			probe_rsp->BSSID);
1109 
1110             DBG_TRACE( DbgInfo, "(%s) sequence    : 0x%04x.\n", lp->dev->name,
1111                     probe_rsp->sequence );
1112 
1113 		DBG_TRACE(DbgInfo, "(%s) address4    : %pM\n", lp->dev->name,
1114 			probe_rsp->address4);
1115 
1116             DBG_TRACE( DbgInfo, "(%s) datalength  : 0x%04x.\n", lp->dev->name,
1117                     probe_rsp->dataLength );
1118 
1119 		DBG_TRACE(DbgInfo, "(%s) DA          : %pM\n", lp->dev->name,
1120 			probe_rsp->DA);
1121 
1122 		DBG_TRACE(DbgInfo, "(%s) SA          : %pM\n", lp->dev->name,
1123 			probe_rsp->SA);
1124 
1125 #ifdef WARP
1126 
1127             DBG_TRACE( DbgInfo, "(%s) channel     : %d\n", lp->dev->name,
1128                     probe_rsp->channel );
1129 
1130             DBG_TRACE( DbgInfo, "(%s) band        : %d\n", lp->dev->name,
1131                     probe_rsp->band );
1132 #else
1133             DBG_TRACE( DbgInfo, "(%s) lenType     : 0x%04x.\n", lp->dev->name,
1134                     probe_rsp->lenType );
1135 #endif  // WARP
1136 
1137             DBG_TRACE( DbgInfo, "(%s) timeStamp   : %d.%d.%d.%d.%d.%d.%d.%d\n",
1138                     lp->dev->name,
1139                     probe_rsp->timeStamp[0],
1140                     probe_rsp->timeStamp[1],
1141                     probe_rsp->timeStamp[2],
1142                     probe_rsp->timeStamp[3],
1143                     probe_rsp->timeStamp[4],
1144                     probe_rsp->timeStamp[5],
1145                     probe_rsp->timeStamp[6],
1146                     probe_rsp->timeStamp[7]);
1147 
1148             DBG_TRACE( DbgInfo, "(%s) beaconInt   : 0x%04x.\n", lp->dev->name,
1149                     probe_rsp->beaconInterval );
1150 
1151             DBG_TRACE( DbgInfo, "(%s) capability  : 0x%04x.\n", lp->dev->name,
1152                     probe_rsp->capability );
1153 
1154             DBG_TRACE( DbgInfo, "(%s) SSID len    : 0x%04x.\n", lp->dev->name,
1155                     probe_rsp->rawData[1] );
1156 
1157 
1158             if( probe_rsp->rawData[1] > 0 ) {
1159                 char ssid[HCF_MAX_NAME_LEN];
1160 
1161                 memset( ssid, 0, sizeof( ssid ));
1162                 strncpy( ssid, &probe_rsp->rawData[2],
1163                             probe_rsp->rawData[1] );
1164 
1165                 DBG_TRACE( DbgInfo, "(%s) SSID        : %s\n",
1166                             lp->dev->name, ssid );
1167             }
1168 
1169 
1170             /* Parse out the WPA-IE, if one exists */
1171             wpa_ie = wl_parse_wpa_ie( probe_rsp, &wpa_ie_len );
1172             if( wpa_ie != NULL ) {
1173                 DBG_TRACE( DbgInfo, "(%s) WPA-IE      : %s\n",
1174                 lp->dev->name, wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
1175             }
1176 
1177             DBG_TRACE( DbgInfo, "(%s) flags       : 0x%04x.\n",
1178                         lp->dev->name, probe_rsp->flags );
1179         }
1180 
1181         DBG_TRACE( DbgInfo, "\n" );
1182 
1183 
1184         /* If probe response length is 1, then the scan is complete */
1185         if( probe_rsp->length == 1 ) {
1186             DBG_TRACE( DbgInfo, "SCAN COMPLETE\n" );
1187             lp->probe_results.num_aps = lp->probe_num_aps;
1188             lp->probe_results.scan_complete = TRUE;
1189 
1190             /* Reset the counter for the next scan request */
1191             lp->probe_num_aps = 0;
1192 
1193             /* Send a wireless extensions event that the scan completed */
1194             wl_wext_event_scan_complete( lp->dev );
1195         } else {
1196             /* Only copy to the table if the entry is unique; APs sometimes
1197                 respond more than once to a probe */
1198             if( lp->probe_num_aps == 0 ) {
1199                 /* Copy the info to the ScanResult structure in the private
1200                 adapter struct */
1201                 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1202                         probe_rsp, sizeof( PROBE_RESP ));
1203 
1204                 /* Increment the number of APs detected */
1205                 lp->probe_num_aps++;
1206             } else {
1207                 int count;
1208                 int unique = 1;
1209 
1210                 for( count = 0; count < lp->probe_num_aps; count++ ) {
1211                     if( memcmp( &( probe_rsp->BSSID ),
1212                         lp->probe_results.ProbeTable[count].BSSID,
1213                         ETH_ALEN ) == 0 ) {
1214                         unique = 0;
1215                     }
1216                 }
1217 
1218                 if( unique ) {
1219                     /* Copy the info to the ScanResult structure in the
1220                     private adapter struct. Only copy if there's room in the
1221                     table */
1222                     if( lp->probe_num_aps < MAX_NAPS )
1223                     {
1224                         memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1225                                 probe_rsp, sizeof( PROBE_RESP ));
1226                     }
1227                     else
1228                     {
1229                         DBG_WARNING( DbgInfo, "Num of scan results exceeds storage, truncating\n" );
1230                     }
1231 
1232                     /* Increment the number of APs detected. Note I do this
1233                         here even when I don't copy the probe response to the
1234                         buffer in order to detect the overflow condition */
1235                     lp->probe_num_aps++;
1236                 }
1237             }
1238         }
1239     }
1240 
1241     DBG_LEAVE( DbgInfo );
1242     return;
1243 } // wl_process_probe_response
1244 /*============================================================================*/
1245 
1246 
1247 
1248 
1249 /*******************************************************************************
1250  *	wl_process_updated_record()
1251  *******************************************************************************
1252  *
1253  *  DESCRIPTION:
1254  *
1255  *      Process the updated information record message signaled by the device.
1256  *
1257  *  PARAMETERS:
1258  *
1259  *      lp - a pointer to the device's private structure
1260  *
1261  *  RETURNS:
1262  *
1263  *      N/A
1264  *
1265  ******************************************************************************/
wl_process_updated_record(struct wl_private * lp)1266 void wl_process_updated_record( struct wl_private *lp )
1267 {
1268     DBG_FUNC( "wl_process_updated_record" );
1269     DBG_ENTER( DbgInfo );
1270 
1271 
1272     if( lp != NULL ) {
1273         lp->updatedRecord.u.u16[0] = CNV_LITTLE_TO_INT( lp->updatedRecord.u.u16[0] );
1274 
1275         switch( lp->updatedRecord.u.u16[0] ) {
1276         case CFG_CUR_COUNTRY_INFO:
1277             DBG_TRACE( DbgInfo, "Updated Record: CFG_CUR_COUNTRY_INFO\n" );
1278             wl_connect( lp );
1279             break;
1280 
1281         case CFG_PORT_STAT:
1282             DBG_TRACE( DbgInfo, "Updated Record: WAIT_FOR_CONNECT (0xFD40)\n" );
1283             //wl_connect( lp );
1284             break;
1285 
1286         default:
1287             DBG_TRACE( DbgInfo, "UNKNOWN: 0x%04x\n",
1288                        lp->updatedRecord.u.u16[0] );
1289         }
1290     }
1291 
1292     DBG_LEAVE( DbgInfo );
1293     return;
1294 } // wl_process_updated_record
1295 /*============================================================================*/
1296 
1297 
1298 
1299 
1300 /*******************************************************************************
1301  *	wl_process_assoc_status()
1302  *******************************************************************************
1303  *
1304  *  DESCRIPTION:
1305  *
1306  *      Process the association status event signaled by the device.
1307  *
1308  *  PARAMETERS:
1309  *
1310  *      lp - a pointer to the device's private structure
1311  *
1312  *  RETURNS:
1313  *
1314  *      N/A
1315  *
1316  ******************************************************************************/
wl_process_assoc_status(struct wl_private * lp)1317 void wl_process_assoc_status( struct wl_private *lp )
1318 {
1319     ASSOC_STATUS_STRCT *assoc_stat;
1320     /*------------------------------------------------------------------------*/
1321 
1322 
1323     DBG_FUNC( "wl_process_assoc_status" );
1324     DBG_ENTER( DbgInfo );
1325 
1326 
1327     if( lp != NULL ) {
1328         assoc_stat = (ASSOC_STATUS_STRCT *)&lp->assoc_stat;
1329 
1330         wl_endian_translate_event( (ltv_t *)assoc_stat );
1331 
1332         switch( assoc_stat->assocStatus ) {
1333         case 1:
1334             DBG_TRACE( DbgInfo, "Association Status : STA Associated\n" );
1335             break;
1336 
1337         case 2:
1338             DBG_TRACE( DbgInfo, "Association Status : STA Reassociated\n" );
1339             break;
1340 
1341         case 3:
1342             DBG_TRACE( DbgInfo, "Association Status : STA Disassociated\n" );
1343             break;
1344 
1345         default:
1346             DBG_TRACE( DbgInfo, "Association Status : UNKNOWN (0x%04x)\n",
1347                         assoc_stat->assocStatus );
1348             break;
1349         }
1350 
1351 	DBG_TRACE(DbgInfo, "STA Address        : %pM\n", assoc_stat->staAddr);
1352 
1353         if(( assoc_stat->assocStatus == 2 )  && ( assoc_stat->len == 8 )) {
1354 		DBG_TRACE(DbgInfo, "Old AP Address     : %pM\n",
1355 			assoc_stat->oldApAddr);
1356         }
1357     }
1358 
1359     DBG_LEAVE( DbgInfo );
1360     return;
1361 } // wl_process_assoc_status
1362 /*============================================================================*/
1363 
1364 
1365 
1366 
1367 /*******************************************************************************
1368  *	wl_process_security_status()
1369  *******************************************************************************
1370  *
1371  *  DESCRIPTION:
1372  *
1373  *      Process the security status message signaled by the device.
1374  *
1375  *  PARAMETERS:
1376  *
1377  *      lp - a pointer to the device's private structure
1378  *
1379  *  RETURNS:
1380  *
1381  *      N/A
1382  *
1383  ******************************************************************************/
wl_process_security_status(struct wl_private * lp)1384 void wl_process_security_status( struct wl_private *lp )
1385 {
1386     SECURITY_STATUS_STRCT *sec_stat;
1387     /*------------------------------------------------------------------------*/
1388 
1389 
1390     DBG_FUNC( "wl_process_security_status" );
1391     DBG_ENTER( DbgInfo );
1392 
1393 
1394     if( lp != NULL ) {
1395         sec_stat = (SECURITY_STATUS_STRCT *)&lp->sec_stat;
1396 
1397         wl_endian_translate_event( (ltv_t *)sec_stat );
1398 
1399         switch( sec_stat->securityStatus ) {
1400         case 1:
1401             DBG_TRACE( DbgInfo, "Security Status : Dissassociate [AP]\n" );
1402             break;
1403 
1404         case 2:
1405             DBG_TRACE( DbgInfo, "Security Status : Deauthenticate [AP]\n" );
1406             break;
1407 
1408         case 3:
1409             DBG_TRACE( DbgInfo, "Security Status : Authenticate Fail [STA] or [AP]\n" );
1410             break;
1411 
1412         case 4:
1413             DBG_TRACE( DbgInfo, "Security Status : MIC Fail\n" );
1414             break;
1415 
1416         case 5:
1417             DBG_TRACE( DbgInfo, "Security Status : Associate Fail\n" );
1418             break;
1419 
1420         default:
1421             DBG_TRACE( DbgInfo, "Security Status : UNKNOWN (0x%04x)\n",
1422                         sec_stat->securityStatus );
1423             break;
1424         }
1425 
1426 	DBG_TRACE(DbgInfo, "STA Address     : %pM\n", sec_stat->staAddr);
1427 	DBG_TRACE(DbgInfo, "Reason          : 0x%04x\n", sec_stat->reason);
1428 
1429     }
1430 
1431     DBG_LEAVE( DbgInfo );
1432     return;
1433 } // wl_process_security_status
1434 /*============================================================================*/
1435 
wl_get_tallies(struct wl_private * lp,CFG_HERMES_TALLIES_STRCT * tallies)1436 int wl_get_tallies(struct wl_private *lp,
1437 		   CFG_HERMES_TALLIES_STRCT *tallies)
1438 {
1439     int ret = 0;
1440     int status;
1441     CFG_HERMES_TALLIES_STRCT *pTallies;
1442 
1443     DBG_FUNC( "wl_get_tallies" );
1444     DBG_ENTER(DbgInfo);
1445 
1446     /* Get the current tallies from the adapter */
1447     lp->ltvRecord.len = 1 + HCF_TOT_TAL_CNT * sizeof(hcf_16);
1448     lp->ltvRecord.typ = CFG_TALLIES;
1449 
1450     status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));
1451 
1452     if( status == HCF_SUCCESS ) {
1453 	pTallies = (CFG_HERMES_TALLIES_STRCT *)&(lp->ltvRecord.u.u32);
1454 	memcpy(tallies, pTallies, sizeof(*tallies));
1455     	DBG_TRACE( DbgInfo, "Get tallies okay, dixe: %d\n", sizeof(*tallies) );
1456     } else {
1457     	DBG_TRACE( DbgInfo, "Get tallies failed\n" );
1458 	ret = -EFAULT;
1459     }
1460 
1461     DBG_LEAVE( DbgInfo );
1462 
1463     return ret;
1464 }
1465 
1466