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