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