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