upload tizen1.0 source
[kernel/linux-2.6.36.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  *  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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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 #if DBG
319 /*******************************************************************************
320  *      DbgHwAddr()
321  *******************************************************************************
322  *
323  *  DESCRIPTION:
324  *
325  *      Convert a hardware ethernet address to a character string
326  *
327  *  PARAMETERS:
328  *
329  *      hwAddr  - an ethernet address
330  *
331  *  RETURNS:
332  *
333  *      a pointer to a string representing the ethernet address
334  *
335  ******************************************************************************/
336 const char *DbgHwAddr(unsigned char *hwAddr)
337 {
338     static char     buffer[18];
339     /*------------------------------------------------------------------------*/
340
341
342     sprintf( buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
343              hwAddr[0], hwAddr[1], hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5] );
344
345     return buffer;
346 } // DbgHwAddr
347 /*============================================================================*/
348
349 #endif /* DBG */
350
351
352
353
354 /*******************************************************************************
355  *      wl_has_wep()
356  *******************************************************************************
357  *
358  *  DESCRIPTION:
359  *
360  *      Checks to see if the device supports WEP
361  *
362  *  PARAMETERS:
363  *
364  *      ifbp    - the IFB pointer of the device in question
365  *
366  *  RETURNS:
367  *
368  *      1 if WEP is known enabled, else 0
369  *
370  ******************************************************************************/
371 int wl_has_wep (IFBP ifbp)
372 {
373     CFG_PRIVACY_OPT_IMPLEMENTED_STRCT ltv;
374         int rc, privacy;
375     /*------------------------------------------------------------------------*/
376
377
378         /* This function allows us to distiguish bronze cards from other types, to
379        know if WEP exists. Does not distinguish (because there's no way to)
380        between silver and gold cards. */
381     ltv.len = 2;
382     ltv.typ = CFG_PRIVACY_OPT_IMPLEMENTED;
383
384         rc = hcf_get_info( ifbp, (LTVP) &ltv );
385
386         privacy = CNV_LITTLE_TO_INT( ltv.privacy_opt_implemented );
387
388         //return rc ? 0 : privacy;
389     return 1;
390 } // wl_has_wep
391 /*============================================================================*/
392
393
394
395
396 /*******************************************************************************
397  *      wl_hcf_error()
398  *******************************************************************************
399  *
400  *  DESCRIPTION:
401  *
402  *      Report the type of HCF error message
403  *
404  *  PARAMETERS:
405  *
406  *      none
407  *
408  *  RETURNS:
409  *
410  *      A descriptive string indicating the error, quiet otherwise.
411  *
412  ******************************************************************************/
413 void wl_hcf_error( struct net_device *dev, int hcfStatus )
414 {
415     char     buffer[64], *pMsg;
416     /*------------------------------------------------------------------------*/
417
418
419     if( hcfStatus != HCF_SUCCESS ) {
420         switch( hcfStatus ) {
421
422         case HCF_ERR_TIME_OUT:
423
424             pMsg = "Expected adapter event did not occur in expected time";
425             break;
426
427
428         case HCF_ERR_NO_NIC:
429
430             pMsg = "Card not found (ejected unexpectedly)";
431             break;
432
433
434         case HCF_ERR_LEN:
435
436             pMsg = "Command buffer size insufficient";
437             break;
438
439
440         case HCF_ERR_INCOMP_PRI:
441
442             pMsg = "Primary functions are not compatible";
443             break;
444
445
446         case HCF_ERR_INCOMP_FW:
447
448             pMsg = "Primary functions are compatible, "
449                 "station/ap functions are not";
450             break;
451
452
453         case HCF_ERR_BUSY:
454
455             pMsg = "Inquire cmd while another Inquire in progress";
456             break;
457
458
459         //case HCF_ERR_SEQ_BUG:
460
461         //    pMsg = "Unexpected command completed";
462         //    break;
463
464
465         case HCF_ERR_DEFUNCT_AUX:
466
467             pMsg = "Timeout on ack for enable/disable of AUX registers";
468             break;
469
470
471         case HCF_ERR_DEFUNCT_TIMER:
472             pMsg = "Timeout on timer calibration during initialization process";
473             break;
474
475
476         case HCF_ERR_DEFUNCT_TIME_OUT:
477             pMsg = "Timeout on Busy bit drop during BAP setup";
478             break;
479
480
481         case HCF_ERR_DEFUNCT_CMD_SEQ:
482             pMsg = "Hermes and HCF are out of sync";
483             break;
484
485
486         default:
487
488             sprintf( buffer, "Error code %d", hcfStatus );
489             pMsg = buffer;
490             break;
491         }
492
493         printk( KERN_INFO "%s: Wireless, HCF failure: \"%s\"\n",
494                 dev->name, pMsg );
495     }
496 } // wl_hcf_error
497 /*============================================================================*/
498
499
500
501
502 /*******************************************************************************
503  *      wl_endian_translate_event()
504  *******************************************************************************
505  *
506  *  DESCRIPTION:
507  *
508  *      Determines what type of data is in the mailbox and performs the proper
509  *  endian translation.
510  *
511  *  PARAMETERS:
512  *
513  *      pLtv - an LTV pointer
514  *
515  *  RETURNS:
516  *
517  *      N/A
518  *
519  ******************************************************************************/
520 void wl_endian_translate_event( ltv_t *pLtv )
521 {
522     DBG_FUNC( "wl_endian_translate_event" );
523     DBG_ENTER( DbgInfo );
524
525
526     switch( pLtv->typ ) {
527     case CFG_TALLIES:
528         break;
529
530
531     case CFG_SCAN:
532         {
533             int numAPs;
534             SCAN_RS_STRCT *pAps = (SCAN_RS_STRCT*)&pLtv->u.u8[0];
535
536             numAPs = (hcf_16)(( (size_t)( pLtv->len - 1 ) * 2 ) /
537                                 (sizeof( SCAN_RS_STRCT )));
538
539             while( numAPs >= 1 ) {
540                 numAPs--;
541
542                 pAps[numAPs].channel_id           =
543                     CNV_LITTLE_TO_INT( pAps[numAPs].channel_id );
544
545                 pAps[numAPs].noise_level          =
546                     CNV_LITTLE_TO_INT( pAps[numAPs].noise_level );
547
548                 pAps[numAPs].signal_level         =
549                     CNV_LITTLE_TO_INT( pAps[numAPs].signal_level );
550
551                 pAps[numAPs].beacon_interval_time =
552                     CNV_LITTLE_TO_INT( pAps[numAPs].beacon_interval_time );
553
554                 pAps[numAPs].capability           =
555                     CNV_LITTLE_TO_INT( pAps[numAPs].capability );
556
557                 pAps[numAPs].ssid_len             =
558                     CNV_LITTLE_TO_INT( pAps[numAPs].ssid_len );
559
560                 pAps[numAPs].ssid_val[pAps[numAPs].ssid_len] = 0;
561
562             }
563         }
564         break;
565
566
567     case CFG_ACS_SCAN:
568         {
569             PROBE_RESP *probe_resp = (PROBE_RESP *)pLtv;
570
571             probe_resp->frameControl   = CNV_LITTLE_TO_INT( probe_resp->frameControl );
572             probe_resp->durID          = CNV_LITTLE_TO_INT( probe_resp->durID );
573             probe_resp->sequence       = CNV_LITTLE_TO_INT( probe_resp->sequence );
574             probe_resp->dataLength     = CNV_LITTLE_TO_INT( probe_resp->dataLength );
575
576 #ifndef WARP
577             probe_resp->lenType        = CNV_LITTLE_TO_INT( probe_resp->lenType );
578 #endif // WARP
579
580             probe_resp->beaconInterval = CNV_LITTLE_TO_INT( probe_resp->beaconInterval );
581             probe_resp->capability     = CNV_LITTLE_TO_INT( probe_resp->capability );
582             probe_resp->flags          = CNV_LITTLE_TO_INT( probe_resp->flags );
583         }
584         break;
585
586
587     case CFG_LINK_STAT:
588 #define ls ((LINK_STATUS_STRCT *)pLtv)
589             ls->linkStatus = CNV_LITTLE_TO_INT( ls->linkStatus );
590         break;
591 #undef ls
592
593     case CFG_ASSOC_STAT:
594         {
595             ASSOC_STATUS_STRCT *pAs = (ASSOC_STATUS_STRCT *)pLtv;
596
597             pAs->assocStatus = CNV_LITTLE_TO_INT( pAs->assocStatus );
598         }
599         break;
600
601
602     case CFG_SECURITY_STAT:
603         {
604             SECURITY_STATUS_STRCT *pSs = (SECURITY_STATUS_STRCT *)pLtv;
605
606             pSs->securityStatus = CNV_LITTLE_TO_INT( pSs->securityStatus );
607             pSs->reason         = CNV_LITTLE_TO_INT( pSs->reason );
608         }
609         break;
610
611
612     case CFG_WMP:
613         break;
614
615
616     case CFG_NULL:
617         break;
618
619
620     default:
621         break;
622     }
623
624     DBG_LEAVE( DbgInfo );
625     return;
626 } // wl_endian_translate_event
627 /*============================================================================*/
628
629
630 /*******************************************************************************
631  *      msf_assert()
632  *******************************************************************************
633  *
634  *  DESCRIPTION:
635  *
636  *      Print statement used to display asserts from within the HCF. Only called
637  *  when asserts in the HCF are turned on. See hcfcfg.h for more information.
638  *
639  *  PARAMETERS:
640  *
641  *      file_namep  - the filename in which the assert occurred.
642  *      line_number - the line number on which the assert occurred.
643  *      trace       - a comment associated with the assert.
644  *      qual        - return code or other value related to the assert
645  *
646  *  RETURNS:
647  *
648  *      N/A
649  *
650  ******************************************************************************/
651 void msf_assert( unsigned int line_number, hcf_16 trace, hcf_32 qual )
652 {
653     DBG_PRINT( "HCF ASSERT: Line %d, VAL: 0x%.8x\n", line_number, /*;?*/(u32)qual );
654 } // msf_assert
655 /*============================================================================*/
656
657
658
659
660 /*******************************************************************************
661  *      wl_parse_ds_ie()
662  *******************************************************************************
663  *
664  *  DESCRIPTION:
665  *
666  *      This function parses the Direct Sequence Parameter Set IE, used to
667  *      determine channel/frequency information.
668  *
669  *  PARAMETERS:
670  *
671  *      probe_rsp - a pointer to a PROBE_RESP structure containing the probe
672  *                  response.
673  *
674  *  RETURNS:
675  *
676  *      The channel on which the BSS represented by this probe response is
677  *      transmitting.
678  *
679  ******************************************************************************/
680 hcf_8 wl_parse_ds_ie( PROBE_RESP *probe_rsp )
681 {
682     int     i;
683     int     ie_length = 0;
684     hcf_8   *buf;
685     hcf_8   buf_size;
686     /*------------------------------------------------------------------------*/
687
688
689     if( probe_rsp == NULL ) {
690         return 0;
691     }
692
693     buf      = probe_rsp->rawData;
694     buf_size = sizeof( probe_rsp->rawData );
695
696
697     for( i = 0; i < buf_size; i++ ) {
698         if( buf[i] == DS_INFO_ELEM ) {
699             /* Increment by 1 to get the length, and test it; in a DS element,
700                length should always be 1 */
701             i++;
702             ie_length = buf[i];
703
704             if( buf[i] == 1 ) {
705                 /* Get the channel information */
706                 i++;
707                 return buf[i];
708             }
709         }
710     }
711
712     /* If we get here, we didn't find a DS-IE, which is strange */
713     return 0;
714 } // wl_parse_ds_ie
715
716
717 /*******************************************************************************
718  *      wl_parse_wpa_ie()
719  *******************************************************************************
720  *
721  *  DESCRIPTION:
722  *
723  *      This function parses the Probe Response for a valid WPA-IE.
724  *
725  *  PARAMETERS:
726  *
727  *      probe_rsp - a pointer to a PROBE_RESP structure containing the probe
728  *                  response
729  *      length    - a pointer to an hcf_16 in which the size of the WPA-IE will
730  *                  be stored (if found).
731  *
732  *  RETURNS:
733  *
734  *      A pointer to the location in the probe response buffer where a valid
735  *      WPA-IE lives. The length of this IE is written back to the 'length'
736  *      argument passed to the function.
737  *
738  ******************************************************************************/
739 hcf_8 * wl_parse_wpa_ie( PROBE_RESP *probe_rsp, hcf_16 *length )
740 {
741     int     i;
742     int     ie_length = 0;
743     hcf_8   *buf;
744     hcf_8   buf_size;
745     hcf_8   wpa_oui[] = WPA_OUI_TYPE;
746     /*------------------------------------------------------------------------*/
747
748
749     if( probe_rsp == NULL || length == NULL ) {
750         return NULL;
751     }
752
753     buf      = probe_rsp->rawData;
754     buf_size = sizeof( probe_rsp->rawData );
755     *length  = 0;
756
757
758     for( i = 0; i < buf_size; i++ ) {
759         if( buf[i] == GENERIC_INFO_ELEM ) {
760             /* Increment by one to get the IE length */
761             i++;
762             ie_length = probe_rsp->rawData[i];
763
764             /* Increment by one to point to the IE payload */
765             i++;
766
767             /* Does the IE contain a WPA OUI? If not, it's a proprietary IE */
768             if( memcmp( &buf[i], &wpa_oui, WPA_SELECTOR_LEN ) == 0 ) {
769                 /* Pass back length and return a pointer to the WPA-IE */
770                 /* NOTE: Length contained in the WPA-IE is only the length of
771                    the payload. The entire WPA-IE, including the IE identifier
772                    and the length, is 2 bytes larger */
773                 *length = ie_length + 2;
774
775                 /* Back up the pointer 2 bytes to include the IE identifier and
776                    the length in the buffer returned */
777                 i -= 2;
778                 return &buf[i];
779             }
780
781             /* Increment past this non-WPA IE and continue looking */
782             i += ( ie_length - 1 );
783         }
784     }
785
786     /* If we're here, we didn't find a WPA-IE in the buffer */
787     return NULL;
788 } // wl_parse_wpa_ie
789
790
791 /*******************************************************************************
792  *      wl_print_wpa_ie()
793  *******************************************************************************
794  *
795  *  DESCRIPTION:
796  *
797  *      Function used to take a WPA Information Element (WPA-IE) buffer and
798  *      display it in a readable format.
799  *
800  *  PARAMETERS:
801  *
802  *      buffer - the byte buffer containing the WPA-IE
803  *      length - the length of the above buffer
804  *
805  *  RETURNS:
806  *
807  *      A pointer to the formatted WPA-IE string. Note that the format used is
808  *      byte-by-byte printing as %02x hex values with no spaces. This is
809  *      required for proper operation with some WPA supplicants.
810  *
811  ******************************************************************************/
812 hcf_8 * wl_print_wpa_ie( hcf_8 *buffer, int length )
813 {
814     int count;
815     int rows;
816     int remainder;
817     int rowsize = 4;
818     hcf_8 row_buf[64];
819     static hcf_8 output[512];
820     /*------------------------------------------------------------------------*/
821
822
823     memset( output, 0, sizeof( output ));
824     memset( row_buf, 0, sizeof( row_buf ));
825
826
827     /* Determine how many rows will be needed, and the remainder */
828     rows = length / rowsize;
829     remainder = length % rowsize;
830
831
832     /* Format the rows */
833     for( count = 0; count < rows; count++ ) {
834         sprintf( row_buf, "%02x%02x%02x%02x",
835                  buffer[count*rowsize], buffer[count*rowsize+1],
836                  buffer[count*rowsize+2], buffer[count*rowsize+3]);
837         strcat( output, row_buf );
838     }
839
840     memset( row_buf, 0, sizeof( row_buf ));
841
842
843     /* Format the remainder */
844     for( count = 0; count < remainder; count++ ) {
845         sprintf( row_buf, "%02x", buffer[(rows*rowsize)+count]);
846         strcat( output, row_buf );
847     }
848
849     return output;
850 } // wl_print_wpa_ie
851 /*============================================================================*/
852
853
854
855
856 /*******************************************************************************
857  *      wl_is_a_valid_chan()
858  *******************************************************************************
859  *
860  *  DESCRIPTION:
861  *
862  *      Checks if a given channel is valid
863  *
864  *  PARAMETERS:
865  *
866  *      channel - the channel
867  *
868  *  RETURNS:
869  *
870  *      1 if TRUE
871  *      0 if FALSE
872  *
873  ******************************************************************************/
874 int wl_is_a_valid_chan( int channel )
875 {
876     int i;
877     /*------------------------------------------------------------------------*/
878
879
880     /* Strip out the high bit set by the FW for 802.11a channels */
881     if( channel & 0x100 ) {
882         channel = channel & 0x0FF;
883     }
884
885     /* Iterate through the matrix and retrieve the frequency */
886     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
887         if( chan_freq_list[i][0] == channel ) {
888             return 1;
889         }
890     }
891
892     return 0;
893 } // wl_is_a_valid_chan
894 /*============================================================================*/
895
896
897
898
899 /*******************************************************************************
900  *      wl_get_chan_from_freq()
901  *******************************************************************************
902  *
903  *  DESCRIPTION:
904  *
905  *      Checks if a given frequency is valid
906  *
907  *  PARAMETERS:
908  *
909  *      freq - the frequency
910  *
911  *  RETURNS:
912  *
913  *      1 if TRUE
914  *      0 if FALSE
915  *
916  ******************************************************************************/
917 int wl_is_a_valid_freq( long frequency )
918 {
919     int i;
920     /*------------------------------------------------------------------------*/
921
922
923     /* Iterate through the matrix and retrieve the channel */
924     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
925         if( chan_freq_list[i][1] == frequency ) {
926             return 1;
927         }
928     }
929
930     return 0;
931 } // wl_is_a_valid_freq
932 /*============================================================================*/
933
934
935
936
937 /*******************************************************************************
938  *      wl_get_freq_from_chan()
939  *******************************************************************************
940  *
941  *  DESCRIPTION:
942  *
943  *      Function used to look up the frequency for a given channel on which the
944  *      adapter is Tx/Rx.
945  *
946  *  PARAMETERS:
947  *
948  *      channel - the channel
949  *
950  *  RETURNS:
951  *
952  *      The corresponding frequency
953  *
954  ******************************************************************************/
955 long wl_get_freq_from_chan( int channel )
956 {
957     int i;
958     /*------------------------------------------------------------------------*/
959
960
961     /* Strip out the high bit set by the FW for 802.11a channels */
962     if( channel & 0x100 ) {
963         channel = channel & 0x0FF;
964     }
965
966     /* Iterate through the matrix and retrieve the frequency */
967     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
968         if( chan_freq_list[i][0] == channel ) {
969             return chan_freq_list[i][1];
970         }
971     }
972
973     return 0;
974 } // wl_get_freq_from_chan
975 /*============================================================================*/
976
977
978
979
980 /*******************************************************************************
981  *      wl_get_chan_from_freq()
982  *******************************************************************************
983  *
984  *  DESCRIPTION:
985  *
986  *      Function used to look up the channel for a given frequency on which the
987  *      adapter is Tx/Rx.
988  *
989  *  PARAMETERS:
990  *
991  *      frequency - the frequency
992  *
993  *  RETURNS:
994  *
995  *      The corresponding channel
996  *
997  ******************************************************************************/
998 int wl_get_chan_from_freq( long frequency )
999 {
1000     int i;
1001     /*------------------------------------------------------------------------*/
1002
1003
1004     /* Iterate through the matrix and retrieve the channel */
1005     for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
1006         if( chan_freq_list[i][1] == frequency ) {
1007             return chan_freq_list[i][0];
1008         }
1009     }
1010
1011     return 0;
1012 } // wl_get_chan_from_freq
1013 /*============================================================================*/
1014
1015
1016
1017
1018 /*******************************************************************************
1019  *      wl_process_link_status()
1020  *******************************************************************************
1021  *
1022  *  DESCRIPTION:
1023  *
1024  *      Process the link status message signaled by the device.
1025  *
1026  *  PARAMETERS:
1027  *
1028  *      lp - a pointer to the device's private structure
1029  *
1030  *  RETURNS:
1031  *
1032  *      N/A
1033  *
1034  ******************************************************************************/
1035 void wl_process_link_status( struct wl_private *lp )
1036 {
1037     hcf_16 link_stat;
1038     /*------------------------------------------------------------------------*/
1039
1040     DBG_FUNC( "wl_process_link_status" );
1041     DBG_ENTER( DbgInfo );
1042
1043     if( lp != NULL ) {
1044         //link_stat = lp->hcfCtx.IFB_DSLinkStat & CFG_LINK_STAT_FW;
1045         link_stat = lp->hcfCtx.IFB_LinkStat & CFG_LINK_STAT_FW;
1046         switch( link_stat ) {
1047         case 1:
1048             DBG_TRACE( DbgInfo, "Link Status : Connected\n" );
1049             wl_wext_event_ap( lp->dev );
1050             break;
1051         case 2:
1052             DBG_TRACE( DbgInfo, "Link Status : Disconnected\n"  );
1053             break;
1054         case 3:
1055             DBG_TRACE( DbgInfo, "Link Status : Access Point Change\n" );
1056             break;
1057         case 4:
1058             DBG_TRACE( DbgInfo, "Link Status : Access Point Out of Range\n" );
1059             break;
1060         case 5:
1061             DBG_TRACE( DbgInfo, "Link Status : Access Point In Range\n" );
1062             break;
1063         default:
1064             DBG_TRACE( DbgInfo, "Link Status : UNKNOWN (0x%04x)\n", link_stat );
1065             break;
1066         }
1067     }
1068     DBG_LEAVE( DbgInfo );
1069     return;
1070 } // wl_process_link_status
1071 /*============================================================================*/
1072
1073
1074
1075
1076 /*******************************************************************************
1077  *      wl_process_probe_response()
1078  *******************************************************************************
1079  *
1080  *  DESCRIPTION:
1081  *
1082  *      Process the probe responses retunred by the device as a result of an
1083  *      active scan.
1084  *
1085  *  PARAMETERS:
1086  *
1087  *      lp - a pointer to the device's private structure
1088  *
1089  *  RETURNS:
1090  *
1091  *      N/A
1092  *
1093  ******************************************************************************/
1094 void wl_process_probe_response( struct wl_private *lp )
1095 {
1096     PROBE_RESP  *probe_rsp;
1097     hcf_8       *wpa_ie = NULL;
1098     hcf_16      wpa_ie_len = 0;
1099     /*------------------------------------------------------------------------*/
1100
1101
1102     DBG_FUNC( "wl_process_probe_response" );
1103     DBG_ENTER( DbgInfo );
1104
1105
1106     if( lp != NULL ) {
1107         probe_rsp = (PROBE_RESP *)&lp->ProbeResp;
1108
1109         wl_endian_translate_event( (ltv_t *)probe_rsp );
1110
1111         DBG_TRACE( DbgInfo, "(%s) =========================\n", lp->dev->name );
1112         DBG_TRACE( DbgInfo, "(%s) length      : 0x%04x.\n",  lp->dev->name,
1113                 probe_rsp->length );
1114
1115         if( probe_rsp->length > 1 ) {
1116             DBG_TRACE( DbgInfo, "(%s) infoType    : 0x%04x.\n", lp->dev->name,
1117                     probe_rsp->infoType );
1118
1119             DBG_TRACE( DbgInfo, "(%s) signal      : 0x%02x.\n", lp->dev->name,
1120                     probe_rsp->signal );
1121
1122             DBG_TRACE( DbgInfo, "(%s) silence     : 0x%02x.\n", lp->dev->name,
1123                     probe_rsp->silence );
1124
1125             DBG_TRACE( DbgInfo, "(%s) rxFlow      : 0x%02x.\n", lp->dev->name,
1126                     probe_rsp->rxFlow );
1127
1128             DBG_TRACE( DbgInfo, "(%s) rate        : 0x%02x.\n", lp->dev->name,
1129                     probe_rsp->rate );
1130
1131             DBG_TRACE( DbgInfo, "(%s) frame cntl  : 0x%04x.\n", lp->dev->name,
1132                     probe_rsp->frameControl );
1133
1134             DBG_TRACE( DbgInfo, "(%s) durID       : 0x%04x.\n", lp->dev->name,
1135                     probe_rsp->durID );
1136
1137             DBG_TRACE( DbgInfo, "(%s) address1    : %s\n", lp->dev->name,
1138                     DbgHwAddr( probe_rsp->address1 ));
1139
1140             DBG_TRACE( DbgInfo, "(%s) address2    : %s\n", lp->dev->name,
1141                     DbgHwAddr( probe_rsp->address2 ));
1142
1143             DBG_TRACE( DbgInfo, "(%s) BSSID       : %s\n", lp->dev->name,
1144                     DbgHwAddr( probe_rsp->BSSID ));
1145
1146             DBG_TRACE( DbgInfo, "(%s) sequence    : 0x%04x.\n", lp->dev->name,
1147                     probe_rsp->sequence );
1148
1149             DBG_TRACE( DbgInfo, "(%s) address4    : %s\n", lp->dev->name,
1150                     DbgHwAddr( probe_rsp->address4 ));
1151
1152             DBG_TRACE( DbgInfo, "(%s) datalength  : 0x%04x.\n", lp->dev->name,
1153                     probe_rsp->dataLength );
1154
1155             DBG_TRACE( DbgInfo, "(%s) DA          : %s\n", lp->dev->name,
1156                     DbgHwAddr( probe_rsp->DA ));
1157
1158             DBG_TRACE( DbgInfo, "(%s) SA          : %s\n", lp->dev->name,
1159                     DbgHwAddr( probe_rsp->SA ));
1160
1161 #ifdef WARP
1162
1163             DBG_TRACE( DbgInfo, "(%s) channel     : %d\n", lp->dev->name,
1164                     probe_rsp->channel );
1165
1166             DBG_TRACE( DbgInfo, "(%s) band        : %d\n", lp->dev->name,
1167                     probe_rsp->band );
1168 #else
1169             DBG_TRACE( DbgInfo, "(%s) lenType     : 0x%04x.\n", lp->dev->name,
1170                     probe_rsp->lenType );
1171 #endif  // WARP
1172
1173             DBG_TRACE( DbgInfo, "(%s) timeStamp   : %d.%d.%d.%d.%d.%d.%d.%d\n",
1174                     lp->dev->name,
1175                     probe_rsp->timeStamp[0],
1176                     probe_rsp->timeStamp[1],
1177                     probe_rsp->timeStamp[2],
1178                     probe_rsp->timeStamp[3],
1179                     probe_rsp->timeStamp[4],
1180                     probe_rsp->timeStamp[5],
1181                     probe_rsp->timeStamp[6],
1182                     probe_rsp->timeStamp[7]);
1183
1184             DBG_TRACE( DbgInfo, "(%s) beaconInt   : 0x%04x.\n", lp->dev->name,
1185                     probe_rsp->beaconInterval );
1186
1187             DBG_TRACE( DbgInfo, "(%s) capability  : 0x%04x.\n", lp->dev->name,
1188                     probe_rsp->capability );
1189
1190             DBG_TRACE( DbgInfo, "(%s) SSID len    : 0x%04x.\n", lp->dev->name,
1191                     probe_rsp->rawData[1] );
1192
1193
1194             if( probe_rsp->rawData[1] > 0 ) {
1195                 char ssid[HCF_MAX_NAME_LEN];
1196
1197                 memset( ssid, 0, sizeof( ssid ));
1198                 strncpy( ssid, &probe_rsp->rawData[2],
1199                             probe_rsp->rawData[1] );
1200
1201                 DBG_TRACE( DbgInfo, "(%s) SSID        : %s\n",
1202                             lp->dev->name, ssid );
1203             }
1204
1205
1206             /* Parse out the WPA-IE, if one exists */
1207             wpa_ie = wl_parse_wpa_ie( probe_rsp, &wpa_ie_len );
1208             if( wpa_ie != NULL ) {
1209                 DBG_TRACE( DbgInfo, "(%s) WPA-IE      : %s\n",
1210                 lp->dev->name, wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
1211             }
1212
1213             DBG_TRACE( DbgInfo, "(%s) flags       : 0x%04x.\n",
1214                         lp->dev->name, probe_rsp->flags );
1215         }
1216
1217         DBG_TRACE( DbgInfo, "\n" );
1218
1219
1220         /* If probe response length is 1, then the scan is complete */
1221         if( probe_rsp->length == 1 ) {
1222             DBG_TRACE( DbgInfo, "SCAN COMPLETE\n" );
1223             lp->probe_results.num_aps = lp->probe_num_aps;
1224             lp->probe_results.scan_complete = TRUE;
1225
1226             /* Reset the counter for the next scan request */
1227             lp->probe_num_aps = 0;
1228
1229             /* Send a wireless extensions event that the scan completed */
1230             wl_wext_event_scan_complete( lp->dev );
1231         } else {
1232             /* Only copy to the table if the entry is unique; APs sometimes
1233                 respond more than once to a probe */
1234             if( lp->probe_num_aps == 0 ) {
1235                 /* Copy the info to the ScanResult structure in the private
1236                 adapter struct */
1237                 memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1238                         probe_rsp, sizeof( PROBE_RESP ));
1239
1240                 /* Increment the number of APs detected */
1241                 lp->probe_num_aps++;
1242             } else {
1243                 int count;
1244                 int unique = 1;
1245
1246                 for( count = 0; count < lp->probe_num_aps; count++ ) {
1247                     if( memcmp( &( probe_rsp->BSSID ),
1248                         lp->probe_results.ProbeTable[count].BSSID,
1249                         ETH_ALEN ) == 0 ) {
1250                         unique = 0;
1251                     }
1252                 }
1253
1254                 if( unique ) {
1255                     /* Copy the info to the ScanResult structure in the
1256                     private adapter struct. Only copy if there's room in the
1257                     table */
1258                     if( lp->probe_num_aps < MAX_NAPS )
1259                     {
1260                         memcpy( &( lp->probe_results.ProbeTable[lp->probe_num_aps] ),
1261                                 probe_rsp, sizeof( PROBE_RESP ));
1262                     }
1263                     else
1264                     {
1265                         DBG_WARNING( DbgInfo, "Num of scan results exceeds storage, truncating\n" );
1266                     }
1267
1268                     /* Increment the number of APs detected. Note I do this
1269                         here even when I don't copy the probe response to the
1270                         buffer in order to detect the overflow condition */
1271                     lp->probe_num_aps++;
1272                 }
1273             }
1274         }
1275     }
1276
1277     DBG_LEAVE( DbgInfo );
1278     return;
1279 } // wl_process_probe_response
1280 /*============================================================================*/
1281
1282
1283
1284
1285 /*******************************************************************************
1286  *      wl_process_updated_record()
1287  *******************************************************************************
1288  *
1289  *  DESCRIPTION:
1290  *
1291  *      Process the updated information record message signaled by the device.
1292  *
1293  *  PARAMETERS:
1294  *
1295  *      lp - a pointer to the device's private structure
1296  *
1297  *  RETURNS:
1298  *
1299  *      N/A
1300  *
1301  ******************************************************************************/
1302 void wl_process_updated_record( struct wl_private *lp )
1303 {
1304     DBG_FUNC( "wl_process_updated_record" );
1305     DBG_ENTER( DbgInfo );
1306
1307
1308     if( lp != NULL ) {
1309         lp->updatedRecord.u.u16[0] = CNV_LITTLE_TO_INT( lp->updatedRecord.u.u16[0] );
1310
1311         switch( lp->updatedRecord.u.u16[0] ) {
1312         case CFG_CUR_COUNTRY_INFO:
1313             DBG_TRACE( DbgInfo, "Updated Record: CFG_CUR_COUNTRY_INFO\n" );
1314             wl_connect( lp );
1315             break;
1316
1317         case CFG_PORT_STAT:
1318             DBG_TRACE( DbgInfo, "Updated Record: WAIT_FOR_CONNECT (0xFD40)\n" );
1319             //wl_connect( lp );
1320             break;
1321
1322         default:
1323             DBG_TRACE( DbgInfo, "UNKNOWN: 0x%04x\n",
1324                        lp->updatedRecord.u.u16[0] );
1325         }
1326     }
1327
1328     DBG_LEAVE( DbgInfo );
1329     return;
1330 } // wl_process_updated_record
1331 /*============================================================================*/
1332
1333
1334
1335
1336 /*******************************************************************************
1337  *      wl_process_assoc_status()
1338  *******************************************************************************
1339  *
1340  *  DESCRIPTION:
1341  *
1342  *      Process the association status event signaled by the device.
1343  *
1344  *  PARAMETERS:
1345  *
1346  *      lp - a pointer to the device's private structure
1347  *
1348  *  RETURNS:
1349  *
1350  *      N/A
1351  *
1352  ******************************************************************************/
1353 void wl_process_assoc_status( struct wl_private *lp )
1354 {
1355     ASSOC_STATUS_STRCT *assoc_stat;
1356     /*------------------------------------------------------------------------*/
1357
1358
1359     DBG_FUNC( "wl_process_assoc_status" );
1360     DBG_ENTER( DbgInfo );
1361
1362
1363     if( lp != NULL ) {
1364         assoc_stat = (ASSOC_STATUS_STRCT *)&lp->assoc_stat;
1365
1366         wl_endian_translate_event( (ltv_t *)assoc_stat );
1367
1368         switch( assoc_stat->assocStatus ) {
1369         case 1:
1370             DBG_TRACE( DbgInfo, "Association Status : STA Associated\n" );
1371             break;
1372
1373         case 2:
1374             DBG_TRACE( DbgInfo, "Association Status : STA Reassociated\n" );
1375             break;
1376
1377         case 3:
1378             DBG_TRACE( DbgInfo, "Association Status : STA Disassociated\n" );
1379             break;
1380
1381         default:
1382             DBG_TRACE( DbgInfo, "Association Status : UNKNOWN (0x%04x)\n",
1383                         assoc_stat->assocStatus );
1384             break;
1385         }
1386
1387         DBG_TRACE( DbgInfo, "STA Address        : %s\n",
1388                     DbgHwAddr( assoc_stat->staAddr ));
1389
1390         if(( assoc_stat->assocStatus == 2 )  && ( assoc_stat->len == 8 )) {
1391             DBG_TRACE( DbgInfo, "Old AP Address     : %s\n",
1392                         DbgHwAddr( assoc_stat->oldApAddr ));
1393         }
1394     }
1395
1396     DBG_LEAVE( DbgInfo );
1397     return;
1398 } // wl_process_assoc_status
1399 /*============================================================================*/
1400
1401
1402
1403
1404 /*******************************************************************************
1405  *      wl_process_security_status()
1406  *******************************************************************************
1407  *
1408  *  DESCRIPTION:
1409  *
1410  *      Process the security status message signaled by the device.
1411  *
1412  *  PARAMETERS:
1413  *
1414  *      lp - a pointer to the device's private structure
1415  *
1416  *  RETURNS:
1417  *
1418  *      N/A
1419  *
1420  ******************************************************************************/
1421 void wl_process_security_status( struct wl_private *lp )
1422 {
1423     SECURITY_STATUS_STRCT *sec_stat;
1424     /*------------------------------------------------------------------------*/
1425
1426
1427     DBG_FUNC( "wl_process_security_status" );
1428     DBG_ENTER( DbgInfo );
1429
1430
1431     if( lp != NULL ) {
1432         sec_stat = (SECURITY_STATUS_STRCT *)&lp->sec_stat;
1433
1434         wl_endian_translate_event( (ltv_t *)sec_stat );
1435
1436         switch( sec_stat->securityStatus ) {
1437         case 1:
1438             DBG_TRACE( DbgInfo, "Security Status : Dissassociate [AP]\n" );
1439             break;
1440
1441         case 2:
1442             DBG_TRACE( DbgInfo, "Security Status : Deauthenticate [AP]\n" );
1443             break;
1444
1445         case 3:
1446             DBG_TRACE( DbgInfo, "Security Status : Authenticate Fail [STA] or [AP]\n" );
1447             break;
1448
1449         case 4:
1450             DBG_TRACE( DbgInfo, "Security Status : MIC Fail\n" );
1451             break;
1452
1453         case 5:
1454             DBG_TRACE( DbgInfo, "Security Status : Associate Fail\n" );
1455             break;
1456
1457         default:
1458             DBG_TRACE( DbgInfo, "Security Status : UNKNOWN (0x%04x)\n",
1459                         sec_stat->securityStatus );
1460             break;
1461         }
1462
1463         DBG_TRACE( DbgInfo, "STA Address     : %s\n",
1464                    DbgHwAddr( sec_stat->staAddr ));
1465         DBG_TRACE( DbgInfo, "Reason          : 0x%04x \n", sec_stat->reason );
1466
1467     }
1468
1469     DBG_LEAVE( DbgInfo );
1470     return;
1471 } // wl_process_security_status
1472 /*============================================================================*/
1473
1474 int wl_get_tallies(struct wl_private *lp,
1475                    CFG_HERMES_TALLIES_STRCT *tallies)
1476 {
1477     int ret = 0;
1478     int status;
1479     CFG_HERMES_TALLIES_STRCT *pTallies;
1480
1481     DBG_FUNC( "wl_get_tallies" );
1482     DBG_ENTER(DbgInfo);
1483
1484     /* Get the current tallies from the adapter */
1485     lp->ltvRecord.len = 1 + HCF_TOT_TAL_CNT * sizeof(hcf_16);
1486     lp->ltvRecord.typ = CFG_TALLIES;
1487
1488     status = hcf_get_info(&(lp->hcfCtx), (LTVP)&(lp->ltvRecord));
1489
1490     if( status == HCF_SUCCESS ) {
1491         pTallies = (CFG_HERMES_TALLIES_STRCT *)&(lp->ltvRecord.u.u32);
1492         memcpy(tallies, pTallies, sizeof(*tallies));
1493         DBG_TRACE( DbgInfo, "Get tallies okay, dixe: %d\n", sizeof(*tallies) );
1494     } else {
1495         DBG_TRACE( DbgInfo, "Get tallies failed\n" );
1496         ret = -EFAULT;
1497     }
1498
1499     DBG_LEAVE( DbgInfo );
1500
1501     return ret;
1502 }
1503