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