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