staging: wlags49_h2: Fixup IW_AUTH handling
[pandora-kernel.git] / drivers / staging / wlags49_h2 / wl_wext.c
1 /*******************************************************************************
2  * Agere Systems Inc.
3  * Wireless device driver for Linux (wlags49).
4  *
5  * Copyright (c) 1998-2003 Agere Systems Inc.
6  * All rights reserved.
7  *   http://www.agere.com
8  *
9  * Initially developed by TriplePoint, Inc.
10  *   http://www.triplepoint.com
11  *
12  *------------------------------------------------------------------------------
13  *
14  * SOFTWARE LICENSE
15  *
16  * This software is provided subject to the following terms and conditions,
17  * which you should read carefully before using the software.  Using this
18  * software indicates your acceptance of these terms and conditions.  If you do
19  * not agree with these terms and conditions, do not use the software.
20  *
21  * Copyright © 2003 Agere Systems Inc.
22  * All rights reserved.
23  *
24  * Redistribution and use in source or binary forms, with or without
25  * modifications, are permitted provided that the following conditions are met:
26  *
27  * . Redistributions of source code must retain the above copyright notice, this
28  *    list of conditions and the following Disclaimer as comments in the code as
29  *    well as in the documentation and/or other materials provided with the
30  *    distribution.
31  *
32  * . Redistributions in binary form must reproduce the above copyright notice,
33  *    this list of conditions and the following Disclaimer in the documentation
34  *    and/or other materials provided with the distribution.
35  *
36  * . Neither the name of Agere Systems Inc. nor the names of the contributors
37  *    may be used to endorse or promote products derived from this software
38  *    without specific prior written permission.
39  *
40  * Disclaimer
41  *
42  * THIS SOFTWARE IS PROVIDED \93AS IS\94 AND ANY EXPRESS OR IMPLIED WARRANTIES,
43  * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  ANY
45  * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
46  * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
47  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
48  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
50  * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
51  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53  * DAMAGE.
54  *
55  ******************************************************************************/
56
57 /*******************************************************************************
58  *  include files
59  ******************************************************************************/
60 #include <wl_version.h>
61
62 #include <linux/if_arp.h>
63 #include <linux/ioport.h>
64 #include <linux/delay.h>
65 #include <asm/uaccess.h>
66
67 #include <debug.h>
68 #include <hcf.h>
69 #include <hcfdef.h>
70
71 #include <wl_if.h>
72 #include <wl_internal.h>
73 #include <wl_util.h>
74 #include <wl_main.h>
75 #include <wl_wext.h>
76 #include <wl_priv.h>
77
78 /*******************************************************************************
79  * global definitions
80  ******************************************************************************/
81 #if DBG
82 extern dbg_info_t *DbgInfo;
83 #endif  // DBG
84
85
86 /* Set up the LTV to program the appropriate key */
87 static 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 */
170 static 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 */
201 static 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         }
269
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
300 out:
301         return ret;
302 }
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  ******************************************************************************/
322 static 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
349 out:
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  ******************************************************************************/
376 static 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  ******************************************************************************/
414 static 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
474 out:
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  ******************************************************************************/
501 static 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
529                 freq->m = wl_get_freq_from_chan( channel ) * 100000;
530                 freq->e = 1;
531         }
532
533         wl_act_int_on( lp );
534
535         wl_unlock(lp, &flags);
536
537         ret = (ret == HCF_SUCCESS ? 0 : -EFAULT);
538
539 out:
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  ******************************************************************************/
568 static 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
595 retry:
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 */
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 );
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
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
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
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
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
732         /* Event capability (kernel + driver) */
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);
741
742         range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
743         range->scan_capa = IW_SCAN_CAPA_NONE;
744
745 out_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  ******************************************************************************/
775 static 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
831 out:
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  ******************************************************************************/
863 static 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
966                                 DBG_PRINT("BSSID: %pM\n",
967                                                 (*p).ProbeTable[count].BSSID);
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         }
980 out:
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  ******************************************************************************/
1008 static 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
1041 out:
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  ******************************************************************************/
1069 static 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 */
1088 out:
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  ******************************************************************************/
1117 static 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
1168 out:
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  ******************************************************************************/
1197 static 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
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
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 */
1277                                 data->length = pName->length;
1278                                 data->flags = 1;
1279                         } else {
1280                                 ret = -EFAULT;
1281                                 goto out_unlock;
1282                         }
1283                 }
1284
1285 #endif // HCF_STA
1286
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
1298 out_unlock:
1299         wl_act_int_on( lp );
1300
1301         wl_unlock(lp, &flags);
1302
1303 out:
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  ******************************************************************************/
1331 static 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;
1335         int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1;
1336         int ret = 0;
1337         bool enable = true;
1338
1339         DBG_ENTER(DbgInfo);
1340
1341         if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
1342                 ret = -EBUSY;
1343                 goto out;
1344         }
1345
1346         if (erq->flags & IW_ENCODE_DISABLED)
1347                 enable = false;
1348
1349         wl_lock(lp, &flags);
1350
1351         wl_act_int_off(lp);
1352
1353         ret = hermes_set_wep_keys(lp, key_idx, keybuf, erq->length,
1354                                   enable, true);
1355
1356         /* Send an event that Encryption has been set */
1357         if (ret == 0)
1358                 wl_wext_event_encode(dev);
1359
1360         wl_act_int_on(lp);
1361
1362         wl_unlock(lp, &flags);
1363
1364 out:
1365         DBG_LEAVE(DbgInfo);
1366         return ret;
1367 }
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  ******************************************************************************/
1388 static 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
1447 out_unlock:
1448
1449         wl_act_int_on( lp );
1450
1451         wl_unlock(lp, &flags);
1452
1453 out:
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  ******************************************************************************/
1481 static 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
1526 out:
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  ******************************************************************************/
1554 static 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
1603 out:
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  ******************************************************************************/
1631 static 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
1717 out:
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  ******************************************************************************/
1745 static 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
1827 out:
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  ******************************************************************************/
1855 static 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
1900 out:
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  ******************************************************************************/
1928 static 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
1962 out:
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  ******************************************************************************/
1990 static 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
2022 out:
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  ******************************************************************************/
2050 static 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
2072         if( rts->disabled ) {
2073                 rthr = 2347;
2074         }
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
2093 out:
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  ******************************************************************************/
2121 static 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
2142         rts->disabled = ( rts->value == 2347 );
2143
2144         rts->fixed = 1;
2145
2146         wl_act_int_on( lp );
2147
2148         wl_unlock(lp, &flags);
2149
2150 out:
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  ******************************************************************************/
2179 static 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
2372 out_unlock:
2373
2374         wl_act_int_on( lp );
2375
2376         wl_unlock(lp, &flags);
2377
2378 out:
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  ******************************************************************************/
2406 static 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
2493 out:
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  ******************************************************************************/
2523 int 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
2561 out:
2562         DBG_LEAVE( DbgInfo );
2563         return ret;
2564 } // wireless_get_private_interface
2565 /*============================================================================*/
2566 #endif
2567
2568
2569
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  ******************************************************************************/
2589 static 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
2616          * cause is still a mystery. Okay, the communication to the
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
2625 retry:
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
2697 out:
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  ******************************************************************************/
2725 static 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
2778                 buf = iwe_stream_add_event(info, buf, buf_end,
2779                                            &iwe, IW_EV_ADDR_LEN);
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
2795                 buf = iwe_stream_add_event(info, buf, buf_end,
2796                                            &iwe, IW_EV_UINT_LEN);
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;
2805                 iwe.u.qual.updated  = lp->probe_results.scan_complete | IW_QUAL_DBM;
2806                 iwe.len             = IW_EV_QUAL_LEN;
2807
2808                 buf = iwe_stream_add_event(info, buf, buf_end,
2809                                            &iwe, IW_EV_QUAL_LEN);
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
2820                         buf = iwe_stream_add_point(info, buf, buf_end,
2821                                                &iwe, &probe_resp->rawData[2]);
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
2839                 buf = iwe_stream_add_point(info, buf, buf_end, &iwe, NULL);
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
2850                 buf = iwe_stream_add_event(info, buf, buf_end,
2851                                            &iwe, IW_EV_FREQ_LEN);
2852
2853
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
2862                 buf = iwe_stream_add_point(info, buf, buf_end, &iwe, msg);
2863
2864
2865                 /* WPA-IE */
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 ) {
2871                         memset(&iwe, 0, sizeof(iwe));
2872
2873                         iwe.cmd = IWEVGENIE;
2874                         iwe.u.data.length = wpa_ie_len;
2875
2876                         buf = iwe_stream_add_point(info, buf, buf_end,
2877                                                    &iwe, wpa_ie);
2878                 }
2879
2880                 /* Add other custom info in formatted string format as needed... */
2881         }
2882
2883         data->length = buf - extra;
2884
2885 out_unlock:
2886
2887         wl_act_int_on( lp );
2888
2889         wl_unlock(lp, &flags);
2890
2891 out:
2892         DBG_LEAVE( DbgInfo );
2893         return ret;
2894 } // wireless_get_scan
2895 /*============================================================================*/
2896
2897 #if DBG
2898 static 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
2915
2916 static 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;
2922         ltv_t ltv;
2923         int ret;
2924         int iwa_idx = data->flags & IW_AUTH_INDEX;
2925         int iwa_val = data->value;
2926
2927         DBG_FUNC( "wireless_set_auth" );
2928         DBG_ENTER( DbgInfo );
2929
2930         if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
2931                 ret = -EBUSY;
2932                 goto out;
2933         }
2934
2935         wl_lock( lp, &flags );
2936
2937         wl_act_int_off( lp );
2938
2939         if (iwa_idx > IW_AUTH_MFP)
2940                 iwa_idx = IW_AUTH_MFP + 1;
2941         DBG_TRACE(DbgInfo, "%s\n", auth_names[iwa_idx]);
2942         switch (iwa_idx) {
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))
2947                         ret = 0;
2948                 else
2949                         ret = -EINVAL;
2950                 break;
2951
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;
2958
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);
2964
2965                 break;
2966
2967         case IW_AUTH_TKIP_COUNTERMEASURES:
2968
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;
2977
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)
2983                         ret = -EINVAL;
2984                 else
2985                         ret = 0;
2986                 break;
2987
2988         case IW_AUTH_KEY_MGMT:
2989
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;
2996
2997                 ret = -EINPROGRESS;
2998                 break;
2999
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
3011                         ret = -EINVAL;
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;
3035         }
3036
3037         wl_act_int_on( lp );
3038
3039         wl_unlock(lp, &flags);
3040
3041 out:
3042         DBG_LEAVE( DbgInfo );
3043         return ret;
3044 } // wireless_set_auth
3045 /*============================================================================*/
3046
3047
3048 static void flush_tx(struct wl_private *lp)
3049 {
3050         ltv_t ltv;
3051         int count;
3052
3053         /*
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         }
3072
3073         if (count >= 100)
3074                 DBG_TRACE(DbgInfo, "Timed out waiting for TxQ flush!\n");
3075
3076 }
3077
3078 static 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;
3090
3091         DBG_ENTER(DbgInfo);
3092
3093         if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
3094                 ret = -EBUSY;
3095                 goto out;
3096         }
3097
3098         if (erq->flags & IW_ENCODE_DISABLED) {
3099                 ext->alg = IW_ENCODE_ALG_NONE;
3100                 enable = false;
3101         }
3102
3103         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
3104                 set_tx = true;
3105
3106         wl_lock(lp, &flags);
3107
3108         wl_act_int_off(lp);
3109
3110         memset(&ltv, 0, sizeof(ltv));
3111
3112         switch (ext->alg) {
3113         case IW_ENCODE_ALG_TKIP:
3114                 DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_TKIP: key(%d)\n", key_idx);
3115
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                 }
3122
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);
3126
3127                 if (ret != 0) {
3128                         DBG_TRACE(DbgInfo, "hermes_set_tkip_keys returned != 0, key not set\n");
3129                         goto out_unlock;
3130                 }
3131
3132                 flush_tx(lp);
3133
3134                 lp->wext_enc = IW_ENCODE_ALG_TKIP;
3135
3136                 /* Write the key */
3137                 ret = hcf_put_info(&(lp->hcfCtx), (LTVP)&ltv);
3138                 break;
3139
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;
3147                 }
3148
3149                 ret = hermes_set_wep_keys(lp, key_idx, ext->key, ext->key_len,
3150                                           enable, set_tx);
3151
3152                 break;
3153
3154         case IW_ENCODE_ALG_CCMP:
3155                 DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_CCMP: key(%d)\n", key_idx);
3156                 ret = -EOPNOTSUPP;
3157                 break;
3158
3159         case IW_ENCODE_ALG_NONE:
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 {
3174                         ret = 0;
3175                 }
3176
3177                 break;
3178
3179         default:
3180                 DBG_TRACE( DbgInfo, "IW_ENCODE_??: key(%d)\n", key_idx);
3181                 ret = -EOPNOTSUPP;
3182                 break;
3183         }
3184
3185 out_unlock:
3186
3187         wl_act_int_on(lp);
3188
3189         wl_unlock(lp, &flags);
3190
3191 out:
3192         DBG_LEAVE(DbgInfo);
3193         return ret;
3194 }
3195 /*============================================================================*/
3196
3197
3198
3199 static int wireless_get_genie(struct net_device *dev,
3200                                            struct iw_request_info *info,
3201                                            struct iw_point *data, char *extra)
3202
3203 {
3204         struct wl_private *lp = wl_priv(dev);
3205         unsigned long flags;
3206         int   ret = 0;
3207         ltv_t ltv;
3208
3209         DBG_FUNC( "wireless_get_genie" );
3210         DBG_ENTER( DbgInfo );
3211
3212         if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
3213                 ret = -EBUSY;
3214                 goto out;
3215         }
3216
3217         wl_lock( lp, &flags );
3218
3219         wl_act_int_off( lp );
3220
3221         memset(&ltv, 0, sizeof(ltv));
3222         ltv.len = 2;
3223         ltv.typ = CFG_SET_WPA_AUTH_KEY_MGMT_SUITE;
3224         lp->AuthKeyMgmtSuite = ltv.u.u16[0] = 4;
3225         ltv.u.u16[0]  = CNV_INT_TO_LITTLE(ltv.u.u16[0]);
3226
3227         ret = hcf_put_info(&(lp->hcfCtx), (LTVP)&ltv);
3228
3229         wl_act_int_on( lp );
3230
3231         wl_unlock(lp, &flags);
3232
3233 out:
3234         DBG_LEAVE( DbgInfo );
3235         return ret;
3236 }
3237 /*============================================================================*/
3238
3239
3240 /*******************************************************************************
3241  *      wl_wireless_stats()
3242  *******************************************************************************
3243  *
3244  *  DESCRIPTION:
3245  *
3246  *      Return the current device wireless statistics.
3247  *
3248  *  PARAMETERS:
3249  *
3250  *      wrq - the wireless request buffer
3251  *      lp  - the device's private adapter structure
3252  *
3253  *  RETURNS:
3254  *
3255  *      0 on success
3256  *      errno value otherwise
3257  *
3258  ******************************************************************************/
3259 struct iw_statistics * wl_wireless_stats( struct net_device *dev )
3260 {
3261         struct iw_statistics    *pStats;
3262         struct wl_private       *lp = wl_priv(dev);
3263         /*------------------------------------------------------------------------*/
3264
3265
3266         DBG_FUNC( "wl_wireless_stats" );
3267         DBG_ENTER(DbgInfo);
3268         DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
3269
3270         pStats = NULL;
3271
3272         /* Initialize the statistics */
3273         pStats                  = &( lp->wstats );
3274         pStats->qual.updated    = 0x00;
3275
3276         if( !( lp->flags & WVLAN2_UIL_BUSY ))
3277         {
3278                 CFG_COMMS_QUALITY_STRCT *pQual;
3279                 CFG_HERMES_TALLIES_STRCT tallies;
3280                 int                         status;
3281
3282                 /* Update driver status */
3283                 pStats->status = 0;
3284
3285                 /* Get the current link quality information */
3286                 lp->ltvRecord.len = 1 + ( sizeof( *pQual ) / sizeof( hcf_16 ));
3287                 lp->ltvRecord.typ = CFG_COMMS_QUALITY;
3288                 status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
3289
3290                 if( status == HCF_SUCCESS ) {
3291                         pQual = (CFG_COMMS_QUALITY_STRCT *)&( lp->ltvRecord );
3292
3293                         pStats->qual.qual  = (u_char) CNV_LITTLE_TO_INT( pQual->coms_qual );
3294                         pStats->qual.level = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->signal_lvl ));
3295                         pStats->qual.noise = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->noise_lvl ));
3296
3297                         pStats->qual.updated |= (IW_QUAL_QUAL_UPDATED  |
3298                                                  IW_QUAL_LEVEL_UPDATED |
3299                                                  IW_QUAL_NOISE_UPDATED |
3300                                                  IW_QUAL_DBM);
3301                 } else {
3302                         memset( &( pStats->qual ), 0, sizeof( pStats->qual ));
3303                 }
3304
3305                 /* Get the current tallies from the adapter */
3306                 /* Only possible when the device is open */
3307                 if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
3308                         if( wl_get_tallies( lp, &tallies ) == 0 ) {
3309                                 /* No endian translation is needed here, as CFG_TALLIES is an
3310                                    MSF RID; all processing is done on the host, not the card! */
3311                                 pStats->discard.nwid = 0L;
3312                                 pStats->discard.code = tallies.RxWEPUndecryptable;
3313                                 pStats->discard.misc = tallies.TxDiscards +
3314                                                        tallies.RxFCSErrors +
3315                                                        //tallies.RxDiscardsNoBuffer +
3316                                                        tallies.TxDiscardsWrongSA;
3317                                 //;? Extra taken over from Linux driver based on 7.18 version
3318                                 pStats->discard.retries = tallies.TxRetryLimitExceeded;
3319                                 pStats->discard.fragment = tallies.RxMsgInBadMsgFragments;
3320                         } else {
3321                                 memset( &( pStats->discard ), 0, sizeof( pStats->discard ));
3322                         }
3323                 } else {
3324                         memset( &( pStats->discard ), 0, sizeof( pStats->discard ));
3325                 }
3326         }
3327
3328         DBG_LEAVE( DbgInfo );
3329         return pStats;
3330 } // wl_wireless_stats
3331 /*============================================================================*/
3332
3333
3334
3335
3336 /*******************************************************************************
3337  *      wl_get_wireless_stats()
3338  *******************************************************************************
3339  *
3340  *  DESCRIPTION:
3341  *
3342  *      Return the current device wireless statistics. This function calls
3343  *      wl_wireless_stats, but acquires spinlocks first as it can be called
3344  *      directly by the network layer.
3345  *
3346  *  PARAMETERS:
3347  *
3348  *      wrq - the wireless request buffer
3349  *      lp  - the device's private adapter structure
3350  *
3351  *  RETURNS:
3352  *
3353  *      0 on success
3354  *      errno value otherwise
3355  *
3356  ******************************************************************************/
3357 struct iw_statistics * wl_get_wireless_stats( struct net_device *dev )
3358 {
3359         unsigned long           flags;
3360         struct wl_private       *lp = wl_priv(dev);
3361         struct iw_statistics    *pStats = NULL;
3362         /*------------------------------------------------------------------------*/
3363
3364         DBG_FUNC( "wl_get_wireless_stats" );
3365         DBG_ENTER(DbgInfo);
3366
3367         wl_lock( lp, &flags );
3368
3369         wl_act_int_off( lp );
3370
3371 #ifdef USE_RTS
3372         if( lp->useRTS == 1 ) {
3373                 DBG_TRACE( DbgInfo, "Skipping wireless stats, in RTS mode\n" );
3374         } else
3375 #endif
3376         {
3377                 pStats = wl_wireless_stats( dev );
3378         }
3379         wl_act_int_on( lp );
3380
3381         wl_unlock(lp, &flags);
3382
3383         DBG_LEAVE( DbgInfo );
3384         return pStats;
3385 } // wl_get_wireless_stats
3386
3387
3388 /*******************************************************************************
3389  *      wl_spy_gather()
3390  *******************************************************************************
3391  *
3392  *  DESCRIPTION:
3393  *
3394  *      Gather wireless spy statistics.
3395  *
3396  *  PARAMETERS:
3397  *
3398  *      wrq - the wireless request buffer
3399  *      lp  - the device's private adapter structure
3400  *
3401  *  RETURNS:
3402  *
3403  *      0 on success
3404  *      errno value otherwise
3405  *
3406  ******************************************************************************/
3407 inline void wl_spy_gather( struct net_device *dev, u_char *mac )
3408 {
3409         struct iw_quality wstats;
3410         int                     status;
3411         u_char                  stats[2];
3412         DESC_STRCT              desc[1];
3413         struct wl_private   *lp = wl_priv(dev);
3414         /*------------------------------------------------------------------------*/
3415
3416         /* shortcut */
3417         if (!lp->spy_data.spy_number) {
3418                 return;
3419         }
3420
3421         /* Gather wireless spy statistics: for each packet, compare the source
3422            address with out list, and if match, get the stats. */
3423         memset( stats, 0, sizeof(stats));
3424         memset( desc, 0, sizeof(DESC_STRCT));
3425
3426         desc[0].buf_addr        = stats;
3427         desc[0].BUF_SIZE        = sizeof(stats);
3428         desc[0].next_desc_addr  = 0;            // terminate list
3429
3430         status = hcf_rcv_msg( &( lp->hcfCtx ), &desc[0], 0 );
3431
3432         if( status == HCF_SUCCESS ) {
3433                 wstats.level = (u_char) dbm(stats[1]);
3434                 wstats.noise = (u_char) dbm(stats[0]);
3435                 wstats.qual  = wstats.level > wstats.noise ? wstats.level - wstats.noise : 0;
3436
3437                 wstats.updated = (IW_QUAL_QUAL_UPDATED  |
3438                                   IW_QUAL_LEVEL_UPDATED |
3439                                   IW_QUAL_NOISE_UPDATED |
3440                                   IW_QUAL_DBM);
3441
3442                 wireless_spy_update( dev, mac, &wstats );
3443         }
3444 } // wl_spy_gather
3445 /*============================================================================*/
3446
3447
3448
3449
3450 /*******************************************************************************
3451  *      wl_wext_event_freq()
3452  *******************************************************************************
3453  *
3454  *  DESCRIPTION:
3455  *
3456  *      This function is used to send an event that the channel/freq
3457  *      configuration for a specific device has changed.
3458  *
3459  *
3460  *  PARAMETERS:
3461  *
3462  *      dev - the network device for which this event is to be issued
3463  *
3464  *  RETURNS:
3465  *
3466  *      N/A
3467  *
3468  ******************************************************************************/
3469 void wl_wext_event_freq( struct net_device *dev )
3470 {
3471         union iwreq_data wrqu;
3472         struct wl_private *lp = wl_priv(dev);
3473         /*------------------------------------------------------------------------*/
3474
3475
3476         memset( &wrqu, 0, sizeof( wrqu ));
3477
3478         wrqu.freq.m = lp->Channel;
3479         wrqu.freq.e = 0;
3480
3481         wireless_send_event( dev, SIOCSIWFREQ, &wrqu, NULL );
3482
3483         return;
3484 } // wl_wext_event_freq
3485 /*============================================================================*/
3486
3487
3488
3489
3490 /*******************************************************************************
3491  *      wl_wext_event_mode()
3492  *******************************************************************************
3493  *
3494  *  DESCRIPTION:
3495  *
3496  *      This function is used to send an event that the mode of operation
3497  *      for a specific device has changed.
3498  *
3499  *
3500  *  PARAMETERS:
3501  *
3502  *      dev - the network device for which this event is to be issued
3503  *
3504  *  RETURNS:
3505  *
3506  *      N/A
3507  *
3508  ******************************************************************************/
3509 void wl_wext_event_mode( struct net_device *dev )
3510 {
3511         union iwreq_data wrqu;
3512         struct wl_private *lp = wl_priv(dev);
3513         /*------------------------------------------------------------------------*/
3514
3515
3516         memset( &wrqu, 0, sizeof( wrqu ));
3517
3518         if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA  ) {
3519                 wrqu.mode = IW_MODE_INFRA;
3520         } else {
3521                 wrqu.mode = IW_MODE_MASTER;
3522         }
3523
3524         wireless_send_event( dev, SIOCSIWMODE, &wrqu, NULL );
3525
3526         return;
3527 } // wl_wext_event_mode
3528 /*============================================================================*/
3529
3530
3531
3532
3533 /*******************************************************************************
3534  *      wl_wext_event_essid()
3535  *******************************************************************************
3536  *
3537  *  DESCRIPTION:
3538  *
3539  *      This function is used to send an event that the ESSID configuration for
3540  *      a specific device has changed.
3541  *
3542  *
3543  *  PARAMETERS:
3544  *
3545  *      dev - the network device for which this event is to be issued
3546  *
3547  *  RETURNS:
3548  *
3549  *      N/A
3550  *
3551  ******************************************************************************/
3552 void wl_wext_event_essid( struct net_device *dev )
3553 {
3554         union iwreq_data wrqu;
3555         struct wl_private *lp = wl_priv(dev);
3556         /*------------------------------------------------------------------------*/
3557
3558
3559         memset( &wrqu, 0, sizeof( wrqu ));
3560
3561         /* Fill out the buffer. Note that the buffer doesn't actually contain the
3562            ESSID, but a pointer to the contents. In addition, the 'extra' field of
3563            the call to wireless_send_event() must also point to where the ESSID
3564            lives */
3565         wrqu.essid.length  = strlen( lp->NetworkName );
3566         wrqu.essid.pointer = (caddr_t)lp->NetworkName;
3567         wrqu.essid.flags   = 1;
3568
3569         wireless_send_event( dev, SIOCSIWESSID, &wrqu, lp->NetworkName );
3570
3571         return;
3572 } // wl_wext_event_essid
3573 /*============================================================================*/
3574
3575
3576
3577
3578 /*******************************************************************************
3579  *      wl_wext_event_encode()
3580  *******************************************************************************
3581  *
3582  *  DESCRIPTION:
3583  *
3584  *      This function is used to send an event that the encryption configuration
3585  *      for a specific device has changed.
3586  *
3587  *
3588  *  PARAMETERS:
3589  *
3590  *      dev - the network device for which this event is to be issued
3591  *
3592  *  RETURNS:
3593  *
3594  *      N/A
3595  *
3596  ******************************************************************************/
3597 void wl_wext_event_encode( struct net_device *dev )
3598 {
3599         union iwreq_data wrqu;
3600         struct wl_private *lp = wl_priv(dev);
3601         int index = 0;
3602         /*------------------------------------------------------------------------*/
3603
3604
3605         memset( &wrqu, 0, sizeof( wrqu ));
3606
3607         if( lp->EnableEncryption == 0 ) {
3608                 wrqu.encoding.flags = IW_ENCODE_DISABLED;
3609         } else {
3610                 wrqu.encoding.flags |= lp->TransmitKeyID;
3611
3612                 index = lp->TransmitKeyID - 1;
3613
3614                 /* Only set IW_ENCODE_RESTRICTED/OPEN flag using lp->ExcludeUnencrypted
3615                    if we're in AP mode */
3616 #if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
3617                 //;?should we restore this to allow smaller memory footprint
3618
3619                 if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP  ) {
3620                         if( lp->ExcludeUnencrypted ) {
3621                                 wrqu.encoding.flags |= IW_ENCODE_RESTRICTED;
3622                         } else {
3623                                 wrqu.encoding.flags |= IW_ENCODE_OPEN;
3624                         }
3625                 }
3626
3627 #endif  // HCF_TYPE_AP
3628
3629                 /* Only provide the key if permissions allow */
3630                 if( capable( CAP_NET_ADMIN )) {
3631                         wrqu.encoding.pointer = (caddr_t)lp->DefaultKeys.key[index].key;
3632                         wrqu.encoding.length  = lp->DefaultKeys.key[index].len;
3633                 } else {
3634                         wrqu.encoding.flags |= IW_ENCODE_NOKEY;
3635                 }
3636         }
3637
3638         wireless_send_event( dev, SIOCSIWENCODE, &wrqu,
3639                                                  lp->DefaultKeys.key[index].key );
3640
3641         return;
3642 } // wl_wext_event_encode
3643 /*============================================================================*/
3644
3645
3646
3647
3648 /*******************************************************************************
3649  *      wl_wext_event_ap()
3650  *******************************************************************************
3651  *
3652  *  DESCRIPTION:
3653  *
3654  *      This function is used to send an event that the device has been
3655  *      associated to a new AP.
3656  *
3657  *
3658  *  PARAMETERS:
3659  *
3660  *      dev - the network device for which this event is to be issued
3661  *
3662  *  RETURNS:
3663  *
3664  *      N/A
3665  *
3666  ******************************************************************************/
3667 void wl_wext_event_ap( struct net_device *dev )
3668 {
3669         union iwreq_data wrqu;
3670         struct wl_private *lp = wl_priv(dev);
3671         int status;
3672         /*------------------------------------------------------------------------*/
3673
3674
3675         /* Retrieve the WPA-IEs used by the firmware and send an event. We must send
3676            this event BEFORE sending the association event, as there are timing
3677            issues with the hostap supplicant. The supplicant will attempt to process
3678            an EAPOL-Key frame from an AP before receiving this information, which
3679            is required properly process the said frame. */
3680         wl_wext_event_assoc_ie( dev );
3681
3682         /* Get the BSSID */
3683         lp->ltvRecord.typ = CFG_CUR_BSSID;
3684         lp->ltvRecord.len = 4;
3685
3686         status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
3687         if( status == HCF_SUCCESS ) {
3688                 memset( &wrqu, 0, sizeof( wrqu ));
3689
3690                 memcpy( wrqu.addr.sa_data, lp->ltvRecord.u.u8, ETH_ALEN );
3691
3692                 wrqu.addr.sa_family = ARPHRD_ETHER;
3693
3694                 wireless_send_event( dev, SIOCGIWAP, &wrqu, NULL );
3695         }
3696
3697         return;
3698 } // wl_wext_event_ap
3699 /*============================================================================*/
3700
3701
3702
3703 /*******************************************************************************
3704  *      wl_wext_event_scan_complete()
3705  *******************************************************************************
3706  *
3707  *  DESCRIPTION:
3708  *
3709  *      This function is used to send an event that a request for a network scan
3710  *      has completed.
3711  *
3712  *
3713  *  PARAMETERS:
3714  *
3715  *      dev - the network device for which this event is to be issued
3716  *
3717  *  RETURNS:
3718  *
3719  *      N/A
3720  *
3721  ******************************************************************************/
3722 void wl_wext_event_scan_complete( struct net_device *dev )
3723 {
3724         union iwreq_data wrqu;
3725         /*------------------------------------------------------------------------*/
3726
3727
3728         memset( &wrqu, 0, sizeof( wrqu ));
3729
3730         wrqu.addr.sa_family = ARPHRD_ETHER;
3731         wireless_send_event( dev, SIOCGIWSCAN, &wrqu, NULL );
3732
3733         return;
3734 } // wl_wext_event_scan_complete
3735 /*============================================================================*/
3736
3737
3738
3739
3740 /*******************************************************************************
3741  *      wl_wext_event_new_sta()
3742  *******************************************************************************
3743  *
3744  *  DESCRIPTION:
3745  *
3746  *      This function is used to send an event that an AP has registered a new
3747  *      station.
3748  *
3749  *
3750  *  PARAMETERS:
3751  *
3752  *      dev - the network device for which this event is to be issued
3753  *
3754  *  RETURNS:
3755  *
3756  *      N/A
3757  *
3758  ******************************************************************************/
3759 void wl_wext_event_new_sta( struct net_device *dev )
3760 {
3761         union iwreq_data wrqu;
3762         /*------------------------------------------------------------------------*/
3763
3764
3765         memset( &wrqu, 0, sizeof( wrqu ));
3766
3767         /* Send the station's mac address here */
3768         memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN );
3769         wrqu.addr.sa_family = ARPHRD_ETHER;
3770         wireless_send_event( dev, IWEVREGISTERED, &wrqu, NULL );
3771
3772         return;
3773 } // wl_wext_event_new_sta
3774 /*============================================================================*/
3775
3776
3777
3778
3779 /*******************************************************************************
3780  *      wl_wext_event_expired_sta()
3781  *******************************************************************************
3782  *
3783  *  DESCRIPTION:
3784  *
3785  *      This function is used to send an event that an AP has deregistered a
3786  *      station.
3787  *
3788  *
3789  *  PARAMETERS:
3790  *
3791  *      dev - the network device for which this event is to be issued
3792  *
3793  *  RETURNS:
3794  *
3795  *      N/A
3796  *
3797  ******************************************************************************/
3798 void wl_wext_event_expired_sta( struct net_device *dev )
3799 {
3800         union iwreq_data wrqu;
3801         /*------------------------------------------------------------------------*/
3802
3803
3804         memset( &wrqu, 0, sizeof( wrqu ));
3805
3806         memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN );
3807         wrqu.addr.sa_family = ARPHRD_ETHER;
3808         wireless_send_event( dev, IWEVEXPIRED, &wrqu, NULL );
3809
3810         return;
3811 } // wl_wext_event_expired_sta
3812 /*============================================================================*/
3813
3814
3815
3816
3817 /*******************************************************************************
3818  *      wl_wext_event_mic_failed()
3819  *******************************************************************************
3820  *
3821  *  DESCRIPTION:
3822  *
3823  *      This function is used to send an event that MIC calculations failed.
3824  *
3825  *
3826  *  PARAMETERS:
3827  *
3828  *      dev - the network device for which this event is to be issued
3829  *
3830  *  RETURNS:
3831  *
3832  *      N/A
3833  *
3834  ******************************************************************************/
3835 void wl_wext_event_mic_failed( struct net_device *dev )
3836 {
3837         union iwreq_data   wrqu;
3838         struct wl_private *lp = wl_priv(dev);
3839         struct iw_michaelmicfailure wxmic;
3840         int                key_idx;
3841         char              *addr1;
3842         char              *addr2;
3843         WVLAN_RX_WMP_HDR  *hdr;
3844         /*------------------------------------------------------------------------*/
3845
3846
3847         key_idx = lp->lookAheadBuf[HFS_STAT+1] >> 3;
3848         key_idx &= 0x03;
3849
3850         /* Cast the lookahead buffer into a RFS format */
3851         hdr = (WVLAN_RX_WMP_HDR *)&lp->lookAheadBuf[HFS_STAT];
3852
3853         /* Cast the addresses to byte buffers, as in the above RFS they are word
3854            length */
3855         addr1 = (char *)hdr->address1;
3856         addr2 = (char *)hdr->address2;
3857
3858         DBG_PRINT( "MIC FAIL - KEY USED : %d, STATUS : 0x%04x\n", key_idx,
3859                            hdr->status );
3860
3861         memset(&wrqu, 0, sizeof(wrqu));
3862         memset(&wxmic, 0, sizeof(wxmic));
3863
3864         wxmic.flags = key_idx & IW_MICFAILURE_KEY_ID;
3865         wxmic.flags |= (addr1[0] & 1) ?
3866                 IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
3867         wxmic.src_addr.sa_family = ARPHRD_ETHER;
3868         memcpy(wxmic.src_addr.sa_data, addr2, ETH_ALEN);
3869
3870         wrqu.data.length = sizeof(wxmic);
3871         wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&wxmic);
3872
3873         return;
3874 } // wl_wext_event_mic_failed
3875 /*============================================================================*/
3876
3877
3878
3879
3880 /*******************************************************************************
3881  *      wl_wext_event_assoc_ie()
3882  *******************************************************************************
3883  *
3884  *  DESCRIPTION:
3885  *
3886  *      This function is used to send an event containing the WPA-IE generated
3887  *      by the firmware in an association request.
3888  *
3889  *
3890  *  PARAMETERS:
3891  *
3892  *      dev - the network device for which this event is to be issued
3893  *
3894  *  RETURNS:
3895  *
3896  *      N/A
3897  *
3898  ******************************************************************************/
3899 void wl_wext_event_assoc_ie( struct net_device *dev )
3900 {
3901         union iwreq_data   wrqu;
3902         struct wl_private *lp = wl_priv(dev);
3903         int status;
3904         PROBE_RESP         data;
3905         hcf_16             length;
3906         hcf_8              *wpa_ie;
3907         /*------------------------------------------------------------------------*/
3908
3909
3910         memset( &wrqu, 0, sizeof( wrqu ));
3911
3912         /* Retrieve the Association Request IE */
3913         lp->ltvRecord.len = 45;
3914         lp->ltvRecord.typ = CFG_CUR_ASSOC_REQ_INFO;
3915
3916         status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
3917         if( status == HCF_SUCCESS )
3918         {
3919                 length = 0;
3920                 memcpy( &data.rawData, &( lp->ltvRecord.u.u8[1] ), 88 );
3921                 wpa_ie = wl_parse_wpa_ie( &data, &length );
3922
3923                 if( length != 0 )
3924                 {
3925                         wrqu.data.length = wpa_ie[1] + 2;
3926                         wireless_send_event(dev, IWEVASSOCREQIE,
3927                                             &wrqu, wpa_ie);
3928
3929                         /* This bit is a hack. We send the respie
3930                          * event at the same time */
3931                         wireless_send_event(dev, IWEVASSOCRESPIE,
3932                                             &wrqu, wpa_ie);
3933                 }
3934         }
3935
3936         return;
3937 }  // wl_wext_event_assoc_ie
3938 /*============================================================================*/
3939 /* Structures to export the Wireless Handlers */
3940
3941 static const iw_handler wl_handler[] =
3942 {
3943         IW_HANDLER(SIOCSIWCOMMIT, (iw_handler) wireless_commit),
3944         IW_HANDLER(SIOCGIWNAME, (iw_handler) wireless_get_protocol),
3945         IW_HANDLER(SIOCSIWFREQ, (iw_handler) wireless_set_frequency),
3946         IW_HANDLER(SIOCGIWFREQ, (iw_handler) wireless_get_frequency),
3947         IW_HANDLER(SIOCSIWMODE, (iw_handler) wireless_set_porttype),
3948         IW_HANDLER(SIOCGIWMODE, (iw_handler) wireless_get_porttype),
3949         IW_HANDLER(SIOCSIWSENS, (iw_handler) wireless_set_sensitivity),
3950         IW_HANDLER(SIOCGIWSENS, (iw_handler) wireless_get_sensitivity),
3951         IW_HANDLER(SIOCGIWRANGE, (iw_handler) wireless_get_range),
3952         IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
3953         IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
3954 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
3955         IW_HANDLER(SIOCGIWAP, (iw_handler) wireless_get_bssid),
3956 #endif
3957         IW_HANDLER(SIOCGIWAPLIST, (iw_handler) wireless_get_ap_list),
3958         IW_HANDLER(SIOCSIWSCAN, (iw_handler) wireless_set_scan),
3959         IW_HANDLER(SIOCGIWSCAN, (iw_handler) wireless_get_scan),
3960         IW_HANDLER(SIOCSIWESSID, (iw_handler) wireless_set_essid),
3961         IW_HANDLER(SIOCGIWESSID, (iw_handler) wireless_get_essid),
3962         IW_HANDLER(SIOCSIWNICKN, (iw_handler) wireless_set_nickname),
3963         IW_HANDLER(SIOCGIWNICKN, (iw_handler) wireless_get_nickname),
3964         IW_HANDLER(SIOCSIWRATE, (iw_handler) wireless_set_rate),
3965         IW_HANDLER(SIOCGIWRATE, (iw_handler) wireless_get_rate),
3966         IW_HANDLER(SIOCSIWRTS, (iw_handler) wireless_set_rts_threshold),
3967         IW_HANDLER(SIOCGIWRTS, (iw_handler) wireless_get_rts_threshold),
3968         IW_HANDLER(SIOCGIWTXPOW, (iw_handler) wireless_get_tx_power),
3969         IW_HANDLER(SIOCSIWENCODE, (iw_handler) wireless_set_encode),
3970         IW_HANDLER(SIOCGIWENCODE, (iw_handler) wireless_get_encode),
3971         IW_HANDLER(SIOCSIWPOWER, (iw_handler) wireless_set_power),
3972         IW_HANDLER(SIOCGIWPOWER, (iw_handler) wireless_get_power),
3973         IW_HANDLER(SIOCSIWGENIE, (iw_handler) wireless_get_genie),
3974         IW_HANDLER(SIOCSIWAUTH, (iw_handler) wireless_set_auth),
3975         IW_HANDLER(SIOCSIWENCODEEXT, (iw_handler) wireless_set_encodeext),
3976 };
3977
3978 static const iw_handler wl_private_handler[] =
3979 {                                                       /* SIOCIWFIRSTPRIV + */
3980                 wvlan_set_netname,                      /* 0: SIOCSIWNETNAME */
3981                 wvlan_get_netname,                      /* 1: SIOCGIWNETNAME */
3982                 wvlan_set_station_nickname,             /* 2: SIOCSIWSTANAME */
3983                 wvlan_get_station_nickname,             /* 3: SIOCGIWSTANAME */
3984 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
3985                 wvlan_set_porttype,                     /* 4: SIOCSIWPORTTYPE */
3986                 wvlan_get_porttype,                     /* 5: SIOCGIWPORTTYPE */
3987 #endif
3988 };
3989
3990 struct iw_priv_args wl_priv_args[] = {
3991         {SIOCSIWNETNAME,    IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" },
3992         {SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN,    "gnetwork_name" },
3993         {SIOCSIWSTANAME,    IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" },
3994         {SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN,    "gstation_name" },
3995 #if 1 //;? #if (HCF_TYPE) & HCF_TYPE_STA
3996         {SIOCSIWPORTTYPE,    IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" },
3997         {SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,    "gport_type" },
3998 #endif
3999 };
4000
4001 const struct iw_handler_def wl_iw_handler_def =
4002 {
4003         .num_private        = sizeof(wl_private_handler) / sizeof(iw_handler),
4004         .private            = (iw_handler *) wl_private_handler,
4005         .private_args       = (struct iw_priv_args *) wl_priv_args,
4006         .num_private_args   = sizeof(wl_priv_args) / sizeof(struct iw_priv_args),
4007         .num_standard       = sizeof(wl_handler) / sizeof(iw_handler),
4008         .standard           = (iw_handler *) wl_handler,
4009         .get_wireless_stats = wl_get_wireless_stats,
4010 };