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