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/netdevice.h>
44 #include <linux/etherdevice.h>
45 #include <linux/wireless.h>
46 #include <net/iw_handler.h>
47 #include <linux/if_arp.h>
48 #include <linux/bitops.h>
49 #include <linux/uaccess.h>
50 #include <asm/byteorder.h>
51 #include <linux/if_ether.h>
53 #include "p80211types.h"
54 #include "p80211hdr.h"
55 #include "p80211conv.h"
56 #include "p80211mgmt.h"
57 #include "p80211msg.h"
58 #include "p80211metastruct.h"
59 #include "p80211metadef.h"
60 #include "p80211netdev.h"
61 #include "p80211ioctl.h"
62 #include "p80211req.h"
64 static int p80211wext_giwrate(netdevice_t *dev,
65 struct iw_request_info *info,
66 struct iw_param *rrq, char *extra);
67 static int p80211wext_giwessid(netdevice_t *dev,
68 struct iw_request_info *info,
69 struct iw_point *data, char *essid);
71 static u8 p80211_mhz_to_channel(u16 mhz)
74 return (mhz - 5000) / 5;
80 return (mhz - 2407) / 5;
85 static u16 p80211_channel_to_mhz(u8 ch, int dot11a)
95 return 5000 + (5 * ch);
101 if ((ch < 14) && (ch > 0))
102 return 2407 + (5 * ch);
107 /* taken from orinoco.c ;-) */
108 static const long p80211wext_channel_freq[] = {
109 2412, 2417, 2422, 2427, 2432, 2437, 2442,
110 2447, 2452, 2457, 2462, 2467, 2472, 2484
113 #define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
115 /* steal a spare bit to store the shared/opensystems state.
116 should default to open if not set */
117 #define HOSTWEP_SHAREDKEY BIT(3)
119 static int qual_as_percent(int snr)
128 static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data)
130 p80211msg_dot11req_mibset_t msg;
131 p80211item_uint32_t mibitem;
134 msg.msgcode = DIDmsg_dot11req_mibset;
135 memset(&mibitem, 0, sizeof(mibitem));
138 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
139 result = p80211req_dorequest(wlandev, (u8 *) &msg);
144 static int p80211wext_autojoin(wlandevice_t *wlandev)
146 p80211msg_lnxreq_autojoin_t msg;
147 struct iw_point data;
148 char ssid[IW_ESSID_MAX_SIZE];
154 result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
161 if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
162 msg.authtype.data = P80211ENUM_authalg_sharedkey;
164 msg.authtype.data = P80211ENUM_authalg_opensystem;
166 msg.msgcode = DIDmsg_lnxreq_autojoin;
168 /* Trim the last '\0' to fit the SSID format */
170 if (data.length && ssid[data.length - 1] == '\0')
171 data.length = data.length - 1;
173 memcpy(msg.ssid.data.data, ssid, data.length);
174 msg.ssid.data.len = data.length;
176 result = p80211req_dorequest(wlandev, (u8 *) &msg);
189 /* called by /proc/net/wireless */
190 struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev)
192 p80211msg_lnxreq_commsquality_t quality;
193 wlandevice_t *wlandev = dev->ml_priv;
194 struct iw_statistics *wstats = &wlandev->wstats;
198 if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
201 /* XXX Only valid in station mode */
204 /* build request message */
205 quality.msgcode = DIDmsg_lnxreq_commsquality;
206 quality.dbm.data = P80211ENUM_truth_true;
207 quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
209 /* send message to nsd */
210 if (wlandev->mlmerequest == NULL)
213 retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) &quality);
215 wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
216 wstats->qual.level = quality.level.data; /* instant signal level */
217 wstats->qual.noise = quality.noise.data; /* instant noise level */
219 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
220 wstats->discard.code = wlandev->rx.decrypt_err;
221 wstats->discard.nwid = 0;
222 wstats->discard.misc = 0;
224 wstats->discard.fragment = 0; /* incomplete fragments */
225 wstats->discard.retries = 0; /* tx retries. */
226 wstats->miss.beacon = 0;
231 static int p80211wext_giwname(netdevice_t *dev,
232 struct iw_request_info *info,
233 char *name, char *extra)
235 struct iw_param rate;
239 result = p80211wext_giwrate(dev, NULL, &rate, NULL);
246 switch (rate.value) {
249 strcpy(name, "IEEE 802.11-DS");
253 strcpy(name, "IEEE 802.11-b");
260 static int p80211wext_giwfreq(netdevice_t *dev,
261 struct iw_request_info *info,
262 struct iw_freq *freq, char *extra)
264 wlandevice_t *wlandev = dev->ml_priv;
265 p80211item_uint32_t mibitem;
266 p80211msg_dot11req_mibset_t msg;
270 msg.msgcode = DIDmsg_dot11req_mibget;
271 memset(&mibitem, 0, sizeof(mibitem));
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 memset(&mibitem, 0, sizeof(mibitem));
313 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
314 mibitem.status = P80211ENUM_msgitem_status_data_ok;
316 if ((freq->e == 0) && (freq->m <= 1000))
317 mibitem.data = freq->m;
319 mibitem.data = p80211_mhz_to_channel(freq->m);
321 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
322 result = p80211req_dorequest(wlandev, (u8 *) &msg);
333 static int p80211wext_giwmode(netdevice_t *dev,
334 struct iw_request_info *info,
335 __u32 *mode, char *extra)
337 wlandevice_t *wlandev = dev->ml_priv;
339 switch (wlandev->macmode) {
340 case WLAN_MACMODE_IBSS_STA:
341 *mode = IW_MODE_ADHOC;
343 case WLAN_MACMODE_ESS_STA:
344 *mode = IW_MODE_INFRA;
346 case WLAN_MACMODE_ESS_AP:
347 *mode = IW_MODE_MASTER;
351 *mode = IW_MODE_AUTO;
357 static int p80211wext_siwmode(netdevice_t *dev,
358 struct iw_request_info *info,
359 __u32 *mode, char *extra)
361 wlandevice_t *wlandev = dev->ml_priv;
362 p80211item_uint32_t mibitem;
363 p80211msg_dot11req_mibset_t msg;
367 if (!wlan_wext_write) {
372 if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
373 *mode != IW_MODE_MASTER) {
378 /* Operation mode is the same with current mode */
379 if (*mode == wlandev->macmode)
384 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
387 wlandev->macmode = WLAN_MACMODE_ESS_STA;
390 wlandev->macmode = WLAN_MACMODE_ESS_AP;
394 printk(KERN_INFO "Operation mode: %d not support\n", *mode);
398 /* Set Operation mode to the PORT TYPE RID */
399 msg.msgcode = DIDmsg_dot11req_mibset;
400 memset(&mibitem, 0, sizeof(mibitem));
401 mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
402 mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
403 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
404 result = p80211req_dorequest(wlandev, (u8 *) &msg);
413 static int p80211wext_giwrange(netdevice_t *dev,
414 struct iw_request_info *info,
415 struct iw_point *data, char *extra)
417 struct iw_range *range = (struct iw_range *)extra;
420 /* for backward compatability set size and zero everything we don't understand */
421 data->length = sizeof(*range);
422 memset(range, 0, sizeof(*range));
424 range->txpower_capa = IW_TXPOW_DBM;
425 /* XXX what about min/max_pmp, min/max_pmt, etc. */
427 range->we_version_compiled = WIRELESS_EXT;
428 range->we_version_source = 13;
430 range->retry_capa = IW_RETRY_LIMIT;
431 range->retry_flags = IW_RETRY_LIMIT;
432 range->min_retry = 0;
433 range->max_retry = 255;
435 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | /* mode/freq/ssid */
436 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
437 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
438 range->event_capa[1] = IW_EVENT_CAPA_K_1; /* encode */
439 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
440 IW_EVENT_CAPA_MASK(IWEVCUSTOM));
442 range->num_channels = NUM_CHANNELS;
444 /* XXX need to filter against the regulatory domain &| active set */
446 for (i = 0; i < NUM_CHANNELS; i++) {
447 range->freq[val].i = i + 1;
448 range->freq[val].m = p80211wext_channel_freq[i] * 100000;
449 range->freq[val].e = 1;
453 range->num_frequency = val;
455 /* Max of /proc/net/wireless */
456 range->max_qual.qual = 100;
457 range->max_qual.level = 0;
458 range->max_qual.noise = 0;
459 range->sensitivity = 3;
460 /* XXX these need to be nsd-specific! */
463 range->max_rts = 2347;
464 range->min_frag = 256;
465 range->max_frag = 2346;
467 range->max_encoding_tokens = NUM_WEPKEYS;
468 range->num_encoding_sizes = 2;
469 range->encoding_size[0] = 5;
470 range->encoding_size[1] = 13;
472 /* XXX what about num_bitrates/throughput? */
473 range->num_bitrates = 0;
475 /* estimated max throughput */
476 /* XXX need to cap it if we're running at ~2Mbps.. */
477 range->throughput = 5500000;
482 static int p80211wext_giwap(netdevice_t *dev,
483 struct iw_request_info *info,
484 struct sockaddr *ap_addr, char *extra)
487 wlandevice_t *wlandev = dev->ml_priv;
489 memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
490 ap_addr->sa_family = ARPHRD_ETHER;
495 static int p80211wext_giwencode(netdevice_t *dev,
496 struct iw_request_info *info,
497 struct iw_point *erq, char *key)
499 wlandevice_t *wlandev = dev->ml_priv;
503 i = (erq->flags & IW_ENCODE_INDEX) - 1;
506 if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
507 erq->flags |= IW_ENCODE_ENABLED;
509 erq->flags |= IW_ENCODE_DISABLED;
511 if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
512 erq->flags |= IW_ENCODE_RESTRICTED;
514 erq->flags |= IW_ENCODE_OPEN;
516 i = (erq->flags & IW_ENCODE_INDEX) - 1;
519 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
521 if ((i < 0) || (i >= NUM_WEPKEYS)) {
528 /* copy the key from the driver cache as the keys are read-only MIBs */
529 erq->length = wlandev->wep_keylens[i];
530 memcpy(key, wlandev->wep_keys[i], erq->length);
536 static int p80211wext_siwencode(netdevice_t *dev,
537 struct iw_request_info *info,
538 struct iw_point *erq, char *key)
540 wlandevice_t *wlandev = dev->ml_priv;
541 p80211msg_dot11req_mibset_t msg;
542 p80211item_pstr32_t pstr;
548 if (!wlan_wext_write) {
553 /* Check the Key index first. */
554 i = (erq->flags & IW_ENCODE_INDEX);
556 if ((i < 1) || (i > NUM_WEPKEYS)) {
562 /* Set current key number only if no keys are given */
563 if (erq->flags & IW_ENCODE_NOKEY) {
565 p80211wext_dorequest(wlandev,
566 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
576 /* Use defaultkey if no Key Index */
577 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
580 /* Check if there is no key information in the iwconfig request */
581 if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
583 /*------------------------------------------------------------
584 * If there is WEP Key for setting, check the Key Information
585 * and then set it to the firmware.
586 -------------------------------------------------------------*/
588 if (erq->length > 0) {
590 /* copy the key from the driver cache as the keys are read-only MIBs */
591 wlandev->wep_keylens[i] = erq->length;
592 memcpy(wlandev->wep_keys[i], key, erq->length);
594 /* Prepare data struture for p80211req_dorequest. */
595 memcpy(pstr.data.data, key, erq->length);
596 pstr.data.len = erq->length;
601 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
606 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
611 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
616 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
624 msg.msgcode = DIDmsg_dot11req_mibset;
625 memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
626 result = p80211req_dorequest(wlandev, (u8 *) &msg);
636 /* Check the PrivacyInvoked flag */
637 if (erq->flags & IW_ENCODE_DISABLED) {
639 p80211wext_dorequest(wlandev,
640 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
641 P80211ENUM_truth_false);
644 p80211wext_dorequest(wlandev,
645 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
646 P80211ENUM_truth_true);
654 /* The security mode may be open or restricted, and its meaning
655 depends on the card used. With most cards, in open mode no
656 authentication is used and the card may also accept non-
657 encrypted sessions, whereas in restricted mode only encrypted
658 sessions are accepted and the card will use authentication if
661 if (erq->flags & IW_ENCODE_RESTRICTED) {
663 p80211wext_dorequest(wlandev,
664 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
665 P80211ENUM_truth_true);
666 } else if (erq->flags & IW_ENCODE_OPEN) {
668 p80211wext_dorequest(wlandev,
669 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
670 P80211ENUM_truth_false);
683 static int p80211wext_giwessid(netdevice_t *dev,
684 struct iw_request_info *info,
685 struct iw_point *data, char *essid)
687 wlandevice_t *wlandev = dev->ml_priv;
689 if (wlandev->ssid.len) {
690 data->length = wlandev->ssid.len;
692 memcpy(essid, wlandev->ssid.data, data->length);
693 essid[data->length] = 0;
695 memset(essid, 0, sizeof(wlandev->ssid.data));
703 static int p80211wext_siwessid(netdevice_t *dev,
704 struct iw_request_info *info,
705 struct iw_point *data, char *essid)
707 wlandevice_t *wlandev = dev->ml_priv;
708 p80211msg_lnxreq_autojoin_t msg;
712 int length = data->length;
714 if (!wlan_wext_write) {
719 if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
720 msg.authtype.data = P80211ENUM_authalg_sharedkey;
722 msg.authtype.data = P80211ENUM_authalg_opensystem;
724 msg.msgcode = DIDmsg_lnxreq_autojoin;
726 /* Trim the last '\0' to fit the SSID format */
727 if (length && essid[length - 1] == '\0')
730 memcpy(msg.ssid.data.data, essid, length);
731 msg.ssid.data.len = length;
733 pr_debug("autojoin_ssid for %s \n", essid);
734 result = p80211req_dorequest(wlandev, (u8 *) &msg);
735 pr_debug("autojoin_ssid %d\n", result);
746 static int p80211wext_siwcommit(netdevice_t *dev,
747 struct iw_request_info *info,
748 struct iw_point *data, char *essid)
750 wlandevice_t *wlandev = dev->ml_priv;
753 if (!wlan_wext_write) {
759 err = p80211wext_autojoin(wlandev);
765 static int p80211wext_giwrate(netdevice_t *dev,
766 struct iw_request_info *info,
767 struct iw_param *rrq, char *extra)
769 wlandevice_t *wlandev = dev->ml_priv;
770 p80211item_uint32_t mibitem;
771 p80211msg_dot11req_mibset_t msg;
775 msg.msgcode = DIDmsg_dot11req_mibget;
776 memset(&mibitem, 0, sizeof(mibitem));
777 mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
778 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
779 result = p80211req_dorequest(wlandev, (u8 *) &msg);
786 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
788 rrq->fixed = 0; /* can it change? */
792 #define HFA384x_RATEBIT_1 ((u16)1)
793 #define HFA384x_RATEBIT_2 ((u16)2)
794 #define HFA384x_RATEBIT_5dot5 ((u16)4)
795 #define HFA384x_RATEBIT_11 ((u16)8)
797 switch (mibitem.data) {
798 case HFA384x_RATEBIT_1:
799 rrq->value = 1000000;
801 case HFA384x_RATEBIT_2:
802 rrq->value = 2000000;
804 case HFA384x_RATEBIT_5dot5:
805 rrq->value = 5500000;
807 case HFA384x_RATEBIT_11:
808 rrq->value = 11000000;
817 static int p80211wext_giwrts(netdevice_t *dev,
818 struct iw_request_info *info,
819 struct iw_param *rts, char *extra)
821 wlandevice_t *wlandev = dev->ml_priv;
822 p80211item_uint32_t mibitem;
823 p80211msg_dot11req_mibset_t msg;
827 msg.msgcode = DIDmsg_dot11req_mibget;
828 memset(&mibitem, 0, sizeof(mibitem));
829 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
830 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
831 result = p80211req_dorequest(wlandev, (u8 *) &msg);
838 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
840 rts->value = mibitem.data;
841 rts->disabled = (rts->value == 2347);
848 static int p80211wext_siwrts(netdevice_t *dev,
849 struct iw_request_info *info,
850 struct iw_param *rts, char *extra)
852 wlandevice_t *wlandev = dev->ml_priv;
853 p80211item_uint32_t mibitem;
854 p80211msg_dot11req_mibset_t msg;
858 if (!wlan_wext_write) {
863 msg.msgcode = DIDmsg_dot11req_mibget;
864 memset(&mibitem, 0, sizeof(mibitem));
865 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
869 mibitem.data = rts->value;
871 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
872 result = p80211req_dorequest(wlandev, (u8 *) &msg);
883 static int p80211wext_giwfrag(netdevice_t *dev,
884 struct iw_request_info *info,
885 struct iw_param *frag, char *extra)
887 wlandevice_t *wlandev = dev->ml_priv;
888 p80211item_uint32_t mibitem;
889 p80211msg_dot11req_mibset_t msg;
893 msg.msgcode = DIDmsg_dot11req_mibget;
894 memset(&mibitem, 0, sizeof(mibitem));
896 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
897 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
898 result = p80211req_dorequest(wlandev, (u8 *) &msg);
905 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
907 frag->value = mibitem.data;
908 frag->disabled = (frag->value == 2346);
915 static int p80211wext_siwfrag(netdevice_t *dev,
916 struct iw_request_info *info,
917 struct iw_param *frag, char *extra)
919 wlandevice_t *wlandev = dev->ml_priv;
920 p80211item_uint32_t mibitem;
921 p80211msg_dot11req_mibset_t msg;
925 if (!wlan_wext_write) {
930 msg.msgcode = DIDmsg_dot11req_mibset;
931 memset(&mibitem, 0, sizeof(mibitem));
933 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
938 mibitem.data = frag->value;
940 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
941 result = p80211req_dorequest(wlandev, (u8 *) &msg);
952 #ifndef IW_RETRY_LONG
953 #define IW_RETRY_LONG IW_RETRY_MAX
956 #ifndef IW_RETRY_SHORT
957 #define IW_RETRY_SHORT IW_RETRY_MIN
960 static int p80211wext_giwretry(netdevice_t *dev,
961 struct iw_request_info *info,
962 struct iw_param *rrq, char *extra)
964 wlandevice_t *wlandev = dev->ml_priv;
965 p80211item_uint32_t mibitem;
966 p80211msg_dot11req_mibset_t msg;
969 u16 shortretry, longretry, lifetime;
971 msg.msgcode = DIDmsg_dot11req_mibget;
972 memset(&mibitem, 0, sizeof(mibitem));
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 memset(&mibitem, 0, sizeof(mibitem));
1050 if (!wlan_wext_write) {
1051 err = (-EOPNOTSUPP);
1055 if (rrq->disabled) {
1060 msg.msgcode = DIDmsg_dot11req_mibset;
1062 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1064 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1065 mibitem.data = rrq->value /= 1024;
1067 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1068 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1075 if (rrq->flags & IW_RETRY_LONG) {
1077 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1078 mibitem.data = rrq->value;
1080 memcpy(&msg.mibattribute.data, &mibitem,
1082 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1090 if (rrq->flags & IW_RETRY_SHORT) {
1092 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1093 mibitem.data = rrq->value;
1095 memcpy(&msg.mibattribute.data, &mibitem,
1097 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1111 static int p80211wext_siwtxpow(netdevice_t *dev,
1112 struct iw_request_info *info,
1113 struct iw_param *rrq, char *extra)
1115 wlandevice_t *wlandev = dev->ml_priv;
1116 p80211item_uint32_t mibitem;
1117 p80211msg_dot11req_mibset_t msg;
1121 if (!wlan_wext_write) {
1122 err = (-EOPNOTSUPP);
1126 msg.msgcode = DIDmsg_dot11req_mibset;
1127 memset(&mibitem, 0, sizeof(mibitem));
1129 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1130 if (rrq->fixed == 0)
1133 mibitem.data = rrq->value;
1134 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1135 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1146 static int p80211wext_giwtxpow(netdevice_t *dev,
1147 struct iw_request_info *info,
1148 struct iw_param *rrq, char *extra)
1150 wlandevice_t *wlandev = dev->ml_priv;
1151 p80211item_uint32_t mibitem;
1152 p80211msg_dot11req_mibset_t msg;
1156 msg.msgcode = DIDmsg_dot11req_mibget;
1158 memset(&mibitem, 0, sizeof(mibitem));
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 :(\n");
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", max_len);
1557 idx = encoding->flags & IW_ENCODE_INDEX;
1559 pr_debug("get_encode_ext index [%d]\n", idx);
1562 if (idx < 1 || idx > NUM_WEPKEYS) {
1563 pr_debug("get_encode_ext invalid key index [%d]\n",
1570 /* default key ? not sure what to do */
1571 /* will just use key[0] for now ! FIX ME */
1574 encoding->flags = idx + 1;
1575 memset(ext, 0, sizeof(*ext));
1577 ext->alg = IW_ENCODE_ALG_WEP;
1578 ext->key_len = wlandev->wep_keylens[idx];
1579 memcpy(ext->key, wlandev->wep_keys[idx], ext->key_len);
1581 encoding->flags |= IW_ENCODE_ENABLED;
1587 static int p80211_wext_set_iwauth(struct net_device *dev,
1588 struct iw_request_info *info,
1589 union iwreq_data *wrqu, char *extra)
1591 wlandevice_t *wlandev = dev->ml_priv;
1592 struct iw_param *param = &wrqu->param;
1595 pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1597 switch (param->flags & IW_AUTH_INDEX) {
1598 case IW_AUTH_DROP_UNENCRYPTED:
1599 pr_debug("drop_unencrypted %d\n", param->value);
1602 p80211wext_dorequest(wlandev,
1603 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1604 P80211ENUM_truth_true);
1607 p80211wext_dorequest(wlandev,
1608 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1609 P80211ENUM_truth_false);
1612 case IW_AUTH_PRIVACY_INVOKED:
1613 pr_debug("privacy invoked %d\n", param->value);
1616 p80211wext_dorequest(wlandev,
1617 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1618 P80211ENUM_truth_true);
1621 p80211wext_dorequest(wlandev,
1622 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1623 P80211ENUM_truth_false);
1627 case IW_AUTH_80211_AUTH_ALG:
1628 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1629 pr_debug("set open_system\n");
1630 wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1631 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1632 pr_debug("set shared key\n");
1633 wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1635 /* don't know what to do know */
1636 pr_debug("unknown AUTH_ALG (%d)\n", param->value);
1649 static int p80211_wext_get_iwauth(struct net_device *dev,
1650 struct iw_request_info *info,
1651 union iwreq_data *wrqu, char *extra)
1653 wlandevice_t *wlandev = dev->ml_priv;
1654 struct iw_param *param = &wrqu->param;
1657 pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1659 switch (param->flags & IW_AUTH_INDEX) {
1660 case IW_AUTH_DROP_UNENCRYPTED:
1662 wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
1665 case IW_AUTH_PRIVACY_INVOKED:
1667 wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
1670 case IW_AUTH_80211_AUTH_ALG:
1672 wlandev->hostwep & HOSTWEP_SHAREDKEY ?
1673 IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
1683 static iw_handler p80211wext_handlers[] = {
1684 (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */
1685 (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */
1686 (iw_handler) NULL, /* SIOCSIWNWID */
1687 (iw_handler) NULL, /* SIOCGIWNWID */
1688 (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */
1689 (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */
1690 (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */
1691 (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */
1692 (iw_handler) NULL, /* SIOCSIWSENS */
1693 (iw_handler) NULL, /* SIOCGIWSENS */
1694 (iw_handler) NULL, /* not used *//* SIOCSIWRANGE */
1695 (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */
1696 (iw_handler) NULL, /* not used *//* SIOCSIWPRIV */
1697 (iw_handler) NULL, /* kernel code *//* SIOCGIWPRIV */
1698 (iw_handler) NULL, /* not used *//* SIOCSIWSTATS */
1699 (iw_handler) NULL, /* kernel code *//* SIOCGIWSTATS */
1700 (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1701 (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1702 (iw_handler) NULL, /* -- hole -- */
1703 (iw_handler) NULL, /* -- hole -- */
1704 (iw_handler) NULL, /* SIOCSIWAP */
1705 (iw_handler) p80211wext_giwap, /* SIOCGIWAP */
1706 (iw_handler) NULL, /* -- hole -- */
1707 (iw_handler) NULL, /* SIOCGIWAPLIST */
1708 (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */
1709 (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */
1710 (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */
1711 (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */
1712 (iw_handler) NULL, /* SIOCSIWNICKN */
1713 (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */
1714 (iw_handler) NULL, /* -- hole -- */
1715 (iw_handler) NULL, /* -- hole -- */
1716 (iw_handler) NULL, /* SIOCSIWRATE */
1717 (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */
1718 (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1719 (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1720 (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
1721 (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
1722 (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */
1723 (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
1724 (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
1725 (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */
1726 (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */
1727 (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */
1728 (iw_handler) NULL, /* SIOCSIWPOWER */
1729 (iw_handler) NULL, /* SIOCGIWPOWER */
1730 /* WPA operations */
1731 (iw_handler) NULL, /* -- hole -- */
1732 (iw_handler) NULL, /* -- hole -- */
1733 (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */
1734 (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */
1735 (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */
1736 (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */
1738 (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */
1739 (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */
1740 (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */
1743 struct iw_handler_def p80211wext_handler_def = {
1744 .num_standard = ARRAY_SIZE(p80211wext_handlers),
1745 .standard = p80211wext_handlers,
1746 .get_wireless_stats = p80211wext_get_wireless_stats
1749 int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
1751 union iwreq_data data;
1753 /* Send the association state first */
1754 data.ap_addr.sa_family = ARPHRD_ETHER;
1756 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
1758 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
1760 if (wlan_wext_write)
1761 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1766 /* XXX send association data, like IEs, etc etc. */