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>
52 #include <linux/bitops.h>
54 #include "p80211types.h"
55 #include "p80211hdr.h"
56 #include "p80211conv.h"
57 #include "p80211mgmt.h"
58 #include "p80211msg.h"
59 #include "p80211metastruct.h"
60 #include "p80211metadef.h"
61 #include "p80211netdev.h"
62 #include "p80211ioctl.h"
63 #include "p80211req.h"
65 static int p80211wext_giwrate(netdevice_t *dev,
66 struct iw_request_info *info,
67 struct iw_param *rrq, char *extra);
68 static int p80211wext_giwessid(netdevice_t *dev,
69 struct iw_request_info *info,
70 struct iw_point *data, char *essid);
72 static u8 p80211_mhz_to_channel(u16 mhz)
75 return (mhz - 5000) / 5;
81 return (mhz - 2407) / 5;
86 static u16 p80211_channel_to_mhz(u8 ch, int dot11a)
96 return 5000 + (5 * ch);
102 if ((ch < 14) && (ch > 0))
103 return 2407 + (5 * ch);
108 /* taken from orinoco.c ;-) */
109 static const long p80211wext_channel_freq[] = {
110 2412, 2417, 2422, 2427, 2432, 2437, 2442,
111 2447, 2452, 2457, 2462, 2467, 2472, 2484
114 #define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
116 /* steal a spare bit to store the shared/opensystems state.
117 should default to open if not set */
118 #define HOSTWEP_SHAREDKEY BIT(3)
120 static int qual_as_percent(int snr)
129 static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data)
131 p80211msg_dot11req_mibset_t msg;
132 p80211item_uint32_t mibitem;
135 msg.msgcode = DIDmsg_dot11req_mibset;
136 memset(&mibitem, 0, sizeof(mibitem));
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 memset(&mibitem, 0, sizeof(mibitem));
273 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
274 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
275 result = p80211req_dorequest(wlandev, (u8 *) &msg);
282 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
284 if (mibitem.data > NUM_CHANNELS) {
289 /* convert into frequency instead of a channel */
291 freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000;
297 static int p80211wext_siwfreq(netdevice_t *dev,
298 struct iw_request_info *info,
299 struct iw_freq *freq, char *extra)
301 wlandevice_t *wlandev = dev->ml_priv;
302 p80211item_uint32_t mibitem;
303 p80211msg_dot11req_mibset_t msg;
307 if (!wlan_wext_write) {
312 msg.msgcode = DIDmsg_dot11req_mibset;
313 memset(&mibitem, 0, sizeof(mibitem));
314 mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
315 mibitem.status = P80211ENUM_msgitem_status_data_ok;
317 if ((freq->e == 0) && (freq->m <= 1000))
318 mibitem.data = freq->m;
320 mibitem.data = p80211_mhz_to_channel(freq->m);
322 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
323 result = p80211req_dorequest(wlandev, (u8 *) &msg);
334 static int p80211wext_giwmode(netdevice_t *dev,
335 struct iw_request_info *info,
336 __u32 *mode, char *extra)
338 wlandevice_t *wlandev = dev->ml_priv;
340 switch (wlandev->macmode) {
341 case WLAN_MACMODE_IBSS_STA:
342 *mode = IW_MODE_ADHOC;
344 case WLAN_MACMODE_ESS_STA:
345 *mode = IW_MODE_INFRA;
347 case WLAN_MACMODE_ESS_AP:
348 *mode = IW_MODE_MASTER;
352 *mode = IW_MODE_AUTO;
358 static int p80211wext_siwmode(netdevice_t *dev,
359 struct iw_request_info *info,
360 __u32 *mode, char *extra)
362 wlandevice_t *wlandev = dev->ml_priv;
363 p80211item_uint32_t mibitem;
364 p80211msg_dot11req_mibset_t msg;
368 if (!wlan_wext_write) {
373 if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
374 *mode != IW_MODE_MASTER) {
379 /* Operation mode is the same with current mode */
380 if (*mode == wlandev->macmode)
385 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
388 wlandev->macmode = WLAN_MACMODE_ESS_STA;
391 wlandev->macmode = WLAN_MACMODE_ESS_AP;
395 printk(KERN_INFO "Operation mode: %d not support\n", *mode);
399 /* Set Operation mode to the PORT TYPE RID */
400 msg.msgcode = DIDmsg_dot11req_mibset;
401 memset(&mibitem, 0, sizeof(mibitem));
402 mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
403 mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
404 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
405 result = p80211req_dorequest(wlandev, (u8 *) &msg);
414 static int p80211wext_giwrange(netdevice_t *dev,
415 struct iw_request_info *info,
416 struct iw_point *data, char *extra)
418 struct iw_range *range = (struct iw_range *)extra;
421 /* for backward compatability set size and zero everything we don't understand */
422 data->length = sizeof(*range);
423 memset(range, 0, sizeof(*range));
425 range->txpower_capa = IW_TXPOW_DBM;
426 /* XXX what about min/max_pmp, min/max_pmt, etc. */
428 range->we_version_compiled = WIRELESS_EXT;
429 range->we_version_source = 13;
431 range->retry_capa = IW_RETRY_LIMIT;
432 range->retry_flags = IW_RETRY_LIMIT;
433 range->min_retry = 0;
434 range->max_retry = 255;
436 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | /* mode/freq/ssid */
437 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
438 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
439 range->event_capa[1] = IW_EVENT_CAPA_K_1; /* encode */
440 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
441 IW_EVENT_CAPA_MASK(IWEVCUSTOM));
443 range->num_channels = NUM_CHANNELS;
445 /* XXX need to filter against the regulatory domain &| active set */
447 for (i = 0; i < NUM_CHANNELS; i++) {
448 range->freq[val].i = i + 1;
449 range->freq[val].m = p80211wext_channel_freq[i] * 100000;
450 range->freq[val].e = 1;
454 range->num_frequency = val;
456 /* Max of /proc/net/wireless */
457 range->max_qual.qual = 100;
458 range->max_qual.level = 0;
459 range->max_qual.noise = 0;
460 range->sensitivity = 3;
461 /* XXX these need to be nsd-specific! */
464 range->max_rts = 2347;
465 range->min_frag = 256;
466 range->max_frag = 2346;
468 range->max_encoding_tokens = NUM_WEPKEYS;
469 range->num_encoding_sizes = 2;
470 range->encoding_size[0] = 5;
471 range->encoding_size[1] = 13;
473 /* XXX what about num_bitrates/throughput? */
474 range->num_bitrates = 0;
476 /* estimated max throughput */
477 /* XXX need to cap it if we're running at ~2Mbps.. */
478 range->throughput = 5500000;
483 static int p80211wext_giwap(netdevice_t *dev,
484 struct iw_request_info *info,
485 struct sockaddr *ap_addr, char *extra)
488 wlandevice_t *wlandev = dev->ml_priv;
490 memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
491 ap_addr->sa_family = ARPHRD_ETHER;
496 static int p80211wext_giwencode(netdevice_t *dev,
497 struct iw_request_info *info,
498 struct iw_point *erq, char *key)
500 wlandevice_t *wlandev = dev->ml_priv;
504 i = (erq->flags & IW_ENCODE_INDEX) - 1;
507 if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
508 erq->flags |= IW_ENCODE_ENABLED;
510 erq->flags |= IW_ENCODE_DISABLED;
512 if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
513 erq->flags |= IW_ENCODE_RESTRICTED;
515 erq->flags |= IW_ENCODE_OPEN;
517 i = (erq->flags & IW_ENCODE_INDEX) - 1;
520 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
522 if ((i < 0) || (i >= NUM_WEPKEYS)) {
529 /* copy the key from the driver cache as the keys are read-only MIBs */
530 erq->length = wlandev->wep_keylens[i];
531 memcpy(key, wlandev->wep_keys[i], erq->length);
537 static int p80211wext_siwencode(netdevice_t *dev,
538 struct iw_request_info *info,
539 struct iw_point *erq, char *key)
541 wlandevice_t *wlandev = dev->ml_priv;
542 p80211msg_dot11req_mibset_t msg;
543 p80211item_pstr32_t pstr;
549 if (!wlan_wext_write) {
554 /* Check the Key index first. */
555 i = (erq->flags & IW_ENCODE_INDEX);
557 if ((i < 1) || (i > NUM_WEPKEYS)) {
563 /* Set current key number only if no keys are given */
564 if (erq->flags & IW_ENCODE_NOKEY) {
566 p80211wext_dorequest(wlandev,
567 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
577 /* Use defaultkey if no Key Index */
578 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
581 /* Check if there is no key information in the iwconfig request */
582 if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
584 /*------------------------------------------------------------
585 * If there is WEP Key for setting, check the Key Information
586 * and then set it to the firmware.
587 -------------------------------------------------------------*/
589 if (erq->length > 0) {
591 /* copy the key from the driver cache as the keys are read-only MIBs */
592 wlandev->wep_keylens[i] = erq->length;
593 memcpy(wlandev->wep_keys[i], key, erq->length);
595 /* Prepare data struture for p80211req_dorequest. */
596 memcpy(pstr.data.data, key, erq->length);
597 pstr.data.len = erq->length;
602 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
607 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
612 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
617 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
625 msg.msgcode = DIDmsg_dot11req_mibset;
626 memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
627 result = p80211req_dorequest(wlandev, (u8 *) &msg);
637 /* Check the PrivacyInvoked flag */
638 if (erq->flags & IW_ENCODE_DISABLED) {
640 p80211wext_dorequest(wlandev,
641 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
642 P80211ENUM_truth_false);
645 p80211wext_dorequest(wlandev,
646 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
647 P80211ENUM_truth_true);
655 /* The security mode may be open or restricted, and its meaning
656 depends on the card used. With most cards, in open mode no
657 authentication is used and the card may also accept non-
658 encrypted sessions, whereas in restricted mode only encrypted
659 sessions are accepted and the card will use authentication if
662 if (erq->flags & IW_ENCODE_RESTRICTED) {
664 p80211wext_dorequest(wlandev,
665 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
666 P80211ENUM_truth_true);
667 } else if (erq->flags & IW_ENCODE_OPEN) {
669 p80211wext_dorequest(wlandev,
670 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
671 P80211ENUM_truth_false);
684 static int p80211wext_giwessid(netdevice_t *dev,
685 struct iw_request_info *info,
686 struct iw_point *data, char *essid)
688 wlandevice_t *wlandev = dev->ml_priv;
690 if (wlandev->ssid.len) {
691 data->length = wlandev->ssid.len;
693 memcpy(essid, wlandev->ssid.data, data->length);
694 essid[data->length] = 0;
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 /* Trim the last '\0' to fit the SSID format */
728 if (length && essid[length - 1] == '\0')
731 memcpy(msg.ssid.data.data, essid, length);
732 msg.ssid.data.len = length;
734 pr_debug("autojoin_ssid for %s \n", essid);
735 result = p80211req_dorequest(wlandev, (u8 *) &msg);
736 pr_debug("autojoin_ssid %d\n", result);
747 static int p80211wext_siwcommit(netdevice_t *dev,
748 struct iw_request_info *info,
749 struct iw_point *data, char *essid)
751 wlandevice_t *wlandev = dev->ml_priv;
754 if (!wlan_wext_write) {
760 err = p80211wext_autojoin(wlandev);
766 static int p80211wext_giwrate(netdevice_t *dev,
767 struct iw_request_info *info,
768 struct iw_param *rrq, char *extra)
770 wlandevice_t *wlandev = dev->ml_priv;
771 p80211item_uint32_t mibitem;
772 p80211msg_dot11req_mibset_t msg;
776 msg.msgcode = DIDmsg_dot11req_mibget;
777 memset(&mibitem, 0, sizeof(mibitem));
778 mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
779 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
780 result = p80211req_dorequest(wlandev, (u8 *) &msg);
787 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
789 rrq->fixed = 0; /* can it change? */
793 #define HFA384x_RATEBIT_1 ((u16)1)
794 #define HFA384x_RATEBIT_2 ((u16)2)
795 #define HFA384x_RATEBIT_5dot5 ((u16)4)
796 #define HFA384x_RATEBIT_11 ((u16)8)
798 switch (mibitem.data) {
799 case HFA384x_RATEBIT_1:
800 rrq->value = 1000000;
802 case HFA384x_RATEBIT_2:
803 rrq->value = 2000000;
805 case HFA384x_RATEBIT_5dot5:
806 rrq->value = 5500000;
808 case HFA384x_RATEBIT_11:
809 rrq->value = 11000000;
818 static int p80211wext_giwrts(netdevice_t *dev,
819 struct iw_request_info *info,
820 struct iw_param *rts, char *extra)
822 wlandevice_t *wlandev = dev->ml_priv;
823 p80211item_uint32_t mibitem;
824 p80211msg_dot11req_mibset_t msg;
828 msg.msgcode = DIDmsg_dot11req_mibget;
829 memset(&mibitem, 0, sizeof(mibitem));
830 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
831 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
832 result = p80211req_dorequest(wlandev, (u8 *) &msg);
839 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
841 rts->value = mibitem.data;
842 rts->disabled = (rts->value == 2347);
849 static int p80211wext_siwrts(netdevice_t *dev,
850 struct iw_request_info *info,
851 struct iw_param *rts, char *extra)
853 wlandevice_t *wlandev = dev->ml_priv;
854 p80211item_uint32_t mibitem;
855 p80211msg_dot11req_mibset_t msg;
859 if (!wlan_wext_write) {
864 msg.msgcode = DIDmsg_dot11req_mibget;
865 memset(&mibitem, 0, sizeof(mibitem));
866 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
870 mibitem.data = rts->value;
872 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
873 result = p80211req_dorequest(wlandev, (u8 *) &msg);
884 static int p80211wext_giwfrag(netdevice_t *dev,
885 struct iw_request_info *info,
886 struct iw_param *frag, char *extra)
888 wlandevice_t *wlandev = dev->ml_priv;
889 p80211item_uint32_t mibitem;
890 p80211msg_dot11req_mibset_t msg;
894 msg.msgcode = DIDmsg_dot11req_mibget;
895 memset(&mibitem, 0, sizeof(mibitem));
897 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
898 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
899 result = p80211req_dorequest(wlandev, (u8 *) &msg);
906 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
908 frag->value = mibitem.data;
909 frag->disabled = (frag->value == 2346);
916 static int p80211wext_siwfrag(netdevice_t *dev,
917 struct iw_request_info *info,
918 struct iw_param *frag, char *extra)
920 wlandevice_t *wlandev = dev->ml_priv;
921 p80211item_uint32_t mibitem;
922 p80211msg_dot11req_mibset_t msg;
926 if (!wlan_wext_write) {
931 msg.msgcode = DIDmsg_dot11req_mibset;
932 memset(&mibitem, 0, sizeof(mibitem));
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 memset(&mibitem, 0, sizeof(mibitem));
974 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
976 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
977 result = p80211req_dorequest(wlandev, (u8 *) &msg);
984 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
986 shortretry = mibitem.data;
988 mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
990 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
991 result = p80211req_dorequest(wlandev, (u8 *) &msg);
998 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1000 longretry = mibitem.data;
1003 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1005 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1006 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1013 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1015 lifetime = mibitem.data;
1019 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1020 rrq->flags = IW_RETRY_LIFETIME;
1021 rrq->value = lifetime * 1024;
1023 if (rrq->flags & IW_RETRY_LONG) {
1024 rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1025 rrq->value = longretry;
1027 rrq->flags = IW_RETRY_LIMIT;
1028 rrq->value = shortretry;
1029 if (shortretry != longretry)
1030 rrq->flags |= IW_RETRY_SHORT;
1039 static int p80211wext_siwretry(netdevice_t *dev,
1040 struct iw_request_info *info,
1041 struct iw_param *rrq, char *extra)
1043 wlandevice_t *wlandev = dev->ml_priv;
1044 p80211item_uint32_t mibitem;
1045 p80211msg_dot11req_mibset_t msg;
1049 memset(&mibitem, 0, sizeof(mibitem));
1051 if (!wlan_wext_write) {
1052 err = (-EOPNOTSUPP);
1056 if (rrq->disabled) {
1061 msg.msgcode = DIDmsg_dot11req_mibset;
1063 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1065 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
1066 mibitem.data = rrq->value /= 1024;
1068 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1069 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1076 if (rrq->flags & IW_RETRY_LONG) {
1078 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
1079 mibitem.data = rrq->value;
1081 memcpy(&msg.mibattribute.data, &mibitem,
1083 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1091 if (rrq->flags & IW_RETRY_SHORT) {
1093 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
1094 mibitem.data = rrq->value;
1096 memcpy(&msg.mibattribute.data, &mibitem,
1098 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1112 static int p80211wext_siwtxpow(netdevice_t *dev,
1113 struct iw_request_info *info,
1114 struct iw_param *rrq, char *extra)
1116 wlandevice_t *wlandev = dev->ml_priv;
1117 p80211item_uint32_t mibitem;
1118 p80211msg_dot11req_mibset_t msg;
1122 if (!wlan_wext_write) {
1123 err = (-EOPNOTSUPP);
1127 msg.msgcode = DIDmsg_dot11req_mibset;
1128 memset(&mibitem, 0, sizeof(mibitem));
1130 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1131 if (rrq->fixed == 0)
1134 mibitem.data = rrq->value;
1135 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1136 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1147 static int p80211wext_giwtxpow(netdevice_t *dev,
1148 struct iw_request_info *info,
1149 struct iw_param *rrq, char *extra)
1151 wlandevice_t *wlandev = dev->ml_priv;
1152 p80211item_uint32_t mibitem;
1153 p80211msg_dot11req_mibset_t msg;
1157 msg.msgcode = DIDmsg_dot11req_mibget;
1159 memset(&mibitem, 0, sizeof(mibitem));
1161 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
1163 memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
1164 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1171 memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
1173 /* XXX handle OFF by setting disabled = 1; */
1175 rrq->flags = 0; /* IW_TXPOW_DBM; */
1178 rrq->value = mibitem.data;
1184 static int p80211wext_siwspy(netdevice_t *dev,
1185 struct iw_request_info *info,
1186 struct iw_point *srq, char *extra)
1188 wlandevice_t *wlandev = dev->ml_priv;
1189 struct sockaddr address[IW_MAX_SPY];
1190 int number = srq->length;
1193 /* Copy the data from the input buffer */
1194 memcpy(address, extra, sizeof(struct sockaddr) * number);
1196 wlandev->spy_number = 0;
1200 /* extract the addresses */
1201 for (i = 0; i < number; i++) {
1203 memcpy(wlandev->spy_address[i], address[i].sa_data,
1208 memset(wlandev->spy_stat, 0,
1209 sizeof(struct iw_quality) * IW_MAX_SPY);
1211 /* set number of addresses */
1212 wlandev->spy_number = number;
1218 /* jkriegl: from orinoco, modified */
1219 static int p80211wext_giwspy(netdevice_t *dev,
1220 struct iw_request_info *info,
1221 struct iw_point *srq, char *extra)
1223 wlandevice_t *wlandev = dev->ml_priv;
1225 struct sockaddr address[IW_MAX_SPY];
1226 struct iw_quality spy_stat[IW_MAX_SPY];
1230 number = wlandev->spy_number;
1234 /* populate address and spy struct's */
1235 for (i = 0; i < number; i++) {
1236 memcpy(address[i].sa_data, wlandev->spy_address[i],
1238 address[i].sa_family = AF_UNIX;
1239 memcpy(&spy_stat[i], &wlandev->spy_stat[i],
1240 sizeof(struct iw_quality));
1243 /* reset update flag */
1244 for (i = 0; i < number; i++)
1245 wlandev->spy_stat[i].updated = 0;
1248 /* push stuff to user space */
1249 srq->length = number;
1250 memcpy(extra, address, sizeof(struct sockaddr) * number);
1251 memcpy(extra + sizeof(struct sockaddr) * number, spy_stat,
1252 sizeof(struct iw_quality) * number);
1257 static int prism2_result2err(int prism2_result)
1261 switch (prism2_result) {
1262 case P80211ENUM_resultcode_invalid_parameters:
1265 case P80211ENUM_resultcode_implementation_failure:
1268 case P80211ENUM_resultcode_not_supported:
1279 static int p80211wext_siwscan(netdevice_t *dev,
1280 struct iw_request_info *info,
1281 struct iw_point *srq, char *extra)
1283 wlandevice_t *wlandev = dev->ml_priv;
1284 p80211msg_dot11req_scan_t msg;
1289 if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
1290 printk(KERN_ERR "Can't scan in AP mode\n");
1291 err = (-EOPNOTSUPP);
1295 memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
1296 msg.msgcode = DIDmsg_dot11req_scan;
1297 msg.bsstype.data = P80211ENUM_bsstype_any;
1299 memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
1300 msg.bssid.data.len = 6;
1302 msg.scantype.data = P80211ENUM_scantype_active;
1303 msg.probedelay.data = 0;
1305 for (i = 1; i <= 14; i++)
1306 msg.channellist.data.data[i - 1] = i;
1307 msg.channellist.data.len = 14;
1309 msg.maxchanneltime.data = 250;
1310 msg.minchanneltime.data = 200;
1312 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1314 err = prism2_result2err(msg.resultcode.data);
1320 /* Helper to translate scan into Wireless Extensions scan results.
1321 * Inspired by the prism54 code, which was in turn inspired by the
1324 static char *wext_translate_bss(struct iw_request_info *info, char *current_ev,
1326 p80211msg_dot11req_scan_results_t *bss)
1328 struct iw_event iwe; /* Temporary buffer */
1330 /* The first entry must be the MAC address */
1331 memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
1332 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1333 iwe.cmd = SIOCGIWAP;
1335 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1338 /* The following entries will be displayed in the same order we give them */
1341 if (bss->ssid.data.len > 0) {
1342 char essid[IW_ESSID_MAX_SIZE + 1];
1346 min_t(unsigned short, IW_ESSID_MAX_SIZE,
1347 bss->ssid.data.len);
1348 memset(&essid, 0, sizeof(essid));
1349 memcpy(&essid, bss->ssid.data.data, size);
1350 pr_debug(" essid size = %d\n", size);
1351 iwe.u.data.length = size;
1352 iwe.u.data.flags = 1;
1353 iwe.cmd = SIOCGIWESSID;
1355 iwe_stream_add_point(info, current_ev, end_buf, &iwe,
1357 pr_debug(" essid size OK.\n");
1360 switch (bss->bsstype.data) {
1361 case P80211ENUM_bsstype_infrastructure:
1362 iwe.u.mode = IW_MODE_MASTER;
1365 case P80211ENUM_bsstype_independent:
1366 iwe.u.mode = IW_MODE_ADHOC;
1373 iwe.cmd = SIOCGIWMODE;
1376 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1379 /* Encryption capability */
1380 if (bss->privacy.data == P80211ENUM_truth_true)
1381 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1383 iwe.u.data.flags = IW_ENCODE_DISABLED;
1384 iwe.u.data.length = 0;
1385 iwe.cmd = SIOCGIWENCODE;
1387 iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
1389 /* Add frequency. (short) bss->channel is the frequency in MHz */
1390 iwe.u.freq.m = bss->dschannel.data;
1392 iwe.cmd = SIOCGIWFREQ;
1394 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1397 /* Add quality statistics */
1398 iwe.u.qual.level = bss->signal.data;
1399 iwe.u.qual.noise = bss->noise.data;
1400 /* do a simple SNR for quality */
1401 iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
1404 iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1410 static int p80211wext_giwscan(netdevice_t *dev,
1411 struct iw_request_info *info,
1412 struct iw_point *srq, char *extra)
1414 wlandevice_t *wlandev = dev->ml_priv;
1415 p80211msg_dot11req_scan_results_t msg;
1420 char *current_ev = extra;
1422 /* Since wireless tools doesn't really have a way of passing how
1423 * many scan results results there were back here, keep grabbing them
1427 memset(&msg, 0, sizeof(msg));
1428 msg.msgcode = DIDmsg_dot11req_scan_results;
1429 msg.bssindex.data = i;
1431 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1432 if ((result != 0) ||
1433 (msg.resultcode.data != P80211ENUM_resultcode_success)) {
1438 wext_translate_bss(info, current_ev,
1439 extra + IW_SCAN_MAX_DATA, &msg);
1442 } while (i < IW_MAX_AP);
1444 srq->length = (current_ev - extra);
1445 srq->flags = 0; /* todo */
1447 if (result && !scan_good)
1448 err = prism2_result2err(msg.resultcode.data);
1453 /* extra wireless extensions stuff to support NetworkManager (I hope) */
1455 /* SIOCSIWENCODEEXT */
1456 static int p80211wext_set_encodeext(struct net_device *dev,
1457 struct iw_request_info *info,
1458 union iwreq_data *wrqu, char *extra)
1460 wlandevice_t *wlandev = dev->ml_priv;
1461 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1462 p80211msg_dot11req_mibset_t msg;
1463 p80211item_pstr32_t *pstr;
1466 struct iw_point *encoding = &wrqu->encoding;
1467 int idx = encoding->flags & IW_ENCODE_INDEX;
1469 pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1470 ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1472 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1473 /* set default key ? I'm not sure if this the the correct thing to do here */
1476 if (idx < 1 || idx > NUM_WEPKEYS)
1481 pr_debug("setting default key (%d)\n", idx);
1483 p80211wext_dorequest(wlandev,
1484 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
1490 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1491 if (ext->alg != IW_ENCODE_ALG_WEP) {
1492 pr_debug("asked to set a non wep key :(\n");
1496 if (idx < 1 || idx > NUM_WEPKEYS)
1501 pr_debug("Set WEP key (%d)\n", idx);
1502 wlandev->wep_keylens[idx] = ext->key_len;
1503 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
1505 memset(&msg, 0, sizeof(msg));
1506 pstr = (p80211item_pstr32_t *) &msg.mibattribute.data;
1507 memcpy(pstr->data.data, ext->key, ext->key_len);
1508 pstr->data.len = ext->key_len;
1512 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
1516 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
1520 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
1524 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
1529 msg.msgcode = DIDmsg_dot11req_mibset;
1530 result = p80211req_dorequest(wlandev, (u8 *) &msg);
1531 pr_debug("result (%d)\n", result);
1536 /* SIOCGIWENCODEEXT */
1537 static int p80211wext_get_encodeext(struct net_device *dev,
1538 struct iw_request_info *info,
1539 union iwreq_data *wrqu, char *extra)
1541 wlandevice_t *wlandev = dev->ml_priv;
1542 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1544 struct iw_point *encoding = &wrqu->encoding;
1549 pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1550 ext->ext_flags, (int)ext->alg, (int)ext->key_len);
1552 max_len = encoding->length - sizeof(*ext);
1554 pr_debug("get_encodeext max_len [%d] invalid\n", max_len);
1558 idx = encoding->flags & IW_ENCODE_INDEX;
1560 pr_debug("get_encode_ext index [%d]\n", idx);
1563 if (idx < 1 || idx > NUM_WEPKEYS) {
1564 pr_debug("get_encode_ext invalid key index [%d]\n",
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", (int)param->flags & IW_AUTH_INDEX);
1598 switch (param->flags & IW_AUTH_INDEX) {
1599 case IW_AUTH_DROP_UNENCRYPTED:
1600 pr_debug("drop_unencrypted %d\n", param->value);
1603 p80211wext_dorequest(wlandev,
1604 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1605 P80211ENUM_truth_true);
1608 p80211wext_dorequest(wlandev,
1609 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
1610 P80211ENUM_truth_false);
1613 case IW_AUTH_PRIVACY_INVOKED:
1614 pr_debug("privacy invoked %d\n", param->value);
1617 p80211wext_dorequest(wlandev,
1618 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1619 P80211ENUM_truth_true);
1622 p80211wext_dorequest(wlandev,
1623 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
1624 P80211ENUM_truth_false);
1628 case IW_AUTH_80211_AUTH_ALG:
1629 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1630 pr_debug("set open_system\n");
1631 wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
1632 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1633 pr_debug("set shared key\n");
1634 wlandev->hostwep |= HOSTWEP_SHAREDKEY;
1636 /* don't know what to do know */
1637 pr_debug("unknown AUTH_ALG (%d)\n", param->value);
1650 static int p80211_wext_get_iwauth(struct net_device *dev,
1651 struct iw_request_info *info,
1652 union iwreq_data *wrqu, char *extra)
1654 wlandevice_t *wlandev = dev->ml_priv;
1655 struct iw_param *param = &wrqu->param;
1658 pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
1660 switch (param->flags & IW_AUTH_INDEX) {
1661 case IW_AUTH_DROP_UNENCRYPTED:
1663 wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
1666 case IW_AUTH_PRIVACY_INVOKED:
1668 wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
1671 case IW_AUTH_80211_AUTH_ALG:
1673 wlandev->hostwep & HOSTWEP_SHAREDKEY ?
1674 IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
1684 static iw_handler p80211wext_handlers[] = {
1685 (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */
1686 (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */
1687 (iw_handler) NULL, /* SIOCSIWNWID */
1688 (iw_handler) NULL, /* SIOCGIWNWID */
1689 (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */
1690 (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */
1691 (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */
1692 (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */
1693 (iw_handler) NULL, /* SIOCSIWSENS */
1694 (iw_handler) NULL, /* SIOCGIWSENS */
1695 (iw_handler) NULL, /* not used *//* SIOCSIWRANGE */
1696 (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */
1697 (iw_handler) NULL, /* not used *//* SIOCSIWPRIV */
1698 (iw_handler) NULL, /* kernel code *//* SIOCGIWPRIV */
1699 (iw_handler) NULL, /* not used *//* SIOCSIWSTATS */
1700 (iw_handler) NULL, /* kernel code *//* SIOCGIWSTATS */
1701 (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
1702 (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
1703 (iw_handler) NULL, /* -- hole -- */
1704 (iw_handler) NULL, /* -- hole -- */
1705 (iw_handler) NULL, /* SIOCSIWAP */
1706 (iw_handler) p80211wext_giwap, /* SIOCGIWAP */
1707 (iw_handler) NULL, /* -- hole -- */
1708 (iw_handler) NULL, /* SIOCGIWAPLIST */
1709 (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */
1710 (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */
1711 (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */
1712 (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */
1713 (iw_handler) NULL, /* SIOCSIWNICKN */
1714 (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */
1715 (iw_handler) NULL, /* -- hole -- */
1716 (iw_handler) NULL, /* -- hole -- */
1717 (iw_handler) NULL, /* SIOCSIWRATE */
1718 (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */
1719 (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
1720 (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
1721 (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
1722 (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
1723 (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */
1724 (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
1725 (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
1726 (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */
1727 (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */
1728 (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */
1729 (iw_handler) NULL, /* SIOCSIWPOWER */
1730 (iw_handler) NULL, /* SIOCGIWPOWER */
1731 /* WPA operations */
1732 (iw_handler) NULL, /* -- hole -- */
1733 (iw_handler) NULL, /* -- hole -- */
1734 (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */
1735 (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */
1736 (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */
1737 (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */
1739 (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */
1740 (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */
1741 (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */
1744 struct iw_handler_def p80211wext_handler_def = {
1745 .num_standard = ARRAY_SIZE(p80211wext_handlers),
1746 .standard = p80211wext_handlers,
1747 .get_wireless_stats = p80211wext_get_wireless_stats
1750 int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
1752 union iwreq_data data;
1754 /* Send the association state first */
1755 data.ap_addr.sa_family = ARPHRD_ETHER;
1757 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
1759 memset(data.ap_addr.sa_data, 0, ETH_ALEN);
1761 if (wlan_wext_write)
1762 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
1767 /* XXX send association data, like IEs, etc etc. */