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