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