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