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 /*================================================================*/
42 #include <linux/kernel.h>
43 #include <linux/sched.h>
44 #include <linux/types.h>
45 #include <linux/slab.h>
46 #include <linux/netdevice.h>
47 #include <linux/etherdevice.h>
48 #include <linux/wireless.h>
49 #include <net/iw_handler.h>
50 #include <linux/if_arp.h>
51 #include <asm/bitops.h>
52 #include <asm/uaccess.h>
53 #include <asm/byteorder.h>
54 #include <linux/if_ether.h>
55 #include <linux/bitops.h>
57 /*================================================================*/
58 /* Project Includes */
60 #include "p80211types.h"
61 #include "p80211hdr.h"
62 #include "p80211conv.h"
63 #include "p80211mgmt.h"
64 #include "p80211msg.h"
65 #include "p80211metastruct.h"
66 #include "p80211metadef.h"
67 #include "p80211netdev.h"
68 #include "p80211ioctl.h"
69 #include "p80211req.h"
71 static int p80211wext_giwrate(netdevice_t *dev,
72 struct iw_request_info *info,
73 struct iw_param *rrq, char *extra);
74 static int p80211wext_giwessid(netdevice_t *dev,
75 struct iw_request_info *info,
76 struct iw_point *data, char *essid);
78 static u8 p80211_mhz_to_channel(u16 mhz)
81 return (mhz - 5000) / 5;
87 return (mhz - 2407) / 5;
92 static u16 p80211_channel_to_mhz(u8 ch, int dot11a)
102 return 5000 + (5 * ch);
108 if ((ch < 14) && (ch > 0))
109 return 2407 + (5 * ch);
114 /* taken from orinoco.c ;-) */
115 static const long p80211wext_channel_freq[] = {
116 2412, 2417, 2422, 2427, 2432, 2437, 2442,
117 2447, 2452, 2457, 2462, 2467, 2472, 2484
120 #define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
122 /* steal a spare bit to store the shared/opensystems state.
123 should default to open if not set */
124 #define HOSTWEP_SHAREDKEY BIT(3)
126 static int qual_as_percent(int snr)
135 static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data)
137 p80211msg_dot11req_mibset_t msg;
138 p80211item_uint32_t mibitem;
141 msg.msgcode = DIDmsg_dot11req_mibset;
144 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
145 result = p80211req_dorequest(wlandev, (u8 *)&msg);
150 static int p80211wext_autojoin(wlandevice_t *wlandev)
152 p80211msg_lnxreq_autojoin_t msg;
153 struct iw_point data;
154 char ssid[IW_ESSID_MAX_SIZE];
160 result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
167 if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
168 msg.authtype.data = P80211ENUM_authalg_sharedkey;
170 msg.authtype.data = P80211ENUM_authalg_opensystem;
172 msg.msgcode = DIDmsg_lnxreq_autojoin;
174 /* Trim the last '\0' to fit the SSID format */
176 if (data.length && ssid[data.length - 1] == '\0')
177 data.length = data.length - 1;
179 memcpy(msg.ssid.data.data, ssid, data.length);
180 msg.ssid.data.len = data.length;
182 result = p80211req_dorequest(wlandev, (u8 *)&msg);
195 /* called by /proc/net/wireless */
196 struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t * dev)
198 p80211msg_lnxreq_commsquality_t quality;
199 wlandevice_t *wlandev = dev->ml_priv;
200 struct iw_statistics *wstats = &wlandev->wstats;
204 if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
207 /* XXX Only valid in station mode */
210 /* build request message */
211 quality.msgcode = DIDmsg_lnxreq_commsquality;
212 quality.dbm.data = P80211ENUM_truth_true;
213 quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
215 /* send message to nsd */
216 if (wlandev->mlmerequest == NULL)
219 retval = wlandev->mlmerequest(wlandev, (p80211msg_t *)&quality);
221 wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
222 wstats->qual.level = quality.level.data; /* instant signal level */
223 wstats->qual.noise = quality.noise.data; /* instant noise level */
225 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
226 wstats->discard.code = wlandev->rx.decrypt_err;
227 wstats->discard.nwid = 0;
228 wstats->discard.misc = 0;
230 wstats->discard.fragment = 0; /* incomplete fragments */
231 wstats->discard.retries = 0; /* tx retries. */
232 wstats->miss.beacon = 0;
237 static int p80211wext_giwname(netdevice_t *dev,
238 struct iw_request_info *info,
239 char *name, char *extra)
241 struct iw_param rate;
245 result = p80211wext_giwrate(dev, NULL, &rate, NULL);
252 switch (rate.value) {
255 strcpy(name, "IEEE 802.11-DS");
259 strcpy(name, "IEEE 802.11-b");
266 static int p80211wext_giwfreq(netdevice_t *dev,
267 struct iw_request_info *info,
268 struct iw_freq *freq, char *extra)
270 wlandevice_t *wlandev = dev->ml_priv;
271 p80211item_uint32_t mibitem;
272 p80211msg_dot11req_mibset_t msg;
276 msg.msgcode = DIDmsg_dot11req_mibget;
277 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
278 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
279 result = p80211req_dorequest(wlandev, (u8 *)&msg);
286 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
288 if (mibitem.data > NUM_CHANNELS) {
293 /* convert into frequency instead of a channel */
295 freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000;
301 static int p80211wext_siwfreq(netdevice_t *dev,
302 struct iw_request_info *info,
303 struct iw_freq *freq, char *extra)
305 wlandevice_t *wlandev = dev->ml_priv;
306 p80211item_uint32_t mibitem;
307 p80211msg_dot11req_mibset_t msg;
311 if (!wlan_wext_write) {
316 msg.msgcode = DIDmsg_dot11req_mibset;
317 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
318 mibitem.status = P80211ENUM_msgitem_status_data_ok;
320 if ((freq->e == 0) && (freq->m <= 1000))
321 mibitem.data = freq->m;
323 mibitem.data = p80211_mhz_to_channel(freq->m);
325 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
326 result = p80211req_dorequest(wlandev, (u8 *)&msg);
337 static int p80211wext_giwmode(netdevice_t *dev,
338 struct iw_request_info *info,
339 __u32 *mode, char *extra)
341 wlandevice_t *wlandev = dev->ml_priv;
343 switch (wlandev->macmode) {
344 case WLAN_MACMODE_IBSS_STA:
345 *mode = IW_MODE_ADHOC;
347 case WLAN_MACMODE_ESS_STA:
348 *mode = IW_MODE_INFRA;
350 case WLAN_MACMODE_ESS_AP:
351 *mode = IW_MODE_MASTER;
355 *mode = IW_MODE_AUTO;
361 static int p80211wext_siwmode(netdevice_t *dev,
362 struct iw_request_info *info,
363 __u32 *mode, char *extra)
365 wlandevice_t *wlandev = dev->ml_priv;
366 p80211item_uint32_t mibitem;
367 p80211msg_dot11req_mibset_t msg;
371 if (!wlan_wext_write) {
376 if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
377 *mode != IW_MODE_MASTER) {
382 /* Operation mode is the same with current mode */
383 if (*mode == wlandev->macmode)
388 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
391 wlandev->macmode = WLAN_MACMODE_ESS_STA;
394 wlandev->macmode = WLAN_MACMODE_ESS_AP;
398 printk(KERN_INFO "Operation mode: %d not support\n", *mode);
402 /* Set Operation mode to the PORT TYPE RID */
403 msg.msgcode = DIDmsg_dot11req_mibset;
404 mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
405 mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
406 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
407 result = p80211req_dorequest(wlandev, (u8 *)&msg);
416 static int p80211wext_giwrange(netdevice_t *dev,
417 struct iw_request_info *info,
418 struct iw_point *data, char *extra)
420 struct iw_range *range = (struct iw_range *)extra;
423 /* for backward compatability set size and zero everything we don't understand */
424 data->length = sizeof(*range);
425 memset(range, 0, sizeof(*range));
427 range->txpower_capa = IW_TXPOW_DBM;
428 /* XXX what about min/max_pmp, min/max_pmt, etc. */
430 range->we_version_compiled = WIRELESS_EXT;
431 range->we_version_source = 13;
433 range->retry_capa = IW_RETRY_LIMIT;
434 range->retry_flags = IW_RETRY_LIMIT;
435 range->min_retry = 0;
436 range->max_retry = 255;
438 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | /* mode/freq/ssid */
439 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
440 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
441 range->event_capa[1] = IW_EVENT_CAPA_K_1; /* encode */
442 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
443 IW_EVENT_CAPA_MASK(IWEVCUSTOM));
445 range->num_channels = NUM_CHANNELS;
447 /* XXX need to filter against the regulatory domain &| active set */
449 for (i = 0; i < NUM_CHANNELS; i++) {
450 range->freq[val].i = i + 1;
451 range->freq[val].m = p80211wext_channel_freq[i] * 100000;
452 range->freq[val].e = 1;
456 range->num_frequency = val;
458 /* Max of /proc/net/wireless */
459 range->max_qual.qual = 100;
460 range->max_qual.level = 0;
461 range->max_qual.noise = 0;
462 range->sensitivity = 3;
463 /* XXX these need to be nsd-specific! */
466 range->max_rts = 2347;
467 range->min_frag = 256;
468 range->max_frag = 2346;
470 range->max_encoding_tokens = NUM_WEPKEYS;
471 range->num_encoding_sizes = 2;
472 range->encoding_size[0] = 5;
473 range->encoding_size[1] = 13;
475 /* XXX what about num_bitrates/throughput? */
476 range->num_bitrates = 0;
478 /* estimated max throughput */
479 /* XXX need to cap it if we're running at ~2Mbps.. */
480 range->throughput = 5500000;
485 static int p80211wext_giwap(netdevice_t *dev,
486 struct iw_request_info *info,
487 struct sockaddr *ap_addr, char *extra)
490 wlandevice_t *wlandev = dev->ml_priv;
492 memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
493 ap_addr->sa_family = ARPHRD_ETHER;
498 static int p80211wext_giwencode(netdevice_t *dev,
499 struct iw_request_info *info,
500 struct iw_point *erq, char *key)
502 wlandevice_t *wlandev = dev->ml_priv;
506 i = (erq->flags & IW_ENCODE_INDEX) - 1;
509 if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
510 erq->flags |= IW_ENCODE_ENABLED;
512 erq->flags |= IW_ENCODE_DISABLED;
514 if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
515 erq->flags |= IW_ENCODE_RESTRICTED;
517 erq->flags |= IW_ENCODE_OPEN;
519 i = (erq->flags & IW_ENCODE_INDEX) - 1;
522 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
524 if ((i < 0) || (i >= NUM_WEPKEYS)) {
531 /* copy the key from the driver cache as the keys are read-only MIBs */
532 erq->length = wlandev->wep_keylens[i];
533 memcpy(key, wlandev->wep_keys[i], erq->length);
539 static int p80211wext_siwencode(netdevice_t *dev,
540 struct iw_request_info *info,
541 struct iw_point *erq, char *key)
543 wlandevice_t *wlandev = dev->ml_priv;
544 p80211msg_dot11req_mibset_t msg;
545 p80211item_pstr32_t pstr;
551 if (!wlan_wext_write) {
556 /* Check the Key index first. */
557 if ((i = (erq->flags & IW_ENCODE_INDEX))) {
559 if ((i < 1) || (i > NUM_WEPKEYS)) {
565 /* Set current key number only if no keys are given */
566 if (erq->flags & IW_ENCODE_NOKEY) {
568 p80211wext_dorequest(wlandev,
569 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
579 /* Use defaultkey if no Key Index */
580 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
583 /* Check if there is no key information in the iwconfig request */
584 if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
586 /*------------------------------------------------------------
587 * If there is WEP Key for setting, check the Key Information
588 * and then set it to the firmware.
589 -------------------------------------------------------------*/
591 if (erq->length > 0) {
593 /* copy the key from the driver cache as the keys are read-only MIBs */
594 wlandev->wep_keylens[i] = erq->length;
595 memcpy(wlandev->wep_keys[i], key, erq->length);
597 /* Prepare data struture for p80211req_dorequest. */
598 memcpy(pstr.data.data, key, erq->length);
599 pstr.data.len = erq->length;
604 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
609 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
614 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
619 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
627 msg.msgcode = DIDmsg_dot11req_mibset;
628 memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
629 result = p80211req_dorequest(wlandev, (u8 *)&msg);
639 /* Check the PrivacyInvoked flag */
640 if (erq->flags & IW_ENCODE_DISABLED) {
642 p80211wext_dorequest(wlandev,
643 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
644 P80211ENUM_truth_false);
647 p80211wext_dorequest(wlandev,
648 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
649 P80211ENUM_truth_true);
657 /* The security mode may be open or restricted, and its meaning
658 depends on the card used. With most cards, in open mode no
659 authentication is used and the card may also accept non-
660 encrypted sessions, whereas in restricted mode only encrypted
661 sessions are accepted and the card will use authentication if
664 if (erq->flags & IW_ENCODE_RESTRICTED) {
666 p80211wext_dorequest(wlandev,
667 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
668 P80211ENUM_truth_true);
669 } else if (erq->flags & IW_ENCODE_OPEN) {
671 p80211wext_dorequest(wlandev,
672 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
673 P80211ENUM_truth_false);
686 static int p80211wext_giwessid(netdevice_t *dev,
687 struct iw_request_info *info,
688 struct iw_point *data, char *essid)
690 wlandevice_t *wlandev = dev->ml_priv;
692 if (wlandev->ssid.len) {
693 data->length = wlandev->ssid.len;
695 memcpy(essid, wlandev->ssid.data, data->length);
696 essid[data->length] = 0;
697 #if (WIRELESS_EXT < 21)
701 memset(essid, 0, sizeof(wlandev->ssid.data));
709 static int p80211wext_siwessid(netdevice_t *dev,
710 struct iw_request_info *info,
711 struct iw_point *data, char *essid)
713 wlandevice_t *wlandev = dev->ml_priv;
714 p80211msg_lnxreq_autojoin_t msg;
718 int length = data->length;
720 if (!wlan_wext_write) {
725 if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
726 msg.authtype.data = P80211ENUM_authalg_sharedkey;
728 msg.authtype.data = P80211ENUM_authalg_opensystem;
730 msg.msgcode = DIDmsg_lnxreq_autojoin;
732 #if (WIRELESS_EXT < 21)
737 /* Trim the last '\0' to fit the SSID format */
738 if (length && essid[length - 1] == '\0')
741 memcpy(msg.ssid.data.data, essid, length);
742 msg.ssid.data.len = length;
744 pr_debug("autojoin_ssid for %s \n", essid);
745 result = p80211req_dorequest(wlandev, (u8 *)&msg);
746 pr_debug("autojoin_ssid %d\n", result);
757 static int p80211wext_siwcommit(netdevice_t *dev,
758 struct iw_request_info *info,
759 struct iw_point *data, char *essid)
761 wlandevice_t *wlandev = dev->ml_priv;
764 if (!wlan_wext_write) {
770 err = p80211wext_autojoin(wlandev);
776 static int p80211wext_giwrate(netdevice_t *dev,
777 struct iw_request_info *info,
778 struct iw_param *rrq, char *extra)
780 wlandevice_t *wlandev = dev->ml_priv;
781 p80211item_uint32_t mibitem;
782 p80211msg_dot11req_mibset_t msg;
786 msg.msgcode = DIDmsg_dot11req_mibget;
787 mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
788 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
789 result = p80211req_dorequest(wlandev, (u8 *)&msg);
796 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
798 rrq->fixed = 0; /* can it change? */
802 #define HFA384x_RATEBIT_1 ((u16)1)
803 #define HFA384x_RATEBIT_2 ((u16)2)
804 #define HFA384x_RATEBIT_5dot5 ((u16)4)
805 #define HFA384x_RATEBIT_11 ((u16)8)
807 switch (mibitem.data) {
808 case HFA384x_RATEBIT_1:
809 rrq->value = 1000000;
811 case HFA384x_RATEBIT_2:
812 rrq->value = 2000000;
814 case HFA384x_RATEBIT_5dot5:
815 rrq->value = 5500000;
817 case HFA384x_RATEBIT_11:
818 rrq->value = 11000000;
827 static int p80211wext_giwrts(netdevice_t *dev,
828 struct iw_request_info *info,
829 struct iw_param *rts, char *extra)
831 wlandevice_t *wlandev = dev->ml_priv;
832 p80211item_uint32_t mibitem;
833 p80211msg_dot11req_mibset_t msg;
837 msg.msgcode = DIDmsg_dot11req_mibget;
838 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
839 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
840 result = p80211req_dorequest(wlandev, (u8 *)&msg);
847 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
849 rts->value = mibitem.data;
850 rts->disabled = (rts->value == 2347);
857 static int p80211wext_siwrts(netdevice_t *dev,
858 struct iw_request_info *info,
859 struct iw_param *rts, char *extra)
861 wlandevice_t *wlandev = dev->ml_priv;
862 p80211item_uint32_t mibitem;
863 p80211msg_dot11req_mibset_t msg;
867 if (!wlan_wext_write) {
872 msg.msgcode = DIDmsg_dot11req_mibget;
873 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
877 mibitem.data = rts->value;
879 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
880 result = p80211req_dorequest(wlandev, (u8 *)&msg);
891 static int p80211wext_giwfrag(netdevice_t *dev,
892 struct iw_request_info *info,
893 struct iw_param *frag, char *extra)
895 wlandevice_t *wlandev = dev->ml_priv;
896 p80211item_uint32_t mibitem;
897 p80211msg_dot11req_mibset_t msg;
901 msg.msgcode = DIDmsg_dot11req_mibget;
903 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
904 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
905 result = p80211req_dorequest(wlandev, (u8 *)&msg);
912 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
914 frag->value = mibitem.data;
915 frag->disabled = (frag->value == 2346);
922 static int p80211wext_siwfrag(netdevice_t *dev,
923 struct iw_request_info *info,
924 struct iw_param *frag, char *extra)
926 wlandevice_t *wlandev = dev->ml_priv;
927 p80211item_uint32_t mibitem;
928 p80211msg_dot11req_mibset_t msg;
932 if (!wlan_wext_write) {
937 msg.msgcode = DIDmsg_dot11req_mibset;
939 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
944 mibitem.data = frag->value;
946 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
947 result = p80211req_dorequest(wlandev, (u8 *)&msg);
958 #ifndef IW_RETRY_LONG
959 #define IW_RETRY_LONG IW_RETRY_MAX
962 #ifndef IW_RETRY_SHORT
963 #define IW_RETRY_SHORT IW_RETRY_MIN
966 static int p80211wext_giwretry(netdevice_t *dev,
967 struct iw_request_info *info,
968 struct iw_param *rrq, char *extra)
970 wlandevice_t *wlandev = dev->ml_priv;
971 p80211item_uint32_t mibitem;
972 p80211msg_dot11req_mibset_t msg;
975 u16 shortretry, longretry, lifetime;
977 msg.msgcode = DIDmsg_dot11req_mibget;
978 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
980 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
981 result = p80211req_dorequest(wlandev, (u8 *)&msg);
988 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
990 shortretry = mibitem.data;
992 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
994 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
995 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1002 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1004 longretry = mibitem.data;
1007 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1009 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1010 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1017 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1019 lifetime = mibitem.data;
1023 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1024 rrq->flags = IW_RETRY_LIFETIME;
1025 rrq->value = lifetime * 1024;
1027 if (rrq->flags & IW_RETRY_LONG) {
1028 rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1029 rrq->value = longretry;
1031 rrq->flags = IW_RETRY_LIMIT;
1032 rrq->value = shortretry;
1033 if (shortretry != longretry)
1034 rrq->flags |= IW_RETRY_SHORT;
1043 static int p80211wext_siwretry(netdevice_t *dev,
1044 struct iw_request_info *info,
1045 struct iw_param *rrq, char *extra)
1047 wlandevice_t *wlandev = dev->ml_priv;
1048 p80211item_uint32_t mibitem;
1049 p80211msg_dot11req_mibset_t msg;
1053 if (!wlan_wext_write) {
1054 err = (-EOPNOTSUPP);
1058 if (rrq->disabled) {
1063 msg.msgcode = DIDmsg_dot11req_mibset;
1065 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1067 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1068 mibitem.data = rrq->value /= 1024;
1070 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1071 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1078 if (rrq->flags & IW_RETRY_LONG) {
1080 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1081 mibitem.data = rrq->value;
1083 memcpy(&msg.mibattribute.data, &mibitem,
1085 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1093 if (rrq->flags & IW_RETRY_SHORT) {
1095 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1096 mibitem.data = rrq->value;
1098 memcpy(&msg.mibattribute.data, &mibitem,
1100 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1114 static int p80211wext_siwtxpow(netdevice_t *dev,
1115 struct iw_request_info *info,
1116 struct iw_param *rrq, char *extra)
1118 wlandevice_t *wlandev = dev->ml_priv;
1119 p80211item_uint32_t mibitem;
1120 p80211msg_dot11req_mibset_t msg;
1124 if (!wlan_wext_write) {
1125 err = (-EOPNOTSUPP);
1129 msg.msgcode = DIDmsg_dot11req_mibset;
1131 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1132 if (rrq->fixed == 0)
1135 mibitem.data = rrq->value;
1136 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1137 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1148 static int p80211wext_giwtxpow(netdevice_t *dev,
1149 struct iw_request_info *info,
1150 struct iw_param *rrq, char *extra)
1152 wlandevice_t *wlandev = dev->ml_priv;
1153 p80211item_uint32_t mibitem;
1154 p80211msg_dot11req_mibset_t msg;
1158 msg.msgcode = DIDmsg_dot11req_mibget;
1160 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1162 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1163 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1170 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1172 /* XXX handle OFF by setting disabled = 1; */
1174 rrq->flags = 0; /* IW_TXPOW_DBM; */
1177 rrq->value = mibitem.data;
1183 static int p80211wext_siwspy(netdevice_t *dev,
1184 struct iw_request_info *info,
1185 struct iw_point *srq, char *extra)
1187 wlandevice_t *wlandev = dev->ml_priv;
1188 struct sockaddr address[IW_MAX_SPY];
1189 int number = srq->length;
1192 /* Copy the data from the input buffer */
1193 memcpy(address, extra, sizeof(struct sockaddr) * number);
1195 wlandev->spy_number = 0;
1199 /* extract the addresses */
1200 for (i = 0; i < number; i++) {
1202 memcpy(wlandev->spy_address[i], address[i].sa_data,
1207 memset(wlandev->spy_stat, 0,
1208 sizeof(struct iw_quality) * IW_MAX_SPY);
1210 /* set number of addresses */
1211 wlandev->spy_number = number;
1217 /* jkriegl: from orinoco, modified */
1218 static int p80211wext_giwspy(netdevice_t *dev,
1219 struct iw_request_info *info,
1220 struct iw_point *srq, char *extra)
1222 wlandevice_t *wlandev = dev->ml_priv;
1224 struct sockaddr address[IW_MAX_SPY];
1225 struct iw_quality spy_stat[IW_MAX_SPY];
1229 number = wlandev->spy_number;
1233 /* populate address and spy struct's */
1234 for (i = 0; i < number; i++) {
1235 memcpy(address[i].sa_data, wlandev->spy_address[i],
1237 address[i].sa_family = AF_UNIX;
1238 memcpy(&spy_stat[i], &wlandev->spy_stat[i],
1239 sizeof(struct iw_quality));
1242 /* reset update flag */
1243 for (i = 0; i < number; i++)
1244 wlandev->spy_stat[i].updated = 0;
1247 /* push stuff to user space */
1248 srq->length = number;
1249 memcpy(extra, address, sizeof(struct sockaddr) * number);
1250 memcpy(extra + sizeof(struct sockaddr) * number, spy_stat,
1251 sizeof(struct iw_quality) * number);
1256 static int prism2_result2err(int prism2_result)
1260 switch (prism2_result) {
1261 case P80211ENUM_resultcode_invalid_parameters:
1264 case P80211ENUM_resultcode_implementation_failure:
1267 case P80211ENUM_resultcode_not_supported:
1278 static int p80211wext_siwscan(netdevice_t *dev,
1279 struct iw_request_info *info,
1280 struct iw_point *srq, char *extra)
1282 wlandevice_t *wlandev = dev->ml_priv;
1283 p80211msg_dot11req_scan_t msg;
1288 if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1289 printk(KERN_ERR "Can't scan in AP mode\n");
1290 err = (-EOPNOTSUPP);
1294 memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1295 msg.msgcode = DIDmsg_dot11req_scan;
1296 msg.bsstype.data = P80211ENUM_bsstype_any;
1298 memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
1299 msg.bssid.data.len = 6;
1301 msg.scantype.data = P80211ENUM_scantype_active;
1302 msg.probedelay.data = 0;
1304 for (i = 1; i <= 14; i++)
1305 msg.channellist.data.data[i - 1] = i;
1306 msg.channellist.data.len = 14;
1308 msg.maxchanneltime.data = 250;
1309 msg.minchanneltime.data = 200;
1311 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1313 err = prism2_result2err(msg.resultcode.data);
1319 /* Helper to translate scan into Wireless Extensions scan results.
1320 * Inspired by the prism54 code, which was in turn inspired by the
1323 static char *wext_translate_bss(struct iw_request_info *info, char *current_ev,
1325 p80211msg_dot11req_scan_results_t *bss)
1327 struct iw_event iwe; /* Temporary buffer */
1329 /* The first entry must be the MAC address */
1330 memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1331 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1332 iwe.cmd = SIOCGIWAP;
1334 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1337 /* The following entries will be displayed in the same order we give them */
1340 if (bss->ssid.data.len > 0) {
1341 char essid[IW_ESSID_MAX_SIZE + 1];
1345 min_t(unsigned short, IW_ESSID_MAX_SIZE,
1346 bss->ssid.data.len);
1347 memset(&essid, 0, sizeof(essid));
1348 memcpy(&essid, bss->ssid.data.data, size);
1349 pr_debug(" essid size = %d\n", size);
1350 iwe.u.data.length = size;
1351 iwe.u.data.flags = 1;
1352 iwe.cmd = SIOCGIWESSID;
1354 iwe_stream_add_point(info, current_ev, end_buf, &iwe,
1356 pr_debug(" essid size OK.\n");
1359 switch (bss->bsstype.data) {
1360 case P80211ENUM_bsstype_infrastructure:
1361 iwe.u.mode = IW_MODE_MASTER;
1364 case P80211ENUM_bsstype_independent:
1365 iwe.u.mode = IW_MODE_ADHOC;
1372 iwe.cmd = SIOCGIWMODE;
1375 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1378 /* Encryption capability */
1379 if (bss->privacy.data == P80211ENUM_truth_true)
1380 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1382 iwe.u.data.flags = IW_ENCODE_DISABLED;
1383 iwe.u.data.length = 0;
1384 iwe.cmd = SIOCGIWENCODE;
1386 iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1388 /* Add frequency. (short) bss->channel is the frequency in MHz */
1389 iwe.u.freq.m = bss->dschannel.data;
1391 iwe.cmd = SIOCGIWFREQ;
1393 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1396 /* Add quality statistics */
1397 iwe.u.qual.level = bss->signal.data;
1398 iwe.u.qual.noise = bss->noise.data;
1399 /* do a simple SNR for quality */
1400 iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1403 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1409 static int p80211wext_giwscan(netdevice_t *dev,
1410 struct iw_request_info *info,
1411 struct iw_point *srq, char *extra)
1413 wlandevice_t *wlandev = dev->ml_priv;
1414 p80211msg_dot11req_scan_results_t msg;
1419 char *current_ev = extra;
1421 /* Since wireless tools doesn't really have a way of passing how
1422 * many scan results results there were back here, keep grabbing them
1426 memset(&msg, 0, sizeof(msg));
1427 msg.msgcode = DIDmsg_dot11req_scan_results;
1428 msg.bssindex.data = i;
1430 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1431 if ((result != 0) ||
1432 (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1437 wext_translate_bss(info, current_ev,
1438 extra + IW_SCAN_MAX_DATA, &msg);
1441 } while (i < IW_MAX_AP);
1443 srq->length = (current_ev - extra);
1444 srq->flags = 0; /* todo */
1446 if (result && !scan_good)
1447 err = prism2_result2err(msg.resultcode.data);
1452 /* extra wireless extensions stuff to support NetworkManager (I hope) */
1454 /* SIOCSIWENCODEEXT */
1455 static int p80211wext_set_encodeext(struct net_device *dev,
1456 struct iw_request_info *info,
1457 union iwreq_data *wrqu, char *extra)
1459 wlandevice_t *wlandev = dev->ml_priv;
1460 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1461 p80211msg_dot11req_mibset_t msg;
1462 p80211item_pstr32_t *pstr;
1465 struct iw_point *encoding = &wrqu->encoding;
1466 int idx = encoding->flags & IW_ENCODE_INDEX;
1468 pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1469 ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1471 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1472 /* set default key ? I'm not sure if this the the correct thing to do here */
1475 if (idx < 1 || idx > NUM_WEPKEYS)
1480 pr_debug("setting default key (%d)\n", idx);
1482 p80211wext_dorequest(wlandev,
1483 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
1489 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1490 if (!(ext->alg & IW_ENCODE_ALG_WEP)) {
1491 pr_debug("asked to set a non wep key :(");
1495 if (idx < 1 || idx > NUM_WEPKEYS)
1500 pr_debug("Set WEP key (%d)\n", idx);
1501 wlandev->wep_keylens[idx] = ext->key_len;
1502 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1504 memset(&msg, 0, sizeof(msg));
1505 pstr = (p80211item_pstr32_t *)&msg.mibattribute.data;
1506 memcpy(pstr->data.data, ext->key, ext->key_len);
1507 pstr->data.len = ext->key_len;
1511 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1515 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1519 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1523 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1528 msg.msgcode = DIDmsg_dot11req_mibset;
1529 result = p80211req_dorequest(wlandev, (u8 *)&msg);
1530 pr_debug("result (%d)\n", result);
1535 /* SIOCGIWENCODEEXT */
1536 static int p80211wext_get_encodeext(struct net_device *dev,
1537 struct iw_request_info *info,
1538 union iwreq_data *wrqu, char *extra)
1540 wlandevice_t *wlandev = dev->ml_priv;
1541 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1543 struct iw_point *encoding = &wrqu->encoding;
1548 pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1549 ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1551 max_len = encoding->length - sizeof(*ext);
1553 pr_debug("get_encodeext max_len [%d] invalid\n",
1558 idx = encoding->flags & IW_ENCODE_INDEX;
1560 pr_debug("get_encode_ext index [%d]\n", idx);
1563 if (idx < 1 || idx > NUM_WEPKEYS) {
1565 "get_encode_ext invalid key index [%d]\n", idx);
1571 /* default key ? not sure what to do */
1572 /* will just use key[0] for now ! FIX ME */
1575 encoding->flags = idx + 1;
1576 memset(ext, 0, sizeof(*ext));
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);
1582 encoding->flags |= IW_ENCODE_ENABLED;
1588 static int p80211_wext_set_iwauth(struct net_device *dev,
1589 struct iw_request_info *info,
1590 union iwreq_data *wrqu, char *extra)
1592 wlandevice_t *wlandev = dev->ml_priv;
1593 struct iw_param *param = &wrqu->param;
1596 pr_debug("set_iwauth flags[%d]\n",
1597 (int)param->flags & IW_AUTH_INDEX);
1599 switch (param->flags & IW_AUTH_INDEX) {
1600 case IW_AUTH_DROP_UNENCRYPTED:
1601 pr_debug("drop_unencrypted %d\n", param->value);
1604 p80211wext_dorequest(wlandev,
1605 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1606 P80211ENUM_truth_true);
1609 p80211wext_dorequest(wlandev,
1610 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1611 P80211ENUM_truth_false);
1614 case IW_AUTH_PRIVACY_INVOKED:
1615 pr_debug("privacy invoked %d\n", param->value);
1618 p80211wext_dorequest(wlandev,
1619 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1620 P80211ENUM_truth_true);
1623 p80211wext_dorequest(wlandev,
1624 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1625 P80211ENUM_truth_false);
1629 case IW_AUTH_80211_AUTH_ALG:
1630 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1631 pr_debug("set open_system\n");
1632 wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1633 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1634 pr_debug("set shared key\n");
1635 wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1637 /* don't know what to do know */
1638 pr_debug("unknown AUTH_ALG (%d)\n",
1652 static int p80211_wext_get_iwauth(struct net_device *dev,
1653 struct iw_request_info *info,
1654 union iwreq_data *wrqu, char *extra)
1656 wlandevice_t *wlandev = dev->ml_priv;
1657 struct iw_param *param = &wrqu->param;
1660 pr_debug("get_iwauth flags[%d]\n",
1661 (int)param->flags & IW_AUTH_INDEX);
1663 switch (param->flags & IW_AUTH_INDEX) {
1664 case IW_AUTH_DROP_UNENCRYPTED:
1666 wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
1669 case IW_AUTH_PRIVACY_INVOKED:
1671 wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
1674 case IW_AUTH_80211_AUTH_ALG:
1677 hostwep & HOSTWEP_SHAREDKEY ? IW_AUTH_ALG_SHARED_KEY :
1678 IW_AUTH_ALG_OPEN_SYSTEM;
1688 static iw_handler p80211wext_handlers[] = {
1689 (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */
1690 (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */
1691 (iw_handler) NULL, /* SIOCSIWNWID */
1692 (iw_handler) NULL, /* SIOCGIWNWID */
1693 (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */
1694 (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */
1695 (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */
1696 (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */
1697 (iw_handler) NULL, /* SIOCSIWSENS */
1698 (iw_handler) NULL, /* SIOCGIWSENS */
1699 (iw_handler) NULL, /* not used *//* SIOCSIWRANGE */
1700 (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */
1701 (iw_handler) NULL, /* not used *//* SIOCSIWPRIV */
1702 (iw_handler) NULL, /* kernel code *//* SIOCGIWPRIV */
1703 (iw_handler) NULL, /* not used *//* SIOCSIWSTATS */
1704 (iw_handler) NULL, /* kernel code *//* SIOCGIWSTATS */
1705 (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1706 (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1707 (iw_handler) NULL, /* -- hole -- */
1708 (iw_handler) NULL, /* -- hole -- */
1709 (iw_handler) NULL, /* SIOCSIWAP */
1710 (iw_handler) p80211wext_giwap, /* SIOCGIWAP */
1711 (iw_handler) NULL, /* -- hole -- */
1712 (iw_handler) NULL, /* SIOCGIWAPLIST */
1713 (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */
1714 (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */
1715 (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */
1716 (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */
1717 (iw_handler) NULL, /* SIOCSIWNICKN */
1718 (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */
1719 (iw_handler) NULL, /* -- hole -- */
1720 (iw_handler) NULL, /* -- hole -- */
1721 (iw_handler) NULL, /* SIOCSIWRATE */
1722 (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */
1723 (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1724 (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1725 (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
1726 (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
1727 (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */
1728 (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
1729 (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
1730 (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */
1731 (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */
1732 (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */
1733 (iw_handler) NULL, /* SIOCSIWPOWER */
1734 (iw_handler) NULL, /* SIOCGIWPOWER */
1735 /* WPA operations */
1736 (iw_handler) NULL, /* -- hole -- */
1737 (iw_handler) NULL, /* -- hole -- */
1738 (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */
1739 (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */
1740 (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */
1741 (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */
1743 (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */
1744 (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */
1745 (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */
1748 struct iw_handler_def p80211wext_handler_def = {
1749 .num_standard = ARRAY_SIZE(p80211wext_handlers),
1751 .num_private_args = 0,
1752 .standard = p80211wext_handlers,
1754 .private_args = NULL,
1755 .get_wireless_stats = p80211wext_get_wireless_stats
1758 int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
1760 union iwreq_data data;
1762 /* Send the association state first */
1763 data.ap_addr.sa_family = ARPHRD_ETHER;
1765 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
1767 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
1769 if (wlan_wext_write)
1770 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1775 /* XXX send association data, like IEs, etc etc. */