Staging: wlan-ng: remove duplicated #include
[sfrench/cifs-2.6.git] / drivers / staging / wlan-ng / p80211wext.c
1 /* src/p80211/p80211wext.c
2 *
3 * Glue code to make linux-wlan-ng a happy wireless extension camper.
4 *
5 * original author:  Reyk Floeter <reyk@synack.de>
6 * Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
7 *
8 * Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
9 * --------------------------------------------------------------------
10 *
11 * linux-wlan
12 *
13 *   The contents of this file are subject to the Mozilla Public
14 *   License Version 1.1 (the "License"); you may not use this file
15 *   except in compliance with the License. You may obtain a copy of
16 *   the License at http://www.mozilla.org/MPL/
17 *
18 *   Software distributed under the License is distributed on an "AS
19 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
20 *   implied. See the License for the specific language governing
21 *   rights and limitations under the License.
22 *
23 *   Alternatively, the contents of this file may be used under the
24 *   terms of the GNU Public License version 2 (the "GPL"), in which
25 *   case the provisions of the GPL are applicable instead of the
26 *   above.  If you wish to allow the use of your version of this file
27 *   only under the terms of the GPL and not to allow others to use
28 *   your version of this file under the MPL, indicate your decision
29 *   by deleting the provisions above and replace them with the notice
30 *   and other provisions required by the GPL.  If you do not delete
31 *   the provisions above, a recipient may use your version of this
32 *   file under either the MPL or the GPL.
33 *
34 * --------------------------------------------------------------------
35 */
36
37 /*================================================================*/
38 /* System Includes */
39
40 #include <linux/kernel.h>
41 #include <linux/sched.h>
42 #include <linux/types.h>
43 #include <linux/netdevice.h>
44 #include <linux/etherdevice.h>
45 #include <linux/wireless.h>
46 #include <net/iw_handler.h>
47 #include <linux/if_arp.h>
48 #include <linux/bitops.h>
49 #include <linux/uaccess.h>
50 #include <asm/byteorder.h>
51 #include <linux/if_ether.h>
52
53 #include "p80211types.h"
54 #include "p80211hdr.h"
55 #include "p80211conv.h"
56 #include "p80211mgmt.h"
57 #include "p80211msg.h"
58 #include "p80211metastruct.h"
59 #include "p80211metadef.h"
60 #include "p80211netdev.h"
61 #include "p80211ioctl.h"
62 #include "p80211req.h"
63
64 static int p80211wext_giwrate(netdevice_t *dev,
65                               struct iw_request_info *info,
66                               struct iw_param *rrq, char *extra);
67 static int p80211wext_giwessid(netdevice_t *dev,
68                                struct iw_request_info *info,
69                                struct iw_point *data, char *essid);
70
71 static u8 p80211_mhz_to_channel(u16 mhz)
72 {
73         if (mhz >= 5000)
74                 return (mhz - 5000) / 5;
75
76         if (mhz == 2482)
77                 return 14;
78
79         if (mhz >= 2407)
80                 return (mhz - 2407) / 5;
81
82         return 0;
83 }
84
85 static u16 p80211_channel_to_mhz(u8 ch, int dot11a)
86 {
87
88         if (ch == 0)
89                 return 0;
90         if (ch > 200)
91                 return 0;
92
93         /* 5G */
94         if (dot11a)
95                 return 5000 + (5 * ch);
96
97         /* 2.4G */
98         if (ch == 14)
99                 return 2484;
100
101         if ((ch < 14) && (ch > 0))
102                 return 2407 + (5 * ch);
103
104         return 0;
105 }
106
107 /* taken from orinoco.c ;-) */
108 static const long p80211wext_channel_freq[] = {
109         2412, 2417, 2422, 2427, 2432, 2437, 2442,
110         2447, 2452, 2457, 2462, 2467, 2472, 2484
111 };
112
113 #define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
114
115 /* steal a spare bit to store the shared/opensystems state.
116    should default to open if not set */
117 #define HOSTWEP_SHAREDKEY BIT(3)
118
119 static int qual_as_percent(int snr)
120 {
121         if (snr <= 0)
122                 return 0;
123         if (snr <= 40)
124                 return snr * 5 / 2;
125         return 100;
126 }
127
128 static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data)
129 {
130         p80211msg_dot11req_mibset_t msg;
131         p80211item_uint32_t mibitem;
132         int result;
133
134         msg.msgcode = DIDmsg_dot11req_mibset;
135         memset(&mibitem, 0, sizeof(mibitem));
136         mibitem.did = did;
137         mibitem.data = data;
138         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
139         result = p80211req_dorequest(wlandev, (u8 *) &msg);
140
141         return result;
142 }
143
144 static int p80211wext_autojoin(wlandevice_t *wlandev)
145 {
146         p80211msg_lnxreq_autojoin_t msg;
147         struct iw_point data;
148         char ssid[IW_ESSID_MAX_SIZE];
149
150         int result;
151         int err = 0;
152
153         /* Get ESSID */
154         result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
155
156         if (result) {
157                 err = -EFAULT;
158                 goto exit;
159         }
160
161         if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
162                 msg.authtype.data = P80211ENUM_authalg_sharedkey;
163         else
164                 msg.authtype.data = P80211ENUM_authalg_opensystem;
165
166         msg.msgcode = DIDmsg_lnxreq_autojoin;
167
168         /* Trim the last '\0' to fit the SSID format */
169
170         if (data.length && ssid[data.length - 1] == '\0')
171                 data.length = data.length - 1;
172
173         memcpy(msg.ssid.data.data, ssid, data.length);
174         msg.ssid.data.len = data.length;
175
176         result = p80211req_dorequest(wlandev, (u8 *) &msg);
177
178         if (result) {
179                 err = -EFAULT;
180                 goto exit;
181         }
182
183 exit:
184
185         return err;
186
187 }
188
189 /* called by /proc/net/wireless */
190 struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev)
191 {
192         p80211msg_lnxreq_commsquality_t quality;
193         wlandevice_t *wlandev = dev->ml_priv;
194         struct iw_statistics *wstats = &wlandev->wstats;
195         int retval;
196
197         /* Check */
198         if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
199                 return NULL;
200
201         /* XXX Only valid in station mode */
202         wstats->status = 0;
203
204         /* build request message */
205         quality.msgcode = DIDmsg_lnxreq_commsquality;
206         quality.dbm.data = P80211ENUM_truth_true;
207         quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
208
209         /* send message to nsd */
210         if (wlandev->mlmerequest == NULL)
211                 return NULL;
212
213         retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) &quality);
214
215         wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
216         wstats->qual.level = quality.level.data;        /* instant signal level */
217         wstats->qual.noise = quality.noise.data;        /* instant noise level */
218
219         wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
220         wstats->discard.code = wlandev->rx.decrypt_err;
221         wstats->discard.nwid = 0;
222         wstats->discard.misc = 0;
223
224         wstats->discard.fragment = 0;   /* incomplete fragments */
225         wstats->discard.retries = 0;    /* tx retries. */
226         wstats->miss.beacon = 0;
227
228         return wstats;
229 }
230
231 static int p80211wext_giwname(netdevice_t *dev,
232                               struct iw_request_info *info,
233                               char *name, char *extra)
234 {
235         struct iw_param rate;
236         int result;
237         int err = 0;
238
239         result = p80211wext_giwrate(dev, NULL, &rate, NULL);
240
241         if (result) {
242                 err = -EFAULT;
243                 goto exit;
244         }
245
246         switch (rate.value) {
247         case 1000000:
248         case 2000000:
249                 strcpy(name, "IEEE 802.11-DS");
250                 break;
251         case 5500000:
252         case 11000000:
253                 strcpy(name, "IEEE 802.11-b");
254                 break;
255         }
256 exit:
257         return err;
258 }
259
260 static int p80211wext_giwfreq(netdevice_t *dev,
261                               struct iw_request_info *info,
262                               struct iw_freq *freq, char *extra)
263 {
264         wlandevice_t *wlandev = dev->ml_priv;
265         p80211item_uint32_t mibitem;
266         p80211msg_dot11req_mibset_t msg;
267         int result;
268         int err = 0;
269
270         msg.msgcode = DIDmsg_dot11req_mibget;
271         memset(&mibitem, 0, sizeof(mibitem));
272         mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
273         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
274         result = p80211req_dorequest(wlandev, (u8 *) &msg);
275
276         if (result) {
277                 err = -EFAULT;
278                 goto exit;
279         }
280
281         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
282
283         if (mibitem.data > NUM_CHANNELS) {
284                 err = -EFAULT;
285                 goto exit;
286         }
287
288         /* convert into frequency instead of a channel */
289         freq->e = 1;
290         freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000;
291
292 exit:
293         return err;
294 }
295
296 static int p80211wext_siwfreq(netdevice_t *dev,
297                               struct iw_request_info *info,
298                               struct iw_freq *freq, char *extra)
299 {
300         wlandevice_t *wlandev = dev->ml_priv;
301         p80211item_uint32_t mibitem;
302         p80211msg_dot11req_mibset_t msg;
303         int result;
304         int err = 0;
305
306         if (!wlan_wext_write) {
307                 err = (-EOPNOTSUPP);
308                 goto exit;
309         }
310
311         msg.msgcode = DIDmsg_dot11req_mibset;
312         memset(&mibitem, 0, sizeof(mibitem));
313         mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
314         mibitem.status = P80211ENUM_msgitem_status_data_ok;
315
316         if ((freq->e == 0) && (freq->m <= 1000))
317                 mibitem.data = freq->m;
318         else
319                 mibitem.data = p80211_mhz_to_channel(freq->m);
320
321         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
322         result = p80211req_dorequest(wlandev, (u8 *) &msg);
323
324         if (result) {
325                 err = -EFAULT;
326                 goto exit;
327         }
328
329 exit:
330         return err;
331 }
332
333 static int p80211wext_giwmode(netdevice_t *dev,
334                               struct iw_request_info *info,
335                               __u32 *mode, char *extra)
336 {
337         wlandevice_t *wlandev = dev->ml_priv;
338
339         switch (wlandev->macmode) {
340         case WLAN_MACMODE_IBSS_STA:
341                 *mode = IW_MODE_ADHOC;
342                 break;
343         case WLAN_MACMODE_ESS_STA:
344                 *mode = IW_MODE_INFRA;
345                 break;
346         case WLAN_MACMODE_ESS_AP:
347                 *mode = IW_MODE_MASTER;
348                 break;
349         default:
350                 /* Not set yet. */
351                 *mode = IW_MODE_AUTO;
352         }
353
354         return 0;
355 }
356
357 static int p80211wext_siwmode(netdevice_t *dev,
358                               struct iw_request_info *info,
359                               __u32 *mode, char *extra)
360 {
361         wlandevice_t *wlandev = dev->ml_priv;
362         p80211item_uint32_t mibitem;
363         p80211msg_dot11req_mibset_t msg;
364         int result;
365         int err = 0;
366
367         if (!wlan_wext_write) {
368                 err = (-EOPNOTSUPP);
369                 goto exit;
370         }
371
372         if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
373             *mode != IW_MODE_MASTER) {
374                 err = (-EOPNOTSUPP);
375                 goto exit;
376         }
377
378         /* Operation mode is the same with current mode */
379         if (*mode == wlandev->macmode)
380                 goto exit;
381
382         switch (*mode) {
383         case IW_MODE_ADHOC:
384                 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
385                 break;
386         case IW_MODE_INFRA:
387                 wlandev->macmode = WLAN_MACMODE_ESS_STA;
388                 break;
389         case IW_MODE_MASTER:
390                 wlandev->macmode = WLAN_MACMODE_ESS_AP;
391                 break;
392         default:
393                 /* Not set yet. */
394                 printk(KERN_INFO "Operation mode: %d not support\n", *mode);
395                 return -EOPNOTSUPP;
396         }
397
398         /* Set Operation mode to the PORT TYPE RID */
399         msg.msgcode = DIDmsg_dot11req_mibset;
400         memset(&mibitem, 0, sizeof(mibitem));
401         mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
402         mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
403         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
404         result = p80211req_dorequest(wlandev, (u8 *) &msg);
405
406         if (result)
407                 err = -EFAULT;
408
409 exit:
410         return err;
411 }
412
413 static int p80211wext_giwrange(netdevice_t *dev,
414                                struct iw_request_info *info,
415                                struct iw_point *data, char *extra)
416 {
417         struct iw_range *range = (struct iw_range *)extra;
418         int i, val;
419
420         /* for backward compatability set size and zero everything we don't understand */
421         data->length = sizeof(*range);
422         memset(range, 0, sizeof(*range));
423
424         range->txpower_capa = IW_TXPOW_DBM;
425         /* XXX what about min/max_pmp, min/max_pmt, etc. */
426
427         range->we_version_compiled = WIRELESS_EXT;
428         range->we_version_source = 13;
429
430         range->retry_capa = IW_RETRY_LIMIT;
431         range->retry_flags = IW_RETRY_LIMIT;
432         range->min_retry = 0;
433         range->max_retry = 255;
434
435         range->event_capa[0] = (IW_EVENT_CAPA_K_0 |     /* mode/freq/ssid */
436                                 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
437                                 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
438         range->event_capa[1] = IW_EVENT_CAPA_K_1;       /* encode */
439         range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
440                                 IW_EVENT_CAPA_MASK(IWEVCUSTOM));
441
442         range->num_channels = NUM_CHANNELS;
443
444         /* XXX need to filter against the regulatory domain &| active set */
445         val = 0;
446         for (i = 0; i < NUM_CHANNELS; i++) {
447                 range->freq[val].i = i + 1;
448                 range->freq[val].m = p80211wext_channel_freq[i] * 100000;
449                 range->freq[val].e = 1;
450                 val++;
451         }
452
453         range->num_frequency = val;
454
455         /* Max of /proc/net/wireless */
456         range->max_qual.qual = 100;
457         range->max_qual.level = 0;
458         range->max_qual.noise = 0;
459         range->sensitivity = 3;
460         /* XXX these need to be nsd-specific! */
461
462         range->min_rts = 0;
463         range->max_rts = 2347;
464         range->min_frag = 256;
465         range->max_frag = 2346;
466
467         range->max_encoding_tokens = NUM_WEPKEYS;
468         range->num_encoding_sizes = 2;
469         range->encoding_size[0] = 5;
470         range->encoding_size[1] = 13;
471
472         /* XXX what about num_bitrates/throughput? */
473         range->num_bitrates = 0;
474
475         /* estimated max throughput */
476         /* XXX need to cap it if we're running at ~2Mbps.. */
477         range->throughput = 5500000;
478
479         return 0;
480 }
481
482 static int p80211wext_giwap(netdevice_t *dev,
483                             struct iw_request_info *info,
484                             struct sockaddr *ap_addr, char *extra)
485 {
486
487         wlandevice_t *wlandev = dev->ml_priv;
488
489         memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
490         ap_addr->sa_family = ARPHRD_ETHER;
491
492         return 0;
493 }
494
495 static int p80211wext_giwencode(netdevice_t *dev,
496                                 struct iw_request_info *info,
497                                 struct iw_point *erq, char *key)
498 {
499         wlandevice_t *wlandev = dev->ml_priv;
500         int err = 0;
501         int i;
502
503         i = (erq->flags & IW_ENCODE_INDEX) - 1;
504         erq->flags = 0;
505
506         if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
507                 erq->flags |= IW_ENCODE_ENABLED;
508         else
509                 erq->flags |= IW_ENCODE_DISABLED;
510
511         if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
512                 erq->flags |= IW_ENCODE_RESTRICTED;
513         else
514                 erq->flags |= IW_ENCODE_OPEN;
515
516         i = (erq->flags & IW_ENCODE_INDEX) - 1;
517
518         if (i == -1)
519                 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
520
521         if ((i < 0) || (i >= NUM_WEPKEYS)) {
522                 err = -EINVAL;
523                 goto exit;
524         }
525
526         erq->flags |= i + 1;
527
528         /* copy the key from the driver cache as the keys are read-only MIBs */
529         erq->length = wlandev->wep_keylens[i];
530         memcpy(key, wlandev->wep_keys[i], erq->length);
531
532 exit:
533         return err;
534 }
535
536 static int p80211wext_siwencode(netdevice_t *dev,
537                                 struct iw_request_info *info,
538                                 struct iw_point *erq, char *key)
539 {
540         wlandevice_t *wlandev = dev->ml_priv;
541         p80211msg_dot11req_mibset_t msg;
542         p80211item_pstr32_t pstr;
543
544         int err = 0;
545         int result = 0;
546         int i;
547
548         if (!wlan_wext_write) {
549                 err = (-EOPNOTSUPP);
550                 goto exit;
551         }
552
553         /* Check the Key index first. */
554         i = (erq->flags & IW_ENCODE_INDEX);
555         if (i) {
556                 if ((i < 1) || (i > NUM_WEPKEYS)) {
557                         err = -EINVAL;
558                         goto exit;
559                 } else {
560                         i--;
561                 }
562                 /* Set current key number only if no keys are given */
563                 if (erq->flags & IW_ENCODE_NOKEY) {
564                         result =
565                             p80211wext_dorequest(wlandev,
566                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
567                                                  i);
568
569                         if (result) {
570                                 err = -EFAULT;
571                                 goto exit;
572                         }
573                 }
574
575         } else {
576                 /* Use defaultkey if no Key Index */
577                 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
578         }
579
580         /* Check if there is no key information in the iwconfig request */
581         if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
582
583                 /*------------------------------------------------------------
584                  * If there is WEP Key for setting, check the Key Information
585                  * and then set it to the firmware.
586                  -------------------------------------------------------------*/
587
588                 if (erq->length > 0) {
589
590                         /* copy the key from the driver cache as the keys are read-only MIBs */
591                         wlandev->wep_keylens[i] = erq->length;
592                         memcpy(wlandev->wep_keys[i], key, erq->length);
593
594                         /* Prepare data struture for p80211req_dorequest. */
595                         memcpy(pstr.data.data, key, erq->length);
596                         pstr.data.len = erq->length;
597
598                         switch (i) {
599                         case 0:
600                                 pstr.did =
601                                     DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
602                                 break;
603
604                         case 1:
605                                 pstr.did =
606                                     DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
607                                 break;
608
609                         case 2:
610                                 pstr.did =
611                                     DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
612                                 break;
613
614                         case 3:
615                                 pstr.did =
616                                     DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
617                                 break;
618
619                         default:
620                                 err = -EINVAL;
621                                 goto exit;
622                         }
623
624                         msg.msgcode = DIDmsg_dot11req_mibset;
625                         memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
626                         result = p80211req_dorequest(wlandev, (u8 *) &msg);
627
628                         if (result) {
629                                 err = -EFAULT;
630                                 goto exit;
631                         }
632                 }
633
634         }
635
636         /* Check the PrivacyInvoked flag */
637         if (erq->flags & IW_ENCODE_DISABLED) {
638                 result =
639                     p80211wext_dorequest(wlandev,
640                                          DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
641                                          P80211ENUM_truth_false);
642         } else {
643                 result =
644                     p80211wext_dorequest(wlandev,
645                                          DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
646                                          P80211ENUM_truth_true);
647         }
648
649         if (result) {
650                 err = -EFAULT;
651                 goto exit;
652         }
653
654         /*  The  security  mode  may  be open or restricted, and its meaning
655            depends on the card used. With  most  cards,  in  open  mode  no
656            authentication  is  used  and  the  card  may  also  accept non-
657            encrypted sessions, whereas in restricted  mode  only  encrypted
658            sessions  are  accepted  and the card will use authentication if
659            available.
660          */
661         if (erq->flags & IW_ENCODE_RESTRICTED) {
662                 result =
663                     p80211wext_dorequest(wlandev,
664                                          DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
665                                          P80211ENUM_truth_true);
666         } else if (erq->flags & IW_ENCODE_OPEN) {
667                 result =
668                     p80211wext_dorequest(wlandev,
669                                          DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
670                                          P80211ENUM_truth_false);
671         }
672
673         if (result) {
674                 err = -EFAULT;
675                 goto exit;
676         }
677
678 exit:
679
680         return err;
681 }
682
683 static int p80211wext_giwessid(netdevice_t *dev,
684                                struct iw_request_info *info,
685                                struct iw_point *data, char *essid)
686 {
687         wlandevice_t *wlandev = dev->ml_priv;
688
689         if (wlandev->ssid.len) {
690                 data->length = wlandev->ssid.len;
691                 data->flags = 1;
692                 memcpy(essid, wlandev->ssid.data, data->length);
693                 essid[data->length] = 0;
694         } else {
695                 memset(essid, 0, sizeof(wlandev->ssid.data));
696                 data->length = 0;
697                 data->flags = 0;
698         }
699
700         return 0;
701 }
702
703 static int p80211wext_siwessid(netdevice_t *dev,
704                                struct iw_request_info *info,
705                                struct iw_point *data, char *essid)
706 {
707         wlandevice_t *wlandev = dev->ml_priv;
708         p80211msg_lnxreq_autojoin_t msg;
709
710         int result;
711         int err = 0;
712         int length = data->length;
713
714         if (!wlan_wext_write) {
715                 err = (-EOPNOTSUPP);
716                 goto exit;
717         }
718
719         if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
720                 msg.authtype.data = P80211ENUM_authalg_sharedkey;
721         else
722                 msg.authtype.data = P80211ENUM_authalg_opensystem;
723
724         msg.msgcode = DIDmsg_lnxreq_autojoin;
725
726         /* Trim the last '\0' to fit the SSID format */
727         if (length && essid[length - 1] == '\0')
728                 length--;
729
730         memcpy(msg.ssid.data.data, essid, length);
731         msg.ssid.data.len = length;
732
733         pr_debug("autojoin_ssid for %s \n", essid);
734         result = p80211req_dorequest(wlandev, (u8 *) &msg);
735         pr_debug("autojoin_ssid %d\n", result);
736
737         if (result) {
738                 err = -EFAULT;
739                 goto exit;
740         }
741
742 exit:
743         return err;
744 }
745
746 static int p80211wext_siwcommit(netdevice_t *dev,
747                                 struct iw_request_info *info,
748                                 struct iw_point *data, char *essid)
749 {
750         wlandevice_t *wlandev = dev->ml_priv;
751         int err = 0;
752
753         if (!wlan_wext_write) {
754                 err = (-EOPNOTSUPP);
755                 goto exit;
756         }
757
758         /* Auto Join */
759         err = p80211wext_autojoin(wlandev);
760
761 exit:
762         return err;
763 }
764
765 static int p80211wext_giwrate(netdevice_t *dev,
766                               struct iw_request_info *info,
767                               struct iw_param *rrq, char *extra)
768 {
769         wlandevice_t *wlandev = dev->ml_priv;
770         p80211item_uint32_t mibitem;
771         p80211msg_dot11req_mibset_t msg;
772         int result;
773         int err = 0;
774
775         msg.msgcode = DIDmsg_dot11req_mibget;
776         memset(&mibitem, 0, sizeof(mibitem));
777         mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
778         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
779         result = p80211req_dorequest(wlandev, (u8 *) &msg);
780
781         if (result) {
782                 err = -EFAULT;
783                 goto exit;
784         }
785
786         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
787
788         rrq->fixed = 0;         /* can it change? */
789         rrq->disabled = 0;
790         rrq->value = 0;
791
792 #define         HFA384x_RATEBIT_1                       ((u16)1)
793 #define         HFA384x_RATEBIT_2                       ((u16)2)
794 #define         HFA384x_RATEBIT_5dot5                   ((u16)4)
795 #define         HFA384x_RATEBIT_11                      ((u16)8)
796
797         switch (mibitem.data) {
798         case HFA384x_RATEBIT_1:
799                 rrq->value = 1000000;
800                 break;
801         case HFA384x_RATEBIT_2:
802                 rrq->value = 2000000;
803                 break;
804         case HFA384x_RATEBIT_5dot5:
805                 rrq->value = 5500000;
806                 break;
807         case HFA384x_RATEBIT_11:
808                 rrq->value = 11000000;
809                 break;
810         default:
811                 err = -EINVAL;
812         }
813 exit:
814         return err;
815 }
816
817 static int p80211wext_giwrts(netdevice_t *dev,
818                              struct iw_request_info *info,
819                              struct iw_param *rts, char *extra)
820 {
821         wlandevice_t *wlandev = dev->ml_priv;
822         p80211item_uint32_t mibitem;
823         p80211msg_dot11req_mibset_t msg;
824         int result;
825         int err = 0;
826
827         msg.msgcode = DIDmsg_dot11req_mibget;
828         memset(&mibitem, 0, sizeof(mibitem));
829         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
830         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
831         result = p80211req_dorequest(wlandev, (u8 *) &msg);
832
833         if (result) {
834                 err = -EFAULT;
835                 goto exit;
836         }
837
838         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
839
840         rts->value = mibitem.data;
841         rts->disabled = (rts->value == 2347);
842         rts->fixed = 1;
843
844 exit:
845         return err;
846 }
847
848 static int p80211wext_siwrts(netdevice_t *dev,
849                              struct iw_request_info *info,
850                              struct iw_param *rts, char *extra)
851 {
852         wlandevice_t *wlandev = dev->ml_priv;
853         p80211item_uint32_t mibitem;
854         p80211msg_dot11req_mibset_t msg;
855         int result;
856         int err = 0;
857
858         if (!wlan_wext_write) {
859                 err = (-EOPNOTSUPP);
860                 goto exit;
861         }
862
863         msg.msgcode = DIDmsg_dot11req_mibget;
864         memset(&mibitem, 0, sizeof(mibitem));
865         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
866         if (rts->disabled)
867                 mibitem.data = 2347;
868         else
869                 mibitem.data = rts->value;
870
871         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
872         result = p80211req_dorequest(wlandev, (u8 *) &msg);
873
874         if (result) {
875                 err = -EFAULT;
876                 goto exit;
877         }
878
879 exit:
880         return err;
881 }
882
883 static int p80211wext_giwfrag(netdevice_t *dev,
884                               struct iw_request_info *info,
885                               struct iw_param *frag, char *extra)
886 {
887         wlandevice_t *wlandev = dev->ml_priv;
888         p80211item_uint32_t mibitem;
889         p80211msg_dot11req_mibset_t msg;
890         int result;
891         int err = 0;
892
893         msg.msgcode = DIDmsg_dot11req_mibget;
894         memset(&mibitem, 0, sizeof(mibitem));
895         mibitem.did =
896             DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
897         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
898         result = p80211req_dorequest(wlandev, (u8 *) &msg);
899
900         if (result) {
901                 err = -EFAULT;
902                 goto exit;
903         }
904
905         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
906
907         frag->value = mibitem.data;
908         frag->disabled = (frag->value == 2346);
909         frag->fixed = 1;
910
911 exit:
912         return err;
913 }
914
915 static int p80211wext_siwfrag(netdevice_t *dev,
916                               struct iw_request_info *info,
917                               struct iw_param *frag, char *extra)
918 {
919         wlandevice_t *wlandev = dev->ml_priv;
920         p80211item_uint32_t mibitem;
921         p80211msg_dot11req_mibset_t msg;
922         int result;
923         int err = 0;
924
925         if (!wlan_wext_write) {
926                 err = (-EOPNOTSUPP);
927                 goto exit;
928         }
929
930         msg.msgcode = DIDmsg_dot11req_mibset;
931         memset(&mibitem, 0, sizeof(mibitem));
932         mibitem.did =
933             DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
934
935         if (frag->disabled)
936                 mibitem.data = 2346;
937         else
938                 mibitem.data = frag->value;
939
940         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
941         result = p80211req_dorequest(wlandev, (u8 *) &msg);
942
943         if (result) {
944                 err = -EFAULT;
945                 goto exit;
946         }
947
948 exit:
949         return err;
950 }
951
952 #ifndef IW_RETRY_LONG
953 #define IW_RETRY_LONG IW_RETRY_MAX
954 #endif
955
956 #ifndef IW_RETRY_SHORT
957 #define IW_RETRY_SHORT IW_RETRY_MIN
958 #endif
959
960 static int p80211wext_giwretry(netdevice_t *dev,
961                                struct iw_request_info *info,
962                                struct iw_param *rrq, char *extra)
963 {
964         wlandevice_t *wlandev = dev->ml_priv;
965         p80211item_uint32_t mibitem;
966         p80211msg_dot11req_mibset_t msg;
967         int result;
968         int err = 0;
969         u16 shortretry, longretry, lifetime;
970
971         msg.msgcode = DIDmsg_dot11req_mibget;
972         memset(&mibitem, 0, sizeof(mibitem));
973         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
974
975         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
976         result = p80211req_dorequest(wlandev, (u8 *) &msg);
977
978         if (result) {
979                 err = -EFAULT;
980                 goto exit;
981         }
982
983         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
984
985         shortretry = mibitem.data;
986
987         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
988
989         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
990         result = p80211req_dorequest(wlandev, (u8 *) &msg);
991
992         if (result) {
993                 err = -EFAULT;
994                 goto exit;
995         }
996
997         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
998
999         longretry = mibitem.data;
1000
1001         mibitem.did =
1002             DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1003
1004         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1005         result = p80211req_dorequest(wlandev, (u8 *) &msg);
1006
1007         if (result) {
1008                 err = -EFAULT;
1009                 goto exit;
1010         }
1011
1012         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1013
1014         lifetime = mibitem.data;
1015
1016         rrq->disabled = 0;
1017
1018         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1019                 rrq->flags = IW_RETRY_LIFETIME;
1020                 rrq->value = lifetime * 1024;
1021         } else {
1022                 if (rrq->flags & IW_RETRY_LONG) {
1023                         rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1024                         rrq->value = longretry;
1025                 } else {
1026                         rrq->flags = IW_RETRY_LIMIT;
1027                         rrq->value = shortretry;
1028                         if (shortretry != longretry)
1029                                 rrq->flags |= IW_RETRY_SHORT;
1030                 }
1031         }
1032
1033 exit:
1034         return err;
1035
1036 }
1037
1038 static int p80211wext_siwretry(netdevice_t *dev,
1039                                struct iw_request_info *info,
1040                                struct iw_param *rrq, char *extra)
1041 {
1042         wlandevice_t *wlandev = dev->ml_priv;
1043         p80211item_uint32_t mibitem;
1044         p80211msg_dot11req_mibset_t msg;
1045         int result;
1046         int err = 0;
1047
1048         memset(&mibitem, 0, sizeof(mibitem));
1049
1050         if (!wlan_wext_write) {
1051                 err = (-EOPNOTSUPP);
1052                 goto exit;
1053         }
1054
1055         if (rrq->disabled) {
1056                 err = -EINVAL;
1057                 goto exit;
1058         }
1059
1060         msg.msgcode = DIDmsg_dot11req_mibset;
1061
1062         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1063                 mibitem.did =
1064                     DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1065                 mibitem.data = rrq->value /= 1024;
1066
1067                 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1068                 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1069
1070                 if (result) {
1071                         err = -EFAULT;
1072                         goto exit;
1073                 }
1074         } else {
1075                 if (rrq->flags & IW_RETRY_LONG) {
1076                         mibitem.did =
1077                             DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1078                         mibitem.data = rrq->value;
1079
1080                         memcpy(&msg.mibattribute.data, &mibitem,
1081                                sizeof(mibitem));
1082                         result = p80211req_dorequest(wlandev, (u8 *) &msg);
1083
1084                         if (result) {
1085                                 err = -EFAULT;
1086                                 goto exit;
1087                         }
1088                 }
1089
1090                 if (rrq->flags & IW_RETRY_SHORT) {
1091                         mibitem.did =
1092                             DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1093                         mibitem.data = rrq->value;
1094
1095                         memcpy(&msg.mibattribute.data, &mibitem,
1096                                sizeof(mibitem));
1097                         result = p80211req_dorequest(wlandev, (u8 *) &msg);
1098
1099                         if (result) {
1100                                 err = -EFAULT;
1101                                 goto exit;
1102                         }
1103                 }
1104         }
1105
1106 exit:
1107         return err;
1108
1109 }
1110
1111 static int p80211wext_siwtxpow(netdevice_t *dev,
1112                                struct iw_request_info *info,
1113                                struct iw_param *rrq, char *extra)
1114 {
1115         wlandevice_t *wlandev = dev->ml_priv;
1116         p80211item_uint32_t mibitem;
1117         p80211msg_dot11req_mibset_t msg;
1118         int result;
1119         int err = 0;
1120
1121         if (!wlan_wext_write) {
1122                 err = (-EOPNOTSUPP);
1123                 goto exit;
1124         }
1125
1126         msg.msgcode = DIDmsg_dot11req_mibset;
1127         memset(&mibitem, 0, sizeof(mibitem));
1128         mibitem.did =
1129             DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1130         if (rrq->fixed == 0)
1131                 mibitem.data = 30;
1132         else
1133                 mibitem.data = rrq->value;
1134         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1135         result = p80211req_dorequest(wlandev, (u8 *) &msg);
1136
1137         if (result) {
1138                 err = -EFAULT;
1139                 goto exit;
1140         }
1141
1142 exit:
1143         return err;
1144 }
1145
1146 static int p80211wext_giwtxpow(netdevice_t *dev,
1147                                struct iw_request_info *info,
1148                                struct iw_param *rrq, char *extra)
1149 {
1150         wlandevice_t *wlandev = dev->ml_priv;
1151         p80211item_uint32_t mibitem;
1152         p80211msg_dot11req_mibset_t msg;
1153         int result;
1154         int err = 0;
1155
1156         msg.msgcode = DIDmsg_dot11req_mibget;
1157
1158         memset(&mibitem, 0, sizeof(mibitem));
1159         mibitem.did =
1160             DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1161
1162         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1163         result = p80211req_dorequest(wlandev, (u8 *) &msg);
1164
1165         if (result) {
1166                 err = -EFAULT;
1167                 goto exit;
1168         }
1169
1170         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1171
1172         /* XXX handle OFF by setting disabled = 1; */
1173
1174         rrq->flags = 0;         /* IW_TXPOW_DBM; */
1175         rrq->disabled = 0;
1176         rrq->fixed = 0;
1177         rrq->value = mibitem.data;
1178
1179 exit:
1180         return err;
1181 }
1182
1183 static int p80211wext_siwspy(netdevice_t *dev,
1184                              struct iw_request_info *info,
1185                              struct iw_point *srq, char *extra)
1186 {
1187         wlandevice_t *wlandev = dev->ml_priv;
1188         struct sockaddr address[IW_MAX_SPY];
1189         int number = srq->length;
1190         int i;
1191
1192         /* Copy the data from the input buffer */
1193         memcpy(address, extra, sizeof(struct sockaddr) * number);
1194
1195         wlandev->spy_number = 0;
1196
1197         if (number > 0) {
1198
1199                 /* extract the addresses */
1200                 for (i = 0; i < number; i++) {
1201
1202                         memcpy(wlandev->spy_address[i], address[i].sa_data,
1203                                ETH_ALEN);
1204                 }
1205
1206                 /* reset stats */
1207                 memset(wlandev->spy_stat, 0,
1208                        sizeof(struct iw_quality) * IW_MAX_SPY);
1209
1210                 /* set number of addresses */
1211                 wlandev->spy_number = number;
1212         }
1213
1214         return 0;
1215 }
1216
1217 /* jkriegl: from orinoco, modified */
1218 static int p80211wext_giwspy(netdevice_t *dev,
1219                              struct iw_request_info *info,
1220                              struct iw_point *srq, char *extra)
1221 {
1222         wlandevice_t *wlandev = dev->ml_priv;
1223
1224         struct sockaddr address[IW_MAX_SPY];
1225         struct iw_quality spy_stat[IW_MAX_SPY];
1226         int number;
1227         int i;
1228
1229         number = wlandev->spy_number;
1230
1231         if (number > 0) {
1232
1233                 /* populate address and spy struct's */
1234                 for (i = 0; i < number; i++) {
1235                         memcpy(address[i].sa_data, wlandev->spy_address[i],
1236                                ETH_ALEN);
1237                         address[i].sa_family = AF_UNIX;
1238                         memcpy(&spy_stat[i], &wlandev->spy_stat[i],
1239                                sizeof(struct iw_quality));
1240                 }
1241
1242                 /* reset update flag */
1243                 for (i = 0; i < number; i++)
1244                         wlandev->spy_stat[i].updated = 0;
1245         }
1246
1247         /* push stuff to user space */
1248         srq->length = number;
1249         memcpy(extra, address, sizeof(struct sockaddr) * number);
1250         memcpy(extra + sizeof(struct sockaddr) * number, spy_stat,
1251                sizeof(struct iw_quality) * number);
1252
1253         return 0;
1254 }
1255
1256 static int prism2_result2err(int prism2_result)
1257 {
1258         int err = 0;
1259
1260         switch (prism2_result) {
1261         case P80211ENUM_resultcode_invalid_parameters:
1262                 err = -EINVAL;
1263                 break;
1264         case P80211ENUM_resultcode_implementation_failure:
1265                 err = -EIO;
1266                 break;
1267         case P80211ENUM_resultcode_not_supported:
1268                 err = -EOPNOTSUPP;
1269                 break;
1270         default:
1271                 err = 0;
1272                 break;
1273         }
1274
1275         return err;
1276 }
1277
1278 static int p80211wext_siwscan(netdevice_t *dev,
1279                               struct iw_request_info *info,
1280                               struct iw_point *srq, char *extra)
1281 {
1282         wlandevice_t *wlandev = dev->ml_priv;
1283         p80211msg_dot11req_scan_t msg;
1284         int result;
1285         int err = 0;
1286         int i = 0;
1287
1288         if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1289                 printk(KERN_ERR "Can't scan in AP mode\n");
1290                 err = (-EOPNOTSUPP);
1291                 goto exit;
1292         }
1293
1294         memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1295         msg.msgcode = DIDmsg_dot11req_scan;
1296         msg.bsstype.data = P80211ENUM_bsstype_any;
1297
1298         memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
1299         msg.bssid.data.len = 6;
1300
1301         msg.scantype.data = P80211ENUM_scantype_active;
1302         msg.probedelay.data = 0;
1303
1304         for (i = 1; i <= 14; i++)
1305                 msg.channellist.data.data[i - 1] = i;
1306         msg.channellist.data.len = 14;
1307
1308         msg.maxchanneltime.data = 250;
1309         msg.minchanneltime.data = 200;
1310
1311         result = p80211req_dorequest(wlandev, (u8 *) &msg);
1312         if (result)
1313                 err = prism2_result2err(msg.resultcode.data);
1314
1315 exit:
1316         return err;
1317 }
1318
1319 /* Helper to translate scan into Wireless Extensions scan results.
1320  * Inspired by the prism54 code, which was in turn inspired by the
1321  * airo driver code.
1322  */
1323 static char *wext_translate_bss(struct iw_request_info *info, char *current_ev,
1324                                 char *end_buf,
1325                                 p80211msg_dot11req_scan_results_t *bss)
1326 {
1327         struct iw_event iwe;    /* Temporary buffer */
1328
1329         /* The first entry must be the MAC address */
1330         memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1331         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1332         iwe.cmd = SIOCGIWAP;
1333         current_ev =
1334             iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1335                                  IW_EV_ADDR_LEN);
1336
1337         /* The following entries will be displayed in the same order we give them */
1338
1339         /* The ESSID. */
1340         if (bss->ssid.data.len > 0) {
1341                 char essid[IW_ESSID_MAX_SIZE + 1];
1342                 int size;
1343
1344                 size =
1345                     min_t(unsigned short, IW_ESSID_MAX_SIZE,
1346                           bss->ssid.data.len);
1347                 memset(&essid, 0, sizeof(essid));
1348                 memcpy(&essid, bss->ssid.data.data, size);
1349                 pr_debug(" essid size = %d\n", size);
1350                 iwe.u.data.length = size;
1351                 iwe.u.data.flags = 1;
1352                 iwe.cmd = SIOCGIWESSID;
1353                 current_ev =
1354                     iwe_stream_add_point(info, current_ev, end_buf, &iwe,
1355                                          &essid[0]);
1356                 pr_debug(" essid size OK.\n");
1357         }
1358
1359         switch (bss->bsstype.data) {
1360         case P80211ENUM_bsstype_infrastructure:
1361                 iwe.u.mode = IW_MODE_MASTER;
1362                 break;
1363
1364         case P80211ENUM_bsstype_independent:
1365                 iwe.u.mode = IW_MODE_ADHOC;
1366                 break;
1367
1368         default:
1369                 iwe.u.mode = 0;
1370                 break;
1371         }
1372         iwe.cmd = SIOCGIWMODE;
1373         if (iwe.u.mode)
1374                 current_ev =
1375                     iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1376                                          IW_EV_UINT_LEN);
1377
1378         /* Encryption capability */
1379         if (bss->privacy.data == P80211ENUM_truth_true)
1380                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1381         else
1382                 iwe.u.data.flags = IW_ENCODE_DISABLED;
1383         iwe.u.data.length = 0;
1384         iwe.cmd = SIOCGIWENCODE;
1385         current_ev =
1386             iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1387
1388         /* Add frequency. (short) bss->channel is the frequency in MHz */
1389         iwe.u.freq.m = bss->dschannel.data;
1390         iwe.u.freq.e = 0;
1391         iwe.cmd = SIOCGIWFREQ;
1392         current_ev =
1393             iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1394                                  IW_EV_FREQ_LEN);
1395
1396         /* Add quality statistics */
1397         iwe.u.qual.level = bss->signal.data;
1398         iwe.u.qual.noise = bss->noise.data;
1399         /* do a simple SNR for quality */
1400         iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1401         iwe.cmd = IWEVQUAL;
1402         current_ev =
1403             iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1404                                  IW_EV_QUAL_LEN);
1405
1406         return current_ev;
1407 }
1408
1409 static int p80211wext_giwscan(netdevice_t *dev,
1410                               struct iw_request_info *info,
1411                               struct iw_point *srq, char *extra)
1412 {
1413         wlandevice_t *wlandev = dev->ml_priv;
1414         p80211msg_dot11req_scan_results_t msg;
1415         int result = 0;
1416         int err = 0;
1417         int i = 0;
1418         int scan_good = 0;
1419         char *current_ev = extra;
1420
1421         /* Since wireless tools doesn't really have a way of passing how
1422          * many scan results results there were back here, keep grabbing them
1423          * until we fail.
1424          */
1425         do {
1426                 memset(&msg, 0, sizeof(msg));
1427                 msg.msgcode = DIDmsg_dot11req_scan_results;
1428                 msg.bssindex.data = i;
1429
1430                 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1431                 if ((result != 0) ||
1432                     (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1433                         break;
1434                 }
1435
1436                 current_ev =
1437                     wext_translate_bss(info, current_ev,
1438                                        extra + IW_SCAN_MAX_DATA, &msg);
1439                 scan_good = 1;
1440                 i++;
1441         } while (i < IW_MAX_AP);
1442
1443         srq->length = (current_ev - extra);
1444         srq->flags = 0;         /* todo */
1445
1446         if (result && !scan_good)
1447                 err = prism2_result2err(msg.resultcode.data);
1448
1449         return err;
1450 }
1451
1452 /* extra wireless extensions stuff to support NetworkManager (I hope) */
1453
1454 /* SIOCSIWENCODEEXT */
1455 static int p80211wext_set_encodeext(struct net_device *dev,
1456                                     struct iw_request_info *info,
1457                                     union iwreq_data *wrqu, char *extra)
1458 {
1459         wlandevice_t *wlandev = dev->ml_priv;
1460         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1461         p80211msg_dot11req_mibset_t msg;
1462         p80211item_pstr32_t *pstr;
1463
1464         int result = 0;
1465         struct iw_point *encoding = &wrqu->encoding;
1466         int idx = encoding->flags & IW_ENCODE_INDEX;
1467
1468         pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1469                  ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1470
1471         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1472                 /* set default key ? I'm not sure if this the the correct thing to do here */
1473
1474                 if (idx) {
1475                         if (idx < 1 || idx > NUM_WEPKEYS)
1476                                 return -EINVAL;
1477                         else
1478                                 idx--;
1479                 }
1480                 pr_debug("setting default key (%d)\n", idx);
1481                 result =
1482                     p80211wext_dorequest(wlandev,
1483                                          DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
1484                                          idx);
1485                 if (result)
1486                         return -EFAULT;
1487         }
1488
1489         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1490                 if (ext->alg != IW_ENCODE_ALG_WEP) {
1491                         pr_debug("asked to set a non wep key :(\n");
1492                         return -EINVAL;
1493                 }
1494                 if (idx) {
1495                         if (idx < 1 || idx > NUM_WEPKEYS)
1496                                 return -EINVAL;
1497                         else
1498                                 idx--;
1499                 }
1500                 pr_debug("Set WEP key (%d)\n", idx);
1501                 wlandev->wep_keylens[idx] = ext->key_len;
1502                 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1503
1504                 memset(&msg, 0, sizeof(msg));
1505                 pstr = (p80211item_pstr32_t *) &msg.mibattribute.data;
1506                 memcpy(pstr->data.data, ext->key, ext->key_len);
1507                 pstr->data.len = ext->key_len;
1508                 switch (idx) {
1509                 case 0:
1510                         pstr->did =
1511                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1512                         break;
1513                 case 1:
1514                         pstr->did =
1515                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1516                         break;
1517                 case 2:
1518                         pstr->did =
1519                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1520                         break;
1521                 case 3:
1522                         pstr->did =
1523                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1524                         break;
1525                 default:
1526                         break;
1527                 }
1528                 msg.msgcode = DIDmsg_dot11req_mibset;
1529                 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1530                 pr_debug("result (%d)\n", result);
1531         }
1532         return result;
1533 }
1534
1535 /* SIOCGIWENCODEEXT */
1536 static int p80211wext_get_encodeext(struct net_device *dev,
1537                                     struct iw_request_info *info,
1538                                     union iwreq_data *wrqu, char *extra)
1539 {
1540         wlandevice_t *wlandev = dev->ml_priv;
1541         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1542
1543         struct iw_point *encoding = &wrqu->encoding;
1544         int result = 0;
1545         int max_len;
1546         int idx;
1547
1548         pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1549                  ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1550
1551         max_len = encoding->length - sizeof(*ext);
1552         if (max_len <= 0) {
1553                 pr_debug("get_encodeext max_len [%d] invalid\n", max_len);
1554                 result = -EINVAL;
1555                 goto exit;
1556         }
1557         idx = encoding->flags & IW_ENCODE_INDEX;
1558
1559         pr_debug("get_encode_ext index [%d]\n", idx);
1560
1561         if (idx) {
1562                 if (idx < 1 || idx > NUM_WEPKEYS) {
1563                         pr_debug("get_encode_ext invalid key index [%d]\n",
1564                                  idx);
1565                         result = -EINVAL;
1566                         goto exit;
1567                 }
1568                 idx--;
1569         } else {
1570                 /* default key ? not sure what to do */
1571                 /* will just use key[0] for now ! FIX ME */
1572         }
1573
1574         encoding->flags = idx + 1;
1575         memset(ext, 0, sizeof(*ext));
1576
1577         ext->alg = IW_ENCODE_ALG_WEP;
1578         ext->key_len = wlandev->wep_keylens[idx];
1579         memcpy(ext->key, wlandev->wep_keys[idx], ext->key_len);
1580
1581         encoding->flags |= IW_ENCODE_ENABLED;
1582 exit:
1583         return result;
1584 }
1585
1586 /* SIOCSIWAUTH */
1587 static int p80211_wext_set_iwauth(struct net_device *dev,
1588                                   struct iw_request_info *info,
1589                                   union iwreq_data *wrqu, char *extra)
1590 {
1591         wlandevice_t *wlandev = dev->ml_priv;
1592         struct iw_param *param = &wrqu->param;
1593         int result = 0;
1594
1595         pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1596
1597         switch (param->flags & IW_AUTH_INDEX) {
1598         case IW_AUTH_DROP_UNENCRYPTED:
1599                 pr_debug("drop_unencrypted %d\n", param->value);
1600                 if (param->value)
1601                         result =
1602                             p80211wext_dorequest(wlandev,
1603                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1604                                                  P80211ENUM_truth_true);
1605                 else
1606                         result =
1607                             p80211wext_dorequest(wlandev,
1608                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1609                                                  P80211ENUM_truth_false);
1610                 break;
1611
1612         case IW_AUTH_PRIVACY_INVOKED:
1613                 pr_debug("privacy invoked %d\n", param->value);
1614                 if (param->value)
1615                         result =
1616                             p80211wext_dorequest(wlandev,
1617                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1618                                                  P80211ENUM_truth_true);
1619                 else
1620                         result =
1621                             p80211wext_dorequest(wlandev,
1622                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1623                                                  P80211ENUM_truth_false);
1624
1625                 break;
1626
1627         case IW_AUTH_80211_AUTH_ALG:
1628                 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1629                         pr_debug("set open_system\n");
1630                         wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1631                 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1632                         pr_debug("set shared key\n");
1633                         wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1634                 } else {
1635                         /* don't know what to do know  */
1636                         pr_debug("unknown AUTH_ALG (%d)\n", param->value);
1637                         result = -EINVAL;
1638                 }
1639                 break;
1640
1641         default:
1642                 break;
1643         }
1644
1645         return result;
1646 }
1647
1648 /* SIOCSIWAUTH */
1649 static int p80211_wext_get_iwauth(struct net_device *dev,
1650                                   struct iw_request_info *info,
1651                                   union iwreq_data *wrqu, char *extra)
1652 {
1653         wlandevice_t *wlandev = dev->ml_priv;
1654         struct iw_param *param = &wrqu->param;
1655         int result = 0;
1656
1657         pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1658
1659         switch (param->flags & IW_AUTH_INDEX) {
1660         case IW_AUTH_DROP_UNENCRYPTED:
1661                 param->value =
1662                     wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
1663                 break;
1664
1665         case IW_AUTH_PRIVACY_INVOKED:
1666                 param->value =
1667                     wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
1668                 break;
1669
1670         case IW_AUTH_80211_AUTH_ALG:
1671                 param->value =
1672                     wlandev->hostwep & HOSTWEP_SHAREDKEY ?
1673                     IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
1674                 break;
1675
1676         default:
1677                 break;
1678         }
1679
1680         return result;
1681 }
1682
1683 static iw_handler p80211wext_handlers[] = {
1684         (iw_handler) p80211wext_siwcommit,      /* SIOCSIWCOMMIT */
1685         (iw_handler) p80211wext_giwname,        /* SIOCGIWNAME */
1686         (iw_handler) NULL,      /* SIOCSIWNWID */
1687         (iw_handler) NULL,      /* SIOCGIWNWID */
1688         (iw_handler) p80211wext_siwfreq,        /* SIOCSIWFREQ */
1689         (iw_handler) p80211wext_giwfreq,        /* SIOCGIWFREQ */
1690         (iw_handler) p80211wext_siwmode,        /* SIOCSIWMODE */
1691         (iw_handler) p80211wext_giwmode,        /* SIOCGIWMODE */
1692         (iw_handler) NULL,      /* SIOCSIWSENS */
1693         (iw_handler) NULL,      /* SIOCGIWSENS */
1694         (iw_handler) NULL,      /* not used *//* SIOCSIWRANGE */
1695         (iw_handler) p80211wext_giwrange,       /* SIOCGIWRANGE */
1696         (iw_handler) NULL,      /* not used *//* SIOCSIWPRIV */
1697         (iw_handler) NULL,      /* kernel code *//* SIOCGIWPRIV */
1698         (iw_handler) NULL,      /* not used *//* SIOCSIWSTATS */
1699         (iw_handler) NULL,      /* kernel code *//* SIOCGIWSTATS */
1700         (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1701         (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1702         (iw_handler) NULL,      /* -- hole -- */
1703         (iw_handler) NULL,      /* -- hole -- */
1704         (iw_handler) NULL,      /* SIOCSIWAP */
1705         (iw_handler) p80211wext_giwap,  /* SIOCGIWAP */
1706         (iw_handler) NULL,      /* -- hole -- */
1707         (iw_handler) NULL,      /* SIOCGIWAPLIST */
1708         (iw_handler) p80211wext_siwscan,        /* SIOCSIWSCAN */
1709         (iw_handler) p80211wext_giwscan,        /* SIOCGIWSCAN */
1710         (iw_handler) p80211wext_siwessid,       /* SIOCSIWESSID */
1711         (iw_handler) p80211wext_giwessid,       /* SIOCGIWESSID */
1712         (iw_handler) NULL,      /* SIOCSIWNICKN */
1713         (iw_handler) p80211wext_giwessid,       /* SIOCGIWNICKN */
1714         (iw_handler) NULL,      /* -- hole -- */
1715         (iw_handler) NULL,      /* -- hole -- */
1716         (iw_handler) NULL,      /* SIOCSIWRATE */
1717         (iw_handler) p80211wext_giwrate,        /* SIOCGIWRATE */
1718         (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1719         (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1720         (iw_handler) p80211wext_siwfrag,        /* SIOCSIWFRAG */
1721         (iw_handler) p80211wext_giwfrag,        /* SIOCGIWFRAG */
1722         (iw_handler) p80211wext_siwtxpow,       /* SIOCSIWTXPOW */
1723         (iw_handler) p80211wext_giwtxpow,       /* SIOCGIWTXPOW */
1724         (iw_handler) p80211wext_siwretry,       /* SIOCSIWRETRY */
1725         (iw_handler) p80211wext_giwretry,       /* SIOCGIWRETRY */
1726         (iw_handler) p80211wext_siwencode,      /* SIOCSIWENCODE */
1727         (iw_handler) p80211wext_giwencode,      /* SIOCGIWENCODE */
1728         (iw_handler) NULL,      /* SIOCSIWPOWER */
1729         (iw_handler) NULL,      /* SIOCGIWPOWER */
1730 /* WPA operations */
1731         (iw_handler) NULL,      /* -- hole -- */
1732         (iw_handler) NULL,      /* -- hole -- */
1733         (iw_handler) NULL,      /* SIOCSIWGENIE      set generic IE */
1734         (iw_handler) NULL,      /* SIOCGIWGENIE      get generic IE */
1735         (iw_handler) p80211_wext_set_iwauth,    /* SIOCSIWAUTH     set authentication mode params */
1736         (iw_handler) p80211_wext_get_iwauth,    /* SIOCGIWAUTH     get authentication mode params */
1737
1738         (iw_handler) p80211wext_set_encodeext,  /* SIOCSIWENCODEEXT  set encoding token & mode */
1739         (iw_handler) p80211wext_get_encodeext,  /* SIOCGIWENCODEEXT  get encoding token & mode */
1740         (iw_handler) NULL,      /* SIOCSIWPMKSA      PMKSA cache operation */
1741 };
1742
1743 struct iw_handler_def p80211wext_handler_def = {
1744         .num_standard = ARRAY_SIZE(p80211wext_handlers),
1745         .standard = p80211wext_handlers,
1746         .get_wireless_stats = p80211wext_get_wireless_stats
1747 };
1748
1749 int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
1750 {
1751         union iwreq_data data;
1752
1753         /* Send the association state first */
1754         data.ap_addr.sa_family = ARPHRD_ETHER;
1755         if (assoc)
1756                 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
1757         else
1758                 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
1759
1760         if (wlan_wext_write)
1761                 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1762
1763         if (!assoc)
1764                 goto done;
1765
1766         /* XXX send association data, like IEs, etc etc. */
1767
1768 done:
1769         return 0;
1770 }