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) <v );
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