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