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