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