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 * SOFTWARE LICENSE
15 *
16 * This software is provided subject to the following terms and conditions,
17 * which you should read carefully before using the software. Using this
18 * software indicates your acceptance of these terms and conditions. If you do
19 * not agree with these terms and conditions, do not use the software.
20 *
21 * Copyright � 2003 Agere Systems Inc.
22 * All rights reserved.
23 *
24 * Redistribution and use in source or binary forms, with or without
25 * modifications, are permitted provided that the following conditions are met:
26 *
27 * . Redistributions of source code must retain the above copyright notice, this
28 * list of conditions and the following Disclaimer as comments in the code as
29 * well as in the documentation and/or other materials provided with the
30 * distribution.
31 *
32 * . Redistributions in binary form must reproduce the above copyright notice,
33 * this list of conditions and the following Disclaimer in the documentation
34 * and/or other materials provided with the distribution.
35 *
36 * . Neither the name of Agere Systems Inc. nor the names of the contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * Disclaimer
41 *
42 * THIS SOFTWARE IS PROVIDED �AS IS� AND ANY EXPRESS OR IMPLIED WARRANTIES,
43 * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
44 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
45 * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
46 * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
48 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
50 * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53 * DAMAGE.
54 *
55 ******************************************************************************/
56
57 /*******************************************************************************
58 * include files
59 ******************************************************************************/
60 #include <wl_version.h>
61
62 #include <linux/if_arp.h>
63 #include <linux/ioport.h>
64 #include <linux/delay.h>
65 #include <asm/uaccess.h>
66
67 #include <debug.h>
68 #include <hcf.h>
69 #include <hcfdef.h>
70
71 #include <wl_if.h>
72 #include <wl_internal.h>
73 #include <wl_util.h>
74 #include <wl_main.h>
75 #include <wl_wext.h>
76 #include <wl_priv.h>
77
78
79
80 /* If WIRELESS_EXT is not defined (as a result of HAS_WIRELESS_EXTENSIONS
81 #including linux/wireless.h), then these functions do not need to be included
82 in the build. */
83 #ifdef WIRELESS_EXT
84
85 #define IWE_STREAM_ADD_EVENT(info, buf, end, iwe, len) \
86 iwe_stream_add_event(info, buf, end, iwe, len)
87 #define IWE_STREAM_ADD_POINT(info, buf, end, iwe, msg) \
88 iwe_stream_add_point(info, buf, end, iwe, msg)
89
90
91
92 /*******************************************************************************
93 * global definitions
94 ******************************************************************************/
95 #if DBG
96 extern dbg_info_t *DbgInfo;
97 #endif // DBG
98
99
100
101
102 /*******************************************************************************
103 * wireless_commit()
104 *******************************************************************************
105 *
106 * DESCRIPTION:
107 *
108 * Commit
109 * protocol used.
110 *
111 * PARAMETERS:
112 *
113 * wrq - the wireless request buffer
114 *
115 * RETURNS:
116 *
117 * N/A
118 *
119 ******************************************************************************/
wireless_commit(struct net_device * dev,struct iw_request_info * info,union iwreq_data * rqu,char * extra)120 static int wireless_commit(struct net_device *dev,
121 struct iw_request_info *info,
122 union iwreq_data *rqu, char *extra)
123 {
124 struct wl_private *lp = wl_priv(dev);
125 unsigned long flags;
126 int ret = 0;
127 /*------------------------------------------------------------------------*/
128
129 DBG_FUNC( "wireless_commit" );
130 DBG_ENTER(DbgInfo);
131
132 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
133 ret = -EBUSY;
134 goto out;
135 }
136
137 wl_lock( lp, &flags );
138
139 wl_act_int_off( lp );
140
141 wl_apply(lp);
142
143 wl_act_int_on( lp );
144
145 wl_unlock(lp, &flags);
146
147 out:
148 DBG_LEAVE( DbgInfo );
149 return ret;
150 } // wireless_commit
151 /*============================================================================*/
152
153
154
155
156 /*******************************************************************************
157 * wireless_get_protocol()
158 *******************************************************************************
159 *
160 * DESCRIPTION:
161 *
162 * Returns a vendor-defined string that should identify the wireless
163 * protocol used.
164 *
165 * PARAMETERS:
166 *
167 * wrq - the wireless request buffer
168 *
169 * RETURNS:
170 *
171 * N/A
172 *
173 ******************************************************************************/
wireless_get_protocol(struct net_device * dev,struct iw_request_info * info,char * name,char * extra)174 static int wireless_get_protocol(struct net_device *dev, struct iw_request_info *info, char *name, char *extra)
175 {
176 DBG_FUNC( "wireless_get_protocol" );
177 DBG_ENTER( DbgInfo );
178
179 /* Originally, the driver was placing the string "Wireless" here. However,
180 the wireless extensions (/linux/wireless.h) indicate this string should
181 describe the wireless protocol. */
182
183 strcpy(name, "IEEE 802.11b");
184
185 DBG_LEAVE(DbgInfo);
186 return 0;
187 } // wireless_get_protocol
188 /*============================================================================*/
189
190
191
192
193 /*******************************************************************************
194 * wireless_set_frequency()
195 *******************************************************************************
196 *
197 * DESCRIPTION:
198 *
199 * Sets the frequency (channel) on which the card should Tx/Rx.
200 *
201 * PARAMETERS:
202 *
203 * wrq - the wireless request buffer
204 * lp - the device's private adapter structure
205 *
206 * RETURNS:
207 *
208 * 0 on success
209 * errno value otherwise
210 *
211 ******************************************************************************/
wireless_set_frequency(struct net_device * dev,struct iw_request_info * info,struct iw_freq * freq,char * extra)212 static int wireless_set_frequency(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra)
213 {
214 struct wl_private *lp = wl_priv(dev);
215 unsigned long flags;
216 int channel = 0;
217 int ret = 0;
218 /*------------------------------------------------------------------------*/
219
220
221 DBG_FUNC( "wireless_set_frequency" );
222 DBG_ENTER( DbgInfo );
223
224 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
225 ret = -EBUSY;
226 goto out;
227 }
228
229 if( !capable( CAP_NET_ADMIN )) {
230 ret = -EPERM;
231 DBG_LEAVE( DbgInfo );
232 return ret;
233 }
234
235
236 /* If frequency specified, look up channel */
237 if( freq->e == 1 ) {
238 int f = freq->m / 100000;
239 channel = wl_get_chan_from_freq( f );
240 }
241
242
243 /* Channel specified */
244 if( freq->e == 0 ) {
245 channel = freq->m;
246 }
247
248
249 /* If the channel is an 802.11a channel, set Bit 8 */
250 if( channel > 14 ) {
251 channel = channel | 0x100;
252 }
253
254
255 wl_lock( lp, &flags );
256
257 wl_act_int_off( lp );
258
259 lp->Channel = channel;
260
261
262 /* Commit the adapter parameters */
263 wl_apply( lp );
264
265 /* Send an event that channel/freq has been set */
266 wl_wext_event_freq( lp->dev );
267
268 wl_act_int_on( lp );
269
270 wl_unlock(lp, &flags);
271
272 out:
273 DBG_LEAVE( DbgInfo );
274 return ret;
275 } // wireless_set_frequency
276 /*============================================================================*/
277
278
279
280
281 /*******************************************************************************
282 * wireless_get_frequency()
283 *******************************************************************************
284 *
285 * DESCRIPTION:
286 *
287 * Gets the frequency (channel) on which the card is Tx/Rx.
288 *
289 * PARAMETERS:
290 *
291 * wrq - the wireless request buffer
292 * lp - the device's private adapter structure
293 *
294 * RETURNS:
295 *
296 * N/A
297 *
298 ******************************************************************************/
wireless_get_frequency(struct net_device * dev,struct iw_request_info * info,struct iw_freq * freq,char * extra)299 static int wireless_get_frequency(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra)
300
301 {
302 struct wl_private *lp = wl_priv(dev);
303 unsigned long flags;
304 int ret = -1;
305 /*------------------------------------------------------------------------*/
306
307
308 DBG_FUNC( "wireless_get_frequency" );
309 DBG_ENTER( DbgInfo );
310
311 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
312 ret = -EBUSY;
313 goto out;
314 }
315
316 wl_lock( lp, &flags );
317
318 wl_act_int_off( lp );
319
320 lp->ltvRecord.len = 2;
321 lp->ltvRecord.typ = CFG_CUR_CHANNEL;
322
323 ret = hcf_get_info( &(lp->hcfCtx), (LTVP)&( lp->ltvRecord ));
324 if( ret == HCF_SUCCESS ) {
325 hcf_16 channel = CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] );
326
327 #ifdef USE_FREQUENCY
328
329 freq->m = wl_get_freq_from_chan( channel ) * 100000;
330 freq->e = 1;
331 #else
332
333 freq->m = channel;
334 freq->e = 0;
335
336 #endif /* USE_FREQUENCY */
337 }
338
339 wl_act_int_on( lp );
340
341 wl_unlock(lp, &flags);
342
343 ret = (ret == HCF_SUCCESS ? 0 : -EFAULT);
344
345 out:
346 DBG_LEAVE( DbgInfo );
347 return ret;
348 } // wireless_get_frequency
349 /*============================================================================*/
350
351
352
353
354 /*******************************************************************************
355 * wireless_get_range()
356 *******************************************************************************
357 *
358 * DESCRIPTION:
359 *
360 * This function is used to provide misc info and statistics about the
361 * wireless device.
362 *
363 * PARAMETERS:
364 *
365 * wrq - the wireless request buffer
366 * lp - the device's private adapter structure
367 *
368 * RETURNS:
369 *
370 * 0 on success
371 * errno value otherwise
372 *
373 ******************************************************************************/
wireless_get_range(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)374 static int wireless_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
375 {
376 struct wl_private *lp = wl_priv(dev);
377 unsigned long flags;
378 struct iw_range *range = (struct iw_range *) extra;
379 int ret = 0;
380 int status = -1;
381 int count;
382 __u16 *pTxRate;
383 int retries = 0;
384 /*------------------------------------------------------------------------*/
385
386
387 DBG_FUNC( "wireless_get_range" );
388 DBG_ENTER( DbgInfo );
389
390 /* Set range information */
391 data->length = sizeof(struct iw_range);
392 memset(range, 0, sizeof(struct iw_range));
393
394 wl_lock( lp, &flags );
395
396 wl_act_int_off( lp );
397
398 /* Set range information */
399 memset( range, 0, sizeof( struct iw_range ));
400
401 retry:
402 /* Get the current transmit rate from the adapter */
403 lp->ltvRecord.len = 1 + (sizeof(*pTxRate) / sizeof(hcf_16));
404 lp->ltvRecord.typ = CFG_CUR_TX_RATE;
405
406 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
407 if( status != HCF_SUCCESS ) {
408 /* Recovery action: reset and retry up to 10 times */
409 DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE failed: 0x%x\n", status );
410
411 if (retries < 10) {
412 retries++;
413
414 /* Holding the lock too long, make a gap to allow other processes */
415 wl_unlock(lp, &flags);
416 wl_lock( lp, &flags );
417
418 status = wl_reset( dev );
419 if ( status != HCF_SUCCESS ) {
420 DBG_TRACE( DbgInfo, "reset failed: 0x%x\n", status );
421
422 ret = -EFAULT;
423 goto out_unlock;
424 }
425
426 /* Holding the lock too long, make a gap to allow other processes */
427 wl_unlock(lp, &flags);
428 wl_lock( lp, &flags );
429
430 goto retry;
431
432 } else {
433 DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE failed: %d retries\n", retries );
434 ret = -EFAULT;
435 goto out_unlock;
436 }
437 }
438
439 /* Holding the lock too long, make a gap to allow other processes */
440 wl_unlock(lp, &flags);
441 wl_lock( lp, &flags );
442
443 pTxRate = (__u16 *)&( lp->ltvRecord.u.u32 );
444
445 range->throughput = CNV_LITTLE_TO_INT( *pTxRate ) * MEGABIT;
446
447 if (retries > 0) {
448 DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE succes: %d retries\n", retries );
449 }
450
451 // NWID - NOT SUPPORTED
452
453
454 /* Channel/Frequency Info */
455 range->num_channels = RADIO_CHANNELS;
456
457
458 /* Signal Level Thresholds */
459 range->sensitivity = RADIO_SENSITIVITY_LEVELS;
460
461
462 /* Link quality */
463 #ifdef USE_DBM
464
465 range->max_qual.qual = (u_char)HCF_MAX_COMM_QUALITY;
466
467 /* If the value returned in /proc/net/wireless is greater than the maximum range,
468 iwconfig assumes that the value is in dBm. Because an unsigned char is used,
469 it requires a bit of contorsion... */
470
471 range->max_qual.level = (u_char)( dbm( HCF_MIN_SIGNAL_LEVEL ) - 1 );
472 range->max_qual.noise = (u_char)( dbm( HCF_MIN_NOISE_LEVEL ) - 1 );
473 #else
474
475 range->max_qual.qual = 100;
476 range->max_qual.level = 100;
477 range->max_qual.noise = 100;
478
479 #endif /* USE_DBM */
480
481
482 /* Set available rates */
483 range->num_bitrates = 0;
484
485 lp->ltvRecord.len = 6;
486 lp->ltvRecord.typ = CFG_SUPPORTED_DATA_RATES;
487
488 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
489 if( status == HCF_SUCCESS ) {
490 for( count = 0; count < MAX_RATES; count++ )
491 if( lp->ltvRecord.u.u8[count+2] != 0 ) {
492 range->bitrate[count] = lp->ltvRecord.u.u8[count+2] * MEGABIT / 2;
493 range->num_bitrates++;
494 }
495 } else {
496 DBG_TRACE( DbgInfo, "CFG_SUPPORTED_DATA_RATES: 0x%x\n", status );
497 ret = -EFAULT;
498 goto out_unlock;
499 }
500
501 /* RTS Threshold info */
502 range->min_rts = MIN_RTS_BYTES;
503 range->max_rts = MAX_RTS_BYTES;
504
505 // Frag Threshold info - NOT SUPPORTED
506
507 // Power Management info - NOT SUPPORTED
508
509 /* Encryption */
510
511 #if WIRELESS_EXT > 8
512
513 /* Holding the lock too long, make a gap to allow other processes */
514 wl_unlock(lp, &flags);
515 wl_lock( lp, &flags );
516
517 /* Is WEP supported? */
518
519 if( wl_has_wep( &( lp->hcfCtx ))) {
520 /* WEP: RC4 40 bits */
521 range->encoding_size[0] = MIN_KEY_SIZE;
522
523 /* RC4 ~128 bits */
524 range->encoding_size[1] = MAX_KEY_SIZE;
525 range->num_encoding_sizes = 2;
526 range->max_encoding_tokens = MAX_KEYS;
527 }
528
529 #endif /* WIRELESS_EXT > 8 */
530
531 /* Tx Power Info */
532 range->txpower_capa = IW_TXPOW_MWATT;
533 range->num_txpower = 1;
534 range->txpower[0] = RADIO_TX_POWER_MWATT;
535
536 #if WIRELESS_EXT > 10
537
538 /* Wireless Extension Info */
539 range->we_version_compiled = WIRELESS_EXT;
540 range->we_version_source = WIRELESS_SUPPORT;
541
542 // Retry Limits and Lifetime - NOT SUPPORTED
543
544 #endif
545
546
547 #if WIRELESS_EXT > 11
548
549 /* Holding the lock too long, make a gap to allow other processes */
550 wl_unlock(lp, &flags);
551 wl_lock( lp, &flags );
552
553 DBG_TRACE( DbgInfo, "calling wl_wireless_stats\n" );
554 wl_wireless_stats( lp->dev );
555 range->avg_qual = lp->wstats.qual;
556 DBG_TRACE( DbgInfo, "wl_wireless_stats done\n" );
557
558 #endif
559
560 /* Event capability (kernel + driver) */
561 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
562 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
563 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
564 range->event_capa[1] = IW_EVENT_CAPA_K_1;
565 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
566 IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
567 IW_EVENT_CAPA_MASK(IWEVEXPIRED));
568
569 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
570
571 out_unlock:
572 wl_act_int_on( lp );
573
574 wl_unlock(lp, &flags);
575
576 DBG_LEAVE(DbgInfo);
577 return ret;
578 } // wireless_get_range
579 /*============================================================================*/
580
581
582 /*******************************************************************************
583 * wireless_get_bssid()
584 *******************************************************************************
585 *
586 * DESCRIPTION:
587 *
588 * Gets the BSSID the wireless device is currently associated with.
589 *
590 * PARAMETERS:
591 *
592 * wrq - the wireless request buffer
593 * lp - the device's private adapter structure
594 *
595 * RETURNS:
596 *
597 * 0 on success
598 * errno value otherwise
599 *
600 ******************************************************************************/
wireless_get_bssid(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)601 static int wireless_get_bssid(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
602 {
603 struct wl_private *lp = wl_priv(dev);
604 unsigned long flags;
605 int ret = 0;
606 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
607 int status = -1;
608 #endif /* (HCF_TYPE) & HCF_TYPE_STA */
609 /*------------------------------------------------------------------------*/
610
611
612 DBG_FUNC( "wireless_get_bssid" );
613 DBG_ENTER( DbgInfo );
614
615 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
616 ret = -EBUSY;
617 goto out;
618 }
619
620 wl_lock( lp, &flags );
621
622 wl_act_int_off( lp );
623
624 memset( &ap_addr->sa_data, 0, ETH_ALEN );
625
626 ap_addr->sa_family = ARPHRD_ETHER;
627
628 /* Assume AP mode here, which means the BSSID is our own MAC address. In
629 STA mode, this address will be overwritten with the actual BSSID using
630 the code below. */
631 memcpy(&ap_addr->sa_data, lp->dev->dev_addr, ETH_ALEN);
632
633
634 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
635 //;?should we return an error status in AP mode
636
637 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
638 /* Get Current BSSID */
639 lp->ltvRecord.typ = CFG_CUR_BSSID;
640 lp->ltvRecord.len = 4;
641 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
642
643 if( status == HCF_SUCCESS ) {
644 /* Copy info into sockaddr struct */
645 memcpy(&ap_addr->sa_data, lp->ltvRecord.u.u8, ETH_ALEN);
646 } else {
647 ret = -EFAULT;
648 }
649 }
650
651 #endif // (HCF_TYPE) & HCF_TYPE_STA
652
653 wl_act_int_on( lp );
654
655 wl_unlock(lp, &flags);
656
657 out:
658 DBG_LEAVE(DbgInfo);
659 return ret;
660 } // wireless_get_bssid
661 /*============================================================================*/
662
663
664
665
666 /*******************************************************************************
667 * wireless_get_ap_list()
668 *******************************************************************************
669 *
670 * DESCRIPTION:
671 *
672 * Gets the results of a network scan.
673 *
674 * PARAMETERS:
675 *
676 * wrq - the wireless request buffer
677 * lp - the device's private adapter structure
678 *
679 * RETURNS:
680 *
681 * 0 on success
682 * errno value otherwise
683 *
684 * NOTE: SIOCGIWAPLIST has been deprecated by SIOCSIWSCAN. This function
685 * implements SIOCGIWAPLIST only to provide backwards compatibility. For
686 * all systems using WIRELESS_EXT v14 and higher, use SIOCSIWSCAN!
687 *
688 ******************************************************************************/
wireless_get_ap_list(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)689 static int wireless_get_ap_list (struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
690 {
691 struct wl_private *lp = wl_priv(dev);
692 unsigned long flags;
693 int ret;
694 int num_aps = -1;
695 int sec_count = 0;
696 hcf_32 count;
697 struct sockaddr *hwa = NULL;
698 struct iw_quality *qual = NULL;
699 #ifdef WARP
700 ScanResult *p = &lp->scan_results;
701 #else
702 ProbeResult *p = &lp->probe_results;
703 #endif // WARP
704 /*------------------------------------------------------------------------*/
705
706 DBG_FUNC( "wireless_get_ap_list" );
707 DBG_ENTER( DbgInfo );
708
709 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
710 ret = -EBUSY;
711 goto out;
712 }
713
714 wl_lock( lp, &flags );
715
716 wl_act_int_off( lp );
717
718 /* Set the completion state to FALSE */
719 lp->scan_results.scan_complete = FALSE;
720 lp->probe_results.scan_complete = FALSE;
721 /* Channels to scan */
722 lp->ltvRecord.len = 2;
723 lp->ltvRecord.typ = CFG_SCAN_CHANNELS_2GHZ;
724 lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x7FFF );
725 ret = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
726 DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNELS_2GHZ result: 0x%x\n", ret );
727
728 /* Set the SCAN_SSID to "ANY". Using this RID for scan prevents the need to
729 disassociate from the network we are currently on */
730 lp->ltvRecord.len = 2;
731 lp->ltvRecord.typ = CFG_SCAN_SSID;
732 lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
733 ret = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
734 DBG_TRACE( DbgInfo, "CFG_SCAN_SSID to 'any' ret: 0x%x\n", ret );
735
736 /* Initiate the scan */
737 #ifdef WARP
738 ret = hcf_action( &( lp->hcfCtx ), MDD_ACT_SCAN );
739 #else
740 ret = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN );
741 #endif // WARP
742
743 wl_act_int_on( lp );
744
745 //;? unlock? what about the access to lp below? is it broken?
746 wl_unlock(lp, &flags);
747
748 if( ret == HCF_SUCCESS ) {
749 DBG_TRACE( DbgInfo, "SUCCESSFULLY INITIATED SCAN...\n" );
750 while( (*p).scan_complete == FALSE && ret == HCF_SUCCESS ) {
751 DBG_TRACE( DbgInfo, "Waiting for scan results...\n" );
752 /* Abort the scan if we've waited for more than MAX_SCAN_TIME_SEC */
753 if( sec_count++ > MAX_SCAN_TIME_SEC ) {
754 ret = -EIO;
755 } else {
756 /* Wait for 1 sec in 10ms intervals, scheduling the kernel to do
757 other things in the meantime, This prevents system lockups by
758 giving some time back to the kernel */
759 for( count = 0; count < 100; count ++ ) {
760 mdelay( 10 );
761 schedule( );
762 }
763 }
764 }
765
766 rmb();
767
768 if ( ret != HCF_SUCCESS ) {
769 DBG_ERROR( DbgInfo, "timeout waiting for scan results\n" );
770 } else {
771 num_aps = (*p)/*lp->probe_results*/.num_aps;
772 if (num_aps > IW_MAX_AP) {
773 num_aps = IW_MAX_AP;
774 }
775 data->length = num_aps;
776 hwa = (struct sockaddr *)extra;
777 qual = (struct iw_quality *) extra +
778 ( sizeof( struct sockaddr ) * num_aps );
779
780 /* This flag is used to tell the user if we provide quality
781 information. Since we provide signal/noise levels but no
782 quality info on a scan, this is set to 0. Setting to 1 and
783 providing a quality of 0 produces weird results. If we ever
784 provide quality (or can calculate it), this can be changed */
785 data->flags = 0;
786
787 for( count = 0; count < num_aps; count++ ) {
788 #ifdef WARP
789 memcpy( hwa[count].sa_data,
790 (*p)/*lp->scan_results*/.APTable[count].bssid, ETH_ALEN );
791 #else //;?why use BSSID and bssid as names in seemingly very comparable situations
792 DBG_PRINT("BSSID: %pM\n",
793 (*p).ProbeTable[count].BSSID);
794 memcpy( hwa[count].sa_data,
795 (*p)/*lp->probe_results*/.ProbeTable[count].BSSID, ETH_ALEN );
796 #endif // WARP
797 }
798 /* Once the data is copied to the wireless struct, invalidate the
799 scan result to initiate a rescan on the next request */
800 (*p)/*lp->probe_results*/.scan_complete = FALSE;
801 /* Send the wireless event that the scan has completed, just in case
802 it's needed */
803 wl_wext_event_scan_complete( lp->dev );
804 }
805 }
806 out:
807 DBG_LEAVE( DbgInfo );
808 return ret;
809 } // wireless_get_ap_list
810 /*============================================================================*/
811
812
813
814
815 /*******************************************************************************
816 * wireless_set_sensitivity()
817 *******************************************************************************
818 *
819 * DESCRIPTION:
820 *
821 * Sets the sensitivity (distance between APs) of the wireless card.
822 *
823 * PARAMETERS:
824 *
825 * wrq - the wireless request buffer
826 * lp - the device's private adapter structure
827 *
828 * RETURNS:
829 *
830 * 0 on success
831 * errno value otherwise
832 *
833 ******************************************************************************/
wireless_set_sensitivity(struct net_device * dev,struct iw_request_info * info,struct iw_param * sens,char * extra)834 static int wireless_set_sensitivity(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra)
835 {
836 struct wl_private *lp = wl_priv(dev);
837 unsigned long flags;
838 int ret = 0;
839 int dens = sens->value;
840 /*------------------------------------------------------------------------*/
841
842
843 DBG_FUNC( "wireless_set_sensitivity" );
844 DBG_ENTER( DbgInfo );
845
846 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
847 ret = -EBUSY;
848 goto out;
849 }
850
851 if(( dens < 1 ) || ( dens > 3 )) {
852 ret = -EINVAL;
853 goto out;
854 }
855
856 wl_lock( lp, &flags );
857
858 wl_act_int_off( lp );
859
860 lp->DistanceBetweenAPs = dens;
861 wl_apply( lp );
862
863 wl_act_int_on( lp );
864
865 wl_unlock(lp, &flags);
866
867 out:
868 DBG_LEAVE( DbgInfo );
869 return ret;
870 } // wireless_set_sensitivity
871 /*============================================================================*/
872
873
874
875
876 /*******************************************************************************
877 * wireless_get_sensitivity()
878 *******************************************************************************
879 *
880 * DESCRIPTION:
881 *
882 * Gets the sensitivity (distance between APs) of the wireless card.
883 *
884 * PARAMETERS:
885 *
886 * wrq - the wireless request buffer
887 * lp - the device's private adapter structure
888 *
889 * RETURNS:
890 *
891 * 0 on success
892 * errno value otherwise
893 *
894 ******************************************************************************/
wireless_get_sensitivity(struct net_device * dev,struct iw_request_info * info,struct iw_param * sens,char * extra)895 static int wireless_get_sensitivity(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra)
896 {
897 struct wl_private *lp = wl_priv(dev);
898 int ret = 0;
899 /*------------------------------------------------------------------------*/
900 /*------------------------------------------------------------------------*/
901
902
903 DBG_FUNC( "wireless_get_sensitivity" );
904 DBG_ENTER( DbgInfo );
905
906 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
907 ret = -EBUSY;
908 goto out;
909 }
910
911 /* not worth locking ... */
912 sens->value = lp->DistanceBetweenAPs;
913 sens->fixed = 0; /* auto */
914 out:
915 DBG_LEAVE( DbgInfo );
916 return ret;
917 } // wireless_get_sensitivity
918 /*============================================================================*/
919
920
921
922
923 /*******************************************************************************
924 * wireless_set_essid()
925 *******************************************************************************
926 *
927 * DESCRIPTION:
928 *
929 * Sets the ESSID (network name) that the wireless device should associate
930 * with.
931 *
932 * PARAMETERS:
933 *
934 * wrq - the wireless request buffer
935 * lp - the device's private adapter structure
936 *
937 * RETURNS:
938 *
939 * 0 on success
940 * errno value otherwise
941 *
942 ******************************************************************************/
wireless_set_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * ssid)943 static int wireless_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid)
944 {
945 struct wl_private *lp = wl_priv(dev);
946 unsigned long flags;
947 int ret = 0;
948
949 DBG_FUNC( "wireless_set_essid" );
950 DBG_ENTER( DbgInfo );
951
952 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
953 ret = -EBUSY;
954 goto out;
955 }
956
957 if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN + 1) {
958 ret = -EINVAL;
959 goto out;
960 }
961
962 wl_lock( lp, &flags );
963
964 wl_act_int_off( lp );
965
966 memset( lp->NetworkName, 0, sizeof( lp->NetworkName ));
967
968 /* data->flags is zero to ask for "any" */
969 if( data->flags == 0 ) {
970 /* Need this because in STAP build PARM_DEFAULT_SSID is "LinuxAP"
971 * ;?but there ain't no STAP anymore*/
972 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
973 strcpy( lp->NetworkName, "ANY" );
974 } else {
975 //strcpy( lp->NetworkName, "ANY" );
976 strcpy( lp->NetworkName, PARM_DEFAULT_SSID );
977 }
978 } else {
979 memcpy( lp->NetworkName, ssid, data->length );
980 }
981
982 DBG_NOTICE( DbgInfo, "set NetworkName: %s\n", ssid );
983
984 /* Commit the adapter parameters */
985 wl_apply( lp );
986
987 /* Send an event that ESSID has been set */
988 wl_wext_event_essid( lp->dev );
989
990 wl_act_int_on( lp );
991
992 wl_unlock(lp, &flags);
993
994 out:
995 DBG_LEAVE( DbgInfo );
996 return ret;
997 } // wireless_set_essid
998 /*============================================================================*/
999
1000
1001
1002
1003 /*******************************************************************************
1004 * wireless_get_essid()
1005 *******************************************************************************
1006 *
1007 * DESCRIPTION:
1008 *
1009 * Gets the ESSID (network name) that the wireless device is associated
1010 * with.
1011 *
1012 * PARAMETERS:
1013 *
1014 * wrq - the wireless request buffer
1015 * lp - the device's private adapter structure
1016 *
1017 * RETURNS:
1018 *
1019 * 0 on success
1020 * errno value otherwise
1021 *
1022 ******************************************************************************/
wireless_get_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * essid)1023 static int wireless_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid)
1024
1025 {
1026 struct wl_private *lp = wl_priv(dev);
1027 unsigned long flags;
1028 int ret = 0;
1029 int status = -1;
1030 wvName_t *pName;
1031 /*------------------------------------------------------------------------*/
1032
1033
1034 DBG_FUNC( "wireless_get_essid" );
1035 DBG_ENTER( DbgInfo );
1036
1037 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1038 ret = -EBUSY;
1039 goto out;
1040 }
1041
1042 wl_lock( lp, &flags );
1043
1044 wl_act_int_off( lp );
1045
1046 /* Get the desired network name */
1047 lp->ltvRecord.len = 1 + ( sizeof( *pName ) / sizeof( hcf_16 ));
1048
1049
1050 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
1051 //;?should we return an error status in AP mode
1052
1053 lp->ltvRecord.typ = CFG_DESIRED_SSID;
1054
1055 #endif
1056
1057
1058 #if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
1059 //;?should we restore this to allow smaller memory footprint
1060
1061 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
1062 lp->ltvRecord.typ = CFG_CNF_OWN_SSID;
1063 }
1064
1065 #endif // HCF_AP
1066
1067
1068 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1069 if( status == HCF_SUCCESS ) {
1070 pName = (wvName_t *)&( lp->ltvRecord.u.u32 );
1071
1072 /* Endian translate the string length */
1073 pName->length = CNV_LITTLE_TO_INT( pName->length );
1074
1075 /* Copy the information into the user buffer */
1076 data->length = pName->length;
1077
1078 /* NOTE: Null terminating is necessary for proper display of the SSID in
1079 the wireless tools */
1080 data->length = pName->length + 1;
1081 if( pName->length < HCF_MAX_NAME_LEN ) {
1082 pName->name[pName->length] = '\0';
1083 }
1084
1085 data->flags = 1;
1086
1087
1088 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
1089 //;?should we return an error status in AP mode
1090 #ifdef RETURN_CURRENT_NETWORKNAME
1091
1092 /* if desired is null ("any"), return current or "any" */
1093 if( pName->name[0] == '\0' ) {
1094 /* Get the current network name */
1095 lp->ltvRecord.len = 1 + ( sizeof(*pName ) / sizeof( hcf_16 ));
1096 lp->ltvRecord.typ = CFG_CUR_SSID;
1097
1098 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1099
1100 if( status == HCF_SUCCESS ) {
1101 pName = (wvName_t *)&( lp->ltvRecord.u.u32 );
1102
1103 /* Endian translate the string length */
1104 pName->length = CNV_LITTLE_TO_INT( pName->length );
1105
1106 /* Copy the information into the user buffer */
1107 data->length = pName->length + 1;
1108 if( pName->length < HCF_MAX_NAME_LEN ) {
1109 pName->name[pName->length] = '\0';
1110 }
1111
1112 data->flags = 1;
1113 } else {
1114 ret = -EFAULT;
1115 goto out_unlock;
1116 }
1117 }
1118
1119 #endif // RETURN_CURRENT_NETWORKNAME
1120 #endif // HCF_STA
1121
1122 data->length--;
1123
1124 if (pName->length > IW_ESSID_MAX_SIZE) {
1125 ret = -EFAULT;
1126 goto out_unlock;
1127 }
1128
1129 memcpy(essid, pName->name, pName->length);
1130 } else {
1131 ret = -EFAULT;
1132 goto out_unlock;
1133 }
1134
1135 out_unlock:
1136 wl_act_int_on( lp );
1137
1138 wl_unlock(lp, &flags);
1139
1140 out:
1141 DBG_LEAVE( DbgInfo );
1142 return ret;
1143 } // wireless_get_essid
1144 /*============================================================================*/
1145
1146
1147
1148
1149 /*******************************************************************************
1150 * wireless_set_encode()
1151 *******************************************************************************
1152 *
1153 * DESCRIPTION:
1154 *
1155 * Sets the encryption keys and status (enable or disable).
1156 *
1157 * PARAMETERS:
1158 *
1159 * wrq - the wireless request buffer
1160 * lp - the device's private adapter structure
1161 *
1162 * RETURNS:
1163 *
1164 * 0 on success
1165 * errno value otherwise
1166 *
1167 ******************************************************************************/
wireless_set_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * keybuf)1168 static int wireless_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf)
1169 {
1170 struct wl_private *lp = wl_priv(dev);
1171 unsigned long flags;
1172 int ret = 0;
1173
1174 #if 1 //;? #if WIRELESS_EXT > 8 - used unconditionally in the rest of the code...
1175 hcf_8 encryption_state;
1176 #endif // WIRELESS_EXT > 8
1177 /*------------------------------------------------------------------------*/
1178
1179
1180 DBG_FUNC( "wireless_set_encode" );
1181 DBG_ENTER( DbgInfo );
1182
1183 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1184 ret = -EBUSY;
1185 goto out;
1186 }
1187
1188 wl_lock( lp, &flags );
1189
1190 wl_act_int_off( lp );
1191
1192 /* Is encryption supported? */
1193 if( !wl_has_wep( &( lp->hcfCtx ))) {
1194 DBG_WARNING( DbgInfo, "WEP not supported on this device\n" );
1195 ret = -EOPNOTSUPP;
1196 goto out_unlock;
1197 }
1198
1199 DBG_NOTICE( DbgInfo, "pointer: %p, length: %d, flags: %#x\n",
1200 keybuf, erq->length,
1201 erq->flags);
1202
1203 /* Save state of Encryption switch */
1204 encryption_state = lp->EnableEncryption;
1205
1206 /* Basic checking: do we have a key to set? */
1207 if((erq->length) != 0) {
1208 int index = ( erq->flags & IW_ENCODE_INDEX ) - 1;
1209 int tk = lp->TransmitKeyID - 1; // current key
1210
1211
1212 /* Check the size of the key */
1213 switch(erq->length) {
1214 case 0:
1215 break;
1216
1217 case MIN_KEY_SIZE:
1218 case MAX_KEY_SIZE:
1219
1220 /* Check the index */
1221 if(( index < 0 ) || ( index >= MAX_KEYS )) {
1222 index = tk;
1223 }
1224
1225 /* Cleanup */
1226 memset( lp->DefaultKeys.key[index].key, 0, MAX_KEY_SIZE );
1227
1228 /* Copy the key in the driver */
1229 memcpy( lp->DefaultKeys.key[index].key, keybuf, erq->length);
1230
1231 /* Set the length */
1232 lp->DefaultKeys.key[index].len = erq->length;
1233
1234 DBG_NOTICE( DbgInfo, "encoding.length: %d\n", erq->length );
1235 DBG_NOTICE( DbgInfo, "set key: %s(%d) [%d]\n", lp->DefaultKeys.key[index].key,
1236 lp->DefaultKeys.key[index].len, index );
1237
1238 /* Enable WEP (if possible) */
1239 if(( index == tk ) && ( lp->DefaultKeys.key[tk].len > 0 )) {
1240 lp->EnableEncryption = 1;
1241 }
1242
1243 break;
1244
1245 default:
1246 DBG_WARNING( DbgInfo, "Invalid Key length\n" );
1247 ret = -EINVAL;
1248 goto out_unlock;
1249 }
1250 } else {
1251 int index = ( erq->flags & IW_ENCODE_INDEX ) - 1;
1252
1253
1254 /* Do we want to just set the current transmit key? */
1255 if(( index >= 0 ) && ( index < MAX_KEYS )) {
1256 DBG_NOTICE( DbgInfo, "index: %d; len: %d\n", index,
1257 lp->DefaultKeys.key[index].len );
1258
1259 if( lp->DefaultKeys.key[index].len > 0 ) {
1260 lp->TransmitKeyID = index + 1;
1261 lp->EnableEncryption = 1;
1262 } else {
1263 DBG_WARNING( DbgInfo, "Problem setting the current TxKey\n" );
1264 DBG_LEAVE( DbgInfo );
1265 ret = -EINVAL;
1266 }
1267 }
1268 }
1269
1270 /* Read the flags */
1271 if( erq->flags & IW_ENCODE_DISABLED ) {
1272 lp->EnableEncryption = 0; // disable encryption
1273 } else {
1274 lp->EnableEncryption = 1;
1275 }
1276
1277 if( erq->flags & IW_ENCODE_RESTRICTED ) {
1278 DBG_WARNING( DbgInfo, "IW_ENCODE_RESTRICTED invalid\n" );
1279 ret = -EINVAL; // Invalid
1280 }
1281
1282 DBG_TRACE( DbgInfo, "encryption_state : %d\n", encryption_state );
1283 DBG_TRACE( DbgInfo, "lp->EnableEncryption : %d\n", lp->EnableEncryption );
1284 DBG_TRACE( DbgInfo, "erq->length : %d\n",
1285 erq->length);
1286 DBG_TRACE( DbgInfo, "erq->flags : 0x%x\n",
1287 erq->flags);
1288
1289 /* Write the changes to the card */
1290 if( ret == 0 ) {
1291 DBG_NOTICE( DbgInfo, "encrypt: %d, ID: %d\n", lp->EnableEncryption,
1292 lp->TransmitKeyID );
1293
1294 if( lp->EnableEncryption == encryption_state ) {
1295 if( erq->length != 0 ) {
1296 /* Dynamic WEP key update */
1297 wl_set_wep_keys( lp );
1298 }
1299 } else {
1300 /* To switch encryption on/off, soft reset is required */
1301 wl_apply( lp );
1302 }
1303 }
1304
1305 /* Send an event that Encryption has been set */
1306 wl_wext_event_encode( dev );
1307
1308 out_unlock:
1309
1310 wl_act_int_on( lp );
1311
1312 wl_unlock(lp, &flags);
1313
1314 out:
1315 DBG_LEAVE( DbgInfo );
1316 return ret;
1317 } // wireless_set_encode
1318 /*============================================================================*/
1319
1320
1321
1322
1323 /*******************************************************************************
1324 * wireless_get_encode()
1325 *******************************************************************************
1326 *
1327 * DESCRIPTION:
1328 *
1329 * Gets the encryption keys and status.
1330 *
1331 * PARAMETERS:
1332 *
1333 * wrq - the wireless request buffer
1334 * lp - the device's private adapter structure
1335 *
1336 * RETURNS:
1337 *
1338 * 0 on success
1339 * errno value otherwise
1340 *
1341 ******************************************************************************/
wireless_get_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * key)1342 static int wireless_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key)
1343
1344 {
1345 struct wl_private *lp = wl_priv(dev);
1346 unsigned long flags;
1347 int ret = 0;
1348 int index;
1349 /*------------------------------------------------------------------------*/
1350
1351
1352 DBG_FUNC( "wireless_get_encode" );
1353 DBG_ENTER( DbgInfo );
1354 DBG_NOTICE(DbgInfo, "GIWENCODE: encrypt: %d, ID: %d\n", lp->EnableEncryption, lp->TransmitKeyID);
1355
1356 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1357 ret = -EBUSY;
1358 goto out;
1359 }
1360
1361 /* Only super-user can see WEP key */
1362 if( !capable( CAP_NET_ADMIN )) {
1363 ret = -EPERM;
1364 DBG_LEAVE( DbgInfo );
1365 return ret;
1366 }
1367
1368 wl_lock( lp, &flags );
1369
1370 wl_act_int_off( lp );
1371
1372 /* Is it supported? */
1373 if( !wl_has_wep( &( lp->hcfCtx ))) {
1374 ret = -EOPNOTSUPP;
1375 goto out_unlock;
1376 }
1377
1378 /* Basic checking */
1379 index = (erq->flags & IW_ENCODE_INDEX ) - 1;
1380
1381
1382 /* Set the flags */
1383 erq->flags = 0;
1384
1385 if( lp->EnableEncryption == 0 ) {
1386 erq->flags |= IW_ENCODE_DISABLED;
1387 }
1388
1389 /* Which key do we want */
1390 if(( index < 0 ) || ( index >= MAX_KEYS )) {
1391 index = lp->TransmitKeyID - 1;
1392 }
1393
1394 erq->flags |= index + 1;
1395
1396 /* Copy the key to the user buffer */
1397 erq->length = lp->DefaultKeys.key[index].len;
1398
1399 memcpy(key, lp->DefaultKeys.key[index].key, erq->length);
1400
1401 out_unlock:
1402
1403 wl_act_int_on( lp );
1404
1405 wl_unlock(lp, &flags);
1406
1407 out:
1408 DBG_LEAVE( DbgInfo );
1409 return ret;
1410 } // wireless_get_encode
1411 /*============================================================================*/
1412
1413
1414
1415
1416 /*******************************************************************************
1417 * wireless_set_nickname()
1418 *******************************************************************************
1419 *
1420 * DESCRIPTION:
1421 *
1422 * Sets the nickname, or station name, of the wireless device.
1423 *
1424 * PARAMETERS:
1425 *
1426 * wrq - the wireless request buffer
1427 * lp - the device's private adapter structure
1428 *
1429 * RETURNS:
1430 *
1431 * 0 on success
1432 * errno value otherwise
1433 *
1434 ******************************************************************************/
wireless_set_nickname(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * nickname)1435 static int wireless_set_nickname(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname)
1436 {
1437 struct wl_private *lp = wl_priv(dev);
1438 unsigned long flags;
1439 int ret = 0;
1440 /*------------------------------------------------------------------------*/
1441
1442
1443 DBG_FUNC( "wireless_set_nickname" );
1444 DBG_ENTER( DbgInfo );
1445
1446 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1447 ret = -EBUSY;
1448 goto out;
1449 }
1450
1451 #if 0 //;? Needed, was present in original code but not in 7.18 Linux 2.6 kernel version
1452 if( !capable(CAP_NET_ADMIN )) {
1453 ret = -EPERM;
1454 DBG_LEAVE( DbgInfo );
1455 return ret;
1456 }
1457 #endif
1458
1459 /* Validate the new value */
1460 if(data->length > HCF_MAX_NAME_LEN) {
1461 ret = -EINVAL;
1462 goto out;
1463 }
1464
1465 wl_lock( lp, &flags );
1466
1467 wl_act_int_off( lp );
1468
1469 memset( lp->StationName, 0, sizeof( lp->StationName ));
1470
1471 memcpy( lp->StationName, nickname, data->length );
1472
1473 /* Commit the adapter parameters */
1474 wl_apply( lp );
1475
1476 wl_act_int_on( lp );
1477
1478 wl_unlock(lp, &flags);
1479
1480 out:
1481 DBG_LEAVE( DbgInfo );
1482 return ret;
1483 } // wireless_set_nickname
1484 /*============================================================================*/
1485
1486
1487
1488
1489 /*******************************************************************************
1490 * wireless_get_nickname()
1491 *******************************************************************************
1492 *
1493 * DESCRIPTION:
1494 *
1495 * Gets the nickname, or station name, of the wireless device.
1496 *
1497 * PARAMETERS:
1498 *
1499 * wrq - the wireless request buffer
1500 * lp - the device's private adapter structure
1501 *
1502 * RETURNS:
1503 *
1504 * 0 on success
1505 * errno value otherwise
1506 *
1507 ******************************************************************************/
wireless_get_nickname(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * nickname)1508 static int wireless_get_nickname(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname)
1509 {
1510 struct wl_private *lp = wl_priv(dev);
1511 unsigned long flags;
1512 int ret = 0;
1513 int status = -1;
1514 wvName_t *pName;
1515 /*------------------------------------------------------------------------*/
1516
1517
1518 DBG_FUNC( "wireless_get_nickname" );
1519 DBG_ENTER( DbgInfo );
1520
1521 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1522 ret = -EBUSY;
1523 goto out;
1524 }
1525
1526 wl_lock( lp, &flags );
1527
1528 wl_act_int_off( lp );
1529
1530 /* Get the current station name */
1531 lp->ltvRecord.len = 1 + ( sizeof( *pName ) / sizeof( hcf_16 ));
1532 lp->ltvRecord.typ = CFG_CNF_OWN_NAME;
1533
1534 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1535
1536 if( status == HCF_SUCCESS ) {
1537 pName = (wvName_t *)&( lp->ltvRecord.u.u32 );
1538
1539 /* Endian translate the length */
1540 pName->length = CNV_LITTLE_TO_INT( pName->length );
1541
1542 if ( pName->length > IW_ESSID_MAX_SIZE ) {
1543 ret = -EFAULT;
1544 } else {
1545 /* Copy the information into the user buffer */
1546 data->length = pName->length;
1547 memcpy(nickname, pName->name, pName->length);
1548 }
1549 } else {
1550 ret = -EFAULT;
1551 }
1552
1553 wl_act_int_on( lp );
1554
1555 wl_unlock(lp, &flags);
1556
1557 out:
1558 DBG_LEAVE(DbgInfo);
1559 return ret;
1560 } // wireless_get_nickname
1561 /*============================================================================*/
1562
1563
1564
1565
1566 /*******************************************************************************
1567 * wireless_set_porttype()
1568 *******************************************************************************
1569 *
1570 * DESCRIPTION:
1571 *
1572 * Sets the port type of the wireless device.
1573 *
1574 * PARAMETERS:
1575 *
1576 * wrq - the wireless request buffer
1577 * lp - the device's private adapter structure
1578 *
1579 * RETURNS:
1580 *
1581 * 0 on success
1582 * errno value otherwise
1583 *
1584 ******************************************************************************/
wireless_set_porttype(struct net_device * dev,struct iw_request_info * info,__u32 * mode,char * extra)1585 static int wireless_set_porttype(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra)
1586 {
1587 struct wl_private *lp = wl_priv(dev);
1588 unsigned long flags;
1589 int ret = 0;
1590 hcf_16 portType;
1591 hcf_16 createIBSS;
1592 /*------------------------------------------------------------------------*/
1593
1594 DBG_FUNC( "wireless_set_porttype" );
1595 DBG_ENTER( DbgInfo );
1596
1597 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1598 ret = -EBUSY;
1599 goto out;
1600 }
1601
1602 wl_lock( lp, &flags );
1603
1604 wl_act_int_off( lp );
1605
1606 /* Validate the new value */
1607 switch( *mode ) {
1608 case IW_MODE_ADHOC:
1609
1610 /* When user requests ad-hoc, set IBSS mode! */
1611 portType = 1;
1612 createIBSS = 1;
1613
1614 lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //1;
1615
1616 break;
1617
1618
1619 case IW_MODE_AUTO:
1620 case IW_MODE_INFRA:
1621
1622 /* Both automatic and infrastructure set port to BSS/STA mode */
1623 portType = 1;
1624 createIBSS = 0;
1625
1626 lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //1;
1627
1628 break;
1629
1630
1631 #if 0 //;? (HCF_TYPE) & HCF_TYPE_AP
1632
1633 case IW_MODE_MASTER:
1634
1635 /* Set BSS/AP mode */
1636 portType = 1;
1637
1638 lp->CreateIBSS = 0;
1639 lp->DownloadFirmware = WVLAN_DRV_MODE_AP; //2;
1640
1641 break;
1642
1643 #endif /* (HCF_TYPE) & HCF_TYPE_AP */
1644
1645
1646 default:
1647
1648 portType = 0;
1649 createIBSS = 0;
1650 ret = -EINVAL;
1651 }
1652
1653 if( portType != 0 ) {
1654 /* Only do something if there is a mode change */
1655 if( ( lp->PortType != portType ) || (lp->CreateIBSS != createIBSS)) {
1656 lp->PortType = portType;
1657 lp->CreateIBSS = createIBSS;
1658
1659 /* Commit the adapter parameters */
1660 wl_go( lp );
1661
1662 /* Send an event that mode has been set */
1663 wl_wext_event_mode( lp->dev );
1664 }
1665 }
1666
1667 wl_act_int_on( lp );
1668
1669 wl_unlock(lp, &flags);
1670
1671 out:
1672 DBG_LEAVE( DbgInfo );
1673 return ret;
1674 } // wireless_set_porttype
1675 /*============================================================================*/
1676
1677
1678
1679
1680 /*******************************************************************************
1681 * wireless_get_porttype()
1682 *******************************************************************************
1683 *
1684 * DESCRIPTION:
1685 *
1686 * Gets the port type of the wireless device.
1687 *
1688 * PARAMETERS:
1689 *
1690 * wrq - the wireless request buffer
1691 * lp - the device's private adapter structure
1692 *
1693 * RETURNS:
1694 *
1695 * 0 on success
1696 * errno value otherwise
1697 *
1698 ******************************************************************************/
wireless_get_porttype(struct net_device * dev,struct iw_request_info * info,__u32 * mode,char * extra)1699 static int wireless_get_porttype(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra)
1700
1701 {
1702 struct wl_private *lp = wl_priv(dev);
1703 unsigned long flags;
1704 int ret = 0;
1705 int status = -1;
1706 hcf_16 *pPortType;
1707 /*------------------------------------------------------------------------*/
1708
1709
1710 DBG_FUNC( "wireless_get_porttype" );
1711 DBG_ENTER( DbgInfo );
1712
1713 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1714 ret = -EBUSY;
1715 goto out;
1716 }
1717
1718 wl_lock( lp, &flags );
1719
1720 wl_act_int_off( lp );
1721
1722 /* Get the current port type */
1723 lp->ltvRecord.len = 1 + ( sizeof( *pPortType ) / sizeof( hcf_16 ));
1724 lp->ltvRecord.typ = CFG_CNF_PORT_TYPE;
1725
1726 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1727
1728 if( status == HCF_SUCCESS ) {
1729 pPortType = (hcf_16 *)&( lp->ltvRecord.u.u32 );
1730
1731 *pPortType = CNV_LITTLE_TO_INT( *pPortType );
1732
1733 switch( *pPortType ) {
1734 case 1:
1735
1736 #if 0
1737 #if (HCF_TYPE) & HCF_TYPE_AP
1738
1739 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
1740 *mode = IW_MODE_MASTER;
1741 } else {
1742 *mode = IW_MODE_INFRA;
1743 }
1744
1745 #else
1746
1747 *mode = IW_MODE_INFRA;
1748
1749 #endif /* (HCF_TYPE) & HCF_TYPE_AP */
1750 #endif
1751
1752 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
1753 *mode = IW_MODE_MASTER;
1754 } else {
1755 if( lp->CreateIBSS ) {
1756 *mode = IW_MODE_ADHOC;
1757 } else {
1758 *mode = IW_MODE_INFRA;
1759 }
1760 }
1761
1762 break;
1763
1764
1765 case 3:
1766 *mode = IW_MODE_ADHOC;
1767 break;
1768
1769 default:
1770 ret = -EFAULT;
1771 break;
1772 }
1773 } else {
1774 ret = -EFAULT;
1775 }
1776
1777 wl_act_int_on( lp );
1778
1779 wl_unlock(lp, &flags);
1780
1781 out:
1782 DBG_LEAVE( DbgInfo );
1783 return ret;
1784 } // wireless_get_porttype
1785 /*============================================================================*/
1786
1787
1788
1789
1790 /*******************************************************************************
1791 * wireless_set_power()
1792 *******************************************************************************
1793 *
1794 * DESCRIPTION:
1795 *
1796 * Sets the power management settings of the wireless device.
1797 *
1798 * PARAMETERS:
1799 *
1800 * wrq - the wireless request buffer
1801 * lp - the device's private adapter structure
1802 *
1803 * RETURNS:
1804 *
1805 * 0 on success
1806 * errno value otherwise
1807 *
1808 ******************************************************************************/
wireless_set_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * wrq,char * extra)1809 static int wireless_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, char *extra)
1810 {
1811 struct wl_private *lp = wl_priv(dev);
1812 unsigned long flags;
1813 int ret = 0;
1814 /*------------------------------------------------------------------------*/
1815
1816
1817 DBG_FUNC( "wireless_set_power" );
1818 DBG_ENTER( DbgInfo );
1819
1820 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1821 ret = -EBUSY;
1822 goto out;
1823 }
1824
1825 DBG_PRINT( "THIS CORRUPTS PMEnabled ;?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
1826
1827 #if 0 //;? Needed, was present in original code but not in 7.18 Linux 2.6 kernel version
1828 if( !capable( CAP_NET_ADMIN )) {
1829 ret = -EPERM;
1830
1831 DBG_LEAVE( DbgInfo );
1832 return ret;
1833 }
1834 #endif
1835
1836 wl_lock( lp, &flags );
1837
1838 wl_act_int_off( lp );
1839
1840 /* Set the power management state based on the 'disabled' value */
1841 if( wrq->disabled ) {
1842 lp->PMEnabled = 0;
1843 } else {
1844 lp->PMEnabled = 1;
1845 }
1846
1847 /* Commit the adapter parameters */
1848 wl_apply( lp );
1849
1850 wl_act_int_on( lp );
1851
1852 wl_unlock(lp, &flags);
1853
1854 out:
1855 DBG_LEAVE( DbgInfo );
1856 return ret;
1857 } // wireless_set_power
1858 /*============================================================================*/
1859
1860
1861
1862
1863 /*******************************************************************************
1864 * wireless_get_power()
1865 *******************************************************************************
1866 *
1867 * DESCRIPTION:
1868 *
1869 * Gets the power management settings of the wireless device.
1870 *
1871 * PARAMETERS:
1872 *
1873 * wrq - the wireless request buffer
1874 * lp - the device's private adapter structure
1875 *
1876 * RETURNS:
1877 *
1878 * 0 on success
1879 * errno value otherwise
1880 *
1881 ******************************************************************************/
wireless_get_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)1882 static int wireless_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
1883
1884 {
1885 struct wl_private *lp = wl_priv(dev);
1886 unsigned long flags;
1887 int ret = 0;
1888 /*------------------------------------------------------------------------*/
1889 DBG_FUNC( "wireless_get_power" );
1890 DBG_ENTER( DbgInfo );
1891
1892 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1893 ret = -EBUSY;
1894 goto out;
1895 }
1896
1897 DBG_PRINT( "THIS IS PROBABLY AN OVER-SIMPLIFICATION ;?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
1898
1899 wl_lock( lp, &flags );
1900
1901 wl_act_int_off( lp );
1902
1903 rrq->flags = 0;
1904 rrq->value = 0;
1905
1906 if( lp->PMEnabled ) {
1907 rrq->disabled = 0;
1908 } else {
1909 rrq->disabled = 1;
1910 }
1911
1912 wl_act_int_on( lp );
1913
1914 wl_unlock(lp, &flags);
1915
1916 out:
1917 DBG_LEAVE( DbgInfo );
1918 return ret;
1919 } // wireless_get_power
1920 /*============================================================================*/
1921
1922
1923
1924
1925 /*******************************************************************************
1926 * wireless_get_tx_power()
1927 *******************************************************************************
1928 *
1929 * DESCRIPTION:
1930 *
1931 * Gets the transmit power of the wireless device's radio.
1932 *
1933 * PARAMETERS:
1934 *
1935 * wrq - the wireless request buffer
1936 * lp - the device's private adapter structure
1937 *
1938 * RETURNS:
1939 *
1940 * 0 on success
1941 * errno value otherwise
1942 *
1943 ******************************************************************************/
wireless_get_tx_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)1944 static int wireless_get_tx_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
1945 {
1946 struct wl_private *lp = wl_priv(dev);
1947 unsigned long flags;
1948 int ret = 0;
1949 /*------------------------------------------------------------------------*/
1950 DBG_FUNC( "wireless_get_tx_power" );
1951 DBG_ENTER( DbgInfo );
1952
1953 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
1954 ret = -EBUSY;
1955 goto out;
1956 }
1957
1958 wl_lock( lp, &flags );
1959
1960 wl_act_int_off( lp );
1961
1962 #ifdef USE_POWER_DBM
1963 rrq->value = RADIO_TX_POWER_DBM;
1964 rrq->flags = IW_TXPOW_DBM;
1965 #else
1966 rrq->value = RADIO_TX_POWER_MWATT;
1967 rrq->flags = IW_TXPOW_MWATT;
1968 #endif
1969 rrq->fixed = 1;
1970 rrq->disabled = 0;
1971
1972 wl_act_int_on( lp );
1973
1974 wl_unlock(lp, &flags);
1975
1976 out:
1977 DBG_LEAVE( DbgInfo );
1978 return ret;
1979 } // wireless_get_tx_power
1980 /*============================================================================*/
1981
1982
1983
1984
1985 /*******************************************************************************
1986 * wireless_set_rts_threshold()
1987 *******************************************************************************
1988 *
1989 * DESCRIPTION:
1990 *
1991 * Sets the RTS threshold for the wireless card.
1992 *
1993 * PARAMETERS:
1994 *
1995 * wrq - the wireless request buffer
1996 * lp - the device's private adapter structure
1997 *
1998 * RETURNS:
1999 *
2000 * 0 on success
2001 * errno value otherwise
2002 *
2003 ******************************************************************************/
wireless_set_rts_threshold(struct net_device * dev,struct iw_request_info * info,struct iw_param * rts,char * extra)2004 static int wireless_set_rts_threshold (struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra)
2005 {
2006 int ret = 0;
2007 struct wl_private *lp = wl_priv(dev);
2008 unsigned long flags;
2009 int rthr = rts->value;
2010 /*------------------------------------------------------------------------*/
2011
2012
2013 DBG_FUNC( "wireless_set_rts_threshold" );
2014 DBG_ENTER( DbgInfo );
2015
2016 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2017 ret = -EBUSY;
2018 goto out;
2019 }
2020
2021 if(rts->fixed == 0) {
2022 ret = -EINVAL;
2023 goto out;
2024 }
2025
2026 #if WIRELESS_EXT > 8
2027 if( rts->disabled ) {
2028 rthr = 2347;
2029 }
2030 #endif /* WIRELESS_EXT > 8 */
2031
2032 if(( rthr < 256 ) || ( rthr > 2347 )) {
2033 ret = -EINVAL;
2034 goto out;
2035 }
2036
2037 wl_lock( lp, &flags );
2038
2039 wl_act_int_off( lp );
2040
2041 lp->RTSThreshold = rthr;
2042
2043 wl_apply( lp );
2044
2045 wl_act_int_on( lp );
2046
2047 wl_unlock(lp, &flags);
2048
2049 out:
2050 DBG_LEAVE( DbgInfo );
2051 return ret;
2052 } // wireless_set_rts_threshold
2053 /*============================================================================*/
2054
2055
2056
2057
2058 /*******************************************************************************
2059 * wireless_get_rts_threshold()
2060 *******************************************************************************
2061 *
2062 * DESCRIPTION:
2063 *
2064 * Gets the RTS threshold for the wireless card.
2065 *
2066 * PARAMETERS:
2067 *
2068 * wrq - the wireless request buffer
2069 * lp - the device's private adapter structure
2070 *
2071 * RETURNS:
2072 *
2073 * 0 on success
2074 * errno value otherwise
2075 *
2076 ******************************************************************************/
wireless_get_rts_threshold(struct net_device * dev,struct iw_request_info * info,struct iw_param * rts,char * extra)2077 static int wireless_get_rts_threshold (struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra)
2078 {
2079 int ret = 0;
2080 struct wl_private *lp = wl_priv(dev);
2081 unsigned long flags;
2082 /*------------------------------------------------------------------------*/
2083
2084 DBG_FUNC( "wireless_get_rts_threshold" );
2085 DBG_ENTER( DbgInfo );
2086
2087 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2088 ret = -EBUSY;
2089 goto out;
2090 }
2091
2092 wl_lock( lp, &flags );
2093
2094 wl_act_int_off( lp );
2095
2096 rts->value = lp->RTSThreshold;
2097
2098 #if WIRELESS_EXT > 8
2099
2100 rts->disabled = ( rts->value == 2347 );
2101
2102 #endif /* WIRELESS_EXT > 8 */
2103
2104 rts->fixed = 1;
2105
2106 wl_act_int_on( lp );
2107
2108 wl_unlock(lp, &flags);
2109
2110 out:
2111 DBG_LEAVE( DbgInfo );
2112 return ret;
2113 } // wireless_get_rts_threshold
2114 /*============================================================================*/
2115
2116
2117
2118
2119
2120 /*******************************************************************************
2121 * wireless_set_rate()
2122 *******************************************************************************
2123 *
2124 * DESCRIPTION:
2125 *
2126 * Set the default data rate setting used by the wireless device.
2127 *
2128 * PARAMETERS:
2129 *
2130 * wrq - the wireless request buffer
2131 * lp - the device's private adapter structure
2132 *
2133 * RETURNS:
2134 *
2135 * 0 on success
2136 * errno value otherwise
2137 *
2138 ******************************************************************************/
wireless_set_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)2139 static int wireless_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
2140 {
2141 struct wl_private *lp = wl_priv(dev);
2142 unsigned long flags;
2143 int ret = 0;
2144 #ifdef WARP
2145 int status = -1;
2146 int index = 0;
2147 #endif // WARP
2148 /*------------------------------------------------------------------------*/
2149
2150
2151 DBG_FUNC( "wireless_set_rate" );
2152 DBG_ENTER( DbgInfo );
2153
2154 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2155 ret = -EBUSY;
2156 goto out;
2157 }
2158
2159 wl_lock( lp, &flags );
2160
2161 wl_act_int_off( lp );
2162
2163 #ifdef WARP
2164
2165 /* Determine if the card is operating in the 2.4 or 5.0 GHz band; check
2166 if Bit 9 is set in the current channel RID */
2167 lp->ltvRecord.len = 2;
2168 lp->ltvRecord.typ = CFG_CUR_CHANNEL;
2169
2170 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
2171
2172 if( status == HCF_SUCCESS ) {
2173 index = ( CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] ) & 0x100 ) ? 1 : 0;
2174
2175 DBG_PRINT( "Index: %d\n", index );
2176 } else {
2177 DBG_ERROR( DbgInfo, "Could not determine radio frequency\n" );
2178 DBG_LEAVE( DbgInfo );
2179 ret = -EINVAL;
2180 goto out_unlock;
2181 }
2182
2183 if( rrq->value > 0 &&
2184 rrq->value <= 1 * MEGABIT ) {
2185 lp->TxRateControl[index] = 0x0001;
2186 }
2187 else if( rrq->value > 1 * MEGABIT &&
2188 rrq->value <= 2 * MEGABIT ) {
2189 if( rrq->fixed == 1 ) {
2190 lp->TxRateControl[index] = 0x0002;
2191 } else {
2192 lp->TxRateControl[index] = 0x0003;
2193 }
2194 }
2195 else if( rrq->value > 2 * MEGABIT &&
2196 rrq->value <= 5 * MEGABIT ) {
2197 if( rrq->fixed == 1 ) {
2198 lp->TxRateControl[index] = 0x0004;
2199 } else {
2200 lp->TxRateControl[index] = 0x0007;
2201 }
2202 }
2203 else if( rrq->value > 5 * MEGABIT &&
2204 rrq->value <= 6 * MEGABIT ) {
2205 if( rrq->fixed == 1 ) {
2206 lp->TxRateControl[index] = 0x0010;
2207 } else {
2208 lp->TxRateControl[index] = 0x0017;
2209 }
2210 }
2211 else if( rrq->value > 6 * MEGABIT &&
2212 rrq->value <= 9 * MEGABIT ) {
2213 if( rrq->fixed == 1 ) {
2214 lp->TxRateControl[index] = 0x0020;
2215 } else {
2216 lp->TxRateControl[index] = 0x0037;
2217 }
2218 }
2219 else if( rrq->value > 9 * MEGABIT &&
2220 rrq->value <= 11 * MEGABIT ) {
2221 if( rrq->fixed == 1 ) {
2222 lp->TxRateControl[index] = 0x0008;
2223 } else {
2224 lp->TxRateControl[index] = 0x003F;
2225 }
2226 }
2227 else if( rrq->value > 11 * MEGABIT &&
2228 rrq->value <= 12 * MEGABIT ) {
2229 if( rrq->fixed == 1 ) {
2230 lp->TxRateControl[index] = 0x0040;
2231 } else {
2232 lp->TxRateControl[index] = 0x007F;
2233 }
2234 }
2235 else if( rrq->value > 12 * MEGABIT &&
2236 rrq->value <= 18 * MEGABIT ) {
2237 if( rrq->fixed == 1 ) {
2238 lp->TxRateControl[index] = 0x0080;
2239 } else {
2240 lp->TxRateControl[index] = 0x00FF;
2241 }
2242 }
2243 else if( rrq->value > 18 * MEGABIT &&
2244 rrq->value <= 24 * MEGABIT ) {
2245 if( rrq->fixed == 1 ) {
2246 lp->TxRateControl[index] = 0x0100;
2247 } else {
2248 lp->TxRateControl[index] = 0x01FF;
2249 }
2250 }
2251 else if( rrq->value > 24 * MEGABIT &&
2252 rrq->value <= 36 * MEGABIT ) {
2253 if( rrq->fixed == 1 ) {
2254 lp->TxRateControl[index] = 0x0200;
2255 } else {
2256 lp->TxRateControl[index] = 0x03FF;
2257 }
2258 }
2259 else if( rrq->value > 36 * MEGABIT &&
2260 rrq->value <= 48 * MEGABIT ) {
2261 if( rrq->fixed == 1 ) {
2262 lp->TxRateControl[index] = 0x0400;
2263 } else {
2264 lp->TxRateControl[index] = 0x07FF;
2265 }
2266 }
2267 else if( rrq->value > 48 * MEGABIT &&
2268 rrq->value <= 54 * MEGABIT ) {
2269 if( rrq->fixed == 1 ) {
2270 lp->TxRateControl[index] = 0x0800;
2271 } else {
2272 lp->TxRateControl[index] = 0x0FFF;
2273 }
2274 }
2275 else if( rrq->fixed == 0 ) {
2276 /* In this case, the user has not specified a bitrate, only the "auto"
2277 moniker. So, set to all supported rates */
2278 lp->TxRateControl[index] = PARM_MAX_TX_RATE;
2279 } else {
2280 rrq->value = 0;
2281 ret = -EINVAL;
2282 goto out_unlock;
2283 }
2284
2285
2286 #else
2287
2288 if( rrq->value > 0 &&
2289 rrq->value <= 1 * MEGABIT ) {
2290 lp->TxRateControl[0] = 1;
2291 }
2292 else if( rrq->value > 1 * MEGABIT &&
2293 rrq->value <= 2 * MEGABIT ) {
2294 if( rrq->fixed ) {
2295 lp->TxRateControl[0] = 2;
2296 } else {
2297 lp->TxRateControl[0] = 6;
2298 }
2299 }
2300 else if( rrq->value > 2 * MEGABIT &&
2301 rrq->value <= 5 * MEGABIT ) {
2302 if( rrq->fixed ) {
2303 lp->TxRateControl[0] = 4;
2304 } else {
2305 lp->TxRateControl[0] = 7;
2306 }
2307 }
2308 else if( rrq->value > 5 * MEGABIT &&
2309 rrq->value <= 11 * MEGABIT ) {
2310 if( rrq->fixed) {
2311 lp->TxRateControl[0] = 5;
2312 } else {
2313 lp->TxRateControl[0] = 3;
2314 }
2315 }
2316 else if( rrq->fixed == 0 ) {
2317 /* In this case, the user has not specified a bitrate, only the "auto"
2318 moniker. So, set the rate to 11Mb auto */
2319 lp->TxRateControl[0] = 3;
2320 } else {
2321 rrq->value = 0;
2322 ret = -EINVAL;
2323 goto out_unlock;
2324 }
2325
2326 #endif // WARP
2327
2328
2329 /* Commit the adapter parameters */
2330 wl_apply( lp );
2331
2332 out_unlock:
2333
2334 wl_act_int_on( lp );
2335
2336 wl_unlock(lp, &flags);
2337
2338 out:
2339 DBG_LEAVE( DbgInfo );
2340 return ret;
2341 } // wireless_set_rate
2342 /*============================================================================*/
2343
2344
2345
2346
2347 /*******************************************************************************
2348 * wireless_get_rate()
2349 *******************************************************************************
2350 *
2351 * DESCRIPTION:
2352 *
2353 * Get the default data rate setting used by the wireless device.
2354 *
2355 * PARAMETERS:
2356 *
2357 * wrq - the wireless request buffer
2358 * lp - the device's private adapter structure
2359 *
2360 * RETURNS:
2361 *
2362 * 0 on success
2363 * errno value otherwise
2364 *
2365 ******************************************************************************/
wireless_get_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)2366 static int wireless_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
2367
2368 {
2369 struct wl_private *lp = wl_priv(dev);
2370 unsigned long flags;
2371 int ret = 0;
2372 int status = -1;
2373 hcf_16 txRate;
2374 /*------------------------------------------------------------------------*/
2375
2376
2377 DBG_FUNC( "wireless_get_rate" );
2378 DBG_ENTER( DbgInfo );
2379
2380 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2381 ret = -EBUSY;
2382 goto out;
2383 }
2384
2385 wl_lock( lp, &flags );
2386
2387 wl_act_int_off( lp );
2388
2389 /* Get the current transmit rate from the adapter */
2390 lp->ltvRecord.len = 1 + ( sizeof(txRate)/sizeof(hcf_16));
2391 lp->ltvRecord.typ = CFG_CUR_TX_RATE;
2392
2393 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
2394
2395 if( status == HCF_SUCCESS ) {
2396 #ifdef WARP
2397
2398 txRate = CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] );
2399
2400 if( txRate & 0x0001 ) {
2401 txRate = 1;
2402 }
2403 else if( txRate & 0x0002 ) {
2404 txRate = 2;
2405 }
2406 else if( txRate & 0x0004 ) {
2407 txRate = 5;
2408 }
2409 else if( txRate & 0x0008 ) {
2410 txRate = 11;
2411 }
2412 else if( txRate & 0x00010 ) {
2413 txRate = 6;
2414 }
2415 else if( txRate & 0x00020 ) {
2416 txRate = 9;
2417 }
2418 else if( txRate & 0x00040 ) {
2419 txRate = 12;
2420 }
2421 else if( txRate & 0x00080 ) {
2422 txRate = 18;
2423 }
2424 else if( txRate & 0x00100 ) {
2425 txRate = 24;
2426 }
2427 else if( txRate & 0x00200 ) {
2428 txRate = 36;
2429 }
2430 else if( txRate & 0x00400 ) {
2431 txRate = 48;
2432 }
2433 else if( txRate & 0x00800 ) {
2434 txRate = 54;
2435 }
2436
2437 #else
2438
2439 txRate = (hcf_16)CNV_LITTLE_TO_LONG( lp->ltvRecord.u.u32[0] );
2440
2441 #endif // WARP
2442
2443 rrq->value = txRate * MEGABIT;
2444 } else {
2445 rrq->value = 0;
2446 ret = -EFAULT;
2447 }
2448
2449 wl_act_int_on( lp );
2450
2451 wl_unlock(lp, &flags);
2452
2453 out:
2454 DBG_LEAVE( DbgInfo );
2455 return ret;
2456 } // wireless_get_rate
2457 /*============================================================================*/
2458
2459
2460
2461
2462 #if 0 //;? Not used anymore
2463 /*******************************************************************************
2464 * wireless_get_private_interface()
2465 *******************************************************************************
2466 *
2467 * DESCRIPTION:
2468 *
2469 * Returns the Linux Wireless Extensions' compatible private interface of
2470 * the driver.
2471 *
2472 * PARAMETERS:
2473 *
2474 * wrq - the wireless request buffer
2475 * lp - the device's private adapter structure
2476 *
2477 * RETURNS:
2478 *
2479 * 0 on success
2480 * errno value otherwise
2481 *
2482 ******************************************************************************/
2483 int wireless_get_private_interface( struct iwreq *wrq, struct wl_private *lp )
2484 {
2485 int ret = 0;
2486 /*------------------------------------------------------------------------*/
2487
2488
2489 DBG_FUNC( "wireless_get_private_interface" );
2490 DBG_ENTER( DbgInfo );
2491
2492 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2493 ret = -EBUSY;
2494 goto out;
2495 }
2496
2497 if( wrq->u.data.pointer != NULL ) {
2498 struct iw_priv_args priv[] =
2499 {
2500 { SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" },
2501 { SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" },
2502 { SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" },
2503 { SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gstation_name" },
2504 { SIOCSIWPORTTYPE, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" },
2505 { SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "gport_type" },
2506 };
2507
2508 /* Verify the user buffer */
2509 ret = verify_area( VERIFY_WRITE, wrq->u.data.pointer, sizeof( priv ));
2510
2511 if( ret != 0 ) {
2512 DBG_LEAVE( DbgInfo );
2513 return ret;
2514 }
2515
2516 /* Copy the data into the user's buffer */
2517 wrq->u.data.length = NELEM( priv );
2518 copy_to_user( wrq->u.data.pointer, &priv, sizeof( priv ));
2519 }
2520
2521 out:
2522 DBG_LEAVE( DbgInfo );
2523 return ret;
2524 } // wireless_get_private_interface
2525 /*============================================================================*/
2526 #endif
2527
2528
2529
2530 #if WIRELESS_EXT > 13
2531
2532 /*******************************************************************************
2533 * wireless_set_scan()
2534 *******************************************************************************
2535 *
2536 * DESCRIPTION:
2537 *
2538 * Instructs the driver to initiate a network scan.
2539 *
2540 * PARAMETERS:
2541 *
2542 * wrq - the wireless request buffer
2543 * lp - the device's private adapter structure
2544 *
2545 * RETURNS:
2546 *
2547 * 0 on success
2548 * errno value otherwise
2549 *
2550 ******************************************************************************/
wireless_set_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)2551 static int wireless_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
2552 {
2553 struct wl_private *lp = wl_priv(dev);
2554 unsigned long flags;
2555 int ret = 0;
2556 int status = -1;
2557 int retries = 0;
2558 /*------------------------------------------------------------------------*/
2559
2560 //;? Note: shows results as trace, retruns always 0 unless BUSY
2561
2562 DBG_FUNC( "wireless_set_scan" );
2563 DBG_ENTER( DbgInfo );
2564
2565 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2566 ret = -EBUSY;
2567 goto out;
2568 }
2569
2570 wl_lock( lp, &flags );
2571
2572 wl_act_int_off( lp );
2573
2574 /*
2575 * This looks like a nice place to test if the HCF is still
2576 * communicating with the card. It seems that sometimes BAP_1
2577 * gets corrupted. By looking at the comments in HCF the
2578 * cause is still a mystery. Okay, the communication to the
2579 * card is dead, reset the card to revive.
2580 */
2581 if((lp->hcfCtx.IFB_CardStat & CARD_STAT_DEFUNCT) != 0)
2582 {
2583 DBG_TRACE( DbgInfo, "CARD is in DEFUNCT mode, reset it to bring it back to life\n" );
2584 wl_reset( dev );
2585 }
2586
2587 retry:
2588 /* Set the completion state to FALSE */
2589 lp->probe_results.scan_complete = FALSE;
2590
2591
2592 /* Channels to scan */
2593 #ifdef WARP
2594 lp->ltvRecord.len = 5;
2595 lp->ltvRecord.typ = CFG_SCAN_CHANNEL;
2596 lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x3FFF ); // 2.4 GHz Band
2597 lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( 0xFFFF ); // 5.0 GHz Band
2598 lp->ltvRecord.u.u16[2] = CNV_INT_TO_LITTLE( 0xFFFF ); // ..
2599 lp->ltvRecord.u.u16[3] = CNV_INT_TO_LITTLE( 0x0007 ); // ..
2600 #else
2601 lp->ltvRecord.len = 2;
2602 lp->ltvRecord.typ = CFG_SCAN_CHANNEL;
2603 lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x7FFF );
2604 #endif // WARP
2605
2606 status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
2607
2608 DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNEL result : 0x%x\n", status );
2609
2610 // Holding the lock too long, make a gap to allow other processes
2611 wl_unlock(lp, &flags);
2612 wl_lock( lp, &flags );
2613
2614 if( status != HCF_SUCCESS ) {
2615 //Recovery
2616 retries++;
2617 if(retries <= 10) {
2618 DBG_TRACE( DbgInfo, "Reset card to recover, attempt: %d\n", retries );
2619 wl_reset( dev );
2620
2621 // Holding the lock too long, make a gap to allow other processes
2622 wl_unlock(lp, &flags);
2623 wl_lock( lp, &flags );
2624
2625 goto retry;
2626 }
2627 }
2628
2629 /* Set the SCAN_SSID to "ANY". Using this RID for scan prevents the need to
2630 disassociate from the network we are currently on */
2631 lp->ltvRecord.len = 18;
2632 lp->ltvRecord.typ = CFG_SCAN_SSID;
2633 lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
2634 lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( 0 );
2635
2636 status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
2637
2638 // Holding the lock too long, make a gap to allow other processes
2639 wl_unlock(lp, &flags);
2640 wl_lock( lp, &flags );
2641
2642 DBG_TRACE( DbgInfo, "CFG_SCAN_SSID to 'any' status: 0x%x\n", status );
2643
2644 /* Initiate the scan */
2645 /* NOTE: Using HCF_ACT_SCAN has been removed, as using HCF_ACT_ACS_SCAN to
2646 retrieve probe responses must always be used to support WPA */
2647 status = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN );
2648
2649 if( status == HCF_SUCCESS ) {
2650 DBG_TRACE( DbgInfo, "SUCCESSFULLY INITIATED SCAN...\n" );
2651 } else {
2652 DBG_TRACE( DbgInfo, "INITIATE SCAN FAILED...\n" );
2653 }
2654
2655 wl_act_int_on( lp );
2656
2657 wl_unlock(lp, &flags);
2658
2659 out:
2660 DBG_LEAVE(DbgInfo);
2661 return ret;
2662 } // wireless_set_scan
2663 /*============================================================================*/
2664
2665
2666
2667
2668 /*******************************************************************************
2669 * wireless_get_scan()
2670 *******************************************************************************
2671 *
2672 * DESCRIPTION:
2673 *
2674 * Instructs the driver to gather and return the results of a network scan.
2675 *
2676 * PARAMETERS:
2677 *
2678 * wrq - the wireless request buffer
2679 * lp - the device's private adapter structure
2680 *
2681 * RETURNS:
2682 *
2683 * 0 on success
2684 * errno value otherwise
2685 *
2686 ******************************************************************************/
wireless_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)2687 static int wireless_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
2688 {
2689 struct wl_private *lp = wl_priv(dev);
2690 unsigned long flags;
2691 int ret = 0;
2692 int count;
2693 char *buf;
2694 char *buf_end;
2695 struct iw_event iwe;
2696 PROBE_RESP *probe_resp;
2697 hcf_8 msg[512];
2698 hcf_8 *wpa_ie;
2699 hcf_16 wpa_ie_len;
2700 /*------------------------------------------------------------------------*/
2701
2702
2703 DBG_FUNC( "wireless_get_scan" );
2704 DBG_ENTER( DbgInfo );
2705
2706 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2707 ret = -EBUSY;
2708 goto out;
2709 }
2710
2711 wl_lock( lp, &flags );
2712
2713 wl_act_int_off( lp );
2714
2715 /* If the scan is not done, tell the calling process to try again later */
2716 if( !lp->probe_results.scan_complete ) {
2717 ret = -EAGAIN;
2718 goto out_unlock;
2719 }
2720
2721 DBG_TRACE( DbgInfo, "SCAN COMPLETE, Num of APs: %d\n",
2722 lp->probe_results.num_aps );
2723
2724 buf = extra;
2725 buf_end = extra + IW_SCAN_MAX_DATA;
2726
2727 for( count = 0; count < lp->probe_results.num_aps; count++ ) {
2728 /* Reference the probe response from the table */
2729 probe_resp = (PROBE_RESP *)&lp->probe_results.ProbeTable[count];
2730
2731
2732 /* First entry MUST be the MAC address */
2733 memset( &iwe, 0, sizeof( iwe ));
2734
2735 iwe.cmd = SIOCGIWAP;
2736 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
2737 memcpy( iwe.u.ap_addr.sa_data, probe_resp->BSSID, ETH_ALEN);
2738 iwe.len = IW_EV_ADDR_LEN;
2739
2740 buf = IWE_STREAM_ADD_EVENT(info, buf, buf_end, &iwe, IW_EV_ADDR_LEN);
2741
2742
2743 /* Use the mode to indicate if it's a station or AP */
2744 /* Won't always be an AP if in IBSS mode */
2745 memset( &iwe, 0, sizeof( iwe ));
2746
2747 iwe.cmd = SIOCGIWMODE;
2748
2749 if( probe_resp->capability & CAPABILITY_IBSS ) {
2750 iwe.u.mode = IW_MODE_INFRA;
2751 } else {
2752 iwe.u.mode = IW_MODE_MASTER;
2753 }
2754
2755 iwe.len = IW_EV_UINT_LEN;
2756
2757 buf = IWE_STREAM_ADD_EVENT(info, buf, buf_end, &iwe, IW_EV_UINT_LEN);
2758
2759
2760 /* Any quality information */
2761 memset(&iwe, 0, sizeof(iwe));
2762
2763 iwe.cmd = IWEVQUAL;
2764 iwe.u.qual.level = dbm(probe_resp->signal);
2765 iwe.u.qual.noise = dbm(probe_resp->silence);
2766 iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
2767 iwe.u.qual.updated = lp->probe_results.scan_complete | IW_QUAL_DBM;
2768 iwe.len = IW_EV_QUAL_LEN;
2769
2770 buf = IWE_STREAM_ADD_EVENT(info, buf, buf_end, &iwe, IW_EV_QUAL_LEN);
2771
2772
2773 /* ESSID information */
2774 if( probe_resp->rawData[1] > 0 ) {
2775 memset( &iwe, 0, sizeof( iwe ));
2776
2777 iwe.cmd = SIOCGIWESSID;
2778 iwe.u.data.length = probe_resp->rawData[1];
2779 iwe.u.data.flags = 1;
2780
2781 buf = IWE_STREAM_ADD_POINT(info, buf, buf_end, &iwe, &probe_resp->rawData[2]);
2782 }
2783
2784
2785 /* Encryption Information */
2786 memset( &iwe, 0, sizeof( iwe ));
2787
2788 iwe.cmd = SIOCGIWENCODE;
2789 iwe.u.data.length = 0;
2790
2791 /* Check the capabilities field of the Probe Response to see if
2792 'privacy' is supported on the AP in question */
2793 if( probe_resp->capability & CAPABILITY_PRIVACY ) {
2794 iwe.u.data.flags |= IW_ENCODE_ENABLED;
2795 } else {
2796 iwe.u.data.flags |= IW_ENCODE_DISABLED;
2797 }
2798
2799 buf = IWE_STREAM_ADD_POINT(info, buf, buf_end, &iwe, NULL);
2800
2801
2802 /* Frequency Info */
2803 memset( &iwe, 0, sizeof( iwe ));
2804
2805 iwe.cmd = SIOCGIWFREQ;
2806 iwe.len = IW_EV_FREQ_LEN;
2807 iwe.u.freq.m = wl_parse_ds_ie( probe_resp );
2808 iwe.u.freq.e = 0;
2809
2810 buf = IWE_STREAM_ADD_EVENT(info, buf, buf_end, &iwe, IW_EV_FREQ_LEN);
2811
2812
2813 #if WIRELESS_EXT > 14
2814 /* Custom info (Beacon Interval) */
2815 memset( &iwe, 0, sizeof( iwe ));
2816 memset( msg, 0, sizeof( msg ));
2817
2818 iwe.cmd = IWEVCUSTOM;
2819 sprintf( msg, "beacon_interval=%d", probe_resp->beaconInterval );
2820 iwe.u.data.length = strlen( msg );
2821
2822 buf = IWE_STREAM_ADD_POINT(info, buf, buf_end, &iwe, msg);
2823
2824
2825 /* Custom info (WPA-IE) */
2826 wpa_ie = NULL;
2827 wpa_ie_len = 0;
2828
2829 wpa_ie = wl_parse_wpa_ie( probe_resp, &wpa_ie_len );
2830 if( wpa_ie != NULL ) {
2831 memset( &iwe, 0, sizeof( iwe ));
2832 memset( msg, 0, sizeof( msg ));
2833
2834 iwe.cmd = IWEVCUSTOM;
2835 sprintf( msg, "wpa_ie=%s", wl_print_wpa_ie( wpa_ie, wpa_ie_len ));
2836 iwe.u.data.length = strlen( msg );
2837
2838 buf = IWE_STREAM_ADD_POINT(info, buf, buf_end, &iwe, msg);
2839 }
2840
2841 /* Add other custom info in formatted string format as needed... */
2842 #endif
2843 }
2844
2845 data->length = buf - extra;
2846
2847 out_unlock:
2848
2849 wl_act_int_on( lp );
2850
2851 wl_unlock(lp, &flags);
2852
2853 out:
2854 DBG_LEAVE( DbgInfo );
2855 return ret;
2856 } // wireless_get_scan
2857 /*============================================================================*/
2858
2859 #endif // WIRELESS_EXT > 13
2860
2861
2862 #if WIRELESS_EXT > 17
2863
wireless_set_auth(struct net_device * dev,struct iw_request_info * info,struct iw_param * data,char * extra)2864 static int wireless_set_auth(struct net_device *dev,
2865 struct iw_request_info *info,
2866 struct iw_param *data, char *extra)
2867 {
2868 struct wl_private *lp = wl_priv(dev);
2869 unsigned long flags;
2870 int ret;
2871 int iwa_idx = data->flags & IW_AUTH_INDEX;
2872 int iwa_val = data->value;
2873
2874 DBG_FUNC( "wireless_set_auth" );
2875 DBG_ENTER( DbgInfo );
2876
2877 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
2878 ret = -EBUSY;
2879 goto out;
2880 }
2881
2882 wl_lock( lp, &flags );
2883
2884 wl_act_int_off( lp );
2885
2886 switch (iwa_idx) {
2887 case IW_AUTH_WPA_VERSION:
2888 DBG_TRACE( DbgInfo, "IW_AUTH_WPA_VERSION\n");
2889 /* We do support WPA only; how should DISABLED be treated? */
2890 if (iwa_val == IW_AUTH_WPA_VERSION_WPA)
2891 ret = 0;
2892 else
2893 ret = -EINVAL;
2894 break;
2895
2896 case IW_AUTH_WPA_ENABLED:
2897 DBG_TRACE( DbgInfo, "IW_AUTH_WPA_ENABLED: val = %d\n", iwa_val);
2898 if (iwa_val)
2899 lp->EnableEncryption = 2;
2900 else
2901 lp->EnableEncryption = 0;
2902 ret = 0;
2903 break;
2904
2905 case IW_AUTH_TKIP_COUNTERMEASURES:
2906 DBG_TRACE( DbgInfo, "IW_AUTH_TKIP_COUNTERMEASURES\n");
2907 lp->driverEnable = !iwa_val;
2908 if(lp->driverEnable)
2909 hcf_cntl(&(lp->hcfCtx), HCF_CNTL_ENABLE | HCF_PORT_0);
2910 else
2911 hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISABLE | HCF_PORT_0);
2912 ret = 0;
2913 break;
2914
2915 case IW_AUTH_DROP_UNENCRYPTED:
2916 DBG_TRACE( DbgInfo, "IW_AUTH_DROP_UNENCRYPTED\n");
2917 /* We do not actually do anything here, just to silence
2918 * wpa_supplicant */
2919 ret = 0;
2920 break;
2921
2922 case IW_AUTH_CIPHER_PAIRWISE:
2923 DBG_TRACE( DbgInfo, "IW_AUTH_CIPHER_PAIRWISE\n");
2924 /* not implemented, return an error */
2925 ret = -EINVAL;
2926 break;
2927
2928 case IW_AUTH_CIPHER_GROUP:
2929 DBG_TRACE( DbgInfo, "IW_AUTH_CIPHER_GROUP\n");
2930 /* not implemented, return an error */
2931 ret = -EINVAL;
2932 break;
2933
2934 case IW_AUTH_KEY_MGMT:
2935 DBG_TRACE( DbgInfo, "IW_AUTH_KEY_MGMT\n");
2936 /* not implemented, return an error */
2937 ret = -EINVAL;
2938 break;
2939
2940 case IW_AUTH_80211_AUTH_ALG:
2941 DBG_TRACE( DbgInfo, "IW_AUTH_80211_AUTH_ALG\n");
2942 /* not implemented, return an error */
2943 ret = -EINVAL;
2944 break;
2945
2946 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2947 DBG_TRACE( DbgInfo, "IW_AUTH_RX_UNENCRYPTED_EAPOL\n");
2948 /* not implemented, return an error */
2949 ret = -EINVAL;
2950 break;
2951
2952 case IW_AUTH_ROAMING_CONTROL:
2953 DBG_TRACE( DbgInfo, "IW_AUTH_ROAMING_CONTROL\n");
2954 /* not implemented, return an error */
2955 ret = -EINVAL;
2956 break;
2957
2958 case IW_AUTH_PRIVACY_INVOKED:
2959 DBG_TRACE( DbgInfo, "IW_AUTH_PRIVACY_INVOKED\n");
2960 /* not implemented, return an error */
2961 ret = -EINVAL;
2962 break;
2963
2964 default:
2965 DBG_TRACE( DbgInfo, "IW_AUTH_?? (%d) unknown\n", iwa_idx);
2966 /* return an error */
2967 ret = -EINVAL;
2968 break;
2969 }
2970
2971 wl_act_int_on( lp );
2972
2973 wl_unlock(lp, &flags);
2974
2975 out:
2976 DBG_LEAVE( DbgInfo );
2977 return ret;
2978 } // wireless_set_auth
2979 /*============================================================================*/
2980
2981
2982
hermes_set_key(ltv_t * ltv,int alg,int key_idx,u8 * addr,int set_tx,u8 * seq,u8 * key,size_t key_len)2983 static int hermes_set_key(ltv_t *ltv, int alg, int key_idx, u8 *addr,
2984 int set_tx, u8 *seq, u8 *key, size_t key_len)
2985 {
2986 int ret = -EINVAL;
2987 // int count = 0;
2988 int buf_idx = 0;
2989 hcf_8 tsc[IW_ENCODE_SEQ_MAX_SIZE] =
2990 { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
2991
2992 DBG_FUNC( "hermes_set_key" );
2993 DBG_ENTER( DbgInfo );
2994
2995 /*
2996 * Check the key index here; if 0, load as Pairwise Key, otherwise,
2997 * load as a group key. Note that for the Hermes, the RIDs for
2998 * group/pariwise keys are different from each other and different
2999 * than the default WEP keys as well.
3000 */
3001 switch (alg)
3002 {
3003 case IW_ENCODE_ALG_TKIP:
3004 DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_TKIP: key(%d)\n", key_idx);
3005 #if 0
3006 /*
3007 * Make sure that there is no data queued up in the firmware
3008 * before setting the TKIP keys. If this check is not
3009 * performed, some data may be sent out with incorrect MIC
3010 * and cause synchronizarion errors with the AP
3011 */
3012 /* Check every 1ms for 100ms */
3013 for( count = 0; count < 100; count++ )
3014 {
3015 usleep( 1000 );
3016
3017 ltv.len = 2;
3018 ltv.typ = 0xFD91; // This RID not defined in HCF yet!!!
3019 ltv.u.u16[0] = 0;
3020
3021 wl_get_info( sock, <v, ifname );
3022
3023 if( ltv.u.u16[0] == 0 )
3024 {
3025 break;
3026 }
3027 }
3028
3029 if( count == 100 )
3030 {
3031 wpa_printf( MSG_DEBUG, "Timed out waiting for TxQ!" );
3032 }
3033 #endif
3034
3035 switch (key_idx) {
3036 case 0:
3037 ltv->len = 28;
3038 ltv->typ = CFG_ADD_TKIP_MAPPED_KEY;
3039
3040 /* Load the BSSID */
3041 memcpy(<v->u.u8[buf_idx], addr, ETH_ALEN);
3042 buf_idx += ETH_ALEN;
3043
3044 /* Load the TKIP key */
3045 memcpy(<v->u.u8[buf_idx], &key[0], 16);
3046 buf_idx += 16;
3047
3048 /* Load the TSC */
3049 memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
3050 buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
3051
3052 /* Load the RSC */
3053 memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
3054 buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
3055
3056 /* Load the TxMIC key */
3057 memcpy(<v->u.u8[buf_idx], &key[16], 8);
3058 buf_idx += 8;
3059
3060 /* Load the RxMIC key */
3061 memcpy(<v->u.u8[buf_idx], &key[24], 8);
3062
3063 ret = 0;
3064 break;
3065 case 1:
3066 case 2:
3067 case 3:
3068 ltv->len = 26;
3069 ltv->typ = CFG_ADD_TKIP_DEFAULT_KEY;
3070
3071 /* Load the key Index */
3072 ltv->u.u16[buf_idx] = key_idx;
3073 /* If this is a Tx Key, set bit 8000 */
3074 if(set_tx)
3075 ltv->u.u16[buf_idx] |= 0x8000;
3076 buf_idx += 2;
3077
3078 /* Load the RSC */
3079 memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
3080 buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
3081
3082 /* Load the TKIP, TxMIC, and RxMIC keys in one shot, because in
3083 CFG_ADD_TKIP_DEFAULT_KEY they are back-to-back */
3084 memcpy(<v->u.u8[buf_idx], key, key_len);
3085 buf_idx += key_len;
3086
3087 /* Load the TSC */
3088 memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
3089
3090 ltv->u.u16[0] = CNV_INT_TO_LITTLE(ltv->u.u16[0]);
3091
3092 ret = 0;
3093 break;
3094 default:
3095 break;
3096 }
3097
3098 break;
3099
3100 case IW_ENCODE_ALG_WEP:
3101 DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_WEP: key(%d)\n", key_idx);
3102 break;
3103
3104 case IW_ENCODE_ALG_CCMP:
3105 DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_CCMP: key(%d)\n", key_idx);
3106 break;
3107
3108 case IW_ENCODE_ALG_NONE:
3109 DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_NONE: key(%d)\n", key_idx);
3110 switch (key_idx) {
3111 case 0:
3112 if (memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) {
3113 //if (addr != NULL) {
3114 ltv->len = 7;
3115 ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY;
3116 memcpy(<v->u.u8[0], addr, ETH_ALEN);
3117 ret = 0;
3118 }
3119 break;
3120 case 1:
3121 case 2:
3122 case 3:
3123 /* Clear the Group TKIP keys by index */
3124 ltv->len = 2;
3125 ltv->typ = CFG_REMOVE_TKIP_DEFAULT_KEY;
3126 ltv->u.u16[0] = key_idx;
3127
3128 ret = 0;
3129 break;
3130 default:
3131 break;
3132 }
3133 break;
3134 default:
3135 DBG_TRACE( DbgInfo, "IW_ENCODE_??: key(%d)\n", key_idx);
3136 break;
3137 }
3138
3139 DBG_LEAVE( DbgInfo );
3140 return ret;
3141 } // hermes_set_key
3142 /*============================================================================*/
3143
3144
3145
wireless_set_encodeext(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * keybuf)3146 static int wireless_set_encodeext (struct net_device *dev,
3147 struct iw_request_info *info,
3148 struct iw_point *erq, char *keybuf)
3149 {
3150 struct wl_private *lp = wl_priv(dev);
3151 unsigned long flags;
3152 int ret;
3153 int key_idx = (erq->flags&IW_ENCODE_INDEX) - 1;
3154 ltv_t ltv;
3155 struct iw_encode_ext *ext = (struct iw_encode_ext *)keybuf;
3156
3157 DBG_FUNC( "wireless_set_encodeext" );
3158 DBG_ENTER( DbgInfo );
3159
3160 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
3161 ret = -EBUSY;
3162 goto out;
3163 }
3164
3165 if (sizeof(ext->rx_seq) != 8) {
3166 DBG_TRACE(DbgInfo, "rz_seq size mismatch\n");
3167 DBG_LEAVE(DbgInfo);
3168 return -EINVAL;
3169 }
3170
3171 /* Handle WEP keys via the old set encode procedure */
3172 if(ext->alg == IW_ENCODE_ALG_WEP) {
3173 struct iw_point wep_erq;
3174 char *wep_keybuf;
3175
3176 /* Build request structure */
3177 wep_erq.flags = erq->flags; // take over flags with key index
3178 wep_erq.length = ext->key_len; // take length from extended key info
3179 wep_keybuf = ext->key; // pointer to the key text
3180
3181 /* Call wireless_set_encode tot handle the WEP key */
3182 ret = wireless_set_encode(dev, info, &wep_erq, wep_keybuf);
3183 goto out;
3184 }
3185
3186 /* Proceed for extended encode functions for WAP and NONE */
3187 wl_lock( lp, &flags );
3188
3189 wl_act_int_off( lp );
3190
3191 memset(<v, 0, sizeof(ltv));
3192 ret = hermes_set_key(<v, ext->alg, key_idx, ext->addr.sa_data,
3193 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
3194 ext->rx_seq, ext->key, ext->key_len);
3195
3196 if (ret != 0) {
3197 DBG_TRACE( DbgInfo, "hermes_set_key returned != 0, key not set\n");
3198 goto out_unlock;
3199 }
3200
3201 /* Put the key in HCF */
3202 ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v);
3203
3204 out_unlock:
3205 if(ret == HCF_SUCCESS) {
3206 DBG_TRACE( DbgInfo, "Put key info succes\n");
3207 } else {
3208 DBG_TRACE( DbgInfo, "Put key info failed, key not set\n");
3209 }
3210
3211 wl_act_int_on( lp );
3212
3213 wl_unlock(lp, &flags);
3214
3215 out:
3216 DBG_LEAVE( DbgInfo );
3217 return ret;
3218 } // wireless_set_encodeext
3219 /*============================================================================*/
3220
3221
3222
wireless_get_genie(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)3223 static int wireless_get_genie(struct net_device *dev,
3224 struct iw_request_info *info,
3225 struct iw_point *data, char *extra)
3226
3227 {
3228 struct wl_private *lp = wl_priv(dev);
3229 unsigned long flags;
3230 int ret = 0;
3231 ltv_t ltv;
3232
3233 DBG_FUNC( "wireless_get_genie" );
3234 DBG_ENTER( DbgInfo );
3235
3236 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
3237 ret = -EBUSY;
3238 goto out;
3239 }
3240
3241 wl_lock( lp, &flags );
3242
3243 wl_act_int_off( lp );
3244
3245 memset(<v, 0, sizeof(ltv));
3246 ltv.len = 2;
3247 ltv.typ = CFG_SET_WPA_AUTH_KEY_MGMT_SUITE;
3248 lp->AuthKeyMgmtSuite = ltv.u.u16[0] = 4;
3249 ltv.u.u16[0] = CNV_INT_TO_LITTLE(ltv.u.u16[0]);
3250
3251 ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v);
3252
3253 wl_act_int_on( lp );
3254
3255 wl_unlock(lp, &flags);
3256
3257 out:
3258 DBG_LEAVE( DbgInfo );
3259 return ret;
3260 }
3261 /*============================================================================*/
3262
3263
3264 #endif // WIRELESS_EXT > 17
3265
3266 /*******************************************************************************
3267 * wl_wireless_stats()
3268 *******************************************************************************
3269 *
3270 * DESCRIPTION:
3271 *
3272 * Return the current device wireless statistics.
3273 *
3274 * PARAMETERS:
3275 *
3276 * wrq - the wireless request buffer
3277 * lp - the device's private adapter structure
3278 *
3279 * RETURNS:
3280 *
3281 * 0 on success
3282 * errno value otherwise
3283 *
3284 ******************************************************************************/
wl_wireless_stats(struct net_device * dev)3285 struct iw_statistics * wl_wireless_stats( struct net_device *dev )
3286 {
3287 struct iw_statistics *pStats;
3288 struct wl_private *lp = wl_priv(dev);
3289 /*------------------------------------------------------------------------*/
3290
3291
3292 DBG_FUNC( "wl_wireless_stats" );
3293 DBG_ENTER(DbgInfo);
3294 DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
3295
3296 pStats = NULL;
3297
3298 /* Initialize the statistics */
3299 pStats = &( lp->wstats );
3300 pStats->qual.updated = 0x00;
3301
3302 if( !( lp->flags & WVLAN2_UIL_BUSY ))
3303 {
3304 CFG_COMMS_QUALITY_STRCT *pQual;
3305 CFG_HERMES_TALLIES_STRCT tallies;
3306 int status;
3307
3308 /* Update driver status */
3309 pStats->status = 0;
3310
3311 /* Get the current link quality information */
3312 lp->ltvRecord.len = 1 + ( sizeof( *pQual ) / sizeof( hcf_16 ));
3313 lp->ltvRecord.typ = CFG_COMMS_QUALITY;
3314 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
3315
3316 if( status == HCF_SUCCESS ) {
3317 pQual = (CFG_COMMS_QUALITY_STRCT *)&( lp->ltvRecord );
3318
3319 #ifdef USE_DBM
3320 pStats->qual.qual = (u_char) CNV_LITTLE_TO_INT( pQual->coms_qual );
3321 pStats->qual.level = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->signal_lvl ));
3322 pStats->qual.noise = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->noise_lvl ));
3323
3324 pStats->qual.updated |= (IW_QUAL_QUAL_UPDATED |
3325 IW_QUAL_LEVEL_UPDATED |
3326 IW_QUAL_NOISE_UPDATED |
3327 IW_QUAL_DBM);
3328 #else
3329 pStats->qual.qual = percent( CNV_LITTLE_TO_INT( pQual->coms_qual ),
3330 HCF_MIN_COMM_QUALITY,
3331 HCF_MAX_COMM_QUALITY );
3332
3333 pStats->qual.level = percent( CNV_LITTLE_TO_INT( pQual->signal_lvl ),
3334 HCF_MIN_SIGNAL_LEVEL,
3335 HCF_MAX_SIGNAL_LEVEL );
3336
3337 pStats->qual.noise = percent( CNV_LITTLE_TO_INT( pQual->noise_lvl ),
3338 HCF_MIN_NOISE_LEVEL,
3339 HCF_MAX_NOISE_LEVEL );
3340
3341 pStats->qual.updated |= (IW_QUAL_QUAL_UPDATED |
3342 IW_QUAL_LEVEL_UPDATED |
3343 IW_QUAL_NOISE_UPDATED);
3344 #endif /* USE_DBM */
3345 } else {
3346 memset( &( pStats->qual ), 0, sizeof( pStats->qual ));
3347 }
3348
3349 /* Get the current tallies from the adapter */
3350 /* Only possible when the device is open */
3351 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
3352 if( wl_get_tallies( lp, &tallies ) == 0 ) {
3353 /* No endian translation is needed here, as CFG_TALLIES is an
3354 MSF RID; all processing is done on the host, not the card! */
3355 pStats->discard.nwid = 0L;
3356 pStats->discard.code = tallies.RxWEPUndecryptable;
3357 pStats->discard.misc = tallies.TxDiscards +
3358 tallies.RxFCSErrors +
3359 //tallies.RxDiscardsNoBuffer +
3360 tallies.TxDiscardsWrongSA;
3361 //;? Extra taken over from Linux driver based on 7.18 version
3362 pStats->discard.retries = tallies.TxRetryLimitExceeded;
3363 pStats->discard.fragment = tallies.RxMsgInBadMsgFragments;
3364 } else {
3365 memset( &( pStats->discard ), 0, sizeof( pStats->discard ));
3366 }
3367 } else {
3368 memset( &( pStats->discard ), 0, sizeof( pStats->discard ));
3369 }
3370 }
3371
3372 DBG_LEAVE( DbgInfo );
3373 return pStats;
3374 } // wl_wireless_stats
3375 /*============================================================================*/
3376
3377
3378
3379
3380 /*******************************************************************************
3381 * wl_get_wireless_stats()
3382 *******************************************************************************
3383 *
3384 * DESCRIPTION:
3385 *
3386 * Return the current device wireless statistics. This function calls
3387 * wl_wireless_stats, but acquires spinlocks first as it can be called
3388 * directly by the network layer.
3389 *
3390 * PARAMETERS:
3391 *
3392 * wrq - the wireless request buffer
3393 * lp - the device's private adapter structure
3394 *
3395 * RETURNS:
3396 *
3397 * 0 on success
3398 * errno value otherwise
3399 *
3400 ******************************************************************************/
wl_get_wireless_stats(struct net_device * dev)3401 struct iw_statistics * wl_get_wireless_stats( struct net_device *dev )
3402 {
3403 unsigned long flags;
3404 struct wl_private *lp = wl_priv(dev);
3405 struct iw_statistics *pStats = NULL;
3406 /*------------------------------------------------------------------------*/
3407
3408 DBG_FUNC( "wl_get_wireless_stats" );
3409 DBG_ENTER(DbgInfo);
3410
3411 wl_lock( lp, &flags );
3412
3413 wl_act_int_off( lp );
3414
3415 #ifdef USE_RTS
3416 if( lp->useRTS == 1 ) {
3417 DBG_TRACE( DbgInfo, "Skipping wireless stats, in RTS mode\n" );
3418 } else
3419 #endif
3420 {
3421 pStats = wl_wireless_stats( dev );
3422 }
3423 wl_act_int_on( lp );
3424
3425 wl_unlock(lp, &flags);
3426
3427 DBG_LEAVE( DbgInfo );
3428 return pStats;
3429 } // wl_get_wireless_stats
3430
3431
3432 /*******************************************************************************
3433 * wl_spy_gather()
3434 *******************************************************************************
3435 *
3436 * DESCRIPTION:
3437 *
3438 * Gather wireless spy statistics.
3439 *
3440 * PARAMETERS:
3441 *
3442 * wrq - the wireless request buffer
3443 * lp - the device's private adapter structure
3444 *
3445 * RETURNS:
3446 *
3447 * 0 on success
3448 * errno value otherwise
3449 *
3450 ******************************************************************************/
wl_spy_gather(struct net_device * dev,u_char * mac)3451 inline void wl_spy_gather( struct net_device *dev, u_char *mac )
3452 {
3453 struct iw_quality wstats;
3454 int status;
3455 u_char stats[2];
3456 DESC_STRCT desc[1];
3457 struct wl_private *lp = wl_priv(dev);
3458 /*------------------------------------------------------------------------*/
3459
3460 /* shortcut */
3461 if (!lp->spy_data.spy_number) {
3462 return;
3463 }
3464
3465 /* Gather wireless spy statistics: for each packet, compare the source
3466 address with out list, and if match, get the stats. */
3467 memset( stats, 0, sizeof(stats));
3468 memset( desc, 0, sizeof(DESC_STRCT));
3469
3470 desc[0].buf_addr = stats;
3471 desc[0].BUF_SIZE = sizeof(stats);
3472 desc[0].next_desc_addr = 0; // terminate list
3473
3474 status = hcf_rcv_msg( &( lp->hcfCtx ), &desc[0], 0 );
3475
3476 if( status == HCF_SUCCESS ) {
3477 wstats.level = (u_char) dbm(stats[1]);
3478 wstats.noise = (u_char) dbm(stats[0]);
3479 wstats.qual = wstats.level > wstats.noise ? wstats.level - wstats.noise : 0;
3480
3481 wstats.updated = (IW_QUAL_QUAL_UPDATED |
3482 IW_QUAL_LEVEL_UPDATED |
3483 IW_QUAL_NOISE_UPDATED |
3484 IW_QUAL_DBM);
3485
3486 wireless_spy_update( dev, mac, &wstats );
3487 }
3488 } // wl_spy_gather
3489 /*============================================================================*/
3490
3491
3492
3493
3494 /*******************************************************************************
3495 * wl_wext_event_freq()
3496 *******************************************************************************
3497 *
3498 * DESCRIPTION:
3499 *
3500 * This function is used to send an event that the channel/freq
3501 * configuration for a specific device has changed.
3502 *
3503 *
3504 * PARAMETERS:
3505 *
3506 * dev - the network device for which this event is to be issued
3507 *
3508 * RETURNS:
3509 *
3510 * N/A
3511 *
3512 ******************************************************************************/
wl_wext_event_freq(struct net_device * dev)3513 void wl_wext_event_freq( struct net_device *dev )
3514 {
3515 #if WIRELESS_EXT > 13
3516 union iwreq_data wrqu;
3517 struct wl_private *lp = wl_priv(dev);
3518 /*------------------------------------------------------------------------*/
3519
3520
3521 memset( &wrqu, 0, sizeof( wrqu ));
3522
3523 wrqu.freq.m = lp->Channel;
3524 wrqu.freq.e = 0;
3525
3526 wireless_send_event( dev, SIOCSIWFREQ, &wrqu, NULL );
3527 #endif /* WIRELESS_EXT > 13 */
3528
3529 return;
3530 } // wl_wext_event_freq
3531 /*============================================================================*/
3532
3533
3534
3535
3536 /*******************************************************************************
3537 * wl_wext_event_mode()
3538 *******************************************************************************
3539 *
3540 * DESCRIPTION:
3541 *
3542 * This function is used to send an event that the mode of operation
3543 * for a specific device has changed.
3544 *
3545 *
3546 * PARAMETERS:
3547 *
3548 * dev - the network device for which this event is to be issued
3549 *
3550 * RETURNS:
3551 *
3552 * N/A
3553 *
3554 ******************************************************************************/
wl_wext_event_mode(struct net_device * dev)3555 void wl_wext_event_mode( struct net_device *dev )
3556 {
3557 #if WIRELESS_EXT > 13
3558 union iwreq_data wrqu;
3559 struct wl_private *lp = wl_priv(dev);
3560 /*------------------------------------------------------------------------*/
3561
3562
3563 memset( &wrqu, 0, sizeof( wrqu ));
3564
3565 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
3566 wrqu.mode = IW_MODE_INFRA;
3567 } else {
3568 wrqu.mode = IW_MODE_MASTER;
3569 }
3570
3571 wireless_send_event( dev, SIOCSIWMODE, &wrqu, NULL );
3572 #endif /* WIRELESS_EXT > 13 */
3573
3574 return;
3575 } // wl_wext_event_mode
3576 /*============================================================================*/
3577
3578
3579
3580
3581 /*******************************************************************************
3582 * wl_wext_event_essid()
3583 *******************************************************************************
3584 *
3585 * DESCRIPTION:
3586 *
3587 * This function is used to send an event that the ESSID configuration for
3588 * a specific device has changed.
3589 *
3590 *
3591 * PARAMETERS:
3592 *
3593 * dev - the network device for which this event is to be issued
3594 *
3595 * RETURNS:
3596 *
3597 * N/A
3598 *
3599 ******************************************************************************/
wl_wext_event_essid(struct net_device * dev)3600 void wl_wext_event_essid( struct net_device *dev )
3601 {
3602 #if WIRELESS_EXT > 13
3603 union iwreq_data wrqu;
3604 struct wl_private *lp = wl_priv(dev);
3605 /*------------------------------------------------------------------------*/
3606
3607
3608 memset( &wrqu, 0, sizeof( wrqu ));
3609
3610 /* Fill out the buffer. Note that the buffer doesn't actually contain the
3611 ESSID, but a pointer to the contents. In addition, the 'extra' field of
3612 the call to wireless_send_event() must also point to where the ESSID
3613 lives */
3614 wrqu.essid.length = strlen( lp->NetworkName );
3615 wrqu.essid.pointer = (caddr_t)lp->NetworkName;
3616 wrqu.essid.flags = 1;
3617
3618 wireless_send_event( dev, SIOCSIWESSID, &wrqu, lp->NetworkName );
3619 #endif /* WIRELESS_EXT > 13 */
3620
3621 return;
3622 } // wl_wext_event_essid
3623 /*============================================================================*/
3624
3625
3626
3627
3628 /*******************************************************************************
3629 * wl_wext_event_encode()
3630 *******************************************************************************
3631 *
3632 * DESCRIPTION:
3633 *
3634 * This function is used to send an event that the encryption configuration
3635 * for a specific device has changed.
3636 *
3637 *
3638 * PARAMETERS:
3639 *
3640 * dev - the network device for which this event is to be issued
3641 *
3642 * RETURNS:
3643 *
3644 * N/A
3645 *
3646 ******************************************************************************/
wl_wext_event_encode(struct net_device * dev)3647 void wl_wext_event_encode( struct net_device *dev )
3648 {
3649 #if WIRELESS_EXT > 13
3650 union iwreq_data wrqu;
3651 struct wl_private *lp = wl_priv(dev);
3652 int index = 0;
3653 /*------------------------------------------------------------------------*/
3654
3655
3656 memset( &wrqu, 0, sizeof( wrqu ));
3657
3658 if( lp->EnableEncryption == 0 ) {
3659 wrqu.encoding.flags = IW_ENCODE_DISABLED;
3660 } else {
3661 wrqu.encoding.flags |= lp->TransmitKeyID;
3662
3663 index = lp->TransmitKeyID - 1;
3664
3665 /* Only set IW_ENCODE_RESTRICTED/OPEN flag using lp->ExcludeUnencrypted
3666 if we're in AP mode */
3667 #if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
3668 //;?should we restore this to allow smaller memory footprint
3669
3670 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
3671 if( lp->ExcludeUnencrypted ) {
3672 wrqu.encoding.flags |= IW_ENCODE_RESTRICTED;
3673 } else {
3674 wrqu.encoding.flags |= IW_ENCODE_OPEN;
3675 }
3676 }
3677
3678 #endif // HCF_TYPE_AP
3679
3680 /* Only provide the key if permissions allow */
3681 if( capable( CAP_NET_ADMIN )) {
3682 wrqu.encoding.pointer = (caddr_t)lp->DefaultKeys.key[index].key;
3683 wrqu.encoding.length = lp->DefaultKeys.key[index].len;
3684 } else {
3685 wrqu.encoding.flags |= IW_ENCODE_NOKEY;
3686 }
3687 }
3688
3689 wireless_send_event( dev, SIOCSIWENCODE, &wrqu,
3690 lp->DefaultKeys.key[index].key );
3691 #endif /* WIRELESS_EXT > 13 */
3692
3693 return;
3694 } // wl_wext_event_encode
3695 /*============================================================================*/
3696
3697
3698
3699
3700 /*******************************************************************************
3701 * wl_wext_event_ap()
3702 *******************************************************************************
3703 *
3704 * DESCRIPTION:
3705 *
3706 * This function is used to send an event that the device has been
3707 * associated to a new AP.
3708 *
3709 *
3710 * PARAMETERS:
3711 *
3712 * dev - the network device for which this event is to be issued
3713 *
3714 * RETURNS:
3715 *
3716 * N/A
3717 *
3718 ******************************************************************************/
wl_wext_event_ap(struct net_device * dev)3719 void wl_wext_event_ap( struct net_device *dev )
3720 {
3721 #if WIRELESS_EXT > 13
3722 union iwreq_data wrqu;
3723 struct wl_private *lp = wl_priv(dev);
3724 int status;
3725 /*------------------------------------------------------------------------*/
3726
3727
3728 /* Retrieve the WPA-IEs used by the firmware and send an event. We must send
3729 this event BEFORE sending the association event, as there are timing
3730 issues with the hostap supplicant. The supplicant will attempt to process
3731 an EAPOL-Key frame from an AP before receiving this information, which
3732 is required properly process the said frame. */
3733 wl_wext_event_assoc_ie( dev );
3734
3735 /* Get the BSSID */
3736 lp->ltvRecord.typ = CFG_CUR_BSSID;
3737 lp->ltvRecord.len = 4;
3738
3739 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
3740 if( status == HCF_SUCCESS ) {
3741 memset( &wrqu, 0, sizeof( wrqu ));
3742
3743 memcpy( wrqu.addr.sa_data, lp->ltvRecord.u.u8, ETH_ALEN );
3744
3745 wrqu.addr.sa_family = ARPHRD_ETHER;
3746
3747 wireless_send_event( dev, SIOCGIWAP, &wrqu, NULL );
3748 }
3749
3750 #endif /* WIRELESS_EXT > 13 */
3751
3752 return;
3753 } // wl_wext_event_ap
3754 /*============================================================================*/
3755
3756
3757
3758 /*******************************************************************************
3759 * wl_wext_event_scan_complete()
3760 *******************************************************************************
3761 *
3762 * DESCRIPTION:
3763 *
3764 * This function is used to send an event that a request for a network scan
3765 * has completed.
3766 *
3767 *
3768 * PARAMETERS:
3769 *
3770 * dev - the network device for which this event is to be issued
3771 *
3772 * RETURNS:
3773 *
3774 * N/A
3775 *
3776 ******************************************************************************/
wl_wext_event_scan_complete(struct net_device * dev)3777 void wl_wext_event_scan_complete( struct net_device *dev )
3778 {
3779 #if WIRELESS_EXT > 13
3780 union iwreq_data wrqu;
3781 /*------------------------------------------------------------------------*/
3782
3783
3784 memset( &wrqu, 0, sizeof( wrqu ));
3785
3786 wrqu.addr.sa_family = ARPHRD_ETHER;
3787 wireless_send_event( dev, SIOCGIWSCAN, &wrqu, NULL );
3788 #endif /* WIRELESS_EXT > 13 */
3789
3790 return;
3791 } // wl_wext_event_scan_complete
3792 /*============================================================================*/
3793
3794
3795
3796
3797 /*******************************************************************************
3798 * wl_wext_event_new_sta()
3799 *******************************************************************************
3800 *
3801 * DESCRIPTION:
3802 *
3803 * This function is used to send an event that an AP has registered a new
3804 * station.
3805 *
3806 *
3807 * PARAMETERS:
3808 *
3809 * dev - the network device for which this event is to be issued
3810 *
3811 * RETURNS:
3812 *
3813 * N/A
3814 *
3815 ******************************************************************************/
wl_wext_event_new_sta(struct net_device * dev)3816 void wl_wext_event_new_sta( struct net_device *dev )
3817 {
3818 #if WIRELESS_EXT > 14
3819 union iwreq_data wrqu;
3820 /*------------------------------------------------------------------------*/
3821
3822
3823 memset( &wrqu, 0, sizeof( wrqu ));
3824
3825 /* Send the station's mac address here */
3826 memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN );
3827 wrqu.addr.sa_family = ARPHRD_ETHER;
3828 wireless_send_event( dev, IWEVREGISTERED, &wrqu, NULL );
3829 #endif /* WIRELESS_EXT > 14 */
3830
3831 return;
3832 } // wl_wext_event_new_sta
3833 /*============================================================================*/
3834
3835
3836
3837
3838 /*******************************************************************************
3839 * wl_wext_event_expired_sta()
3840 *******************************************************************************
3841 *
3842 * DESCRIPTION:
3843 *
3844 * This function is used to send an event that an AP has deregistered a
3845 * station.
3846 *
3847 *
3848 * PARAMETERS:
3849 *
3850 * dev - the network device for which this event is to be issued
3851 *
3852 * RETURNS:
3853 *
3854 * N/A
3855 *
3856 ******************************************************************************/
wl_wext_event_expired_sta(struct net_device * dev)3857 void wl_wext_event_expired_sta( struct net_device *dev )
3858 {
3859 #if WIRELESS_EXT > 14
3860 union iwreq_data wrqu;
3861 /*------------------------------------------------------------------------*/
3862
3863
3864 memset( &wrqu, 0, sizeof( wrqu ));
3865
3866 memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN );
3867 wrqu.addr.sa_family = ARPHRD_ETHER;
3868 wireless_send_event( dev, IWEVEXPIRED, &wrqu, NULL );
3869 #endif /* WIRELESS_EXT > 14 */
3870
3871 return;
3872 } // wl_wext_event_expired_sta
3873 /*============================================================================*/
3874
3875
3876
3877
3878 /*******************************************************************************
3879 * wl_wext_event_mic_failed()
3880 *******************************************************************************
3881 *
3882 * DESCRIPTION:
3883 *
3884 * This function is used to send an event that MIC calculations failed.
3885 *
3886 *
3887 * PARAMETERS:
3888 *
3889 * dev - the network device for which this event is to be issued
3890 *
3891 * RETURNS:
3892 *
3893 * N/A
3894 *
3895 ******************************************************************************/
wl_wext_event_mic_failed(struct net_device * dev)3896 void wl_wext_event_mic_failed( struct net_device *dev )
3897 {
3898 #if WIRELESS_EXT > 14
3899 char msg[512];
3900 union iwreq_data wrqu;
3901 struct wl_private *lp = wl_priv(dev);
3902 int key_idx;
3903 char *addr1;
3904 char *addr2;
3905 WVLAN_RX_WMP_HDR *hdr;
3906 /*------------------------------------------------------------------------*/
3907
3908
3909 key_idx = lp->lookAheadBuf[HFS_STAT+1] >> 3;
3910 key_idx &= 0x03;
3911
3912 /* Cast the lookahead buffer into a RFS format */
3913 hdr = (WVLAN_RX_WMP_HDR *)&lp->lookAheadBuf[HFS_STAT];
3914
3915 /* Cast the addresses to byte buffers, as in the above RFS they are word
3916 length */
3917 addr1 = (char *)hdr->address1;
3918 addr2 = (char *)hdr->address2;
3919
3920 DBG_PRINT( "MIC FAIL - KEY USED : %d, STATUS : 0x%04x\n", key_idx,
3921 hdr->status );
3922
3923 memset( &wrqu, 0, sizeof( wrqu ));
3924 memset( msg, 0, sizeof( msg ));
3925
3926
3927 /* Because MIC failures are not part of the Wireless Extensions yet, they
3928 must be passed as a string using an IWEVCUSTOM event. In order for the
3929 event to be effective, the string format must be known by both the
3930 driver and the supplicant. The following is the string format used by the
3931 hostap project's WPA supplicant, and will be used here until the Wireless
3932 Extensions interface adds this support:
3933
3934 MLME-MICHAELMICFAILURE.indication(keyid=# broadcast/unicast addr=addr2)
3935 */
3936
3937 /* NOTE: Format of MAC address (using colons to separate bytes) may cause
3938 a problem in future versions of the supplicant, if they ever
3939 actually parse these parameters */
3940 #if DBG
3941 sprintf(msg, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast "
3942 "addr=%pM)", key_idx, addr1[0] & 0x01 ? "broad" : "uni",
3943 addr2);
3944 #endif
3945 wrqu.data.length = strlen( msg );
3946 wireless_send_event( dev, IWEVCUSTOM, &wrqu, msg );
3947 #endif /* WIRELESS_EXT > 14 */
3948
3949 return;
3950 } // wl_wext_event_mic_failed
3951 /*============================================================================*/
3952
3953
3954
3955
3956 /*******************************************************************************
3957 * wl_wext_event_assoc_ie()
3958 *******************************************************************************
3959 *
3960 * DESCRIPTION:
3961 *
3962 * This function is used to send an event containing the WPA-IE generated
3963 * by the firmware in an association request.
3964 *
3965 *
3966 * PARAMETERS:
3967 *
3968 * dev - the network device for which this event is to be issued
3969 *
3970 * RETURNS:
3971 *
3972 * N/A
3973 *
3974 ******************************************************************************/
wl_wext_event_assoc_ie(struct net_device * dev)3975 void wl_wext_event_assoc_ie( struct net_device *dev )
3976 {
3977 #if WIRELESS_EXT > 14
3978 char msg[512];
3979 union iwreq_data wrqu;
3980 struct wl_private *lp = wl_priv(dev);
3981 int status;
3982 PROBE_RESP data;
3983 hcf_16 length;
3984 hcf_8 *wpa_ie;
3985 /*------------------------------------------------------------------------*/
3986
3987
3988 memset( &wrqu, 0, sizeof( wrqu ));
3989 memset( msg, 0, sizeof( msg ));
3990
3991 /* Retrieve the Association Request IE */
3992 lp->ltvRecord.len = 45;
3993 lp->ltvRecord.typ = CFG_CUR_ASSOC_REQ_INFO;
3994
3995 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
3996 if( status == HCF_SUCCESS )
3997 {
3998 length = 0;
3999 memcpy( &data.rawData, &( lp->ltvRecord.u.u8[1] ), 88 );
4000 wpa_ie = wl_parse_wpa_ie( &data, &length );
4001
4002 /* Because this event (Association WPA-IE) is not part of the Wireless
4003 Extensions yet, it must be passed as a string using an IWEVCUSTOM event.
4004 In order for the event to be effective, the string format must be known
4005 by both the driver and the supplicant. The following is the string format
4006 used by the hostap project's WPA supplicant, and will be used here until
4007 the Wireless Extensions interface adds this support:
4008
4009 ASSOCINFO(ReqIEs=WPA-IE RespIEs=WPA-IE)
4010 */
4011
4012 if( length != 0 )
4013 {
4014 sprintf( msg, "ASSOCINFO(ReqIEs=%s)", wl_print_wpa_ie( wpa_ie, length ));
4015 wrqu.data.length = strlen( msg );
4016 wireless_send_event( dev, IWEVCUSTOM, &wrqu, msg );
4017 }
4018 }
4019 #endif /* WIRELESS_EXT > 14 */
4020
4021 return;
4022 } // wl_wext_event_assoc_ie
4023 /*============================================================================*/
4024 /* Structures to export the Wireless Handlers */
4025
4026 static const iw_handler wl_handler[] =
4027 {
4028 (iw_handler) wireless_commit, /* SIOCSIWCOMMIT */
4029 (iw_handler) wireless_get_protocol, /* SIOCGIWNAME */
4030 (iw_handler) NULL, /* SIOCSIWNWID */
4031 (iw_handler) NULL, /* SIOCGIWNWID */
4032 (iw_handler) wireless_set_frequency, /* SIOCSIWFREQ */
4033 (iw_handler) wireless_get_frequency, /* SIOCGIWFREQ */
4034 (iw_handler) wireless_set_porttype, /* SIOCSIWMODE */
4035 (iw_handler) wireless_get_porttype, /* SIOCGIWMODE */
4036 (iw_handler) wireless_set_sensitivity, /* SIOCSIWSENS */
4037 (iw_handler) wireless_get_sensitivity, /* SIOCGIWSENS */
4038 (iw_handler) NULL , /* SIOCSIWRANGE */
4039 (iw_handler) wireless_get_range, /* SIOCGIWRANGE */
4040 (iw_handler) NULL , /* SIOCSIWPRIV */
4041 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
4042 (iw_handler) NULL , /* SIOCSIWSTATS */
4043 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
4044 iw_handler_set_spy, /* SIOCSIWSPY */
4045 iw_handler_get_spy, /* SIOCGIWSPY */
4046 NULL, /* SIOCSIWTHRSPY */
4047 NULL, /* SIOCGIWTHRSPY */
4048 (iw_handler) NULL, /* SIOCSIWAP */
4049 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
4050 (iw_handler) wireless_get_bssid, /* SIOCGIWAP */
4051 #else
4052 (iw_handler) NULL, /* SIOCGIWAP */
4053 #endif
4054 (iw_handler) NULL, /* SIOCSIWMLME */
4055 (iw_handler) wireless_get_ap_list, /* SIOCGIWAPLIST */
4056 (iw_handler) wireless_set_scan, /* SIOCSIWSCAN */
4057 (iw_handler) wireless_get_scan, /* SIOCGIWSCAN */
4058 (iw_handler) wireless_set_essid, /* SIOCSIWESSID */
4059 (iw_handler) wireless_get_essid, /* SIOCGIWESSID */
4060 (iw_handler) wireless_set_nickname, /* SIOCSIWNICKN */
4061 (iw_handler) wireless_get_nickname, /* SIOCGIWNICKN */
4062 (iw_handler) NULL, /* -- hole -- */
4063 (iw_handler) NULL, /* -- hole -- */
4064 (iw_handler) wireless_set_rate, /* SIOCSIWRATE */
4065 (iw_handler) wireless_get_rate, /* SIOCGIWRATE */
4066 (iw_handler) wireless_set_rts_threshold,/* SIOCSIWRTS */
4067 (iw_handler) wireless_get_rts_threshold,/* SIOCGIWRTS */
4068 (iw_handler) NULL, /* SIOCSIWFRAG */
4069 (iw_handler) NULL, /* SIOCGIWFRAG */
4070 (iw_handler) NULL, /* SIOCSIWTXPOW */
4071 (iw_handler) wireless_get_tx_power, /* SIOCGIWTXPOW */
4072 (iw_handler) NULL, /* SIOCSIWRETRY */
4073 (iw_handler) NULL, /* SIOCGIWRETRY */
4074 (iw_handler) wireless_set_encode, /* SIOCSIWENCODE */
4075 (iw_handler) wireless_get_encode, /* SIOCGIWENCODE */
4076 (iw_handler) wireless_set_power, /* SIOCSIWPOWER */
4077 (iw_handler) wireless_get_power, /* SIOCGIWPOWER */
4078 (iw_handler) NULL, /* -- hole -- */
4079 (iw_handler) NULL, /* -- hole -- */
4080 (iw_handler) wireless_get_genie, /* SIOCSIWGENIE */
4081 (iw_handler) NULL, /* SIOCGIWGENIE */
4082 (iw_handler) wireless_set_auth, /* SIOCSIWAUTH */
4083 (iw_handler) NULL, /* SIOCGIWAUTH */
4084 (iw_handler) wireless_set_encodeext, /* SIOCSIWENCODEEXT */
4085 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
4086 (iw_handler) NULL, /* SIOCSIWPMKSA */
4087 (iw_handler) NULL, /* -- hole -- */
4088 };
4089
4090 static const iw_handler wl_private_handler[] =
4091 { /* SIOCIWFIRSTPRIV + */
4092 wvlan_set_netname, /* 0: SIOCSIWNETNAME */
4093 wvlan_get_netname, /* 1: SIOCGIWNETNAME */
4094 wvlan_set_station_nickname, /* 2: SIOCSIWSTANAME */
4095 wvlan_get_station_nickname, /* 3: SIOCGIWSTANAME */
4096 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
4097 wvlan_set_porttype, /* 4: SIOCSIWPORTTYPE */
4098 wvlan_get_porttype, /* 5: SIOCGIWPORTTYPE */
4099 #endif
4100 };
4101
4102 struct iw_priv_args wl_priv_args[] = {
4103 {SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" },
4104 {SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" },
4105 {SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" },
4106 {SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gstation_name" },
4107 #if 1 //;? #if (HCF_TYPE) & HCF_TYPE_STA
4108 {SIOCSIWPORTTYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" },
4109 {SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gport_type" },
4110 #endif
4111 };
4112
4113 const struct iw_handler_def wl_iw_handler_def =
4114 {
4115 .num_private = sizeof(wl_private_handler) / sizeof(iw_handler),
4116 .private = (iw_handler *) wl_private_handler,
4117 .private_args = (struct iw_priv_args *) wl_priv_args,
4118 .num_private_args = sizeof(wl_priv_args) / sizeof(struct iw_priv_args),
4119 .num_standard = sizeof(wl_handler) / sizeof(iw_handler),
4120 .standard = (iw_handler *) wl_handler,
4121 .get_wireless_stats = wl_get_wireless_stats,
4122 };
4123
4124 #endif // WIRELESS_EXT
4125