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