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