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