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