Staging: add wlan-ng prism2 usb driver
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / wlan-ng / p80211wext.c
blob906ba439237669b0150f12fb0f57cd42afd36ea4
1 /* src/p80211/p80211wext.c
3 * Glue code to make linux-wlan-ng a happy wireless extension camper.
5 * original author: Reyk Floeter <reyk@synack.de>
6 * Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
8 * Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved.
9 * --------------------------------------------------------------------
11 * linux-wlan
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/
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.
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.
34 * --------------------------------------------------------------------
37 /*================================================================*/
38 /* System Includes */
41 #include <linux/version.h>
43 #include <linux/kernel.h>
44 #include <linux/sched.h>
45 #include <linux/types.h>
46 #include <linux/slab.h>
47 #include <linux/netdevice.h>
48 #include <linux/etherdevice.h>
49 #include <linux/wireless.h>
50 #if WIRELESS_EXT > 12
51 #include <net/iw_handler.h>
52 #endif
53 #include <linux/if_arp.h>
54 #include <asm/bitops.h>
55 #include <asm/uaccess.h>
56 #include <asm/byteorder.h>
58 /*================================================================*/
59 /* Project Includes */
61 #include "version.h"
62 #include "wlan_compat.h"
64 #include "p80211types.h"
65 #include "p80211hdr.h"
66 #include "p80211conv.h"
67 #include "p80211mgmt.h"
68 #include "p80211msg.h"
69 #include "p80211metastruct.h"
70 #include "p80211metadef.h"
71 #include "p80211netdev.h"
72 #include "p80211ioctl.h"
73 #include "p80211req.h"
75 static int p80211wext_giwrate(netdevice_t *dev,
76 struct iw_request_info *info,
77 struct iw_param *rrq, char *extra);
78 static int p80211wext_giwessid(netdevice_t *dev,
79 struct iw_request_info *info,
80 struct iw_point *data, char *essid);
81 /* compatibility to wireless extensions */
82 #ifdef WIRELESS_EXT
84 static UINT8 p80211_mhz_to_channel(UINT16 mhz)
86 if (mhz >= 5000) {
87 return ((mhz - 5000) / 5);
90 if (mhz == 2482)
91 return 14;
93 if (mhz >= 2407) {
94 return ((mhz - 2407) / 5);
97 return 0;
100 static UINT16 p80211_channel_to_mhz(UINT8 ch, int dot11a)
103 if (ch == 0)
104 return 0;
105 if (ch > 200)
106 return 0;
108 /* 5G */
110 if (dot11a) {
111 return (5000 + (5 * ch));
114 /* 2.4G */
116 if (ch == 14)
117 return 2484;
119 if ((ch < 14) && (ch > 0)) {
120 return (2407 + (5 * ch));
123 return 0;
126 /* taken from orinoco.c ;-) */
127 static const long p80211wext_channel_freq[] = {
128 2412, 2417, 2422, 2427, 2432, 2437, 2442,
129 2447, 2452, 2457, 2462, 2467, 2472, 2484
131 #define NUM_CHANNELS (sizeof(p80211wext_channel_freq) / sizeof(p80211wext_channel_freq[0]))
133 /* steal a spare bit to store the shared/opensystems state. should default to open if not set */
134 #define HOSTWEP_SHAREDKEY BIT3
137 /** function declarations =============== */
139 static int qual_as_percent(int snr ) {
140 if ( snr <= 0 )
141 return 0;
142 if ( snr <= 40 )
143 return snr*5/2;
144 return 100;
150 static int p80211wext_dorequest(wlandevice_t *wlandev, UINT32 did, UINT32 data)
152 p80211msg_dot11req_mibset_t msg;
153 p80211item_uint32_t mibitem;
154 int result;
156 DBFENTER;
158 msg.msgcode = DIDmsg_dot11req_mibset;
159 mibitem.did = did;
160 mibitem.data = data;
161 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
162 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
164 DBFEXIT;
165 return result;
168 static int p80211wext_autojoin(wlandevice_t *wlandev)
170 p80211msg_lnxreq_autojoin_t msg;
171 struct iw_point data;
172 char ssid[IW_ESSID_MAX_SIZE];
174 int result;
175 int err = 0;
177 DBFENTER;
179 /* Get ESSID */
180 result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
182 if (result) {
183 err = -EFAULT;
184 goto exit;
187 if ( wlandev->hostwep & HOSTWEP_SHAREDKEY )
188 msg.authtype.data = P80211ENUM_authalg_sharedkey;
189 else
190 msg.authtype.data = P80211ENUM_authalg_opensystem;
192 msg.msgcode = DIDmsg_lnxreq_autojoin;
194 /* Trim the last '\0' to fit the SSID format */
196 if (data.length && ssid[data.length-1] == '\0') {
197 data.length = data.length - 1;
200 memcpy(msg.ssid.data.data, ssid, data.length);
201 msg.ssid.data.len = data.length;
203 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
205 if (result) {
206 err = -EFAULT;
207 goto exit;
210 exit:
212 DBFEXIT;
213 return err;
217 /* called by /proc/net/wireless */
218 struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev)
220 p80211msg_lnxreq_commsquality_t quality;
221 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
222 struct iw_statistics* wstats = &wlandev->wstats;
223 int retval;
225 DBFENTER;
226 /* Check */
227 if ( (wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING) )
228 return NULL;
230 /* XXX Only valid in station mode */
231 wstats->status = 0;
233 /* build request message */
234 quality.msgcode = DIDmsg_lnxreq_commsquality;
235 quality.dbm.data = P80211ENUM_truth_true;
236 quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
238 /* send message to nsd */
239 if ( wlandev->mlmerequest == NULL )
240 return NULL;
242 retval = wlandev->mlmerequest(wlandev, (p80211msg_t*) &quality);
244 wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
245 wstats->qual.level = quality.level.data; /* instant signal level */
246 wstats->qual.noise = quality.noise.data; /* instant noise level */
248 #if WIRELESS_EXT > 18
249 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
250 #else
251 wstats->qual.updated = 7;
252 #endif
253 wstats->discard.code = wlandev->rx.decrypt_err;
254 wstats->discard.nwid = 0;
255 wstats->discard.misc = 0;
257 #if WIRELESS_EXT > 11
258 wstats->discard.fragment = 0; // incomplete fragments
259 wstats->discard.retries = 0; // tx retries.
260 wstats->miss.beacon = 0;
261 #endif
263 DBFEXIT;
265 return wstats;
268 static int p80211wext_giwname(netdevice_t *dev,
269 struct iw_request_info *info,
270 char *name, char *extra)
272 struct iw_param rate;
273 int result;
274 int err = 0;
276 DBFENTER;
278 result = p80211wext_giwrate(dev, NULL, &rate, NULL);
280 if (result) {
281 err = -EFAULT;
282 goto exit;
285 switch (rate.value) {
286 case 1000000:
287 case 2000000:
288 strcpy(name, "IEEE 802.11-DS");
289 break;
290 case 5500000:
291 case 11000000:
292 strcpy(name, "IEEE 802.11-b");
293 break;
295 exit:
296 DBFEXIT;
297 return err;
300 static int p80211wext_giwfreq(netdevice_t *dev,
301 struct iw_request_info *info,
302 struct iw_freq *freq, char *extra)
304 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
305 p80211item_uint32_t mibitem;
306 p80211msg_dot11req_mibset_t msg;
307 int result;
308 int err = 0;
310 DBFENTER;
312 msg.msgcode = DIDmsg_dot11req_mibget;
313 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
314 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
315 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
317 if (result) {
318 err = -EFAULT;
319 goto exit;
322 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
324 if (mibitem.data > NUM_CHANNELS) {
325 err = -EFAULT;
326 goto exit;
329 /* convert into frequency instead of a channel */
330 freq->e = 1;
331 freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000;
333 exit:
334 DBFEXIT;
335 return err;
338 static int p80211wext_siwfreq(netdevice_t *dev,
339 struct iw_request_info *info,
340 struct iw_freq *freq, char *extra)
342 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
343 p80211item_uint32_t mibitem;
344 p80211msg_dot11req_mibset_t msg;
345 int result;
346 int err = 0;
348 DBFENTER;
350 if (!wlan_wext_write) {
351 err = (-EOPNOTSUPP);
352 goto exit;
355 msg.msgcode = DIDmsg_dot11req_mibset;
356 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
357 mibitem.status = P80211ENUM_msgitem_status_data_ok;
359 if ( (freq->e == 0) && (freq->m <= 1000) )
360 mibitem.data = freq->m;
361 else
362 mibitem.data = p80211_mhz_to_channel(freq->m);
364 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
365 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
367 if (result) {
368 err = -EFAULT;
369 goto exit;
372 exit:
373 DBFEXIT;
374 return err;
377 #if WIRELESS_EXT > 8
379 static int p80211wext_giwmode(netdevice_t *dev,
380 struct iw_request_info *info,
381 __u32 *mode, char *extra)
383 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
385 DBFENTER;
387 switch (wlandev->macmode) {
388 case WLAN_MACMODE_IBSS_STA:
389 *mode = IW_MODE_ADHOC;
390 break;
391 case WLAN_MACMODE_ESS_STA:
392 *mode = IW_MODE_INFRA;
393 break;
394 case WLAN_MACMODE_ESS_AP:
395 *mode = IW_MODE_MASTER;
396 break;
397 default:
398 /* Not set yet. */
399 *mode = IW_MODE_AUTO;
402 DBFEXIT;
403 return 0;
406 static int p80211wext_siwmode(netdevice_t *dev,
407 struct iw_request_info *info,
408 __u32 *mode, char *extra)
410 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
411 p80211item_uint32_t mibitem;
412 p80211msg_dot11req_mibset_t msg;
413 int result;
414 int err = 0;
416 DBFENTER;
418 if (!wlan_wext_write) {
419 err = (-EOPNOTSUPP);
420 goto exit;
423 if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
424 *mode != IW_MODE_MASTER) {
425 err = (-EOPNOTSUPP);
426 goto exit;
429 /* Operation mode is the same with current mode */
430 if (*mode == wlandev->macmode)
431 goto exit;
433 switch (*mode) {
434 case IW_MODE_ADHOC:
435 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
436 break;
437 case IW_MODE_INFRA:
438 wlandev->macmode = WLAN_MACMODE_ESS_STA;
439 break;
440 case IW_MODE_MASTER:
441 wlandev->macmode = WLAN_MACMODE_ESS_AP;
442 break;
443 default:
444 /* Not set yet. */
445 WLAN_LOG_INFO("Operation mode: %d not support\n", *mode);
446 return -EOPNOTSUPP;
449 /* Set Operation mode to the PORT TYPE RID */
451 #warning "get rid of p2mib here"
453 msg.msgcode = DIDmsg_dot11req_mibset;
454 mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
455 mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
456 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
457 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
459 if (result)
460 err = -EFAULT;
462 exit:
463 DBFEXIT;
465 return err;
469 static int p80211wext_giwrange(netdevice_t *dev,
470 struct iw_request_info *info,
471 struct iw_point *data, char *extra)
473 struct iw_range *range = (struct iw_range *) extra;
474 int i, val;
476 DBFENTER;
478 // for backward compatability set size & zero everything we don't understand
479 data->length = sizeof(*range);
480 memset(range,0,sizeof(*range));
482 #if WIRELESS_EXT > 9
483 range->txpower_capa = IW_TXPOW_DBM;
484 // XXX what about min/max_pmp, min/max_pmt, etc.
485 #endif
487 #if WIRELESS_EXT > 10
488 range->we_version_compiled = WIRELESS_EXT;
489 range->we_version_source = 13;
491 range->retry_capa = IW_RETRY_LIMIT;
492 range->retry_flags = IW_RETRY_LIMIT;
493 range->min_retry = 0;
494 range->max_retry = 255;
495 #endif /* WIRELESS_EXT > 10 */
497 #if WIRELESS_EXT > 16
498 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | //mode/freq/ssid
499 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
500 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
501 range->event_capa[1] = IW_EVENT_CAPA_K_1; //encode
502 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
503 IW_EVENT_CAPA_MASK(IWEVCUSTOM) );
504 #endif
506 range->num_channels = NUM_CHANNELS;
508 /* XXX need to filter against the regulatory domain &| active set */
509 val = 0;
510 for (i = 0; i < NUM_CHANNELS ; i++) {
511 range->freq[val].i = i + 1;
512 range->freq[val].m = p80211wext_channel_freq[i] * 100000;
513 range->freq[val].e = 1;
514 val++;
517 range->num_frequency = val;
519 /* Max of /proc/net/wireless */
520 range->max_qual.qual = 100;
521 range->max_qual.level = 0;
522 range->max_qual.noise = 0;
523 range->sensitivity = 3;
524 // XXX these need to be nsd-specific!
526 range->min_rts = 0;
527 range->max_rts = 2347;
528 range->min_frag = 256;
529 range->max_frag = 2346;
531 range->max_encoding_tokens = NUM_WEPKEYS;
532 range->num_encoding_sizes = 2;
533 range->encoding_size[0] = 5;
534 range->encoding_size[1] = 13;
536 // XXX what about num_bitrates/throughput?
537 range->num_bitrates = 0;
539 /* estimated max throughput */
540 // XXX need to cap it if we're running at ~2Mbps..
541 range->throughput = 5500000;
543 DBFEXIT;
544 return 0;
546 #endif
548 static int p80211wext_giwap(netdevice_t *dev,
549 struct iw_request_info *info,
550 struct sockaddr *ap_addr, char *extra)
553 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
555 DBFENTER;
557 memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
558 ap_addr->sa_family = ARPHRD_ETHER;
560 DBFEXIT;
561 return 0;
564 #if WIRELESS_EXT > 8
565 static int p80211wext_giwencode(netdevice_t *dev,
566 struct iw_request_info *info,
567 struct iw_point *erq, char *key)
569 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
570 int err = 0;
571 int i;
573 DBFENTER;
575 if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
576 erq->flags = IW_ENCODE_ENABLED;
577 else
578 erq->flags = IW_ENCODE_DISABLED;
580 if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
581 erq->flags |= IW_ENCODE_RESTRICTED;
582 else
583 erq->flags |= IW_ENCODE_OPEN;
585 i = (erq->flags & IW_ENCODE_INDEX) - 1;
587 if (i == -1)
588 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
590 if ((i < 0) || (i >= NUM_WEPKEYS)) {
591 err = -EINVAL;
592 goto exit;
595 erq->flags |= i + 1;
597 /* copy the key from the driver cache as the keys are read-only MIBs */
598 erq->length = wlandev->wep_keylens[i];
599 memcpy(key, wlandev->wep_keys[i], erq->length);
601 exit:
602 DBFEXIT;
603 return err;
606 static int p80211wext_siwencode(netdevice_t *dev,
607 struct iw_request_info *info,
608 struct iw_point *erq, char *key)
610 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
611 p80211msg_dot11req_mibset_t msg;
612 p80211item_pstr32_t pstr;
614 int err = 0;
615 int result = 0;
616 int enable = 0;
617 int i;
619 DBFENTER;
620 if (!wlan_wext_write) {
621 err = (-EOPNOTSUPP);
622 goto exit;
625 /* Check the Key index first. */
626 if((i = (erq->flags & IW_ENCODE_INDEX))) {
628 if ((i < 1) || (i > NUM_WEPKEYS)) {
629 err = -EINVAL;
630 goto exit;
632 else
633 i--;
635 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, i);
637 if (result) {
638 err = -EFAULT;
639 goto exit;
641 else {
642 enable = 1;
646 else {
647 // Do not thing when no Key Index
650 /* Check if there is no key information in the iwconfig request */
651 if((erq->flags & IW_ENCODE_NOKEY) == 0 && enable == 1) {
653 /*------------------------------------------------------------
654 * If there is WEP Key for setting, check the Key Information
655 * and then set it to the firmware.
656 -------------------------------------------------------------*/
658 if (erq->length > 0) {
660 /* copy the key from the driver cache as the keys are read-only MIBs */
661 wlandev->wep_keylens[i] = erq->length;
662 memcpy(wlandev->wep_keys[i], key, erq->length);
664 /* Prepare data struture for p80211req_dorequest. */
665 memcpy(pstr.data.data, key, erq->length);
666 pstr.data.len = erq->length;
668 switch(i)
670 case 0:
671 pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
672 break;
674 case 1:
675 pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
676 break;
678 case 2:
679 pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
680 break;
682 case 3:
683 pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
684 break;
686 default:
687 err = -EINVAL;
688 goto exit;
691 msg.msgcode = DIDmsg_dot11req_mibset;
692 memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
693 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
695 if (result) {
696 err = -EFAULT;
697 goto exit;
703 /* Check the PrivacyInvoked flag */
704 if (erq->flags & IW_ENCODE_DISABLED) {
705 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false);
707 else if((erq->flags & IW_ENCODE_ENABLED) || enable == 1) {
708 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true);
711 if (result) {
712 err = -EFAULT;
713 goto exit;
716 /* Check the ExcludeUnencrypted flag */
717 if (erq->flags & IW_ENCODE_RESTRICTED) {
718 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true);
720 else if (erq->flags & IW_ENCODE_OPEN) {
721 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false);
724 if (result) {
725 err = -EFAULT;
726 goto exit;
729 exit:
731 DBFEXIT;
732 return err;
735 static int p80211wext_giwessid(netdevice_t *dev,
736 struct iw_request_info *info,
737 struct iw_point *data, char *essid)
739 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
741 DBFENTER;
743 if (wlandev->ssid.len) {
744 data->length = wlandev->ssid.len;
745 data->flags = 1;
746 memcpy(essid, wlandev->ssid.data, data->length);
747 essid[data->length] = 0;
748 #if (WIRELESS_EXT < 21)
749 data->length++;
750 #endif
751 } else {
752 memset(essid, 0, sizeof(wlandev->ssid.data));
753 data->length = 0;
754 data->flags = 0;
757 DBFEXIT;
758 return 0;
761 static int p80211wext_siwessid(netdevice_t *dev,
762 struct iw_request_info *info,
763 struct iw_point *data, char *essid)
765 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
766 p80211msg_lnxreq_autojoin_t msg;
768 int result;
769 int err = 0;
770 int length = data->length;
772 DBFENTER;
774 if (!wlan_wext_write) {
775 err = (-EOPNOTSUPP);
776 goto exit;
780 if ( wlandev->hostwep & HOSTWEP_SHAREDKEY )
781 msg.authtype.data = P80211ENUM_authalg_sharedkey;
782 else
783 msg.authtype.data = P80211ENUM_authalg_opensystem;
785 msg.msgcode = DIDmsg_lnxreq_autojoin;
787 #if (WIRELESS_EXT < 21)
788 if (length) length--;
789 #endif
791 /* Trim the last '\0' to fit the SSID format */
793 if (length && essid[length-1] == '\0') {
794 length--;
797 memcpy(msg.ssid.data.data, essid, length);
798 msg.ssid.data.len = length;
800 WLAN_LOG_DEBUG(1,"autojoin_ssid for %s \n",essid);
801 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
802 WLAN_LOG_DEBUG(1,"autojoin_ssid %d\n",result);
804 if (result) {
805 err = -EFAULT;
806 goto exit;
809 exit:
810 DBFEXIT;
811 return err;
815 static int p80211wext_siwcommit(netdevice_t *dev,
816 struct iw_request_info *info,
817 struct iw_point *data, char *essid)
819 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
820 int err = 0;
822 DBFENTER;
824 if (!wlan_wext_write) {
825 err = (-EOPNOTSUPP);
826 goto exit;
829 /* Auto Join */
830 err = p80211wext_autojoin(wlandev);
832 exit:
833 DBFEXIT;
834 return err;
838 static int p80211wext_giwrate(netdevice_t *dev,
839 struct iw_request_info *info,
840 struct iw_param *rrq, char *extra)
842 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
843 p80211item_uint32_t mibitem;
844 p80211msg_dot11req_mibset_t msg;
845 int result;
846 int err = 0;
848 DBFENTER;
850 msg.msgcode = DIDmsg_dot11req_mibget;
851 mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
852 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
853 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
855 if (result) {
856 err = -EFAULT;
857 goto exit;
860 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
862 rrq->fixed = 0; /* can it change? */
863 rrq->disabled = 0;
864 rrq->value = 0;
866 #define HFA384x_RATEBIT_1 ((UINT16)1)
867 #define HFA384x_RATEBIT_2 ((UINT16)2)
868 #define HFA384x_RATEBIT_5dot5 ((UINT16)4)
869 #define HFA384x_RATEBIT_11 ((UINT16)8)
871 switch (mibitem.data) {
872 case HFA384x_RATEBIT_1:
873 rrq->value = 1000000;
874 break;
875 case HFA384x_RATEBIT_2:
876 rrq->value = 2000000;
877 break;
878 case HFA384x_RATEBIT_5dot5:
879 rrq->value = 5500000;
880 break;
881 case HFA384x_RATEBIT_11:
882 rrq->value = 11000000;
883 break;
884 default:
885 err = -EINVAL;
887 exit:
888 DBFEXIT;
889 return err;
892 static int p80211wext_giwrts(netdevice_t *dev,
893 struct iw_request_info *info,
894 struct iw_param *rts, char *extra)
896 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
897 p80211item_uint32_t mibitem;
898 p80211msg_dot11req_mibset_t msg;
899 int result;
900 int err = 0;
902 DBFENTER;
904 msg.msgcode = DIDmsg_dot11req_mibget;
905 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
906 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
907 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
909 if (result) {
910 err = -EFAULT;
911 goto exit;
914 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
916 rts->value = mibitem.data;
917 rts->disabled = (rts->value == 2347);
918 rts->fixed = 1;
920 exit:
921 DBFEXIT;
922 return err;
926 static int p80211wext_siwrts(netdevice_t *dev,
927 struct iw_request_info *info,
928 struct iw_param *rts, char *extra)
930 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
931 p80211item_uint32_t mibitem;
932 p80211msg_dot11req_mibset_t msg;
933 int result;
934 int err = 0;
936 DBFENTER;
938 if (!wlan_wext_write) {
939 err = (-EOPNOTSUPP);
940 goto exit;
943 msg.msgcode = DIDmsg_dot11req_mibget;
944 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
945 if (rts->disabled)
946 mibitem.data = 2347;
947 else
948 mibitem.data = rts->value;
950 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
951 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
953 if (result) {
954 err = -EFAULT;
955 goto exit;
958 exit:
959 DBFEXIT;
960 return err;
963 static int p80211wext_giwfrag(netdevice_t *dev,
964 struct iw_request_info *info,
965 struct iw_param *frag, char *extra)
967 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
968 p80211item_uint32_t mibitem;
969 p80211msg_dot11req_mibset_t msg;
970 int result;
971 int err = 0;
973 DBFENTER;
975 msg.msgcode = DIDmsg_dot11req_mibget;
976 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
977 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
978 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
980 if (result) {
981 err = -EFAULT;
982 goto exit;
985 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
987 frag->value = mibitem.data;
988 frag->disabled = (frag->value == 2346);
989 frag->fixed = 1;
991 exit:
992 DBFEXIT;
993 return err;
996 static int p80211wext_siwfrag(netdevice_t *dev,
997 struct iw_request_info *info,
998 struct iw_param *frag, char *extra)
1000 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1001 p80211item_uint32_t mibitem;
1002 p80211msg_dot11req_mibset_t msg;
1003 int result;
1004 int err = 0;
1006 DBFENTER;
1008 if (!wlan_wext_write) {
1009 err = (-EOPNOTSUPP);
1010 goto exit;
1013 msg.msgcode = DIDmsg_dot11req_mibset;
1014 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
1016 if (frag->disabled)
1017 mibitem.data = 2346;
1018 else
1019 mibitem.data = frag->value;
1021 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1022 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1024 if (result) {
1025 err = -EFAULT;
1026 goto exit;
1029 exit:
1030 DBFEXIT;
1031 return err;
1034 #endif /* WIRELESS_EXT > 8 */
1036 #if WIRELESS_EXT > 10
1038 #ifndef IW_RETRY_LONG
1039 #define IW_RETRY_LONG IW_RETRY_MAX
1040 #endif
1042 #ifndef IW_RETRY_SHORT
1043 #define IW_RETRY_SHORT IW_RETRY_MIN
1044 #endif
1046 static int p80211wext_giwretry(netdevice_t *dev,
1047 struct iw_request_info *info,
1048 struct iw_param *rrq, char *extra)
1050 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1051 p80211item_uint32_t mibitem;
1052 p80211msg_dot11req_mibset_t msg;
1053 int result;
1054 int err = 0;
1055 UINT16 shortretry, longretry, lifetime;
1057 DBFENTER;
1059 msg.msgcode = DIDmsg_dot11req_mibget;
1060 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1062 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1063 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1065 if (result) {
1066 err = -EFAULT;
1067 goto exit;
1070 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1072 shortretry = mibitem.data;
1074 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1076 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1077 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1079 if (result) {
1080 err = -EFAULT;
1081 goto exit;
1084 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1086 longretry = mibitem.data;
1088 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1090 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1091 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1093 if (result) {
1094 err = -EFAULT;
1095 goto exit;
1098 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1100 lifetime = mibitem.data;
1102 rrq->disabled = 0;
1104 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1105 rrq->flags = IW_RETRY_LIFETIME;
1106 rrq->value = lifetime * 1024;
1107 } else {
1108 if (rrq->flags & IW_RETRY_LONG) {
1109 rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1110 rrq->value = longretry;
1111 } else {
1112 rrq->flags = IW_RETRY_LIMIT;
1113 rrq->value = shortretry;
1114 if (shortretry != longretry)
1115 rrq->flags |= IW_RETRY_SHORT;
1119 exit:
1120 DBFEXIT;
1121 return err;
1125 static int p80211wext_siwretry(netdevice_t *dev,
1126 struct iw_request_info *info,
1127 struct iw_param *rrq, char *extra)
1129 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1130 p80211item_uint32_t mibitem;
1131 p80211msg_dot11req_mibset_t msg;
1132 int result;
1133 int err = 0;
1135 DBFENTER;
1137 if (!wlan_wext_write) {
1138 err = (-EOPNOTSUPP);
1139 goto exit;
1142 if (rrq->disabled) {
1143 err = -EINVAL;
1144 goto exit;
1147 msg.msgcode = DIDmsg_dot11req_mibset;
1149 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1150 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1151 mibitem.data = rrq->value /= 1024;
1153 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1154 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1156 if (result) {
1157 err = -EFAULT;
1158 goto exit;
1160 } else {
1161 if (rrq->flags & IW_RETRY_LONG) {
1162 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1163 mibitem.data = rrq->value;
1165 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1166 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1168 if (result) {
1169 err = -EFAULT;
1170 goto exit;
1174 if (rrq->flags & IW_RETRY_SHORT) {
1175 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1176 mibitem.data = rrq->value;
1178 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1179 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1181 if (result) {
1182 err = -EFAULT;
1183 goto exit;
1188 exit:
1189 DBFEXIT;
1190 return err;
1194 #endif /* WIRELESS_EXT > 10 */
1196 #if WIRELESS_EXT > 9
1197 static int p80211wext_siwtxpow(netdevice_t *dev,
1198 struct iw_request_info *info,
1199 struct iw_param *rrq, char *extra)
1201 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1202 p80211item_uint32_t mibitem;
1203 p80211msg_dot11req_mibset_t msg;
1204 int result;
1205 int err = 0;
1207 DBFENTER;
1209 if (!wlan_wext_write) {
1210 err = (-EOPNOTSUPP);
1211 goto exit;
1214 msg.msgcode = DIDmsg_dot11req_mibset;
1216 switch (rrq->value) {
1218 case 1 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1; break;
1219 case 2 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2; break;
1220 case 3 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3; break;
1221 case 4 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4; break;
1222 case 5 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5; break;
1223 case 6 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6; break;
1224 case 7 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7; break;
1225 case 8 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break;
1226 default: mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break;
1229 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1230 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1232 if (result) {
1233 err = -EFAULT;
1234 goto exit;
1237 exit:
1238 DBFEXIT;
1239 return err;
1242 static int p80211wext_giwtxpow(netdevice_t *dev,
1243 struct iw_request_info *info,
1244 struct iw_param *rrq, char *extra)
1246 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1247 p80211item_uint32_t mibitem;
1248 p80211msg_dot11req_mibset_t msg;
1249 int result;
1250 int err = 0;
1252 DBFENTER;
1254 msg.msgcode = DIDmsg_dot11req_mibget;
1255 mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1257 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1258 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1260 if (result) {
1261 err = -EFAULT;
1262 goto exit;
1265 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1267 // XXX handle OFF by setting disabled = 1;
1269 rrq->flags = 0; // IW_TXPOW_DBM;
1270 rrq->disabled = 0;
1271 rrq->fixed = 0;
1272 rrq->value = mibitem.data;
1274 exit:
1275 DBFEXIT;
1276 return err;
1278 #endif /* WIRELESS_EXT > 9 */
1280 static int p80211wext_siwspy(netdevice_t *dev,
1281 struct iw_request_info *info,
1282 struct iw_point *srq, char *extra)
1284 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1285 struct sockaddr address[IW_MAX_SPY];
1286 int number = srq->length;
1287 int i;
1289 DBFENTER;
1291 /* Copy the data from the input buffer */
1292 memcpy(address, extra, sizeof(struct sockaddr)*number);
1294 wlandev->spy_number = 0;
1296 if (number > 0) {
1298 /* extract the addresses */
1299 for (i = 0; i < number; i++) {
1301 memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN);
1304 /* reset stats */
1305 memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
1307 /* set number of addresses */
1308 wlandev->spy_number = number;
1311 DBFEXIT;
1312 return 0;
1315 /* jkriegl: from orinoco, modified */
1316 static int p80211wext_giwspy(netdevice_t *dev,
1317 struct iw_request_info *info,
1318 struct iw_point *srq, char *extra)
1320 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1322 struct sockaddr address[IW_MAX_SPY];
1323 struct iw_quality spy_stat[IW_MAX_SPY];
1324 int number;
1325 int i;
1327 DBFENTER;
1329 number = wlandev->spy_number;
1331 if (number > 0) {
1333 /* populate address and spy struct's */
1334 for (i = 0; i < number; i++) {
1335 memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN);
1336 address[i].sa_family = AF_UNIX;
1337 memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality));
1340 /* reset update flag */
1341 for (i=0; i < number; i++)
1342 wlandev->spy_stat[i].updated = 0;
1345 /* push stuff to user space */
1346 srq->length = number;
1347 memcpy(extra, address, sizeof(struct sockaddr)*number);
1348 memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number);
1350 DBFEXIT;
1351 return 0;
1354 static int prism2_result2err (int prism2_result)
1356 int err = 0;
1358 switch (prism2_result) {
1359 case P80211ENUM_resultcode_invalid_parameters:
1360 err = -EINVAL;
1361 break;
1362 case P80211ENUM_resultcode_implementation_failure:
1363 err = -EIO;
1364 break;
1365 case P80211ENUM_resultcode_not_supported:
1366 err = -EOPNOTSUPP;
1367 break;
1368 default:
1369 err = 0;
1370 break;
1373 return err;
1376 #if WIRELESS_EXT > 13
1377 static int p80211wext_siwscan(netdevice_t *dev,
1378 struct iw_request_info *info,
1379 struct iw_point *srq, char *extra)
1381 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1382 p80211msg_dot11req_scan_t msg;
1383 int result;
1384 int err = 0;
1385 int i = 0;
1387 DBFENTER;
1389 if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1390 WLAN_LOG_ERROR("Can't scan in AP mode\n");
1391 err = (-EOPNOTSUPP);
1392 goto exit;
1395 memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1396 msg.msgcode = DIDmsg_dot11req_scan;
1397 msg.bsstype.data = P80211ENUM_bsstype_any;
1399 memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t));
1400 msg.bssid.data.len = 6;
1402 msg.scantype.data = P80211ENUM_scantype_active;
1403 msg.probedelay.data = 0;
1405 for (i = 1; i <= 14; i++)
1406 msg.channellist.data.data[i-1] = i;
1407 msg.channellist.data.len = 14;
1409 msg.maxchanneltime.data = 250;
1410 msg.minchanneltime.data = 200;
1412 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1413 if (result)
1414 err = prism2_result2err (msg.resultcode.data);
1416 exit:
1417 DBFEXIT;
1418 return err;
1422 /* Helper to translate scan into Wireless Extensions scan results.
1423 * Inspired by the prism54 code, which was in turn inspired by the
1424 * airo driver code.
1426 static char *
1427 wext_translate_bss(struct iw_request_info *info, char *current_ev,
1428 char *end_buf, p80211msg_dot11req_scan_results_t *bss)
1430 struct iw_event iwe; /* Temporary buffer */
1432 /* The first entry must be the MAC address */
1433 memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1434 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1435 iwe.cmd = SIOCGIWAP;
1436 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
1438 /* The following entries will be displayed in the same order we give them */
1440 /* The ESSID. */
1441 if (bss->ssid.data.len > 0) {
1442 char essid[IW_ESSID_MAX_SIZE + 1];
1443 int size;
1445 size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len);
1446 memset(&essid, 0, sizeof (essid));
1447 memcpy(&essid, bss->ssid.data.data, size);
1448 WLAN_LOG_DEBUG(1, " essid size = %d\n", size);
1449 iwe.u.data.length = size;
1450 iwe.u.data.flags = 1;
1451 iwe.cmd = SIOCGIWESSID;
1452 current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &essid[0]);
1453 WLAN_LOG_DEBUG(1, " essid size OK.\n");
1456 switch (bss->bsstype.data) {
1457 case P80211ENUM_bsstype_infrastructure:
1458 iwe.u.mode = IW_MODE_MASTER;
1459 break;
1461 case P80211ENUM_bsstype_independent:
1462 iwe.u.mode = IW_MODE_ADHOC;
1463 break;
1465 default:
1466 iwe.u.mode = 0;
1467 break;
1469 iwe.cmd = SIOCGIWMODE;
1470 if (iwe.u.mode)
1471 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
1473 /* Encryption capability */
1474 if (bss->privacy.data == P80211ENUM_truth_true)
1475 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1476 else
1477 iwe.u.data.flags = IW_ENCODE_DISABLED;
1478 iwe.u.data.length = 0;
1479 iwe.cmd = SIOCGIWENCODE;
1480 current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1482 /* Add frequency. (short) bss->channel is the frequency in MHz */
1483 iwe.u.freq.m = bss->dschannel.data;
1484 iwe.u.freq.e = 0;
1485 iwe.cmd = SIOCGIWFREQ;
1486 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
1488 /* Add quality statistics */
1489 iwe.u.qual.level = bss->signal.data;
1490 iwe.u.qual.noise = bss->noise.data;
1491 /* do a simple SNR for quality */
1492 iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1493 iwe.cmd = IWEVQUAL;
1494 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
1496 return current_ev;
1500 static int p80211wext_giwscan(netdevice_t *dev,
1501 struct iw_request_info *info,
1502 struct iw_point *srq, char *extra)
1504 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1505 p80211msg_dot11req_scan_results_t msg;
1506 int result = 0;
1507 int err = 0;
1508 int i = 0;
1509 int scan_good = 0;
1510 char *current_ev = extra;
1512 DBFENTER;
1514 /* Since wireless tools doesn't really have a way of passing how
1515 * many scan results results there were back here, keep grabbing them
1516 * until we fail.
1518 do {
1519 memset(&msg, 0, sizeof(msg));
1520 msg.msgcode = DIDmsg_dot11req_scan_results;
1521 msg.bssindex.data = i;
1523 result = p80211req_dorequest(wlandev, (UINT8*)&msg);
1524 if ((result != 0) ||
1525 (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1526 break;
1529 current_ev = wext_translate_bss(info, current_ev, extra + IW_SCAN_MAX_DATA, &msg);
1530 scan_good = 1;
1531 i++;
1532 } while (i < IW_MAX_AP);
1534 srq->length = (current_ev - extra);
1535 srq->flags = 0; /* todo */
1537 if (result && !scan_good)
1538 err = prism2_result2err (msg.resultcode.data);
1540 DBFEXIT;
1541 return err;
1543 #endif
1545 /*****************************************************/
1546 //extra wireless extensions stuff to support NetworkManager (I hope)
1548 #if WIRELESS_EXT > 17
1549 /* SIOCSIWENCODEEXT */
1550 static int p80211wext_set_encodeext(struct net_device *dev,
1551 struct iw_request_info *info,
1552 union iwreq_data *wrqu, char *extra)
1554 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1555 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1556 p80211msg_dot11req_mibset_t msg;
1557 p80211item_pstr32_t *pstr;
1559 int result = 0;
1560 struct iw_point *encoding = &wrqu->encoding;
1561 int idx = encoding->flags & IW_ENCODE_INDEX;
1563 WLAN_LOG_DEBUG(1,"set_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len);
1566 if ( ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY ) {
1567 // set default key ? I'm not sure if this the the correct thing to do here
1569 if ( idx ) {
1570 if (idx < 1 || idx > NUM_WEPKEYS) {
1571 return -EINVAL;
1572 } else
1573 idx--;
1575 WLAN_LOG_DEBUG(1,"setting default key (%d)\n",idx);
1576 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, idx);
1577 if ( result )
1578 return -EFAULT;
1582 if ( ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) {
1583 if ( ! ext->alg & IW_ENCODE_ALG_WEP) {
1584 WLAN_LOG_DEBUG(1,"asked to set a non wep key :(");
1585 return -EINVAL;
1587 if (idx) {
1588 if (idx <1 || idx > NUM_WEPKEYS)
1589 return -EINVAL;
1590 else
1591 idx--;
1593 WLAN_LOG_DEBUG(1,"Set WEP key (%d)\n",idx);
1594 wlandev->wep_keylens[idx] = ext->key_len;
1595 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1597 memset( &msg,0,sizeof(msg));
1598 pstr = (p80211item_pstr32_t*)&msg.mibattribute.data;
1599 memcpy(pstr->data.data, ext->key,ext->key_len);
1600 pstr->data.len = ext->key_len;
1601 switch (idx) {
1602 case 0:
1603 pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1604 break;
1605 case 1:
1606 pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1607 break;
1608 case 2:
1609 pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1610 break;
1611 case 3:
1612 pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1613 break;
1614 default:
1615 break;
1617 msg.msgcode = DIDmsg_dot11req_mibset;
1618 result = p80211req_dorequest(wlandev,(UINT8*)&msg);
1619 WLAN_LOG_DEBUG(1,"result (%d)\n",result);
1621 return result;
1624 /* SIOCGIWENCODEEXT */
1625 static int p80211wext_get_encodeext(struct net_device *dev,
1626 struct iw_request_info *info,
1627 union iwreq_data *wrqu, char *extra)
1630 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1631 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1633 struct iw_point *encoding = &wrqu->encoding;
1634 int result = 0;
1635 int max_len;
1636 int idx;
1638 DBFENTER;
1640 WLAN_LOG_DEBUG(1,"get_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len);
1643 max_len = encoding->length - sizeof(*ext);
1644 if ( max_len <= 0) {
1645 WLAN_LOG_DEBUG(1,"get_encodeext max_len [%d] invalid\n",max_len);
1646 result = -EINVAL;
1647 goto exit;
1649 idx = encoding->flags & IW_ENCODE_INDEX;
1651 WLAN_LOG_DEBUG(1,"get_encode_ext index [%d]\n",idx);
1653 if (idx) {
1654 if (idx < 1 || idx > NUM_WEPKEYS ) {
1655 WLAN_LOG_DEBUG(1,"get_encode_ext invalid key index [%d]\n",idx);
1656 result = -EINVAL;
1657 goto exit;
1659 idx--;
1660 } else {
1661 /* default key ? not sure what to do */
1662 /* will just use key[0] for now ! FIX ME */
1665 encoding->flags = idx + 1;
1666 memset(ext,0,sizeof(*ext));
1668 ext->alg = IW_ENCODE_ALG_WEP;
1669 ext->key_len = wlandev->wep_keylens[idx];
1670 memcpy( ext->key, wlandev->wep_keys[idx] , ext->key_len );
1672 encoding->flags |= IW_ENCODE_ENABLED;
1673 exit:
1674 DBFEXIT;
1676 return result;
1680 /* SIOCSIWAUTH */
1681 static int p80211_wext_set_iwauth (struct net_device *dev,
1682 struct iw_request_info *info,
1683 union iwreq_data *wrqu, char *extra)
1685 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1686 struct iw_param *param = &wrqu->param;
1687 int result =0;
1689 WLAN_LOG_DEBUG(1,"set_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX );
1691 switch (param->flags & IW_AUTH_INDEX) {
1692 case IW_AUTH_DROP_UNENCRYPTED:
1693 WLAN_LOG_DEBUG(1,"drop_unencrypted %d\n",param->value);
1694 if (param->value)
1695 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true);
1696 else
1697 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false);
1698 break;
1700 case IW_AUTH_PRIVACY_INVOKED:
1701 WLAN_LOG_DEBUG(1,"privacy invoked %d\n",param->value);
1702 if ( param->value)
1703 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true);
1704 else
1705 result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false);
1707 break;
1709 case IW_AUTH_80211_AUTH_ALG:
1710 if ( param->value & IW_AUTH_ALG_OPEN_SYSTEM ) {
1711 WLAN_LOG_DEBUG(1,"set open_system\n");
1712 wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1713 } else if ( param->value & IW_AUTH_ALG_SHARED_KEY) {
1714 WLAN_LOG_DEBUG(1,"set shared key\n");
1715 wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1716 } else {
1717 /* don't know what to do know :( */
1718 WLAN_LOG_DEBUG(1,"unknown AUTH_ALG (%d)\n",param->value);
1719 result = -EINVAL;
1721 break;
1723 default:
1724 break;
1729 return result;
1732 /* SIOCSIWAUTH */
1733 static int p80211_wext_get_iwauth (struct net_device *dev,
1734 struct iw_request_info *info,
1735 union iwreq_data *wrqu, char *extra)
1737 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1738 struct iw_param *param = &wrqu->param;
1739 int result =0;
1741 WLAN_LOG_DEBUG(1,"get_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX );
1743 switch (param->flags & IW_AUTH_INDEX) {
1744 case IW_AUTH_DROP_UNENCRYPTED:
1745 param->value = wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED?1:0;
1746 break;
1748 case IW_AUTH_PRIVACY_INVOKED:
1749 param->value = wlandev->hostwep & HOSTWEP_PRIVACYINVOKED?1:0;
1750 break;
1752 case IW_AUTH_80211_AUTH_ALG:
1753 param->value = wlandev->hostwep & HOSTWEP_SHAREDKEY?IW_AUTH_ALG_SHARED_KEY:IW_AUTH_ALG_OPEN_SYSTEM;
1754 break;
1757 default:
1758 break;
1763 return result;
1767 #endif
1774 /*****************************************************/
1781 typedef int (*iw_handler)(netdevice_t *dev, struct iw_request_info *info,
1782 union iwreq_data *wrqu, char *extra);
1785 #if WIRELESS_EXT > 12
1786 static iw_handler p80211wext_handlers[] = {
1787 (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */
1788 (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */
1789 (iw_handler) NULL, /* SIOCSIWNWID */
1790 (iw_handler) NULL, /* SIOCGIWNWID */
1791 (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */
1792 (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */
1793 (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */
1794 (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */
1795 (iw_handler) NULL, /* SIOCSIWSENS */
1796 (iw_handler) NULL, /* SIOCGIWSENS */
1797 (iw_handler) NULL, /* not used */ /* SIOCSIWRANGE */
1798 (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */
1799 (iw_handler) NULL, /* not used */ /* SIOCSIWPRIV */
1800 (iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */
1801 (iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */
1802 (iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */
1803 (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1804 (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1805 (iw_handler) NULL, /* -- hole -- */
1806 (iw_handler) NULL, /* -- hole -- */
1807 (iw_handler) NULL, /* SIOCSIWAP */
1808 (iw_handler) p80211wext_giwap, /* SIOCGIWAP */
1809 (iw_handler) NULL, /* -- hole -- */
1810 (iw_handler) NULL, /* SIOCGIWAPLIST */
1811 #if WIRELESS_EXT > 13
1812 (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */
1813 (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */
1814 #else /* WIRELESS_EXT > 13 */
1815 (iw_handler) NULL, /* null */ /* SIOCSIWSCAN */
1816 (iw_handler) NULL, /* null */ /* SIOCGIWSCAN */
1817 #endif /* WIRELESS_EXT > 13 */
1818 (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */
1819 (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */
1820 (iw_handler) NULL, /* SIOCSIWNICKN */
1821 (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */
1822 (iw_handler) NULL, /* -- hole -- */
1823 (iw_handler) NULL, /* -- hole -- */
1824 (iw_handler) NULL, /* SIOCSIWRATE */
1825 (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */
1826 (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1827 (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1828 (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
1829 (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
1830 (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */
1831 (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
1832 (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
1833 (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */
1834 (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */
1835 (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */
1836 (iw_handler) NULL, /* SIOCSIWPOWER */
1837 (iw_handler) NULL, /* SIOCGIWPOWER */
1838 #if WIRELESS_EXT > 17
1839 /* WPA operations */
1841 (iw_handler) NULL, /* -- hole -- */
1842 (iw_handler) NULL, /* -- hole -- */
1843 (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */
1844 (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */
1845 (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */
1846 (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */
1848 (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */
1849 (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */
1850 (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */
1851 #endif
1854 struct iw_handler_def p80211wext_handler_def = {
1855 .num_standard = sizeof(p80211wext_handlers) / sizeof(iw_handler),
1856 .num_private = 0,
1857 .num_private_args = 0,
1858 .standard = p80211wext_handlers,
1859 .private = NULL,
1860 .private_args = NULL,
1861 #if WIRELESS_EXT > 16
1862 .get_wireless_stats = p80211wext_get_wireless_stats
1863 #endif
1866 #endif
1868 /* wireless extensions' ioctls */
1869 int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
1871 wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
1873 #if WIRELESS_EXT < 13
1874 struct iwreq *iwr = (struct iwreq*)ifr;
1875 #endif
1877 p80211item_uint32_t mibitem;
1878 int err = 0;
1880 DBFENTER;
1882 mibitem.status = P80211ENUM_msgitem_status_data_ok;
1884 if ( wlandev->msdstate != WLAN_MSD_RUNNING ) {
1885 err = -ENODEV;
1886 goto exit;
1889 WLAN_LOG_DEBUG(1, "Received wireless extension ioctl #%d.\n", cmd);
1891 switch (cmd) {
1892 #if WIRELESS_EXT < 13
1893 case SIOCSIWNAME: /* unused */
1894 err = (-EOPNOTSUPP);
1895 break;
1896 case SIOCGIWNAME: /* get name == wireless protocol */
1897 err = p80211wext_giwname(dev, NULL, (char *) &iwr->u, NULL);
1898 break;
1899 case SIOCSIWNWID:
1900 case SIOCGIWNWID:
1901 err = (-EOPNOTSUPP);
1902 break;
1903 case SIOCSIWFREQ: /* set channel */
1904 err = p80211wext_siwfreq(dev, NULL, &(iwr->u.freq), NULL);
1905 break;
1906 case SIOCGIWFREQ: /* get channel */
1907 err = p80211wext_giwfreq(dev, NULL, &(iwr->u.freq), NULL);
1908 break;
1909 case SIOCSIWRANGE:
1910 case SIOCSIWPRIV:
1911 case SIOCSIWAP: /* set access point MAC addresses (BSSID) */
1912 err = (-EOPNOTSUPP);
1913 break;
1915 case SIOCGIWAP: /* get access point MAC addresses (BSSID) */
1916 err = p80211wext_giwap(dev, NULL, &(iwr->u.ap_addr), NULL);
1917 break;
1919 #if WIRELESS_EXT > 8
1920 case SIOCSIWMODE: /* set operation mode */
1921 case SIOCSIWESSID: /* set SSID (network name) */
1922 case SIOCSIWRATE: /* set default bit rate (bps) */
1923 err = (-EOPNOTSUPP);
1924 break;
1926 case SIOCGIWMODE: /* get operation mode */
1927 err = p80211wext_giwmode(dev, NULL, &iwr->u.mode, NULL);
1929 break;
1930 case SIOCGIWNICKN: /* get node name/nickname */
1931 case SIOCGIWESSID: /* get SSID */
1932 if(iwr->u.essid.pointer) {
1933 char ssid[IW_ESSID_MAX_SIZE+1];
1934 memset(ssid, 0, sizeof(ssid));
1936 err = p80211wext_giwessid(dev, NULL, &iwr->u.essid, ssid);
1937 if(copy_to_user(iwr->u.essid.pointer, ssid, sizeof(ssid)))
1938 err = (-EFAULT);
1940 break;
1941 case SIOCGIWRATE:
1942 err = p80211wext_giwrate(dev, NULL, &iwr->u.bitrate, NULL);
1943 break;
1944 case SIOCGIWRTS:
1945 err = p80211wext_giwrts(dev, NULL, &iwr->u.rts, NULL);
1946 break;
1947 case SIOCGIWFRAG:
1948 err = p80211wext_giwfrag(dev, NULL, &iwr->u.rts, NULL);
1949 break;
1950 case SIOCGIWENCODE:
1951 if (!capable(CAP_NET_ADMIN))
1952 err = -EPERM;
1953 else if (iwr->u.encoding.pointer) {
1954 char keybuf[MAX_KEYLEN];
1955 err = p80211wext_giwencode(dev, NULL,
1956 &iwr->u.encoding, keybuf);
1957 if (copy_to_user(iwr->u.encoding.pointer, keybuf,
1958 iwr->u.encoding.length))
1959 err = -EFAULT;
1961 break;
1962 case SIOCGIWAPLIST:
1963 case SIOCSIWRTS:
1964 case SIOCSIWFRAG:
1965 case SIOCSIWSENS:
1966 case SIOCGIWSENS:
1967 case SIOCSIWNICKN: /* set node name/nickname */
1968 case SIOCSIWENCODE: /* set encoding token & mode */
1969 case SIOCSIWSPY:
1970 case SIOCGIWSPY:
1971 case SIOCSIWPOWER:
1972 case SIOCGIWPOWER:
1973 case SIOCGIWPRIV:
1974 err = (-EOPNOTSUPP);
1975 break;
1976 case SIOCGIWRANGE:
1977 if(iwr->u.data.pointer != NULL) {
1978 struct iw_range range;
1979 err = p80211wext_giwrange(dev, NULL, &iwr->u.data,
1980 (char *) &range);
1981 /* Push that up to the caller */
1982 if (copy_to_user(iwr->u.data.pointer, &range, sizeof(range)))
1983 err = -EFAULT;
1985 break;
1986 #endif /* WIRELESS_EXT > 8 */
1987 #if WIRELESS_EXT > 9
1988 case SIOCSIWTXPOW:
1989 err = (-EOPNOTSUPP);
1990 break;
1991 case SIOCGIWTXPOW:
1992 err = p80211wext_giwtxpow(dev, NULL, &iwr->u.txpower, NULL);
1993 break;
1994 #endif /* WIRELESS_EXT > 9 */
1995 #if WIRELESS_EXT > 10
1996 case SIOCSIWRETRY:
1997 err = (-EOPNOTSUPP);
1998 break;
1999 case SIOCGIWRETRY:
2000 err = p80211wext_giwretry(dev, NULL, &iwr->u.retry, NULL);
2001 break;
2002 #endif /* WIRELESS_EXT > 10 */
2004 #endif /* WIRELESS_EXT <= 12 */
2006 default:
2007 err = (-EOPNOTSUPP);
2008 break;
2011 exit:
2012 DBFEXIT;
2013 return (err);
2016 int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
2018 union iwreq_data data;
2020 DBFENTER;
2022 #if WIRELESS_EXT > 13
2023 /* Send the association state first */
2024 data.ap_addr.sa_family = ARPHRD_ETHER;
2025 if (assoc) {
2026 memcpy(data.ap_addr.sa_data, wlandev->bssid, WLAN_ADDR_LEN);
2027 } else {
2028 memset(data.ap_addr.sa_data, 0, WLAN_ADDR_LEN);
2031 if (wlan_wext_write)
2032 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
2034 if (!assoc) goto done;
2036 // XXX send association data, like IEs, etc etc.
2037 #endif
2038 done:
2039 DBFEXIT;
2040 return 0;
2044 #endif /* compatibility to wireless extensions */