Staging: wlan-ng: remove unused #include <version.h>
[safe/jmp/linux-2.6] / drivers / staging / wlan-ng / p80211wext.c
1 /* src/p80211/p80211wext.c
2 *
3 * Glue code to make linux-wlan-ng a happy wireless extension camper.
4 *
5 * original author:  Reyk Floeter <reyk@synack.de>
6 * Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
7 *
8 * Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
9 * --------------------------------------------------------------------
10 *
11 * linux-wlan
12 *
13 *   The contents of this file are subject to the Mozilla Public
14 *   License Version 1.1 (the "License"); you may not use this file
15 *   except in compliance with the License. You may obtain a copy of
16 *   the License at http://www.mozilla.org/MPL/
17 *
18 *   Software distributed under the License is distributed on an "AS
19 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
20 *   implied. See the License for the specific language governing
21 *   rights and limitations under the License.
22 *
23 *   Alternatively, the contents of this file may be used under the
24 *   terms of the GNU Public License version 2 (the "GPL"), in which
25 *   case the provisions of the GPL are applicable instead of the
26 *   above.  If you wish to allow the use of your version of this file
27 *   only under the terms of the GPL and not to allow others to use
28 *   your version of this file under the MPL, indicate your decision
29 *   by deleting the provisions above and replace them with the notice
30 *   and other provisions required by the GPL.  If you do not delete
31 *   the provisions above, a recipient may use your version of this
32 *   file under either the MPL or the GPL.
33 *
34 * --------------------------------------------------------------------
35 */
36
37 /*================================================================*/
38 /* System Includes */
39
40
41
42 #include <linux/kernel.h>
43 #include <linux/sched.h>
44 #include <linux/types.h>
45 #include <linux/slab.h>
46 #include <linux/netdevice.h>
47 #include <linux/etherdevice.h>
48 #include <linux/wireless.h>
49 #include <net/iw_handler.h>
50 #include <linux/if_arp.h>
51 #include <asm/bitops.h>
52 #include <asm/uaccess.h>
53 #include <asm/byteorder.h>
54
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 (sizeof(p80211wext_channel_freq) / sizeof(p80211wext_channel_freq[0]))
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 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                 /* Set current key number only if no keys are given */
614                 if (erq->flags & IW_ENCODE_NOKEY) {
615                         result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, i);
616
617                         if (result) {
618                                 err = -EFAULT;
619                                 goto exit;
620                         }
621                 }
622
623         } else {
624                 // Use defaultkey if no Key Index
625                 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
626         }
627
628         /* Check if there is no key information in the iwconfig request */
629         if((erq->flags & IW_ENCODE_NOKEY) == 0 ) {
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         } else {
685                 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true);
686         }
687
688         if (result) {
689                 err = -EFAULT;
690                 goto exit;
691         }
692
693         /*  The  security  mode  may  be open or restricted, and its meaning
694             depends on the card used. With  most  cards,  in  open  mode  no
695             authentication  is  used  and  the  card  may  also  accept non-
696             encrypted sessions, whereas in restricted  mode  only  encrypted
697             sessions  are  accepted  and the card will use authentication if
698             available.
699         */
700         if (erq->flags & IW_ENCODE_RESTRICTED) {
701                 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true);
702         }
703         else if (erq->flags & IW_ENCODE_OPEN) {
704                 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false);
705         }
706
707         if (result) {
708                 err = -EFAULT;
709                 goto exit;
710         }
711
712  exit:
713
714         DBFEXIT;
715         return err;
716 }
717
718 static int p80211wext_giwessid(netdevice_t *dev,
719                                struct iw_request_info *info,
720                                struct iw_point *data, char *essid)
721 {
722         wlandevice_t *wlandev = dev->ml_priv;
723
724         DBFENTER;
725
726         if (wlandev->ssid.len) {
727                 data->length = wlandev->ssid.len;
728                 data->flags = 1;
729                 memcpy(essid, wlandev->ssid.data, data->length);
730                 essid[data->length] = 0;
731 #if (WIRELESS_EXT < 21)
732                 data->length++;
733 #endif
734         } else {
735                 memset(essid, 0, sizeof(wlandev->ssid.data));
736                 data->length = 0;
737                 data->flags = 0;
738         }
739
740         DBFEXIT;
741         return 0;
742 }
743
744 static int p80211wext_siwessid(netdevice_t *dev,
745                                struct iw_request_info *info,
746                                struct iw_point *data, char *essid)
747 {
748         wlandevice_t *wlandev = dev->ml_priv;
749         p80211msg_lnxreq_autojoin_t     msg;
750
751         int result;
752         int err = 0;
753         int length = data->length;
754
755         DBFENTER;
756
757         if (!wlan_wext_write) {
758                 err = (-EOPNOTSUPP);
759                 goto exit;
760         }
761
762
763         if ( wlandev->hostwep & HOSTWEP_SHAREDKEY )
764           msg.authtype.data = P80211ENUM_authalg_sharedkey;
765         else
766           msg.authtype.data = P80211ENUM_authalg_opensystem;
767
768         msg.msgcode = DIDmsg_lnxreq_autojoin;
769
770 #if (WIRELESS_EXT < 21)
771         if (length) length--;
772 #endif
773
774         /* Trim the last '\0' to fit the SSID format */
775
776         if (length && essid[length-1] == '\0') {
777           length--;
778         }
779
780         memcpy(msg.ssid.data.data, essid, length);
781         msg.ssid.data.len = length;
782
783         WLAN_LOG_DEBUG(1,"autojoin_ssid for %s \n",essid);
784         result = p80211req_dorequest(wlandev, (u8*)&msg);
785         WLAN_LOG_DEBUG(1,"autojoin_ssid %d\n",result);
786
787         if (result) {
788                 err = -EFAULT;
789                 goto exit;
790         }
791
792  exit:
793         DBFEXIT;
794         return err;
795 }
796
797
798 static int p80211wext_siwcommit(netdevice_t *dev,
799                                 struct iw_request_info *info,
800                                 struct iw_point *data, char *essid)
801 {
802         wlandevice_t *wlandev = dev->ml_priv;
803         int err = 0;
804
805         DBFENTER;
806
807         if (!wlan_wext_write) {
808                 err = (-EOPNOTSUPP);
809                 goto exit;
810         }
811
812         /* Auto Join */
813         err = p80211wext_autojoin(wlandev);
814
815  exit:
816         DBFEXIT;
817         return err;
818 }
819
820
821 static int p80211wext_giwrate(netdevice_t *dev,
822                               struct iw_request_info *info,
823                               struct iw_param *rrq, char *extra)
824 {
825         wlandevice_t *wlandev = dev->ml_priv;
826         p80211item_uint32_t             mibitem;
827         p80211msg_dot11req_mibset_t     msg;
828         int result;
829         int err = 0;
830
831         DBFENTER;
832
833         msg.msgcode = DIDmsg_dot11req_mibget;
834         mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
835         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
836         result = p80211req_dorequest(wlandev, (u8*)&msg);
837
838         if (result) {
839                 err = -EFAULT;
840                 goto exit;
841         }
842
843         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
844
845         rrq->fixed = 0;   /* can it change? */
846         rrq->disabled = 0;
847         rrq->value = 0;
848
849 #define         HFA384x_RATEBIT_1                       ((u16)1)
850 #define         HFA384x_RATEBIT_2                       ((u16)2)
851 #define         HFA384x_RATEBIT_5dot5                   ((u16)4)
852 #define         HFA384x_RATEBIT_11                      ((u16)8)
853
854         switch (mibitem.data) {
855         case HFA384x_RATEBIT_1:
856                 rrq->value = 1000000;
857                 break;
858         case HFA384x_RATEBIT_2:
859                 rrq->value = 2000000;
860                 break;
861         case HFA384x_RATEBIT_5dot5:
862                 rrq->value = 5500000;
863                 break;
864         case HFA384x_RATEBIT_11:
865                 rrq->value = 11000000;
866                 break;
867         default:
868                 err = -EINVAL;
869         }
870  exit:
871         DBFEXIT;
872         return err;
873 }
874
875 static int p80211wext_giwrts(netdevice_t *dev,
876                              struct iw_request_info *info,
877                              struct iw_param *rts, char *extra)
878 {
879         wlandevice_t *wlandev = dev->ml_priv;
880         p80211item_uint32_t             mibitem;
881         p80211msg_dot11req_mibset_t     msg;
882         int result;
883         int err = 0;
884
885         DBFENTER;
886
887         msg.msgcode = DIDmsg_dot11req_mibget;
888         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
889         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
890         result = p80211req_dorequest(wlandev, (u8*)&msg);
891
892         if (result) {
893                 err = -EFAULT;
894                 goto exit;
895         }
896
897         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
898
899         rts->value = mibitem.data;
900         rts->disabled = (rts->value == 2347);
901         rts->fixed = 1;
902
903  exit:
904         DBFEXIT;
905         return err;
906 }
907
908
909 static int p80211wext_siwrts(netdevice_t *dev,
910                              struct iw_request_info *info,
911                              struct iw_param *rts, char *extra)
912 {
913         wlandevice_t *wlandev = dev->ml_priv;
914         p80211item_uint32_t             mibitem;
915         p80211msg_dot11req_mibset_t     msg;
916         int result;
917         int err = 0;
918
919         DBFENTER;
920
921         if (!wlan_wext_write) {
922                 err = (-EOPNOTSUPP);
923                 goto exit;
924         }
925
926         msg.msgcode = DIDmsg_dot11req_mibget;
927         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
928         if (rts->disabled)
929                 mibitem.data = 2347;
930         else
931                 mibitem.data = rts->value;
932
933         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
934         result = p80211req_dorequest(wlandev, (u8*)&msg);
935
936         if (result) {
937                 err = -EFAULT;
938                 goto exit;
939         }
940
941  exit:
942         DBFEXIT;
943         return err;
944 }
945
946 static int p80211wext_giwfrag(netdevice_t *dev,
947                               struct iw_request_info *info,
948                               struct iw_param *frag, char *extra)
949 {
950         wlandevice_t *wlandev = dev->ml_priv;
951         p80211item_uint32_t             mibitem;
952         p80211msg_dot11req_mibset_t     msg;
953         int result;
954         int err = 0;
955
956         DBFENTER;
957
958         msg.msgcode = DIDmsg_dot11req_mibget;
959         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
960         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
961         result = p80211req_dorequest(wlandev, (u8*)&msg);
962
963         if (result) {
964                 err = -EFAULT;
965                 goto exit;
966         }
967
968         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
969
970         frag->value = mibitem.data;
971         frag->disabled = (frag->value == 2346);
972         frag->fixed = 1;
973
974  exit:
975         DBFEXIT;
976         return err;
977 }
978
979 static int p80211wext_siwfrag(netdevice_t *dev,
980                               struct iw_request_info *info,
981                               struct iw_param *frag, char *extra)
982 {
983         wlandevice_t *wlandev = dev->ml_priv;
984         p80211item_uint32_t             mibitem;
985         p80211msg_dot11req_mibset_t     msg;
986         int result;
987         int err = 0;
988
989         DBFENTER;
990
991         if (!wlan_wext_write) {
992                 err = (-EOPNOTSUPP);
993                 goto exit;
994         }
995
996         msg.msgcode = DIDmsg_dot11req_mibset;
997         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
998
999         if (frag->disabled)
1000                 mibitem.data = 2346;
1001         else
1002                 mibitem.data = frag->value;
1003
1004         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1005         result = p80211req_dorequest(wlandev, (u8*)&msg);
1006
1007         if (result) {
1008                 err = -EFAULT;
1009                 goto exit;
1010         }
1011
1012  exit:
1013         DBFEXIT;
1014         return err;
1015 }
1016
1017 #ifndef IW_RETRY_LONG
1018 #define IW_RETRY_LONG IW_RETRY_MAX
1019 #endif
1020
1021 #ifndef IW_RETRY_SHORT
1022 #define IW_RETRY_SHORT IW_RETRY_MIN
1023 #endif
1024
1025 static int p80211wext_giwretry(netdevice_t *dev,
1026                                struct iw_request_info *info,
1027                                struct iw_param *rrq, char *extra)
1028 {
1029         wlandevice_t *wlandev = dev->ml_priv;
1030         p80211item_uint32_t             mibitem;
1031         p80211msg_dot11req_mibset_t     msg;
1032         int result;
1033         int err = 0;
1034         u16 shortretry, longretry, lifetime;
1035
1036         DBFENTER;
1037
1038         msg.msgcode = DIDmsg_dot11req_mibget;
1039         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1040
1041         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1042         result = p80211req_dorequest(wlandev, (u8*)&msg);
1043
1044         if (result) {
1045                 err = -EFAULT;
1046                 goto exit;
1047         }
1048
1049         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1050
1051         shortretry = mibitem.data;
1052
1053         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1054
1055         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1056         result = p80211req_dorequest(wlandev, (u8*)&msg);
1057
1058         if (result) {
1059                 err = -EFAULT;
1060                 goto exit;
1061         }
1062
1063         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1064
1065         longretry = mibitem.data;
1066
1067         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1068
1069         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1070         result = p80211req_dorequest(wlandev, (u8*)&msg);
1071
1072         if (result) {
1073                 err = -EFAULT;
1074                 goto exit;
1075         }
1076
1077         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1078
1079         lifetime = mibitem.data;
1080
1081         rrq->disabled = 0;
1082
1083         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1084                 rrq->flags = IW_RETRY_LIFETIME;
1085                 rrq->value = lifetime * 1024;
1086         } else {
1087                 if (rrq->flags & IW_RETRY_LONG) {
1088                         rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1089                         rrq->value = longretry;
1090                 } else {
1091                         rrq->flags = IW_RETRY_LIMIT;
1092                         rrq->value = shortretry;
1093                         if (shortretry != longretry)
1094                                 rrq->flags |= IW_RETRY_SHORT;
1095                 }
1096         }
1097
1098  exit:
1099         DBFEXIT;
1100         return err;
1101
1102 }
1103
1104 static int p80211wext_siwretry(netdevice_t *dev,
1105                                struct iw_request_info *info,
1106                                struct iw_param *rrq, char *extra)
1107 {
1108         wlandevice_t *wlandev = dev->ml_priv;
1109         p80211item_uint32_t             mibitem;
1110         p80211msg_dot11req_mibset_t     msg;
1111         int result;
1112         int err = 0;
1113
1114         DBFENTER;
1115
1116         if (!wlan_wext_write) {
1117                 err = (-EOPNOTSUPP);
1118                 goto exit;
1119         }
1120
1121         if (rrq->disabled) {
1122                 err = -EINVAL;
1123                 goto exit;
1124         }
1125
1126         msg.msgcode = DIDmsg_dot11req_mibset;
1127
1128         if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1129                 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1130                 mibitem.data =  rrq->value /= 1024;
1131
1132                 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1133                 result = p80211req_dorequest(wlandev, (u8*)&msg);
1134
1135                 if (result) {
1136                         err = -EFAULT;
1137                         goto exit;
1138                 }
1139         } else {
1140                 if (rrq->flags & IW_RETRY_LONG) {
1141                         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1142                         mibitem.data = rrq->value;
1143
1144                         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1145                         result = p80211req_dorequest(wlandev, (u8*)&msg);
1146
1147                         if (result) {
1148                                 err = -EFAULT;
1149                                 goto exit;
1150                         }
1151                 }
1152
1153                 if (rrq->flags & IW_RETRY_SHORT) {
1154                         mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1155                         mibitem.data = rrq->value;
1156
1157                         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1158                         result = p80211req_dorequest(wlandev, (u8*)&msg);
1159
1160                         if (result) {
1161                                 err = -EFAULT;
1162                                 goto exit;
1163                         }
1164                 }
1165         }
1166
1167  exit:
1168         DBFEXIT;
1169         return err;
1170
1171 }
1172
1173 static int p80211wext_siwtxpow(netdevice_t *dev,
1174                                struct iw_request_info *info,
1175                                struct iw_param *rrq, char *extra)
1176 {
1177         wlandevice_t *wlandev = dev->ml_priv;
1178         p80211item_uint32_t             mibitem;
1179         p80211msg_dot11req_mibset_t     msg;
1180         int result;
1181         int err = 0;
1182
1183         DBFENTER;
1184
1185        if (!wlan_wext_write) {
1186                 err = (-EOPNOTSUPP);
1187                 goto exit;
1188         }
1189
1190         msg.msgcode = DIDmsg_dot11req_mibset;
1191         mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1192         if (rrq->fixed == 0)
1193           mibitem.data = 30;
1194         else
1195           mibitem.data = rrq->value;
1196         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1197         result = p80211req_dorequest(wlandev, (u8*)&msg);
1198
1199         if (result) {
1200                 err = -EFAULT;
1201                 goto exit;
1202         }
1203
1204  exit:
1205         DBFEXIT;
1206         return err;
1207 }
1208
1209 static int p80211wext_giwtxpow(netdevice_t *dev,
1210                                struct iw_request_info *info,
1211                                struct iw_param *rrq, char *extra)
1212 {
1213         wlandevice_t *wlandev = dev->ml_priv;
1214         p80211item_uint32_t             mibitem;
1215         p80211msg_dot11req_mibset_t     msg;
1216         int result;
1217         int err = 0;
1218
1219         DBFENTER;
1220
1221         msg.msgcode = DIDmsg_dot11req_mibget;
1222         mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1223
1224         memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1225         result = p80211req_dorequest(wlandev, (u8*)&msg);
1226
1227         if (result) {
1228                 err = -EFAULT;
1229                 goto exit;
1230         }
1231
1232         memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1233
1234         // XXX handle OFF by setting disabled = 1;
1235
1236         rrq->flags = 0; // IW_TXPOW_DBM;
1237         rrq->disabled = 0;
1238         rrq->fixed = 0;
1239         rrq->value = mibitem.data;
1240
1241  exit:
1242         DBFEXIT;
1243         return err;
1244 }
1245
1246 static int p80211wext_siwspy(netdevice_t *dev,
1247                              struct iw_request_info *info,
1248                              struct iw_point *srq, char *extra)
1249 {
1250         wlandevice_t *wlandev = dev->ml_priv;
1251         struct sockaddr address[IW_MAX_SPY];
1252         int number = srq->length;
1253         int i;
1254
1255         DBFENTER;
1256
1257         /* Copy the data from the input buffer */
1258         memcpy(address, extra, sizeof(struct sockaddr)*number);
1259
1260         wlandev->spy_number = 0;
1261
1262         if (number > 0) {
1263
1264                 /* extract the addresses */
1265                 for (i = 0; i < number; i++) {
1266
1267                         memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN);
1268                 }
1269
1270                 /* reset stats */
1271                 memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
1272
1273                 /* set number of addresses */
1274                 wlandev->spy_number = number;
1275         }
1276
1277         DBFEXIT;
1278         return 0;
1279 }
1280
1281 /* jkriegl: from orinoco, modified */
1282 static int p80211wext_giwspy(netdevice_t *dev,
1283                              struct iw_request_info *info,
1284                              struct iw_point *srq, char *extra)
1285 {
1286         wlandevice_t *wlandev = dev->ml_priv;
1287
1288         struct sockaddr address[IW_MAX_SPY];
1289         struct iw_quality spy_stat[IW_MAX_SPY];
1290         int number;
1291         int i;
1292
1293         DBFENTER;
1294
1295         number = wlandev->spy_number;
1296
1297         if (number > 0) {
1298
1299                 /* populate address and spy struct's */
1300                 for (i = 0; i < number; i++) {
1301                         memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN);
1302                         address[i].sa_family = AF_UNIX;
1303                         memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality));
1304                 }
1305
1306                 /* reset update flag */
1307                 for (i=0; i < number; i++)
1308                         wlandev->spy_stat[i].updated = 0;
1309         }
1310
1311         /* push stuff to user space */
1312         srq->length = number;
1313         memcpy(extra, address, sizeof(struct sockaddr)*number);
1314         memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number);
1315
1316         DBFEXIT;
1317         return 0;
1318 }
1319
1320 static int prism2_result2err (int prism2_result)
1321 {
1322         int err = 0;
1323
1324         switch (prism2_result) {
1325                 case P80211ENUM_resultcode_invalid_parameters:
1326                         err = -EINVAL;
1327                         break;
1328                 case P80211ENUM_resultcode_implementation_failure:
1329                         err = -EIO;
1330                         break;
1331                 case P80211ENUM_resultcode_not_supported:
1332                         err = -EOPNOTSUPP;
1333                         break;
1334                 default:
1335                         err = 0;
1336                         break;
1337         }
1338
1339         return err;
1340 }
1341
1342 static int p80211wext_siwscan(netdevice_t *dev,
1343                              struct iw_request_info *info,
1344                              struct iw_point *srq, char *extra)
1345 {
1346         wlandevice_t *wlandev = dev->ml_priv;
1347         p80211msg_dot11req_scan_t       msg;
1348         int result;
1349         int err = 0;
1350         int i = 0;
1351
1352         DBFENTER;
1353
1354         if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1355                 WLAN_LOG_ERROR("Can't scan in AP mode\n");
1356                 err = (-EOPNOTSUPP);
1357                 goto exit;
1358         }
1359
1360         memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1361         msg.msgcode = DIDmsg_dot11req_scan;
1362         msg.bsstype.data = P80211ENUM_bsstype_any;
1363
1364         memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t));
1365         msg.bssid.data.len = 6;
1366
1367         msg.scantype.data = P80211ENUM_scantype_active;
1368         msg.probedelay.data = 0;
1369
1370         for (i = 1; i <= 14; i++)
1371                 msg.channellist.data.data[i-1] = i;
1372         msg.channellist.data.len = 14;
1373
1374         msg.maxchanneltime.data = 250;
1375         msg.minchanneltime.data = 200;
1376
1377         result = p80211req_dorequest(wlandev, (u8*)&msg);
1378         if (result)
1379                 err = prism2_result2err (msg.resultcode.data);
1380
1381  exit:
1382         DBFEXIT;
1383         return err;
1384 }
1385
1386
1387 /* Helper to translate scan into Wireless Extensions scan results.
1388  * Inspired by the prism54 code, which was in turn inspired by the
1389  * airo driver code.
1390  */
1391 static char *
1392 wext_translate_bss(struct iw_request_info *info, char *current_ev,
1393                    char *end_buf, p80211msg_dot11req_scan_results_t *bss)
1394 {
1395         struct iw_event iwe;    /* Temporary buffer */
1396
1397         /* The first entry must be the MAC address */
1398         memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1399         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1400         iwe.cmd = SIOCGIWAP;
1401         current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
1402
1403         /* The following entries will be displayed in the same order we give them */
1404
1405         /* The ESSID. */
1406         if (bss->ssid.data.len > 0) {
1407                 char essid[IW_ESSID_MAX_SIZE + 1];
1408                 int size;
1409
1410                 size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len);
1411                 memset(&essid, 0, sizeof (essid));
1412                 memcpy(&essid, bss->ssid.data.data, size);
1413                 WLAN_LOG_DEBUG(1, " essid size = %d\n", size);
1414                 iwe.u.data.length = size;
1415                 iwe.u.data.flags = 1;
1416                 iwe.cmd = SIOCGIWESSID;
1417                 current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &essid[0]);
1418                 WLAN_LOG_DEBUG(1, " essid size OK.\n");
1419         }
1420
1421         switch (bss->bsstype.data) {
1422                 case P80211ENUM_bsstype_infrastructure:
1423                         iwe.u.mode = IW_MODE_MASTER;
1424                         break;
1425
1426                 case P80211ENUM_bsstype_independent:
1427                         iwe.u.mode = IW_MODE_ADHOC;
1428                         break;
1429
1430                 default:
1431                         iwe.u.mode = 0;
1432                         break;
1433         }
1434         iwe.cmd = SIOCGIWMODE;
1435         if (iwe.u.mode)
1436                 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
1437
1438         /* Encryption capability */
1439         if (bss->privacy.data == P80211ENUM_truth_true)
1440                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1441         else
1442                 iwe.u.data.flags = IW_ENCODE_DISABLED;
1443         iwe.u.data.length = 0;
1444         iwe.cmd = SIOCGIWENCODE;
1445         current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1446
1447         /* Add frequency. (short) bss->channel is the frequency in MHz */
1448         iwe.u.freq.m = bss->dschannel.data;
1449         iwe.u.freq.e = 0;
1450         iwe.cmd = SIOCGIWFREQ;
1451         current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
1452
1453         /* Add quality statistics */
1454         iwe.u.qual.level = bss->signal.data;
1455         iwe.u.qual.noise = bss->noise.data;
1456         /* do a simple SNR for quality */
1457         iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1458         iwe.cmd = IWEVQUAL;
1459         current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
1460
1461         return current_ev;
1462 }
1463
1464
1465 static int p80211wext_giwscan(netdevice_t *dev,
1466                              struct iw_request_info *info,
1467                              struct iw_point *srq, char *extra)
1468 {
1469         wlandevice_t *wlandev = dev->ml_priv;
1470         p80211msg_dot11req_scan_results_t       msg;
1471         int result = 0;
1472         int err = 0;
1473         int i = 0;
1474         int scan_good = 0;
1475         char *current_ev = extra;
1476
1477         DBFENTER;
1478
1479         /* Since wireless tools doesn't really have a way of passing how
1480          * many scan results results there were back here, keep grabbing them
1481          * until we fail.
1482          */
1483         do {
1484                 memset(&msg, 0, sizeof(msg));
1485                 msg.msgcode = DIDmsg_dot11req_scan_results;
1486                 msg.bssindex.data = i;
1487
1488                 result = p80211req_dorequest(wlandev, (u8*)&msg);
1489                 if ((result != 0) ||
1490                     (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1491                         break;
1492                 }
1493
1494                 current_ev = wext_translate_bss(info, current_ev, extra + IW_SCAN_MAX_DATA, &msg);
1495                 scan_good = 1;
1496                 i++;
1497         } while (i < IW_MAX_AP);
1498
1499         srq->length = (current_ev - extra);
1500         srq->flags = 0; /* todo */
1501
1502         if (result && !scan_good)
1503                 err = prism2_result2err (msg.resultcode.data);
1504
1505         DBFEXIT;
1506         return err;
1507 }
1508
1509 /*****************************************************/
1510 //extra wireless extensions stuff to support NetworkManager (I hope)
1511
1512 /* SIOCSIWENCODEEXT */
1513 static int p80211wext_set_encodeext(struct net_device *dev,
1514                                 struct iw_request_info *info,
1515                                 union iwreq_data *wrqu, char *extra)
1516 {
1517   wlandevice_t *wlandev = dev->ml_priv;
1518   struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1519         p80211msg_dot11req_mibset_t     msg;
1520         p80211item_pstr32_t             *pstr;
1521
1522   int result = 0;
1523   struct iw_point *encoding = &wrqu->encoding;
1524   int idx = encoding->flags & IW_ENCODE_INDEX;
1525
1526   WLAN_LOG_DEBUG(1,"set_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len);
1527
1528
1529   if ( ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY ) {
1530     // set default key ? I'm not sure if this the the correct thing to do here
1531
1532     if ( idx ) {
1533       if (idx < 1 || idx > NUM_WEPKEYS) {
1534         return -EINVAL;
1535       } else
1536         idx--;
1537     }
1538     WLAN_LOG_DEBUG(1,"setting default key (%d)\n",idx);
1539     result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, idx);
1540     if ( result )
1541       return -EFAULT;
1542   }
1543
1544
1545   if ( ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) {
1546     if (!(ext->alg & IW_ENCODE_ALG_WEP)) {
1547       WLAN_LOG_DEBUG(1,"asked to set a non wep key :(");
1548       return -EINVAL;
1549     }
1550     if (idx) {
1551       if (idx <1 || idx > NUM_WEPKEYS)
1552         return -EINVAL;
1553       else
1554         idx--;
1555     }
1556     WLAN_LOG_DEBUG(1,"Set WEP key (%d)\n",idx);
1557     wlandev->wep_keylens[idx] = ext->key_len;
1558     memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1559
1560     memset( &msg,0,sizeof(msg));
1561     pstr = (p80211item_pstr32_t*)&msg.mibattribute.data;
1562     memcpy(pstr->data.data, ext->key,ext->key_len);
1563     pstr->data.len = ext->key_len;
1564     switch (idx) {
1565     case 0:
1566       pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1567       break;
1568     case 1:
1569       pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1570       break;
1571     case 2:
1572       pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1573       break;
1574     case 3:
1575       pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1576       break;
1577     default:
1578       break;
1579     }
1580     msg.msgcode = DIDmsg_dot11req_mibset;
1581     result = p80211req_dorequest(wlandev,(u8*)&msg);
1582     WLAN_LOG_DEBUG(1,"result (%d)\n",result);
1583   }
1584   return result;
1585 }
1586
1587 /* SIOCGIWENCODEEXT */
1588 static int p80211wext_get_encodeext(struct net_device *dev,
1589                                 struct iw_request_info *info,
1590                                 union iwreq_data *wrqu, char *extra)
1591
1592 {
1593         wlandevice_t *wlandev = dev->ml_priv;
1594         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1595
1596         struct iw_point *encoding = &wrqu->encoding;
1597         int result = 0;
1598         int max_len;
1599         int idx;
1600
1601         DBFENTER;
1602
1603         WLAN_LOG_DEBUG(1,"get_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len);
1604
1605
1606         max_len = encoding->length - sizeof(*ext);
1607         if ( max_len <= 0) {
1608                 WLAN_LOG_DEBUG(1,"get_encodeext max_len [%d] invalid\n",max_len);
1609                 result = -EINVAL;
1610                 goto exit;
1611         }
1612         idx = encoding->flags & IW_ENCODE_INDEX;
1613
1614         WLAN_LOG_DEBUG(1,"get_encode_ext index [%d]\n",idx);
1615
1616         if (idx) {
1617                 if (idx < 1 || idx > NUM_WEPKEYS ) {
1618                         WLAN_LOG_DEBUG(1,"get_encode_ext invalid key index [%d]\n",idx);
1619                         result = -EINVAL;
1620                         goto exit;
1621                 }
1622                 idx--;
1623         } else {
1624                 /* default key ? not sure what to do */
1625                 /* will just use key[0] for now ! FIX ME */
1626         }
1627
1628         encoding->flags = idx + 1;
1629         memset(ext,0,sizeof(*ext));
1630
1631         ext->alg = IW_ENCODE_ALG_WEP;
1632         ext->key_len = wlandev->wep_keylens[idx];
1633         memcpy( ext->key, wlandev->wep_keys[idx] , ext->key_len );
1634
1635         encoding->flags |= IW_ENCODE_ENABLED;
1636 exit:
1637         DBFEXIT;
1638
1639         return result;
1640 }
1641
1642
1643 /* SIOCSIWAUTH */
1644 static int p80211_wext_set_iwauth (struct net_device *dev,
1645                                    struct iw_request_info *info,
1646                                    union iwreq_data *wrqu, char *extra)
1647 {
1648   wlandevice_t *wlandev = dev->ml_priv;
1649   struct iw_param *param = &wrqu->param;
1650   int result =0;
1651
1652   WLAN_LOG_DEBUG(1,"set_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX );
1653
1654   switch (param->flags & IW_AUTH_INDEX) {
1655   case IW_AUTH_DROP_UNENCRYPTED:
1656     WLAN_LOG_DEBUG(1,"drop_unencrypted %d\n",param->value);
1657     if (param->value)
1658       result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true);
1659     else
1660       result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false);
1661     break;
1662
1663   case IW_AUTH_PRIVACY_INVOKED:
1664     WLAN_LOG_DEBUG(1,"privacy invoked %d\n",param->value);
1665     if ( param->value)
1666       result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true);
1667     else
1668       result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false);
1669
1670     break;
1671
1672   case IW_AUTH_80211_AUTH_ALG:
1673     if ( param->value & IW_AUTH_ALG_OPEN_SYSTEM ) {
1674       WLAN_LOG_DEBUG(1,"set open_system\n");
1675       wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1676     } else if ( param->value & IW_AUTH_ALG_SHARED_KEY) {
1677       WLAN_LOG_DEBUG(1,"set shared key\n");
1678       wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1679     } else {
1680       /* don't know what to do know :( */
1681       WLAN_LOG_DEBUG(1,"unknown AUTH_ALG (%d)\n",param->value);
1682       result = -EINVAL;
1683     }
1684     break;
1685
1686   default:
1687     break;
1688   }
1689
1690
1691
1692   return result;
1693 }
1694
1695 /* SIOCSIWAUTH */
1696 static int p80211_wext_get_iwauth (struct net_device *dev,
1697                                    struct iw_request_info *info,
1698                                    union iwreq_data *wrqu, char *extra)
1699 {
1700   wlandevice_t *wlandev = dev->ml_priv;
1701   struct iw_param *param = &wrqu->param;
1702   int result =0;
1703
1704   WLAN_LOG_DEBUG(1,"get_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX );
1705
1706   switch (param->flags & IW_AUTH_INDEX) {
1707   case IW_AUTH_DROP_UNENCRYPTED:
1708     param->value = wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED?1:0;
1709     break;
1710
1711   case IW_AUTH_PRIVACY_INVOKED:
1712     param->value = wlandev->hostwep & HOSTWEP_PRIVACYINVOKED?1:0;
1713     break;
1714
1715   case IW_AUTH_80211_AUTH_ALG:
1716     param->value = wlandev->hostwep & HOSTWEP_SHAREDKEY?IW_AUTH_ALG_SHARED_KEY:IW_AUTH_ALG_OPEN_SYSTEM;
1717     break;
1718
1719
1720   default:
1721     break;
1722   }
1723
1724
1725
1726   return result;
1727 }
1728
1729 static iw_handler p80211wext_handlers[] =  {
1730         (iw_handler) p80211wext_siwcommit,              /* SIOCSIWCOMMIT */
1731         (iw_handler) p80211wext_giwname,                /* SIOCGIWNAME */
1732         (iw_handler) NULL,                              /* SIOCSIWNWID */
1733         (iw_handler) NULL,                              /* SIOCGIWNWID */
1734         (iw_handler) p80211wext_siwfreq,                /* SIOCSIWFREQ */
1735         (iw_handler) p80211wext_giwfreq,                /* SIOCGIWFREQ */
1736         (iw_handler) p80211wext_siwmode,                /* SIOCSIWMODE */
1737         (iw_handler) p80211wext_giwmode,                /* SIOCGIWMODE */
1738         (iw_handler) NULL,                              /* SIOCSIWSENS */
1739         (iw_handler) NULL,                              /* SIOCGIWSENS */
1740         (iw_handler) NULL, /* not used */               /* SIOCSIWRANGE */
1741         (iw_handler) p80211wext_giwrange,               /* SIOCGIWRANGE */
1742         (iw_handler) NULL, /* not used */               /* SIOCSIWPRIV */
1743         (iw_handler) NULL, /* kernel code */            /* SIOCGIWPRIV */
1744         (iw_handler) NULL, /* not used */               /* SIOCSIWSTATS */
1745         (iw_handler) NULL, /* kernel code */            /* SIOCGIWSTATS */
1746         (iw_handler) p80211wext_siwspy,                 /* SIOCSIWSPY */
1747         (iw_handler) p80211wext_giwspy,                 /* SIOCGIWSPY */
1748         (iw_handler) NULL,                              /* -- hole -- */
1749         (iw_handler) NULL,                              /* -- hole -- */
1750         (iw_handler) NULL,                              /* SIOCSIWAP */
1751         (iw_handler) p80211wext_giwap,                  /* SIOCGIWAP */
1752         (iw_handler) NULL,                              /* -- hole -- */
1753         (iw_handler) NULL,                              /* SIOCGIWAPLIST */
1754         (iw_handler) p80211wext_siwscan,                /* SIOCSIWSCAN */
1755         (iw_handler) p80211wext_giwscan,                /* SIOCGIWSCAN */
1756         (iw_handler) p80211wext_siwessid,               /* SIOCSIWESSID */
1757         (iw_handler) p80211wext_giwessid,               /* SIOCGIWESSID */
1758         (iw_handler) NULL,                              /* SIOCSIWNICKN */
1759         (iw_handler) p80211wext_giwessid,               /* SIOCGIWNICKN */
1760         (iw_handler) NULL,                              /* -- hole -- */
1761         (iw_handler) NULL,                              /* -- hole -- */
1762         (iw_handler) NULL,                              /* SIOCSIWRATE */
1763         (iw_handler) p80211wext_giwrate,                /* SIOCGIWRATE */
1764         (iw_handler) p80211wext_siwrts,                 /* SIOCSIWRTS */
1765         (iw_handler) p80211wext_giwrts,                 /* SIOCGIWRTS */
1766         (iw_handler) p80211wext_siwfrag,                /* SIOCSIWFRAG */
1767         (iw_handler) p80211wext_giwfrag,                /* SIOCGIWFRAG */
1768         (iw_handler) p80211wext_siwtxpow,               /* SIOCSIWTXPOW */
1769         (iw_handler) p80211wext_giwtxpow,               /* SIOCGIWTXPOW */
1770         (iw_handler) p80211wext_siwretry,               /* SIOCSIWRETRY */
1771         (iw_handler) p80211wext_giwretry,               /* SIOCGIWRETRY */
1772         (iw_handler) p80211wext_siwencode,              /* SIOCSIWENCODE */
1773         (iw_handler) p80211wext_giwencode,              /* SIOCGIWENCODE */
1774         (iw_handler) NULL,                              /* SIOCSIWPOWER */
1775         (iw_handler) NULL,                              /* SIOCGIWPOWER */
1776 /* WPA operations */
1777         (iw_handler) NULL,                              /* -- hole -- */
1778         (iw_handler) NULL,                              /* -- hole -- */
1779         (iw_handler) NULL, /* SIOCSIWGENIE      set generic IE */
1780         (iw_handler) NULL, /* SIOCGIWGENIE      get generic IE */
1781         (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH     set authentication mode params */
1782         (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH     get authentication mode params */
1783
1784         (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT  set encoding token & mode */
1785         (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT  get encoding token & mode */
1786         (iw_handler) NULL, /* SIOCSIWPMKSA      PMKSA cache operation */
1787 };
1788
1789 struct iw_handler_def p80211wext_handler_def = {
1790         .num_standard = sizeof(p80211wext_handlers) / sizeof(iw_handler),
1791         .num_private = 0,
1792         .num_private_args = 0,
1793         .standard = p80211wext_handlers,
1794         .private = NULL,
1795         .private_args = NULL,
1796         .get_wireless_stats = p80211wext_get_wireless_stats
1797 };
1798
1799
1800 int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
1801 {
1802         union iwreq_data data;
1803
1804         DBFENTER;
1805
1806         /* Send the association state first */
1807         data.ap_addr.sa_family = ARPHRD_ETHER;
1808         if (assoc) {
1809                 memcpy(data.ap_addr.sa_data, wlandev->bssid, WLAN_ADDR_LEN);
1810         } else {
1811                 memset(data.ap_addr.sa_data, 0, WLAN_ADDR_LEN);
1812         }
1813
1814         if (wlan_wext_write)
1815                 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1816
1817         if (!assoc) goto done;
1818
1819         // XXX send association data, like IEs, etc etc.
1820
1821  done:
1822         DBFEXIT;
1823         return 0;
1824 }
1825
1826
1827
1828