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