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