Staging: wlan-ng: Drop the special case handling of older wireless extensions, WIRELE...
[safe/jmp/linux-2.6] / drivers / staging / wlan-ng / p80211wext.c
1 /* src/p80211/p80211wext.c
2 *
3 * Glue code to make linux-wlan-ng a happy wireless extension camper.
4 *
5 * original author:  Reyk Floeter <reyk@synack.de>
6 * Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
7 *
8 * Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
9 * --------------------------------------------------------------------
10 *
11 * linux-wlan
12 *
13 *   The contents of this file are subject to the Mozilla Public
14 *   License Version 1.1 (the "License"); you may not use this file
15 *   except in compliance with the License. You may obtain a copy of
16 *   the License at http://www.mozilla.org/MPL/
17 *
18 *   Software distributed under the License is distributed on an "AS
19 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
20 *   implied. See the License for the specific language governing
21 *   rights and limitations under the License.
22 *
23 *   Alternatively, the contents of this file may be used under the
24 *   terms of the GNU Public License version 2 (the "GPL"), in which
25 *   case the provisions of the GPL are applicable instead of the
26 *   above.  If you wish to allow the use of your version of this file
27 *   only under the terms of the GPL and not to allow others to use
28 *   your version of this file under the MPL, indicate your decision
29 *   by deleting the provisions above and replace them with the notice
30 *   and other provisions required by the GPL.  If you do not delete
31 *   the provisions above, a recipient may use your version of this
32 *   file under either the MPL or the GPL.
33 *
34 * --------------------------------------------------------------------
35 */
36
37 /*================================================================*/
38 /* System Includes */
39
40 #include <linux/kernel.h>
41 #include <linux/sched.h>
42 #include <linux/types.h>
43 #include <linux/slab.h>
44 #include <linux/netdevice.h>
45 #include <linux/etherdevice.h>
46 #include <linux/wireless.h>
47 #include <net/iw_handler.h>
48 #include <linux/if_arp.h>
49 #include <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         } else {
693                 memset(essid, 0, sizeof(wlandev->ssid.data));
694                 data->length = 0;
695                 data->flags = 0;
696         }
697
698         return 0;
699 }
700
701 static int p80211wext_siwessid(netdevice_t *dev,
702                                struct iw_request_info *info,
703                                struct iw_point *data, char *essid)
704 {
705         wlandevice_t *wlandev = dev->ml_priv;
706         p80211msg_lnxreq_autojoin_t msg;
707
708         int result;
709         int err = 0;
710         int length = data->length;
711
712         if (!wlan_wext_write) {
713                 err = (-EOPNOTSUPP);
714                 goto exit;
715         }
716
717         if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
718                 msg.authtype.data = P80211ENUM_authalg_sharedkey;
719         else
720                 msg.authtype.data = P80211ENUM_authalg_opensystem;
721
722         msg.msgcode = DIDmsg_lnxreq_autojoin;
723
724         /* Trim the last '\0' to fit the SSID format */
725         if (length && essid[length - 1] == '\0')
726                 length--;
727
728         memcpy(msg.ssid.data.data, essid, length);
729         msg.ssid.data.len = length;
730
731         pr_debug("autojoin_ssid for %s \n", essid);
732         result = p80211req_dorequest(wlandev, (u8 *) & msg);
733         pr_debug("autojoin_ssid %d\n", result);
734
735         if (result) {
736                 err = -EFAULT;
737                 goto exit;
738         }
739
740 exit:
741         return err;
742 }
743
744 static int p80211wext_siwcommit(netdevice_t *dev,
745                                 struct iw_request_info *info,
746                                 struct iw_point *data, char *essid)
747 {
748         wlandevice_t *wlandev = dev->ml_priv;
749         int err = 0;
750
751         if (!wlan_wext_write) {
752                 err = (-EOPNOTSUPP);
753                 goto exit;
754         }
755
756         /* Auto Join */
757         err = p80211wext_autojoin(wlandev);
758
759 exit:
760         return err;
761 }
762
763 static int p80211wext_giwrate(netdevice_t *dev,
764                               struct iw_request_info *info,
765                               struct iw_param *rrq, char *extra)
766 {
767         wlandevice_t *wlandev = dev->ml_priv;
768         p80211item_uint32_t mibitem;
769         p80211msg_dot11req_mibset_t msg;
770         int result;
771         int err = 0;
772
773         msg.msgcode = DIDmsg_dot11req_mibget;
774         mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
775         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
776         result = p80211req_dorequest(wlandev, (u8 *) & msg);
777
778         if (result) {
779                 err = -EFAULT;
780                 goto exit;
781         }
782
783         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
784
785         rrq->fixed = 0;         /* can it change? */
786         rrq->disabled = 0;
787         rrq->value = 0;
788
789 #define         HFA384x_RATEBIT_1                       ((u16)1)
790 #define         HFA384x_RATEBIT_2                       ((u16)2)
791 #define         HFA384x_RATEBIT_5dot5                   ((u16)4)
792 #define         HFA384x_RATEBIT_11                      ((u16)8)
793
794         switch (mibitem.data) {
795         case HFA384x_RATEBIT_1:
796                 rrq->value = 1000000;
797                 break;
798         case HFA384x_RATEBIT_2:
799                 rrq->value = 2000000;
800                 break;
801         case HFA384x_RATEBIT_5dot5:
802                 rrq->value = 5500000;
803                 break;
804         case HFA384x_RATEBIT_11:
805                 rrq->value = 11000000;
806                 break;
807         default:
808                 err = -EINVAL;
809         }
810 exit:
811         return err;
812 }
813
814 static int p80211wext_giwrts(netdevice_t *dev,
815                              struct iw_request_info *info,
816                              struct iw_param *rts, char *extra)
817 {
818         wlandevice_t *wlandev = dev->ml_priv;
819         p80211item_uint32_t mibitem;
820         p80211msg_dot11req_mibset_t msg;
821         int result;
822         int err = 0;
823
824         msg.msgcode = DIDmsg_dot11req_mibget;
825         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
826         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
827         result = p80211req_dorequest(wlandev, (u8 *) & msg);
828
829         if (result) {
830                 err = -EFAULT;
831                 goto exit;
832         }
833
834         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
835
836         rts->value = mibitem.data;
837         rts->disabled = (rts->value == 2347);
838         rts->fixed = 1;
839
840 exit:
841         return err;
842 }
843
844 static int p80211wext_siwrts(netdevice_t *dev,
845                              struct iw_request_info *info,
846                              struct iw_param *rts, char *extra)
847 {
848         wlandevice_t *wlandev = dev->ml_priv;
849         p80211item_uint32_t mibitem;
850         p80211msg_dot11req_mibset_t msg;
851         int result;
852         int err = 0;
853
854         if (!wlan_wext_write) {
855                 err = (-EOPNOTSUPP);
856                 goto exit;
857         }
858
859         msg.msgcode = DIDmsg_dot11req_mibget;
860         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
861         if (rts->disabled)
862                 mibitem.data = 2347;
863         else
864                 mibitem.data = rts->value;
865
866         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
867         result = p80211req_dorequest(wlandev, (u8 *) & msg);
868
869         if (result) {
870                 err = -EFAULT;
871                 goto exit;
872         }
873
874 exit:
875         return err;
876 }
877
878 static int p80211wext_giwfrag(netdevice_t *dev,
879                               struct iw_request_info *info,
880                               struct iw_param *frag, char *extra)
881 {
882         wlandevice_t *wlandev = dev->ml_priv;
883         p80211item_uint32_t mibitem;
884         p80211msg_dot11req_mibset_t msg;
885         int result;
886         int err = 0;
887
888         msg.msgcode = DIDmsg_dot11req_mibget;
889         mibitem.did =
890             DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
891         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
892         result = p80211req_dorequest(wlandev, (u8 *) & msg);
893
894         if (result) {
895                 err = -EFAULT;
896                 goto exit;
897         }
898
899         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
900
901         frag->value = mibitem.data;
902         frag->disabled = (frag->value == 2346);
903         frag->fixed = 1;
904
905 exit:
906         return err;
907 }
908
909 static int p80211wext_siwfrag(netdevice_t *dev,
910                               struct iw_request_info *info,
911                               struct iw_param *frag, char *extra)
912 {
913         wlandevice_t *wlandev = dev->ml_priv;
914         p80211item_uint32_t mibitem;
915         p80211msg_dot11req_mibset_t msg;
916         int result;
917         int err = 0;
918
919         if (!wlan_wext_write) {
920                 err = (-EOPNOTSUPP);
921                 goto exit;
922         }
923
924         msg.msgcode = DIDmsg_dot11req_mibset;
925         mibitem.did =
926             DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
927
928         if (frag->disabled)
929                 mibitem.data = 2346;
930         else
931                 mibitem.data = frag->value;
932
933         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
934         result = p80211req_dorequest(wlandev, (u8 *) & msg);
935
936         if (result) {
937                 err = -EFAULT;
938                 goto exit;
939         }
940
941 exit:
942         return err;
943 }
944
945 #ifndef IW_RETRY_LONG
946 #define IW_RETRY_LONG IW_RETRY_MAX
947 #endif
948
949 #ifndef IW_RETRY_SHORT
950 #define IW_RETRY_SHORT IW_RETRY_MIN
951 #endif
952
953 static int p80211wext_giwretry(netdevice_t *dev,
954                                struct iw_request_info *info,
955                                struct iw_param *rrq, char *extra)
956 {
957         wlandevice_t *wlandev = dev->ml_priv;
958         p80211item_uint32_t mibitem;
959         p80211msg_dot11req_mibset_t msg;
960         int result;
961         int err = 0;
962         u16 shortretry, longretry, lifetime;
963
964         msg.msgcode = DIDmsg_dot11req_mibget;
965         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
966
967         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
968         result = p80211req_dorequest(wlandev, (u8 *) & msg);
969
970         if (result) {
971                 err = -EFAULT;
972                 goto exit;
973         }
974
975         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
976
977         shortretry = mibitem.data;
978
979         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
980
981         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
982         result = p80211req_dorequest(wlandev, (u8 *) & msg);
983
984         if (result) {
985                 err = -EFAULT;
986                 goto exit;
987         }
988
989         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
990
991         longretry = mibitem.data;
992
993         mibitem.did =
994             DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
995
996         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
997         result = p80211req_dorequest(wlandev, (u8 *) & msg);
998
999         if (result) {
1000                 err = -EFAULT;
1001                 goto exit;
1002         }
1003
1004         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1005
1006         lifetime = mibitem.data;
1007
1008         rrq->disabled = 0;
1009
1010         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1011                 rrq->flags = IW_RETRY_LIFETIME;
1012                 rrq->value = lifetime * 1024;
1013         } else {
1014                 if (rrq->flags & IW_RETRY_LONG) {
1015                         rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1016                         rrq->value = longretry;
1017                 } else {
1018                         rrq->flags = IW_RETRY_LIMIT;
1019                         rrq->value = shortretry;
1020                         if (shortretry != longretry)
1021                                 rrq->flags |= IW_RETRY_SHORT;
1022                 }
1023         }
1024
1025 exit:
1026         return err;
1027
1028 }
1029
1030 static int p80211wext_siwretry(netdevice_t *dev,
1031                                struct iw_request_info *info,
1032                                struct iw_param *rrq, char *extra)
1033 {
1034         wlandevice_t *wlandev = dev->ml_priv;
1035         p80211item_uint32_t mibitem;
1036         p80211msg_dot11req_mibset_t msg;
1037         int result;
1038         int err = 0;
1039
1040         if (!wlan_wext_write) {
1041                 err = (-EOPNOTSUPP);
1042                 goto exit;
1043         }
1044
1045         if (rrq->disabled) {
1046                 err = -EINVAL;
1047                 goto exit;
1048         }
1049
1050         msg.msgcode = DIDmsg_dot11req_mibset;
1051
1052         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1053                 mibitem.did =
1054                     DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1055                 mibitem.data = rrq->value /= 1024;
1056
1057                 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1058                 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1059
1060                 if (result) {
1061                         err = -EFAULT;
1062                         goto exit;
1063                 }
1064         } else {
1065                 if (rrq->flags & IW_RETRY_LONG) {
1066                         mibitem.did =
1067                             DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1068                         mibitem.data = rrq->value;
1069
1070                         memcpy(&msg.mibattribute.data, &mibitem,
1071                                sizeof(mibitem));
1072                         result = p80211req_dorequest(wlandev, (u8 *) & msg);
1073
1074                         if (result) {
1075                                 err = -EFAULT;
1076                                 goto exit;
1077                         }
1078                 }
1079
1080                 if (rrq->flags & IW_RETRY_SHORT) {
1081                         mibitem.did =
1082                             DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1083                         mibitem.data = rrq->value;
1084
1085                         memcpy(&msg.mibattribute.data, &mibitem,
1086                                sizeof(mibitem));
1087                         result = p80211req_dorequest(wlandev, (u8 *) & msg);
1088
1089                         if (result) {
1090                                 err = -EFAULT;
1091                                 goto exit;
1092                         }
1093                 }
1094         }
1095
1096 exit:
1097         return err;
1098
1099 }
1100
1101 static int p80211wext_siwtxpow(netdevice_t *dev,
1102                                struct iw_request_info *info,
1103                                struct iw_param *rrq, char *extra)
1104 {
1105         wlandevice_t *wlandev = dev->ml_priv;
1106         p80211item_uint32_t mibitem;
1107         p80211msg_dot11req_mibset_t msg;
1108         int result;
1109         int err = 0;
1110
1111         if (!wlan_wext_write) {
1112                 err = (-EOPNOTSUPP);
1113                 goto exit;
1114         }
1115
1116         msg.msgcode = DIDmsg_dot11req_mibset;
1117         mibitem.did =
1118             DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1119         if (rrq->fixed == 0)
1120                 mibitem.data = 30;
1121         else
1122                 mibitem.data = rrq->value;
1123         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1124         result = p80211req_dorequest(wlandev, (u8 *) & msg);
1125
1126         if (result) {
1127                 err = -EFAULT;
1128                 goto exit;
1129         }
1130
1131 exit:
1132         return err;
1133 }
1134
1135 static int p80211wext_giwtxpow(netdevice_t *dev,
1136                                struct iw_request_info *info,
1137                                struct iw_param *rrq, char *extra)
1138 {
1139         wlandevice_t *wlandev = dev->ml_priv;
1140         p80211item_uint32_t mibitem;
1141         p80211msg_dot11req_mibset_t msg;
1142         int result;
1143         int err = 0;
1144
1145         msg.msgcode = DIDmsg_dot11req_mibget;
1146         mibitem.did =
1147             DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1148
1149         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1150         result = p80211req_dorequest(wlandev, (u8 *) & msg);
1151
1152         if (result) {
1153                 err = -EFAULT;
1154                 goto exit;
1155         }
1156
1157         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1158
1159         /* XXX handle OFF by setting disabled = 1; */
1160
1161         rrq->flags = 0;         /* IW_TXPOW_DBM; */
1162         rrq->disabled = 0;
1163         rrq->fixed = 0;
1164         rrq->value = mibitem.data;
1165
1166 exit:
1167         return err;
1168 }
1169
1170 static int p80211wext_siwspy(netdevice_t *dev,
1171                              struct iw_request_info *info,
1172                              struct iw_point *srq, char *extra)
1173 {
1174         wlandevice_t *wlandev = dev->ml_priv;
1175         struct sockaddr address[IW_MAX_SPY];
1176         int number = srq->length;
1177         int i;
1178
1179         /* Copy the data from the input buffer */
1180         memcpy(address, extra, sizeof(struct sockaddr) * number);
1181
1182         wlandev->spy_number = 0;
1183
1184         if (number > 0) {
1185
1186                 /* extract the addresses */
1187                 for (i = 0; i < number; i++) {
1188
1189                         memcpy(wlandev->spy_address[i], address[i].sa_data,
1190                                ETH_ALEN);
1191                 }
1192
1193                 /* reset stats */
1194                 memset(wlandev->spy_stat, 0,
1195                        sizeof(struct iw_quality) * IW_MAX_SPY);
1196
1197                 /* set number of addresses */
1198                 wlandev->spy_number = number;
1199         }
1200
1201         return 0;
1202 }
1203
1204 /* jkriegl: from orinoco, modified */
1205 static int p80211wext_giwspy(netdevice_t *dev,
1206                              struct iw_request_info *info,
1207                              struct iw_point *srq, char *extra)
1208 {
1209         wlandevice_t *wlandev = dev->ml_priv;
1210
1211         struct sockaddr address[IW_MAX_SPY];
1212         struct iw_quality spy_stat[IW_MAX_SPY];
1213         int number;
1214         int i;
1215
1216         number = wlandev->spy_number;
1217
1218         if (number > 0) {
1219
1220                 /* populate address and spy struct's */
1221                 for (i = 0; i < number; i++) {
1222                         memcpy(address[i].sa_data, wlandev->spy_address[i],
1223                                ETH_ALEN);
1224                         address[i].sa_family = AF_UNIX;
1225                         memcpy(&spy_stat[i], &wlandev->spy_stat[i],
1226                                sizeof(struct iw_quality));
1227                 }
1228
1229                 /* reset update flag */
1230                 for (i = 0; i < number; i++)
1231                         wlandev->spy_stat[i].updated = 0;
1232         }
1233
1234         /* push stuff to user space */
1235         srq->length = number;
1236         memcpy(extra, address, sizeof(struct sockaddr) * number);
1237         memcpy(extra + sizeof(struct sockaddr) * number, spy_stat,
1238                sizeof(struct iw_quality) * number);
1239
1240         return 0;
1241 }
1242
1243 static int prism2_result2err(int prism2_result)
1244 {
1245         int err = 0;
1246
1247         switch (prism2_result) {
1248         case P80211ENUM_resultcode_invalid_parameters:
1249                 err = -EINVAL;
1250                 break;
1251         case P80211ENUM_resultcode_implementation_failure:
1252                 err = -EIO;
1253                 break;
1254         case P80211ENUM_resultcode_not_supported:
1255                 err = -EOPNOTSUPP;
1256                 break;
1257         default:
1258                 err = 0;
1259                 break;
1260         }
1261
1262         return err;
1263 }
1264
1265 static int p80211wext_siwscan(netdevice_t *dev,
1266                               struct iw_request_info *info,
1267                               struct iw_point *srq, char *extra)
1268 {
1269         wlandevice_t *wlandev = dev->ml_priv;
1270         p80211msg_dot11req_scan_t msg;
1271         int result;
1272         int err = 0;
1273         int i = 0;
1274
1275         if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1276                 printk(KERN_ERR "Can't scan in AP mode\n");
1277                 err = (-EOPNOTSUPP);
1278                 goto exit;
1279         }
1280
1281         memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1282         msg.msgcode = DIDmsg_dot11req_scan;
1283         msg.bsstype.data = P80211ENUM_bsstype_any;
1284
1285         memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
1286         msg.bssid.data.len = 6;
1287
1288         msg.scantype.data = P80211ENUM_scantype_active;
1289         msg.probedelay.data = 0;
1290
1291         for (i = 1; i <= 14; i++)
1292                 msg.channellist.data.data[i - 1] = i;
1293         msg.channellist.data.len = 14;
1294
1295         msg.maxchanneltime.data = 250;
1296         msg.minchanneltime.data = 200;
1297
1298         result = p80211req_dorequest(wlandev, (u8 *) & msg);
1299         if (result)
1300                 err = prism2_result2err(msg.resultcode.data);
1301
1302 exit:
1303         return err;
1304 }
1305
1306 /* Helper to translate scan into Wireless Extensions scan results.
1307  * Inspired by the prism54 code, which was in turn inspired by the
1308  * airo driver code.
1309  */
1310 static char *wext_translate_bss(struct iw_request_info *info, char *current_ev,
1311                                 char *end_buf,
1312                                 p80211msg_dot11req_scan_results_t *bss)
1313 {
1314         struct iw_event iwe;    /* Temporary buffer */
1315
1316         /* The first entry must be the MAC address */
1317         memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1318         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1319         iwe.cmd = SIOCGIWAP;
1320         current_ev =
1321             iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1322                                  IW_EV_ADDR_LEN);
1323
1324         /* The following entries will be displayed in the same order we give them */
1325
1326         /* The ESSID. */
1327         if (bss->ssid.data.len > 0) {
1328                 char essid[IW_ESSID_MAX_SIZE + 1];
1329                 int size;
1330
1331                 size =
1332                     min_t(unsigned short, IW_ESSID_MAX_SIZE,
1333                           bss->ssid.data.len);
1334                 memset(&essid, 0, sizeof(essid));
1335                 memcpy(&essid, bss->ssid.data.data, size);
1336                 pr_debug(" essid size = %d\n", size);
1337                 iwe.u.data.length = size;
1338                 iwe.u.data.flags = 1;
1339                 iwe.cmd = SIOCGIWESSID;
1340                 current_ev =
1341                     iwe_stream_add_point(info, current_ev, end_buf, &iwe,
1342                                          &essid[0]);
1343                 pr_debug(" essid size OK.\n");
1344         }
1345
1346         switch (bss->bsstype.data) {
1347         case P80211ENUM_bsstype_infrastructure:
1348                 iwe.u.mode = IW_MODE_MASTER;
1349                 break;
1350
1351         case P80211ENUM_bsstype_independent:
1352                 iwe.u.mode = IW_MODE_ADHOC;
1353                 break;
1354
1355         default:
1356                 iwe.u.mode = 0;
1357                 break;
1358         }
1359         iwe.cmd = SIOCGIWMODE;
1360         if (iwe.u.mode)
1361                 current_ev =
1362                     iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1363                                          IW_EV_UINT_LEN);
1364
1365         /* Encryption capability */
1366         if (bss->privacy.data == P80211ENUM_truth_true)
1367                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1368         else
1369                 iwe.u.data.flags = IW_ENCODE_DISABLED;
1370         iwe.u.data.length = 0;
1371         iwe.cmd = SIOCGIWENCODE;
1372         current_ev =
1373             iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1374
1375         /* Add frequency. (short) bss->channel is the frequency in MHz */
1376         iwe.u.freq.m = bss->dschannel.data;
1377         iwe.u.freq.e = 0;
1378         iwe.cmd = SIOCGIWFREQ;
1379         current_ev =
1380             iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1381                                  IW_EV_FREQ_LEN);
1382
1383         /* Add quality statistics */
1384         iwe.u.qual.level = bss->signal.data;
1385         iwe.u.qual.noise = bss->noise.data;
1386         /* do a simple SNR for quality */
1387         iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1388         iwe.cmd = IWEVQUAL;
1389         current_ev =
1390             iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1391                                  IW_EV_QUAL_LEN);
1392
1393         return current_ev;
1394 }
1395
1396 static int p80211wext_giwscan(netdevice_t *dev,
1397                               struct iw_request_info *info,
1398                               struct iw_point *srq, char *extra)
1399 {
1400         wlandevice_t *wlandev = dev->ml_priv;
1401         p80211msg_dot11req_scan_results_t msg;
1402         int result = 0;
1403         int err = 0;
1404         int i = 0;
1405         int scan_good = 0;
1406         char *current_ev = extra;
1407
1408         /* Since wireless tools doesn't really have a way of passing how
1409          * many scan results results there were back here, keep grabbing them
1410          * until we fail.
1411          */
1412         do {
1413                 memset(&msg, 0, sizeof(msg));
1414                 msg.msgcode = DIDmsg_dot11req_scan_results;
1415                 msg.bssindex.data = i;
1416
1417                 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1418                 if ((result != 0) ||
1419                     (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1420                         break;
1421                 }
1422
1423                 current_ev =
1424                     wext_translate_bss(info, current_ev,
1425                                        extra + IW_SCAN_MAX_DATA, &msg);
1426                 scan_good = 1;
1427                 i++;
1428         } while (i < IW_MAX_AP);
1429
1430         srq->length = (current_ev - extra);
1431         srq->flags = 0;         /* todo */
1432
1433         if (result && !scan_good)
1434                 err = prism2_result2err(msg.resultcode.data);
1435
1436         return err;
1437 }
1438
1439 /* extra wireless extensions stuff to support NetworkManager (I hope) */
1440
1441 /* SIOCSIWENCODEEXT */
1442 static int p80211wext_set_encodeext(struct net_device *dev,
1443                                     struct iw_request_info *info,
1444                                     union iwreq_data *wrqu, char *extra)
1445 {
1446         wlandevice_t *wlandev = dev->ml_priv;
1447         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1448         p80211msg_dot11req_mibset_t msg;
1449         p80211item_pstr32_t *pstr;
1450
1451         int result = 0;
1452         struct iw_point *encoding = &wrqu->encoding;
1453         int idx = encoding->flags & IW_ENCODE_INDEX;
1454
1455         pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1456                  ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1457
1458         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1459                 /* set default key ? I'm not sure if this the the correct thing to do here */
1460
1461                 if (idx) {
1462                         if (idx < 1 || idx > NUM_WEPKEYS)
1463                                 return -EINVAL;
1464                         else
1465                                 idx--;
1466                 }
1467                 pr_debug("setting default key (%d)\n", idx);
1468                 result =
1469                     p80211wext_dorequest(wlandev,
1470                                          DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
1471                                          idx);
1472                 if (result)
1473                         return -EFAULT;
1474         }
1475
1476         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1477                 if (ext->alg != IW_ENCODE_ALG_WEP) {
1478                         pr_debug("asked to set a non wep key :(\n");
1479                         return -EINVAL;
1480                 }
1481                 if (idx) {
1482                         if (idx < 1 || idx > NUM_WEPKEYS)
1483                                 return -EINVAL;
1484                         else
1485                                 idx--;
1486                 }
1487                 pr_debug("Set WEP key (%d)\n", idx);
1488                 wlandev->wep_keylens[idx] = ext->key_len;
1489                 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1490
1491                 memset(&msg, 0, sizeof(msg));
1492                 pstr = (p80211item_pstr32_t *) & msg.mibattribute.data;
1493                 memcpy(pstr->data.data, ext->key, ext->key_len);
1494                 pstr->data.len = ext->key_len;
1495                 switch (idx) {
1496                 case 0:
1497                         pstr->did =
1498                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1499                         break;
1500                 case 1:
1501                         pstr->did =
1502                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1503                         break;
1504                 case 2:
1505                         pstr->did =
1506                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1507                         break;
1508                 case 3:
1509                         pstr->did =
1510                             DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1511                         break;
1512                 default:
1513                         break;
1514                 }
1515                 msg.msgcode = DIDmsg_dot11req_mibset;
1516                 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1517                 pr_debug("result (%d)\n", result);
1518         }
1519         return result;
1520 }
1521
1522 /* SIOCGIWENCODEEXT */
1523 static int p80211wext_get_encodeext(struct net_device *dev,
1524                                     struct iw_request_info *info,
1525                                     union iwreq_data *wrqu, char *extra)
1526 {
1527         wlandevice_t *wlandev = dev->ml_priv;
1528         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1529
1530         struct iw_point *encoding = &wrqu->encoding;
1531         int result = 0;
1532         int max_len;
1533         int idx;
1534
1535         pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1536                  ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1537
1538         max_len = encoding->length - sizeof(*ext);
1539         if (max_len <= 0) {
1540                 pr_debug("get_encodeext max_len [%d] invalid\n", max_len);
1541                 result = -EINVAL;
1542                 goto exit;
1543         }
1544         idx = encoding->flags & IW_ENCODE_INDEX;
1545
1546         pr_debug("get_encode_ext index [%d]\n", idx);
1547
1548         if (idx) {
1549                 if (idx < 1 || idx > NUM_WEPKEYS) {
1550                         pr_debug("get_encode_ext invalid key index [%d]\n",
1551                                  idx);
1552                         result = -EINVAL;
1553                         goto exit;
1554                 }
1555                 idx--;
1556         } else {
1557                 /* default key ? not sure what to do */
1558                 /* will just use key[0] for now ! FIX ME */
1559         }
1560
1561         encoding->flags = idx + 1;
1562         memset(ext, 0, sizeof(*ext));
1563
1564         ext->alg = IW_ENCODE_ALG_WEP;
1565         ext->key_len = wlandev->wep_keylens[idx];
1566         memcpy(ext->key, wlandev->wep_keys[idx], ext->key_len);
1567
1568         encoding->flags |= IW_ENCODE_ENABLED;
1569 exit:
1570         return result;
1571 }
1572
1573 /* SIOCSIWAUTH */
1574 static int p80211_wext_set_iwauth(struct net_device *dev,
1575                                   struct iw_request_info *info,
1576                                   union iwreq_data *wrqu, char *extra)
1577 {
1578         wlandevice_t *wlandev = dev->ml_priv;
1579         struct iw_param *param = &wrqu->param;
1580         int result = 0;
1581
1582         pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1583
1584         switch (param->flags & IW_AUTH_INDEX) {
1585         case IW_AUTH_DROP_UNENCRYPTED:
1586                 pr_debug("drop_unencrypted %d\n", param->value);
1587                 if (param->value)
1588                         result =
1589                             p80211wext_dorequest(wlandev,
1590                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1591                                                  P80211ENUM_truth_true);
1592                 else
1593                         result =
1594                             p80211wext_dorequest(wlandev,
1595                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1596                                                  P80211ENUM_truth_false);
1597                 break;
1598
1599         case IW_AUTH_PRIVACY_INVOKED:
1600                 pr_debug("privacy invoked %d\n", param->value);
1601                 if (param->value)
1602                         result =
1603                             p80211wext_dorequest(wlandev,
1604                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1605                                                  P80211ENUM_truth_true);
1606                 else
1607                         result =
1608                             p80211wext_dorequest(wlandev,
1609                                                  DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1610                                                  P80211ENUM_truth_false);
1611
1612                 break;
1613
1614         case IW_AUTH_80211_AUTH_ALG:
1615                 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1616                         pr_debug("set open_system\n");
1617                         wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1618                 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1619                         pr_debug("set shared key\n");
1620                         wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1621                 } else {
1622                         /* don't know what to do know  */
1623                         pr_debug("unknown AUTH_ALG (%d)\n", param->value);
1624                         result = -EINVAL;
1625                 }
1626                 break;
1627
1628         default:
1629                 break;
1630         }
1631
1632         return result;
1633 }
1634
1635 /* SIOCSIWAUTH */
1636 static int p80211_wext_get_iwauth(struct net_device *dev,
1637                                   struct iw_request_info *info,
1638                                   union iwreq_data *wrqu, char *extra)
1639 {
1640         wlandevice_t *wlandev = dev->ml_priv;
1641         struct iw_param *param = &wrqu->param;
1642         int result = 0;
1643
1644         pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1645
1646         switch (param->flags & IW_AUTH_INDEX) {
1647         case IW_AUTH_DROP_UNENCRYPTED:
1648                 param->value =
1649                     wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
1650                 break;
1651
1652         case IW_AUTH_PRIVACY_INVOKED:
1653                 param->value =
1654                     wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
1655                 break;
1656
1657         case IW_AUTH_80211_AUTH_ALG:
1658                 param->value =
1659                     wlandev->hostwep & HOSTWEP_SHAREDKEY ?
1660                     IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
1661                 break;
1662
1663         default:
1664                 break;
1665         }
1666
1667         return result;
1668 }
1669
1670 static iw_handler p80211wext_handlers[] = {
1671         (iw_handler) p80211wext_siwcommit,      /* SIOCSIWCOMMIT */
1672         (iw_handler) p80211wext_giwname,        /* SIOCGIWNAME */
1673         (iw_handler) NULL,      /* SIOCSIWNWID */
1674         (iw_handler) NULL,      /* SIOCGIWNWID */
1675         (iw_handler) p80211wext_siwfreq,        /* SIOCSIWFREQ */
1676         (iw_handler) p80211wext_giwfreq,        /* SIOCGIWFREQ */
1677         (iw_handler) p80211wext_siwmode,        /* SIOCSIWMODE */
1678         (iw_handler) p80211wext_giwmode,        /* SIOCGIWMODE */
1679         (iw_handler) NULL,      /* SIOCSIWSENS */
1680         (iw_handler) NULL,      /* SIOCGIWSENS */
1681         (iw_handler) NULL,      /* not used *//* SIOCSIWRANGE */
1682         (iw_handler) p80211wext_giwrange,       /* SIOCGIWRANGE */
1683         (iw_handler) NULL,      /* not used *//* SIOCSIWPRIV */
1684         (iw_handler) NULL,      /* kernel code *//* SIOCGIWPRIV */
1685         (iw_handler) NULL,      /* not used *//* SIOCSIWSTATS */
1686         (iw_handler) NULL,      /* kernel code *//* SIOCGIWSTATS */
1687         (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1688         (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1689         (iw_handler) NULL,      /* -- hole -- */
1690         (iw_handler) NULL,      /* -- hole -- */
1691         (iw_handler) NULL,      /* SIOCSIWAP */
1692         (iw_handler) p80211wext_giwap,  /* SIOCGIWAP */
1693         (iw_handler) NULL,      /* -- hole -- */
1694         (iw_handler) NULL,      /* SIOCGIWAPLIST */
1695         (iw_handler) p80211wext_siwscan,        /* SIOCSIWSCAN */
1696         (iw_handler) p80211wext_giwscan,        /* SIOCGIWSCAN */
1697         (iw_handler) p80211wext_siwessid,       /* SIOCSIWESSID */
1698         (iw_handler) p80211wext_giwessid,       /* SIOCGIWESSID */
1699         (iw_handler) NULL,      /* SIOCSIWNICKN */
1700         (iw_handler) p80211wext_giwessid,       /* SIOCGIWNICKN */
1701         (iw_handler) NULL,      /* -- hole -- */
1702         (iw_handler) NULL,      /* -- hole -- */
1703         (iw_handler) NULL,      /* SIOCSIWRATE */
1704         (iw_handler) p80211wext_giwrate,        /* SIOCGIWRATE */
1705         (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1706         (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1707         (iw_handler) p80211wext_siwfrag,        /* SIOCSIWFRAG */
1708         (iw_handler) p80211wext_giwfrag,        /* SIOCGIWFRAG */
1709         (iw_handler) p80211wext_siwtxpow,       /* SIOCSIWTXPOW */
1710         (iw_handler) p80211wext_giwtxpow,       /* SIOCGIWTXPOW */
1711         (iw_handler) p80211wext_siwretry,       /* SIOCSIWRETRY */
1712         (iw_handler) p80211wext_giwretry,       /* SIOCGIWRETRY */
1713         (iw_handler) p80211wext_siwencode,      /* SIOCSIWENCODE */
1714         (iw_handler) p80211wext_giwencode,      /* SIOCGIWENCODE */
1715         (iw_handler) NULL,      /* SIOCSIWPOWER */
1716         (iw_handler) NULL,      /* SIOCGIWPOWER */
1717 /* WPA operations */
1718         (iw_handler) NULL,      /* -- hole -- */
1719         (iw_handler) NULL,      /* -- hole -- */
1720         (iw_handler) NULL,      /* SIOCSIWGENIE      set generic IE */
1721         (iw_handler) NULL,      /* SIOCGIWGENIE      get generic IE */
1722         (iw_handler) p80211_wext_set_iwauth,    /* SIOCSIWAUTH     set authentication mode params */
1723         (iw_handler) p80211_wext_get_iwauth,    /* SIOCGIWAUTH     get authentication mode params */
1724
1725         (iw_handler) p80211wext_set_encodeext,  /* SIOCSIWENCODEEXT  set encoding token & mode */
1726         (iw_handler) p80211wext_get_encodeext,  /* SIOCGIWENCODEEXT  get encoding token & mode */
1727         (iw_handler) NULL,      /* SIOCSIWPMKSA      PMKSA cache operation */
1728 };
1729
1730 struct iw_handler_def p80211wext_handler_def = {
1731         .num_standard = ARRAY_SIZE(p80211wext_handlers),
1732         .num_private = 0,
1733         .num_private_args = 0,
1734         .standard = p80211wext_handlers,
1735         .private = NULL,
1736         .private_args = NULL,
1737         .get_wireless_stats = p80211wext_get_wireless_stats
1738 };
1739
1740 int p80211wext_event_associated(wlandevice_t * wlandev, int assoc)
1741 {
1742         union iwreq_data data;
1743
1744         /* Send the association state first */
1745         data.ap_addr.sa_family = ARPHRD_ETHER;
1746         if (assoc)
1747                 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
1748         else
1749                 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
1750
1751         if (wlan_wext_write)
1752                 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1753
1754         if (!assoc)
1755                 goto done;
1756
1757         /* XXX send association data, like IEs, etc etc. */
1758
1759 done:
1760         return 0;
1761 }