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 * --------------------------------------------------------------------
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 /*================================================================*/
40 #include <linux/kernel.h>
41 #include <linux/sched.h>
42 #include <linux/types.h>
43 #include <linux/slab.h>
44 #include <linux/netdevice.h>
45 #include <linux/etherdevice.h>
46 #include <linux/wireless.h>
47 #include <net/iw_handler.h>
48 #include <linux/if_arp.h>
49 #include <asm/bitops.h>
50 #include <asm/uaccess.h>
51 #include <asm/byteorder.h>
52 #include <linux/if_ether.h>
53 #include <linux/bitops.h>
55 #include "p80211types.h"
56 #include "p80211hdr.h"
57 #include "p80211conv.h"
58 #include "p80211mgmt.h"
59 #include "p80211msg.h"
60 #include "p80211metastruct.h"
61 #include "p80211metadef.h"
62 #include "p80211netdev.h"
63 #include "p80211ioctl.h"
64 #include "p80211req.h"
66 static int p80211wext_giwrate(netdevice_t *dev,
67 struct iw_request_info *info,
68 struct iw_param *rrq, char *extra);
69 static int p80211wext_giwessid(netdevice_t *dev,
70 struct iw_request_info *info,
71 struct iw_point *data, char *essid);
73 static u8 p80211_mhz_to_channel(u16 mhz)
76 return (mhz - 5000) / 5;
82 return (mhz - 2407) / 5;
87 static u16 p80211_channel_to_mhz(u8 ch, int dot11a)
97 return 5000 + (5 * ch);
103 if ((ch < 14) && (ch > 0))
104 return 2407 + (5 * ch);
109 /* taken from orinoco.c ;-) */
110 static const long p80211wext_channel_freq[] = {
111 2412, 2417, 2422, 2427, 2432, 2437, 2442,
112 2447, 2452, 2457, 2462, 2467, 2472, 2484
115 #define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
117 /* steal a spare bit to store the shared/opensystems state.
118 should default to open if not set */
119 #define HOSTWEP_SHAREDKEY BIT(3)
121 static int qual_as_percent(int snr)
130 static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data)
132 p80211msg_dot11req_mibset_t msg;
133 p80211item_uint32_t mibitem;
136 msg.msgcode = DIDmsg_dot11req_mibset;
139 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
140 result = p80211req_dorequest(wlandev, (u8 *) & msg);
145 static int p80211wext_autojoin(wlandevice_t *wlandev)
147 p80211msg_lnxreq_autojoin_t msg;
148 struct iw_point data;
149 char ssid[IW_ESSID_MAX_SIZE];
155 result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
162 if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
163 msg.authtype.data = P80211ENUM_authalg_sharedkey;
165 msg.authtype.data = P80211ENUM_authalg_opensystem;
167 msg.msgcode = DIDmsg_lnxreq_autojoin;
169 /* Trim the last '\0' to fit the SSID format */
171 if (data.length && ssid[data.length - 1] == '\0')
172 data.length = data.length - 1;
174 memcpy(msg.ssid.data.data, ssid, data.length);
175 msg.ssid.data.len = data.length;
177 result = p80211req_dorequest(wlandev, (u8 *) & msg);
190 /* called by /proc/net/wireless */
191 struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev)
193 p80211msg_lnxreq_commsquality_t quality;
194 wlandevice_t *wlandev = dev->ml_priv;
195 struct iw_statistics *wstats = &wlandev->wstats;
199 if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
202 /* XXX Only valid in station mode */
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;
210 /* send message to nsd */
211 if (wlandev->mlmerequest == NULL)
214 retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) & quality);
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 */
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;
225 wstats->discard.fragment = 0; /* incomplete fragments */
226 wstats->discard.retries = 0; /* tx retries. */
227 wstats->miss.beacon = 0;
232 static int p80211wext_giwname(netdevice_t *dev,
233 struct iw_request_info *info,
234 char *name, char *extra)
236 struct iw_param rate;
240 result = p80211wext_giwrate(dev, NULL, &rate, NULL);
247 switch (rate.value) {
250 strcpy(name, "IEEE 802.11-DS");
254 strcpy(name, "IEEE 802.11-b");
261 static int p80211wext_giwfreq(netdevice_t *dev,
262 struct iw_request_info *info,
263 struct iw_freq *freq, char *extra)
265 wlandevice_t *wlandev = dev->ml_priv;
266 p80211item_uint32_t mibitem;
267 p80211msg_dot11req_mibset_t msg;
271 msg.msgcode = DIDmsg_dot11req_mibget;
272 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
273 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
274 result = p80211req_dorequest(wlandev, (u8 *) & msg);
281 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
283 if (mibitem.data > NUM_CHANNELS) {
288 /* convert into frequency instead of a channel */
290 freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000;
296 static int p80211wext_siwfreq(netdevice_t *dev,
297 struct iw_request_info *info,
298 struct iw_freq *freq, char *extra)
300 wlandevice_t *wlandev = dev->ml_priv;
301 p80211item_uint32_t mibitem;
302 p80211msg_dot11req_mibset_t msg;
306 if (!wlan_wext_write) {
311 msg.msgcode = DIDmsg_dot11req_mibset;
312 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
313 mibitem.status = P80211ENUM_msgitem_status_data_ok;
315 if ((freq->e == 0) && (freq->m <= 1000))
316 mibitem.data = freq->m;
318 mibitem.data = p80211_mhz_to_channel(freq->m);
320 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
321 result = p80211req_dorequest(wlandev, (u8 *) & msg);
332 static int p80211wext_giwmode(netdevice_t *dev,
333 struct iw_request_info *info,
334 __u32 *mode, char *extra)
336 wlandevice_t *wlandev = dev->ml_priv;
338 switch (wlandev->macmode) {
339 case WLAN_MACMODE_IBSS_STA:
340 *mode = IW_MODE_ADHOC;
342 case WLAN_MACMODE_ESS_STA:
343 *mode = IW_MODE_INFRA;
345 case WLAN_MACMODE_ESS_AP:
346 *mode = IW_MODE_MASTER;
350 *mode = IW_MODE_AUTO;
356 static int p80211wext_siwmode(netdevice_t *dev,
357 struct iw_request_info *info,
358 __u32 *mode, char *extra)
360 wlandevice_t *wlandev = dev->ml_priv;
361 p80211item_uint32_t mibitem;
362 p80211msg_dot11req_mibset_t msg;
366 if (!wlan_wext_write) {
371 if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
372 *mode != IW_MODE_MASTER) {
377 /* Operation mode is the same with current mode */
378 if (*mode == wlandev->macmode)
383 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
386 wlandev->macmode = WLAN_MACMODE_ESS_STA;
389 wlandev->macmode = WLAN_MACMODE_ESS_AP;
393 printk(KERN_INFO "Operation mode: %d not support\n", *mode);
397 /* Set Operation mode to the PORT TYPE RID */
398 msg.msgcode = DIDmsg_dot11req_mibset;
399 mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
400 mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
401 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
402 result = p80211req_dorequest(wlandev, (u8 *) & msg);
411 static int p80211wext_giwrange(netdevice_t *dev,
412 struct iw_request_info *info,
413 struct iw_point *data, char *extra)
415 struct iw_range *range = (struct iw_range *)extra;
418 /* for backward compatability set size and zero everything we don't understand */
419 data->length = sizeof(*range);
420 memset(range, 0, sizeof(*range));
422 range->txpower_capa = IW_TXPOW_DBM;
423 /* XXX what about min/max_pmp, min/max_pmt, etc. */
425 range->we_version_compiled = WIRELESS_EXT;
426 range->we_version_source = 13;
428 range->retry_capa = IW_RETRY_LIMIT;
429 range->retry_flags = IW_RETRY_LIMIT;
430 range->min_retry = 0;
431 range->max_retry = 255;
433 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | /* mode/freq/ssid */
434 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
435 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
436 range->event_capa[1] = IW_EVENT_CAPA_K_1; /* encode */
437 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
438 IW_EVENT_CAPA_MASK(IWEVCUSTOM));
440 range->num_channels = NUM_CHANNELS;
442 /* XXX need to filter against the regulatory domain &| active set */
444 for (i = 0; i < NUM_CHANNELS; i++) {
445 range->freq[val].i = i + 1;
446 range->freq[val].m = p80211wext_channel_freq[i] * 100000;
447 range->freq[val].e = 1;
451 range->num_frequency = val;
453 /* Max of /proc/net/wireless */
454 range->max_qual.qual = 100;
455 range->max_qual.level = 0;
456 range->max_qual.noise = 0;
457 range->sensitivity = 3;
458 /* XXX these need to be nsd-specific! */
461 range->max_rts = 2347;
462 range->min_frag = 256;
463 range->max_frag = 2346;
465 range->max_encoding_tokens = NUM_WEPKEYS;
466 range->num_encoding_sizes = 2;
467 range->encoding_size[0] = 5;
468 range->encoding_size[1] = 13;
470 /* XXX what about num_bitrates/throughput? */
471 range->num_bitrates = 0;
473 /* estimated max throughput */
474 /* XXX need to cap it if we're running at ~2Mbps.. */
475 range->throughput = 5500000;
480 static int p80211wext_giwap(netdevice_t *dev,
481 struct iw_request_info *info,
482 struct sockaddr *ap_addr, char *extra)
485 wlandevice_t *wlandev = dev->ml_priv;
487 memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
488 ap_addr->sa_family = ARPHRD_ETHER;
493 static int p80211wext_giwencode(netdevice_t *dev,
494 struct iw_request_info *info,
495 struct iw_point *erq, char *key)
497 wlandevice_t *wlandev = dev->ml_priv;
501 i = (erq->flags & IW_ENCODE_INDEX) - 1;
504 if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
505 erq->flags |= IW_ENCODE_ENABLED;
507 erq->flags |= IW_ENCODE_DISABLED;
509 if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
510 erq->flags |= IW_ENCODE_RESTRICTED;
512 erq->flags |= IW_ENCODE_OPEN;
514 i = (erq->flags & IW_ENCODE_INDEX) - 1;
517 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
519 if ((i < 0) || (i >= NUM_WEPKEYS)) {
526 /* copy the key from the driver cache as the keys are read-only MIBs */
527 erq->length = wlandev->wep_keylens[i];
528 memcpy(key, wlandev->wep_keys[i], erq->length);
534 static int p80211wext_siwencode(netdevice_t *dev,
535 struct iw_request_info *info,
536 struct iw_point *erq, char *key)
538 wlandevice_t *wlandev = dev->ml_priv;
539 p80211msg_dot11req_mibset_t msg;
540 p80211item_pstr32_t pstr;
546 if (!wlan_wext_write) {
551 /* Check the Key index first. */
552 if ((i = (erq->flags & IW_ENCODE_INDEX))) {
554 if ((i < 1) || (i > NUM_WEPKEYS)) {
560 /* Set current key number only if no keys are given */
561 if (erq->flags & IW_ENCODE_NOKEY) {
563 p80211wext_dorequest(wlandev,
564 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
574 /* Use defaultkey if no Key Index */
575 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
578 /* Check if there is no key information in the iwconfig request */
579 if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
581 /*------------------------------------------------------------
582 * If there is WEP Key for setting, check the Key Information
583 * and then set it to the firmware.
584 -------------------------------------------------------------*/
586 if (erq->length > 0) {
588 /* copy the key from the driver cache as the keys are read-only MIBs */
589 wlandev->wep_keylens[i] = erq->length;
590 memcpy(wlandev->wep_keys[i], key, erq->length);
592 /* Prepare data struture for p80211req_dorequest. */
593 memcpy(pstr.data.data, key, erq->length);
594 pstr.data.len = erq->length;
599 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
604 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
609 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
614 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
622 msg.msgcode = DIDmsg_dot11req_mibset;
623 memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
624 result = p80211req_dorequest(wlandev, (u8 *) & msg);
634 /* Check the PrivacyInvoked flag */
635 if (erq->flags & IW_ENCODE_DISABLED) {
637 p80211wext_dorequest(wlandev,
638 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
639 P80211ENUM_truth_false);
642 p80211wext_dorequest(wlandev,
643 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
644 P80211ENUM_truth_true);
652 /* The security mode may be open or restricted, and its meaning
653 depends on the card used. With most cards, in open mode no
654 authentication is used and the card may also accept non-
655 encrypted sessions, whereas in restricted mode only encrypted
656 sessions are accepted and the card will use authentication if
659 if (erq->flags & IW_ENCODE_RESTRICTED) {
661 p80211wext_dorequest(wlandev,
662 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
663 P80211ENUM_truth_true);
664 } else if (erq->flags & IW_ENCODE_OPEN) {
666 p80211wext_dorequest(wlandev,
667 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
668 P80211ENUM_truth_false);
681 static int p80211wext_giwessid(netdevice_t *dev,
682 struct iw_request_info *info,
683 struct iw_point *data, char *essid)
685 wlandevice_t *wlandev = dev->ml_priv;
687 if (wlandev->ssid.len) {
688 data->length = wlandev->ssid.len;
690 memcpy(essid, wlandev->ssid.data, data->length);
691 essid[data->length] = 0;
692 #if (WIRELESS_EXT < 21)
696 memset(essid, 0, sizeof(wlandev->ssid.data));
704 static int p80211wext_siwessid(netdevice_t *dev,
705 struct iw_request_info *info,
706 struct iw_point *data, char *essid)
708 wlandevice_t *wlandev = dev->ml_priv;
709 p80211msg_lnxreq_autojoin_t msg;
713 int length = data->length;
715 if (!wlan_wext_write) {
720 if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
721 msg.authtype.data = P80211ENUM_authalg_sharedkey;
723 msg.authtype.data = P80211ENUM_authalg_opensystem;
725 msg.msgcode = DIDmsg_lnxreq_autojoin;
727 #if (WIRELESS_EXT < 21)
732 /* Trim the last '\0' to fit the SSID format */
733 if (length && essid[length - 1] == '\0')
736 memcpy(msg.ssid.data.data, essid, length);
737 msg.ssid.data.len = length;
739 pr_debug("autojoin_ssid for %s \n", essid);
740 result = p80211req_dorequest(wlandev, (u8 *) & msg);
741 pr_debug("autojoin_ssid %d\n", result);
752 static int p80211wext_siwcommit(netdevice_t *dev,
753 struct iw_request_info *info,
754 struct iw_point *data, char *essid)
756 wlandevice_t *wlandev = dev->ml_priv;
759 if (!wlan_wext_write) {
765 err = p80211wext_autojoin(wlandev);
771 static int p80211wext_giwrate(netdevice_t *dev,
772 struct iw_request_info *info,
773 struct iw_param *rrq, char *extra)
775 wlandevice_t *wlandev = dev->ml_priv;
776 p80211item_uint32_t mibitem;
777 p80211msg_dot11req_mibset_t msg;
781 msg.msgcode = DIDmsg_dot11req_mibget;
782 mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
783 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
784 result = p80211req_dorequest(wlandev, (u8 *) & msg);
791 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
793 rrq->fixed = 0; /* can it change? */
797 #define HFA384x_RATEBIT_1 ((u16)1)
798 #define HFA384x_RATEBIT_2 ((u16)2)
799 #define HFA384x_RATEBIT_5dot5 ((u16)4)
800 #define HFA384x_RATEBIT_11 ((u16)8)
802 switch (mibitem.data) {
803 case HFA384x_RATEBIT_1:
804 rrq->value = 1000000;
806 case HFA384x_RATEBIT_2:
807 rrq->value = 2000000;
809 case HFA384x_RATEBIT_5dot5:
810 rrq->value = 5500000;
812 case HFA384x_RATEBIT_11:
813 rrq->value = 11000000;
822 static int p80211wext_giwrts(netdevice_t *dev,
823 struct iw_request_info *info,
824 struct iw_param *rts, char *extra)
826 wlandevice_t *wlandev = dev->ml_priv;
827 p80211item_uint32_t mibitem;
828 p80211msg_dot11req_mibset_t msg;
832 msg.msgcode = DIDmsg_dot11req_mibget;
833 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
834 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
835 result = p80211req_dorequest(wlandev, (u8 *) & msg);
842 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
844 rts->value = mibitem.data;
845 rts->disabled = (rts->value == 2347);
852 static int p80211wext_siwrts(netdevice_t *dev,
853 struct iw_request_info *info,
854 struct iw_param *rts, char *extra)
856 wlandevice_t *wlandev = dev->ml_priv;
857 p80211item_uint32_t mibitem;
858 p80211msg_dot11req_mibset_t msg;
862 if (!wlan_wext_write) {
867 msg.msgcode = DIDmsg_dot11req_mibget;
868 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
872 mibitem.data = rts->value;
874 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
875 result = p80211req_dorequest(wlandev, (u8 *) & msg);
886 static int p80211wext_giwfrag(netdevice_t *dev,
887 struct iw_request_info *info,
888 struct iw_param *frag, char *extra)
890 wlandevice_t *wlandev = dev->ml_priv;
891 p80211item_uint32_t mibitem;
892 p80211msg_dot11req_mibset_t msg;
896 msg.msgcode = DIDmsg_dot11req_mibget;
898 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
899 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
900 result = p80211req_dorequest(wlandev, (u8 *) & msg);
907 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
909 frag->value = mibitem.data;
910 frag->disabled = (frag->value == 2346);
917 static int p80211wext_siwfrag(netdevice_t *dev,
918 struct iw_request_info *info,
919 struct iw_param *frag, char *extra)
921 wlandevice_t *wlandev = dev->ml_priv;
922 p80211item_uint32_t mibitem;
923 p80211msg_dot11req_mibset_t msg;
927 if (!wlan_wext_write) {
932 msg.msgcode = DIDmsg_dot11req_mibset;
934 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
939 mibitem.data = frag->value;
941 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
942 result = p80211req_dorequest(wlandev, (u8 *) & msg);
953 #ifndef IW_RETRY_LONG
954 #define IW_RETRY_LONG IW_RETRY_MAX
957 #ifndef IW_RETRY_SHORT
958 #define IW_RETRY_SHORT IW_RETRY_MIN
961 static int p80211wext_giwretry(netdevice_t *dev,
962 struct iw_request_info *info,
963 struct iw_param *rrq, char *extra)
965 wlandevice_t *wlandev = dev->ml_priv;
966 p80211item_uint32_t mibitem;
967 p80211msg_dot11req_mibset_t msg;
970 u16 shortretry, longretry, lifetime;
972 msg.msgcode = DIDmsg_dot11req_mibget;
973 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
975 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
976 result = p80211req_dorequest(wlandev, (u8 *) & msg);
983 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
985 shortretry = mibitem.data;
987 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
989 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
990 result = p80211req_dorequest(wlandev, (u8 *) & msg);
997 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
999 longretry = mibitem.data;
1002 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1004 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1005 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1012 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1014 lifetime = mibitem.data;
1018 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1019 rrq->flags = IW_RETRY_LIFETIME;
1020 rrq->value = lifetime * 1024;
1022 if (rrq->flags & IW_RETRY_LONG) {
1023 rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1024 rrq->value = longretry;
1026 rrq->flags = IW_RETRY_LIMIT;
1027 rrq->value = shortretry;
1028 if (shortretry != longretry)
1029 rrq->flags |= IW_RETRY_SHORT;
1038 static int p80211wext_siwretry(netdevice_t *dev,
1039 struct iw_request_info *info,
1040 struct iw_param *rrq, char *extra)
1042 wlandevice_t *wlandev = dev->ml_priv;
1043 p80211item_uint32_t mibitem;
1044 p80211msg_dot11req_mibset_t msg;
1048 if (!wlan_wext_write) {
1049 err = (-EOPNOTSUPP);
1053 if (rrq->disabled) {
1058 msg.msgcode = DIDmsg_dot11req_mibset;
1060 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1062 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1063 mibitem.data = rrq->value /= 1024;
1065 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1066 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1073 if (rrq->flags & IW_RETRY_LONG) {
1075 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1076 mibitem.data = rrq->value;
1078 memcpy(&msg.mibattribute.data, &mibitem,
1080 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1088 if (rrq->flags & IW_RETRY_SHORT) {
1090 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1091 mibitem.data = rrq->value;
1093 memcpy(&msg.mibattribute.data, &mibitem,
1095 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1109 static int p80211wext_siwtxpow(netdevice_t *dev,
1110 struct iw_request_info *info,
1111 struct iw_param *rrq, char *extra)
1113 wlandevice_t *wlandev = dev->ml_priv;
1114 p80211item_uint32_t mibitem;
1115 p80211msg_dot11req_mibset_t msg;
1119 if (!wlan_wext_write) {
1120 err = (-EOPNOTSUPP);
1124 msg.msgcode = DIDmsg_dot11req_mibset;
1126 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1127 if (rrq->fixed == 0)
1130 mibitem.data = rrq->value;
1131 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1132 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1143 static int p80211wext_giwtxpow(netdevice_t *dev,
1144 struct iw_request_info *info,
1145 struct iw_param *rrq, char *extra)
1147 wlandevice_t *wlandev = dev->ml_priv;
1148 p80211item_uint32_t mibitem;
1149 p80211msg_dot11req_mibset_t msg;
1153 msg.msgcode = DIDmsg_dot11req_mibget;
1155 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1157 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1158 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1165 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1167 /* XXX handle OFF by setting disabled = 1; */
1169 rrq->flags = 0; /* IW_TXPOW_DBM; */
1172 rrq->value = mibitem.data;
1178 static int p80211wext_siwspy(netdevice_t *dev,
1179 struct iw_request_info *info,
1180 struct iw_point *srq, char *extra)
1182 wlandevice_t *wlandev = dev->ml_priv;
1183 struct sockaddr address[IW_MAX_SPY];
1184 int number = srq->length;
1187 /* Copy the data from the input buffer */
1188 memcpy(address, extra, sizeof(struct sockaddr) * number);
1190 wlandev->spy_number = 0;
1194 /* extract the addresses */
1195 for (i = 0; i < number; i++) {
1197 memcpy(wlandev->spy_address[i], address[i].sa_data,
1202 memset(wlandev->spy_stat, 0,
1203 sizeof(struct iw_quality) * IW_MAX_SPY);
1205 /* set number of addresses */
1206 wlandev->spy_number = number;
1212 /* jkriegl: from orinoco, modified */
1213 static int p80211wext_giwspy(netdevice_t *dev,
1214 struct iw_request_info *info,
1215 struct iw_point *srq, char *extra)
1217 wlandevice_t *wlandev = dev->ml_priv;
1219 struct sockaddr address[IW_MAX_SPY];
1220 struct iw_quality spy_stat[IW_MAX_SPY];
1224 number = wlandev->spy_number;
1228 /* populate address and spy struct's */
1229 for (i = 0; i < number; i++) {
1230 memcpy(address[i].sa_data, wlandev->spy_address[i],
1232 address[i].sa_family = AF_UNIX;
1233 memcpy(&spy_stat[i], &wlandev->spy_stat[i],
1234 sizeof(struct iw_quality));
1237 /* reset update flag */
1238 for (i = 0; i < number; i++)
1239 wlandev->spy_stat[i].updated = 0;
1242 /* push stuff to user space */
1243 srq->length = number;
1244 memcpy(extra, address, sizeof(struct sockaddr) * number);
1245 memcpy(extra + sizeof(struct sockaddr) * number, spy_stat,
1246 sizeof(struct iw_quality) * number);
1251 static int prism2_result2err(int prism2_result)
1255 switch (prism2_result) {
1256 case P80211ENUM_resultcode_invalid_parameters:
1259 case P80211ENUM_resultcode_implementation_failure:
1262 case P80211ENUM_resultcode_not_supported:
1273 static int p80211wext_siwscan(netdevice_t *dev,
1274 struct iw_request_info *info,
1275 struct iw_point *srq, char *extra)
1277 wlandevice_t *wlandev = dev->ml_priv;
1278 p80211msg_dot11req_scan_t msg;
1283 if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1284 printk(KERN_ERR "Can't scan in AP mode\n");
1285 err = (-EOPNOTSUPP);
1289 memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1290 msg.msgcode = DIDmsg_dot11req_scan;
1291 msg.bsstype.data = P80211ENUM_bsstype_any;
1293 memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
1294 msg.bssid.data.len = 6;
1296 msg.scantype.data = P80211ENUM_scantype_active;
1297 msg.probedelay.data = 0;
1299 for (i = 1; i <= 14; i++)
1300 msg.channellist.data.data[i - 1] = i;
1301 msg.channellist.data.len = 14;
1303 msg.maxchanneltime.data = 250;
1304 msg.minchanneltime.data = 200;
1306 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1308 err = prism2_result2err(msg.resultcode.data);
1314 /* Helper to translate scan into Wireless Extensions scan results.
1315 * Inspired by the prism54 code, which was in turn inspired by the
1318 static char *wext_translate_bss(struct iw_request_info *info, char *current_ev,
1320 p80211msg_dot11req_scan_results_t *bss)
1322 struct iw_event iwe; /* Temporary buffer */
1324 /* The first entry must be the MAC address */
1325 memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1326 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1327 iwe.cmd = SIOCGIWAP;
1329 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1332 /* The following entries will be displayed in the same order we give them */
1335 if (bss->ssid.data.len > 0) {
1336 char essid[IW_ESSID_MAX_SIZE + 1];
1340 min_t(unsigned short, IW_ESSID_MAX_SIZE,
1341 bss->ssid.data.len);
1342 memset(&essid, 0, sizeof(essid));
1343 memcpy(&essid, bss->ssid.data.data, size);
1344 pr_debug(" essid size = %d\n", size);
1345 iwe.u.data.length = size;
1346 iwe.u.data.flags = 1;
1347 iwe.cmd = SIOCGIWESSID;
1349 iwe_stream_add_point(info, current_ev, end_buf, &iwe,
1351 pr_debug(" essid size OK.\n");
1354 switch (bss->bsstype.data) {
1355 case P80211ENUM_bsstype_infrastructure:
1356 iwe.u.mode = IW_MODE_MASTER;
1359 case P80211ENUM_bsstype_independent:
1360 iwe.u.mode = IW_MODE_ADHOC;
1367 iwe.cmd = SIOCGIWMODE;
1370 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1373 /* Encryption capability */
1374 if (bss->privacy.data == P80211ENUM_truth_true)
1375 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1377 iwe.u.data.flags = IW_ENCODE_DISABLED;
1378 iwe.u.data.length = 0;
1379 iwe.cmd = SIOCGIWENCODE;
1381 iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1383 /* Add frequency. (short) bss->channel is the frequency in MHz */
1384 iwe.u.freq.m = bss->dschannel.data;
1386 iwe.cmd = SIOCGIWFREQ;
1388 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1391 /* Add quality statistics */
1392 iwe.u.qual.level = bss->signal.data;
1393 iwe.u.qual.noise = bss->noise.data;
1394 /* do a simple SNR for quality */
1395 iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1398 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1404 static int p80211wext_giwscan(netdevice_t *dev,
1405 struct iw_request_info *info,
1406 struct iw_point *srq, char *extra)
1408 wlandevice_t *wlandev = dev->ml_priv;
1409 p80211msg_dot11req_scan_results_t msg;
1414 char *current_ev = extra;
1416 /* Since wireless tools doesn't really have a way of passing how
1417 * many scan results results there were back here, keep grabbing them
1421 memset(&msg, 0, sizeof(msg));
1422 msg.msgcode = DIDmsg_dot11req_scan_results;
1423 msg.bssindex.data = i;
1425 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1426 if ((result != 0) ||
1427 (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1432 wext_translate_bss(info, current_ev,
1433 extra + IW_SCAN_MAX_DATA, &msg);
1436 } while (i < IW_MAX_AP);
1438 srq->length = (current_ev - extra);
1439 srq->flags = 0; /* todo */
1441 if (result && !scan_good)
1442 err = prism2_result2err(msg.resultcode.data);
1447 /* extra wireless extensions stuff to support NetworkManager (I hope) */
1449 /* SIOCSIWENCODEEXT */
1450 static int p80211wext_set_encodeext(struct net_device *dev,
1451 struct iw_request_info *info,
1452 union iwreq_data *wrqu, char *extra)
1454 wlandevice_t *wlandev = dev->ml_priv;
1455 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1456 p80211msg_dot11req_mibset_t msg;
1457 p80211item_pstr32_t *pstr;
1460 struct iw_point *encoding = &wrqu->encoding;
1461 int idx = encoding->flags & IW_ENCODE_INDEX;
1463 pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1464 ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1466 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1467 /* set default key ? I'm not sure if this the the correct thing to do here */
1470 if (idx < 1 || idx > NUM_WEPKEYS)
1475 pr_debug("setting default key (%d)\n", idx);
1477 p80211wext_dorequest(wlandev,
1478 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
1484 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1485 if (ext->alg != IW_ENCODE_ALG_WEP) {
1486 pr_debug("asked to set a non wep key :(\n");
1490 if (idx < 1 || idx > NUM_WEPKEYS)
1495 pr_debug("Set WEP key (%d)\n", idx);
1496 wlandev->wep_keylens[idx] = ext->key_len;
1497 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1499 memset(&msg, 0, sizeof(msg));
1500 pstr = (p80211item_pstr32_t *) & msg.mibattribute.data;
1501 memcpy(pstr->data.data, ext->key, ext->key_len);
1502 pstr->data.len = ext->key_len;
1506 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1510 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1514 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1518 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1523 msg.msgcode = DIDmsg_dot11req_mibset;
1524 result = p80211req_dorequest(wlandev, (u8 *) & msg);
1525 pr_debug("result (%d)\n", result);
1530 /* SIOCGIWENCODEEXT */
1531 static int p80211wext_get_encodeext(struct net_device *dev,
1532 struct iw_request_info *info,
1533 union iwreq_data *wrqu, char *extra)
1535 wlandevice_t *wlandev = dev->ml_priv;
1536 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1538 struct iw_point *encoding = &wrqu->encoding;
1543 pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1544 ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1546 max_len = encoding->length - sizeof(*ext);
1548 pr_debug("get_encodeext max_len [%d] invalid\n", max_len);
1552 idx = encoding->flags & IW_ENCODE_INDEX;
1554 pr_debug("get_encode_ext index [%d]\n", idx);
1557 if (idx < 1 || idx > NUM_WEPKEYS) {
1558 pr_debug("get_encode_ext invalid key index [%d]\n",
1565 /* default key ? not sure what to do */
1566 /* will just use key[0] for now ! FIX ME */
1569 encoding->flags = idx + 1;
1570 memset(ext, 0, sizeof(*ext));
1572 ext->alg = IW_ENCODE_ALG_WEP;
1573 ext->key_len = wlandev->wep_keylens[idx];
1574 memcpy(ext->key, wlandev->wep_keys[idx], ext->key_len);
1576 encoding->flags |= IW_ENCODE_ENABLED;
1582 static int p80211_wext_set_iwauth(struct net_device *dev,
1583 struct iw_request_info *info,
1584 union iwreq_data *wrqu, char *extra)
1586 wlandevice_t *wlandev = dev->ml_priv;
1587 struct iw_param *param = &wrqu->param;
1590 pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1592 switch (param->flags & IW_AUTH_INDEX) {
1593 case IW_AUTH_DROP_UNENCRYPTED:
1594 pr_debug("drop_unencrypted %d\n", param->value);
1597 p80211wext_dorequest(wlandev,
1598 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1599 P80211ENUM_truth_true);
1602 p80211wext_dorequest(wlandev,
1603 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1604 P80211ENUM_truth_false);
1607 case IW_AUTH_PRIVACY_INVOKED:
1608 pr_debug("privacy invoked %d\n", param->value);
1611 p80211wext_dorequest(wlandev,
1612 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1613 P80211ENUM_truth_true);
1616 p80211wext_dorequest(wlandev,
1617 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1618 P80211ENUM_truth_false);
1622 case IW_AUTH_80211_AUTH_ALG:
1623 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1624 pr_debug("set open_system\n");
1625 wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1626 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1627 pr_debug("set shared key\n");
1628 wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1630 /* don't know what to do know */
1631 pr_debug("unknown AUTH_ALG (%d)\n", param->value);
1644 static int p80211_wext_get_iwauth(struct net_device *dev,
1645 struct iw_request_info *info,
1646 union iwreq_data *wrqu, char *extra)
1648 wlandevice_t *wlandev = dev->ml_priv;
1649 struct iw_param *param = &wrqu->param;
1652 pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1654 switch (param->flags & IW_AUTH_INDEX) {
1655 case IW_AUTH_DROP_UNENCRYPTED:
1657 wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
1660 case IW_AUTH_PRIVACY_INVOKED:
1662 wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
1665 case IW_AUTH_80211_AUTH_ALG:
1667 wlandev->hostwep & HOSTWEP_SHAREDKEY ?
1668 IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
1678 static iw_handler p80211wext_handlers[] = {
1679 (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */
1680 (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */
1681 (iw_handler) NULL, /* SIOCSIWNWID */
1682 (iw_handler) NULL, /* SIOCGIWNWID */
1683 (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */
1684 (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */
1685 (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */
1686 (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */
1687 (iw_handler) NULL, /* SIOCSIWSENS */
1688 (iw_handler) NULL, /* SIOCGIWSENS */
1689 (iw_handler) NULL, /* not used *//* SIOCSIWRANGE */
1690 (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */
1691 (iw_handler) NULL, /* not used *//* SIOCSIWPRIV */
1692 (iw_handler) NULL, /* kernel code *//* SIOCGIWPRIV */
1693 (iw_handler) NULL, /* not used *//* SIOCSIWSTATS */
1694 (iw_handler) NULL, /* kernel code *//* SIOCGIWSTATS */
1695 (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1696 (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1697 (iw_handler) NULL, /* -- hole -- */
1698 (iw_handler) NULL, /* -- hole -- */
1699 (iw_handler) NULL, /* SIOCSIWAP */
1700 (iw_handler) p80211wext_giwap, /* SIOCGIWAP */
1701 (iw_handler) NULL, /* -- hole -- */
1702 (iw_handler) NULL, /* SIOCGIWAPLIST */
1703 (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */
1704 (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */
1705 (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */
1706 (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */
1707 (iw_handler) NULL, /* SIOCSIWNICKN */
1708 (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */
1709 (iw_handler) NULL, /* -- hole -- */
1710 (iw_handler) NULL, /* -- hole -- */
1711 (iw_handler) NULL, /* SIOCSIWRATE */
1712 (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */
1713 (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1714 (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1715 (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
1716 (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
1717 (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */
1718 (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
1719 (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
1720 (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */
1721 (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */
1722 (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */
1723 (iw_handler) NULL, /* SIOCSIWPOWER */
1724 (iw_handler) NULL, /* SIOCGIWPOWER */
1725 /* WPA operations */
1726 (iw_handler) NULL, /* -- hole -- */
1727 (iw_handler) NULL, /* -- hole -- */
1728 (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */
1729 (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */
1730 (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */
1731 (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */
1733 (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */
1734 (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */
1735 (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */
1738 struct iw_handler_def p80211wext_handler_def = {
1739 .num_standard = ARRAY_SIZE(p80211wext_handlers),
1741 .num_private_args = 0,
1742 .standard = p80211wext_handlers,
1744 .private_args = NULL,
1745 .get_wireless_stats = p80211wext_get_wireless_stats
1748 int p80211wext_event_associated(wlandevice_t * wlandev, int assoc)
1750 union iwreq_data data;
1752 /* Send the association state first */
1753 data.ap_addr.sa_family = ARPHRD_ETHER;
1755 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
1757 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
1759 if (wlan_wext_write)
1760 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1765 /* XXX send association data, like IEs, etc etc. */