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