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