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