Staging: wlan-ng: Remove use of WLAN_ADDR_LEN
[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 #include <linux/if_ether.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 ARRAY_SIZE(p80211wext_channel_freq)
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 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 = ARRAY_SIZE(p80211wext_handlers),
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, ETH_ALEN);
1810         } else {
1811                 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
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