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