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