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