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