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