summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/drivers
diff options
context:
space:
mode:
authorrpaulo <rpaulo@FreeBSD.org>2010-06-14 15:37:48 +0000
committerrpaulo <rpaulo@FreeBSD.org>2010-06-14 15:37:48 +0000
commitce9c8f380b1fae326c166456a15ae504dce5c1d1 (patch)
tree14bf596282a14863f779d075d7a8f7e60c25f0a8 /contrib/wpa/src/drivers
parentda0290f8d3606ed387adb04fec5d24de81a39032 (diff)
parent60c44471bf25f9e84d8701afe1bbcbcc88e18c89 (diff)
downloadFreeBSD-src-ce9c8f380b1fae326c166456a15ae504dce5c1d1.zip
FreeBSD-src-ce9c8f380b1fae326c166456a15ae504dce5c1d1.tar.gz
MFV hostapd & wpa_supplicant 0.6.10.
Diffstat (limited to 'contrib/wpa/src/drivers')
-rw-r--r--contrib/wpa/src/drivers/Apple80211.h156
-rw-r--r--contrib/wpa/src/drivers/Makefile9
-rw-r--r--contrib/wpa/src/drivers/MobileApple80211.c189
-rw-r--r--contrib/wpa/src/drivers/MobileApple80211.h43
-rw-r--r--contrib/wpa/src/drivers/driver.h4
-rw-r--r--contrib/wpa/src/drivers/driver_atmel.c506
-rw-r--r--contrib/wpa/src/drivers/driver_broadcom.c604
-rw-r--r--contrib/wpa/src/drivers/driver_bsd.c795
-rw-r--r--contrib/wpa/src/drivers/driver_hostap.c513
-rw-r--r--contrib/wpa/src/drivers/driver_hostap.h153
-rw-r--r--contrib/wpa/src/drivers/driver_iphone.m466
-rw-r--r--contrib/wpa/src/drivers/driver_ipw.c463
-rw-r--r--contrib/wpa/src/drivers/driver_madwifi.c601
-rw-r--r--contrib/wpa/src/drivers/driver_ndis.c26
-rw-r--r--contrib/wpa/src/drivers/driver_ndis_.c105
-rw-r--r--contrib/wpa/src/drivers/driver_ndiswrapper.c370
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211.c2766
-rw-r--r--contrib/wpa/src/drivers/driver_osx.m432
-rw-r--r--contrib/wpa/src/drivers/driver_prism54.c381
-rw-r--r--contrib/wpa/src/drivers/driver_privsep.c820
-rw-r--r--contrib/wpa/src/drivers/driver_ps3.c186
-rw-r--r--contrib/wpa/src/drivers/driver_ralink.c1505
-rw-r--r--contrib/wpa/src/drivers/driver_ralink.h382
-rw-r--r--contrib/wpa/src/drivers/driver_roboswitch.c476
-rw-r--r--contrib/wpa/src/drivers/driver_test.c1230
-rw-r--r--contrib/wpa/src/drivers/driver_wext.c2375
-rw-r--r--contrib/wpa/src/drivers/driver_wext.h82
-rw-r--r--contrib/wpa/src/drivers/driver_wired.c286
-rw-r--r--contrib/wpa/src/drivers/ndis_events.c808
-rw-r--r--contrib/wpa/src/drivers/priv_netlink.h104
-rw-r--r--contrib/wpa/src/drivers/radiotap.c287
-rw-r--r--contrib/wpa/src/drivers/radiotap.h242
-rw-r--r--contrib/wpa/src/drivers/radiotap_iter.h41
33 files changed, 17398 insertions, 8 deletions
diff --git a/contrib/wpa/src/drivers/Apple80211.h b/contrib/wpa/src/drivers/Apple80211.h
new file mode 100644
index 0000000..2a612e7
--- /dev/null
+++ b/contrib/wpa/src/drivers/Apple80211.h
@@ -0,0 +1,156 @@
+#ifndef APPLE80211_H
+#define APPLE80211_H
+
+/*
+ * Apple80211 framework definitions
+ * This is an undocumented interface and the definitions here are based on
+ * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
+ * whatever related information can be found with google and experiments ;-).
+ */
+
+typedef struct __WirelessRef *WirelessRef;
+typedef SInt32 WirelessError;
+#define errWirelessNoError 0
+
+typedef struct WirelessInfo {
+ UInt16 link_qual;
+ UInt16 comms_qual;
+ UInt16 signal;
+ UInt16 noise;
+ UInt16 port_stat;
+ UInt16 client_mode;
+ UInt16 res1;
+ UInt16 power;
+ UInt16 res2;
+ UInt8 bssID[6];
+ UInt8 ssid[34];
+} WirelessInfo;
+
+typedef struct WirelessInfo2 {
+ /* TODO - these are probably not in correct order or complete */
+ WirelessInfo info1;
+ UInt8 macAddress[6];
+} WirelessInfo2;
+
+typedef struct WirelessNetworkInfo {
+ UInt16 channel;
+ UInt16 noise;
+ UInt16 signal;
+ UInt8 bssid[6];
+ UInt16 beacon_int;
+ UInt16 capability;
+ UInt16 ssid_len;
+ UInt8 ssid[32];
+} WirelessNetworkInfo;
+
+typedef int wirelessKeyType; /* TODO */
+
+int WirelessIsAvailable(void);
+WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
+WirelessError WirelessDetach(WirelessRef ref);
+WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
+ void *out_ptr, int out_bytes);
+WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
+WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
+WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
+WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
+WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
+WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
+WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
+ UInt32 strip_dups);
+WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
+ CFArrayRef *ibss_results, UInt32 strip_dups);
+WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
+ UInt32 strip_dups, CFStringRef ssid);
+WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
+ UInt32 strip_dups, CFArrayRef *results);
+WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
+WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
+ CFStringRef passwd);
+WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
+/*
+ * Set WEP key
+ * ref: wireless reference from WirelessAttach()
+ * type: ?
+ * key_idx: 0..3
+ * key_len: 13 for WEP-104 or 0 for clearing the key
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
+ int key_idx, int key_len,
+ const unsigned char *key);
+/*
+ * Set WPA key (e.g., PMK for 4-way handshake)
+ * ref: wireless reference from WirelessAttach()
+ * type: 0..4; 1 = PMK
+ * key_len: 16, 32, or 0
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
+ int key_len, const unsigned char *key);
+WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
+ CFStringRef key);
+WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
+ CFStringRef key);
+WirelessError WirelessDisassociate(WirelessRef ref);
+
+/*
+ * Get a copy of scan results for the given SSID
+ * The returned dictionary includes following entries:
+ * beaconInterval: CFNumber(kCFNumberSInt32Type)
+ * SSID: CFData buffer of the SSID
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
+ * name: Name of the network (SSID string)
+ * BSSID: CFData buffer of the BSSID
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * signal: CFNumber(kCFNumberSInt32Type)
+ * appleIE: CFData
+ * WPSNOPINRequired: CFBoolean
+ * noise: CFNumber(kCFNumberSInt32Type)
+ * capability: CFNumber(kCFNumberSInt32Type)
+ * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
+ * appleIE_Version: CFNumber(kCFNumberSInt32Type)
+ * appleIE_Robust: CFBoolean
+ * WPSConfigured: CFBoolean
+ * scanWasDirected: CFBoolean
+ * appleIE_Product: CFNumber(kCFNumberSInt32Type)
+ * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
+ * multiCipher: CFNumber(kCFNumberSInt32Type)
+ */
+CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
+
+/*
+ * Get information about the current association
+ * The returned dictionary includes following entries:
+ * keyData: CFData buffer of the key (e.g., 32-octet PSK)
+ * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * isIBSS: CFBoolean
+ * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
+ * 129 = WPA2-Enterprise
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
+ * SSID: CFData buffer of the SSID
+ * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
+ */
+CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
+
+WirelessError WirelessConfigure(WirelessRef ref);
+
+/*
+ * Get ASP information
+ * The returned dictionary includes following entries:
+ * Version: version number (e.g., 3.0)
+ * Channel: channel (e.g., 1)
+ * Vendor: vendor (e.g., 2)
+ */
+CFDictionaryRef WirelessGetInfoASP(void);
+
+/*
+ * Get a copy of the interface dictionary
+ * The returned dictionary has a key,value pairs for wireless interfaces.
+ * The key is the interface name and the value is the driver identifier, e.g.,
+ * en1: com.apple.driver.AirPort.Atheros
+ */
+CFDictionaryRef WirelessCopyInterfaceDict(void);
+
+#endif /* APPLE80211_H */
diff --git a/contrib/wpa/src/drivers/Makefile b/contrib/wpa/src/drivers/Makefile
new file mode 100644
index 0000000..cffba62
--- /dev/null
+++ b/contrib/wpa/src/drivers/Makefile
@@ -0,0 +1,9 @@
+all:
+ @echo Nothing to be made.
+
+clean:
+ for d in $(SUBDIRS); do make -C $$d clean; done
+ rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
diff --git a/contrib/wpa/src/drivers/MobileApple80211.c b/contrib/wpa/src/drivers/MobileApple80211.c
new file mode 100644
index 0000000..ce004fe
--- /dev/null
+++ b/contrib/wpa/src/drivers/MobileApple80211.c
@@ -0,0 +1,189 @@
+#include "includes.h"
+#include <dlfcn.h>
+
+#include "common.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "MobileApple80211.h"
+
+/*
+ * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
+ * having to link with full Preferences.framework.
+ */
+
+static void *aeropuerto = NULL;
+
+
+int _Apple80211Initialized(void)
+{
+ return aeropuerto ? 1 : 0;
+}
+
+
+static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
+
+int Apple80211Open(Apple80211Ref *ctx)
+{
+ return __Apple80211Open(ctx);
+}
+
+
+static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
+
+int Apple80211Close(Apple80211Ref ctx)
+{
+ return __Apple80211Close(ctx);
+}
+
+
+static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
+ = NULL;
+
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
+{
+ return __Apple80211GetIfListCopy(handle, list);
+}
+
+
+static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
+ CFStringRef interface) = NULL;
+
+int Apple80211BindToInterface(Apple80211Ref handle,
+ CFStringRef interface)
+{
+ return __Apple80211BindToInterface(handle, interface);
+}
+
+
+static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
+ CFStringRef *name) = NULL;
+
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+ CFStringRef *name)
+{
+ return __Apple80211GetInterfaceNameCopy(handle, name);
+}
+
+
+static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
+ CFDictionaryRef *info) = NULL;
+
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+ CFDictionaryRef *info)
+{
+ return __Apple80211GetInfoCopy(handle, info);
+}
+
+
+static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
+
+int Apple80211GetPower(Apple80211Ref handle, char *pwr)
+{
+ return __Apple80211GetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
+
+int Apple80211SetPower(Apple80211Ref handle, char pwr)
+{
+ return __Apple80211SetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters) = NULL;
+
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters)
+{
+ return __Apple80211Scan(handle, list, parameters);
+}
+
+
+static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password) = NULL;
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password)
+{
+ return __Apple80211Associate(handle, bss, password);
+}
+
+
+static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
+ CFDictionaryRef bss,
+ CFStringRef password,
+ CFDictionaryRef *info) =
+ NULL;
+
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password, CFDictionaryRef *info)
+{
+ return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
+}
+
+
+static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
+ CFDictionaryRef arg2, void *value) = NULL;
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
+ void *value)
+{
+ return __Apple80211CopyValue(handle, field, arg2, value);
+}
+
+
+#define DLSYM(s) \
+do { \
+ __ ## s = dlsym(aeropuerto, #s); \
+ if (__ ## s == NULL) { \
+ wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
+ "symbol '" #s "' (%s)", dlerror()); \
+ err = 1; \
+ } \
+} while (0)
+
+
+__attribute__ ((constructor))
+void _Apple80211_constructor(void)
+{
+ const char *fname = "/System/Library/SystemConfiguration/"
+ "Aeropuerto.bundle/Aeropuerto";
+ int err = 0;
+
+ aeropuerto = dlopen(fname, RTLD_LAZY);
+ if (!aeropuerto) {
+ wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
+ "for symbols", fname);
+ return;
+ }
+
+ DLSYM(Apple80211Open);
+ DLSYM(Apple80211Close);
+ DLSYM(Apple80211GetIfListCopy);
+ DLSYM(Apple80211BindToInterface);
+ DLSYM(Apple80211GetInterfaceNameCopy);
+ DLSYM(Apple80211GetInfoCopy);
+ DLSYM(Apple80211GetPower);
+ DLSYM(Apple80211SetPower);
+ DLSYM(Apple80211Scan);
+ DLSYM(Apple80211Associate);
+ DLSYM(Apple80211AssociateAndCopyInfo);
+ DLSYM(Apple80211CopyValue);
+
+ if (err) {
+ dlclose(aeropuerto);
+ aeropuerto = NULL;
+ }
+}
+
+
+__attribute__ ((destructor))
+void _Apple80211_destructor(void)
+{
+ if (aeropuerto) {
+ dlclose(aeropuerto);
+ aeropuerto = NULL;
+ }
+}
diff --git a/contrib/wpa/src/drivers/MobileApple80211.h b/contrib/wpa/src/drivers/MobileApple80211.h
new file mode 100644
index 0000000..64d439d
--- /dev/null
+++ b/contrib/wpa/src/drivers/MobileApple80211.h
@@ -0,0 +1,43 @@
+#ifndef MOBILEAPPLE80211_H
+#define MOBILEAPPLE80211_H
+
+/*
+ * MobileApple80211 interface for iPhone/iPod touch
+ * These functions are available from Aeropuerto.
+ */
+
+struct Apple80211;
+typedef struct Apple80211 *Apple80211Ref;
+
+int Apple80211Open(Apple80211Ref *ctx);
+int Apple80211Close(Apple80211Ref ctx);
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
+int Apple80211BindToInterface(Apple80211Ref handle,
+ CFStringRef interface);
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+ CFStringRef *name);
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+ CFDictionaryRef *info);
+int Apple80211GetPower(Apple80211Ref handle, char *pwr);
+int Apple80211SetPower(Apple80211Ref handle, char pwr);
+
+/* parameters can be NULL; returns scan results in CFArrayRef *list;
+ * caller will need to free with CFRelease() */
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters);
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password);
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password,
+ CFDictionaryRef *info);
+
+enum {
+ APPLE80211_VALUE_SSID = 1,
+ APPLE80211_VALUE_BSSID = 9
+};
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
+ void *value);
+
+#endif /* MOBILEAPPLE80211_H */
diff --git a/contrib/wpa/src/drivers/driver.h b/contrib/wpa/src/drivers/driver.h
index 9bce6c6..c2975d2 100644
--- a/contrib/wpa/src/drivers/driver.h
+++ b/contrib/wpa/src/drivers/driver.h
@@ -131,7 +131,7 @@ struct wpa_scan_results {
* @ifname: Interface name that can be used with init() or init2()
* @desc: Human readable adapter description (e.g., vendor/model) or NULL if
* not available
- * @drv_bame: struct wpa_driver_ops::name (note: unlike other strings, this one
+ * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one
* is not an allocated copy, i.e., get_interfaces() caller will not free
* this)
*/
@@ -702,7 +702,7 @@ struct wpa_driver_ops {
int (*flush_pmkid)(void *priv);
/**
- * flush_pmkid - Flush PMKSA cache
+ * get_capa - Get driver capabilities
* @priv: private driver interface data
*
* Returns: 0 on success, -1 on failure
diff --git a/contrib/wpa/src/drivers/driver_atmel.c b/contrib/wpa/src/drivers/driver_atmel.c
new file mode 100644
index 0000000..0a7a66d
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_atmel.c
@@ -0,0 +1,506 @@
+/*
+ * WPA Supplicant - Driver interaction with Atmel Wireless LAN drivers
+ * Copyright (c) 2000-2005, ATMEL Corporation
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+/******************************************************************************
+ Copyright 2000-2001 ATMEL Corporation.
+
+ WPA Supplicant - driver interaction with Atmel Wireless lan drivers.
+
+ This is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Atmel wireless lan drivers; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+******************************************************************************/
+
+/*
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+struct wpa_driver_atmel_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+
+#define ATMEL_WPA_IOCTL (SIOCIWFIRSTPRIV + 2)
+#define ATMEL_WPA_IOCTL_PARAM (SIOCIWFIRSTPRIV + 3)
+#define ATMEL_WPA_IOCTL_GET_PARAM (SIOCIWFIRSTPRIV + 4)
+
+
+/* ATMEL_WPA_IOCTL ioctl() cmd: */
+enum {
+ SET_WPA_ENCRYPTION = 1,
+ SET_CIPHER_SUITES = 2,
+ MLME_STA_DEAUTH = 3,
+ MLME_STA_DISASSOC = 4
+};
+
+/* ATMEL_WPA_IOCTL_PARAM ioctl() cmd: */
+enum {
+ ATMEL_PARAM_WPA = 1,
+ ATMEL_PARAM_PRIVACY_INVOKED = 2,
+ ATMEL_PARAM_WPA_TYPE = 3
+};
+
+#define MAX_KEY_LENGTH 40
+
+struct atmel_param{
+ unsigned char sta_addr[6];
+ int cmd;
+ u8 alg;
+ u8 key_idx;
+ u8 set_tx;
+ u8 seq[8];
+ u8 seq_len;
+ u16 key_len;
+ u8 key[MAX_KEY_LENGTH];
+ struct{
+ int reason_code;
+ u8 state;
+ }mlme;
+ u8 pairwise_suite;
+ u8 group_suite;
+ u8 key_mgmt_suite;
+};
+
+
+
+static int atmel_ioctl(struct wpa_driver_atmel_data *drv,
+ struct atmel_param *param,
+ int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, ATMEL_WPA_IOCTL, &iwr) < 0) {
+ int ret;
+ ret = errno;
+ if (show_err)
+ perror("ioctl[ATMEL_WPA_IOCTL]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int atmel2param(struct wpa_driver_atmel_data *drv, int param, int value)
+{
+ struct iwreq iwr;
+ int *i, ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->sock, ATMEL_WPA_IOCTL_PARAM, &iwr) < 0) {
+ perror("ioctl[ATMEL_WPA_IOCTL_PARAM]");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+#if 0
+static int wpa_driver_atmel_set_wpa_ie(struct wpa_driver_atmel_data *drv,
+ const char *wpa_ie, size_t wpa_ie_len)
+{
+ struct atmel_param *param;
+ int res;
+ size_t blen = ATMEL_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = ATMEL_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = wpa_ie_len;
+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
+ res = atmel_ioctl(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+#endif
+
+
+static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ int ret = 0;
+
+ printf("wpa_driver_atmel_set_wpa %s\n", drv->ifname);
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+#if 0
+ if (!enabled && wpa_driver_atmel_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+#endif
+ if (atmel2param(drv, ATMEL_PARAM_PRIVACY_INVOKED, enabled) < 0)
+ ret = -1;
+ if (atmel2param(drv, ATMEL_PARAM_WPA, enabled) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_atmel_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ int ret = 0;
+ struct atmel_param *param;
+ u8 *buf;
+ u8 alg_type;
+
+ size_t blen;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ alg_type = 0;
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ alg_type = 1;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ alg_type = 2;
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ alg_type = 3;
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct atmel_param *) buf;
+
+ param->cmd = SET_WPA_ENCRYPTION;
+
+ if (addr == NULL)
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
+
+ param->alg = alg_type;
+ param->key_idx = key_idx;
+ param->set_tx = set_tx;
+ os_memcpy(param->seq, seq, seq_len);
+ param->seq_len = seq_len;
+ param->key_len = key_len;
+ os_memcpy((u8 *)param->key, key, key_len);
+
+ if (atmel_ioctl(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ /* TODO: show key error*/
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_atmel_set_countermeasures(void *priv,
+ int enabled)
+{
+ /* FIX */
+ printf("wpa_driver_atmel_set_countermeasures - not yet "
+ "implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_atmel_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ /* FIX */
+ printf("wpa_driver_atmel_set_drop_unencrypted - not yet "
+ "implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
+ int reason_code)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ struct atmel_param param;
+ int ret;
+ int mgmt_error = 0xaa;
+
+ os_memset(&param, 0, sizeof(param));
+ os_memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.cmd = cmd;
+ param.mlme.reason_code = reason_code;
+ param.mlme.state = mgmt_error;
+ ret = atmel_ioctl(drv, &param, sizeof(param), 1);
+ return ret;
+}
+
+
+#if 0
+static int wpa_driver_atmel_set_suites(struct wpa_driver_atmel_data *drv,
+ u8 pairwise_suite, u8 group_suite,
+ u8 key_mgmt_suite)
+{
+ struct atmel_param param;
+ int ret;
+
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = SET_CIPHER_SUITES;
+ param.pairwise_suite = pairwise_suite;
+ param.group_suite = group_suite;
+ param.key_mgmt_suite = key_mgmt_suite;
+
+ ret = atmel_ioctl(drv, &param, sizeof(param), 1);
+ return ret;
+}
+#endif
+
+
+static int wpa_driver_atmel_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ printf("wpa_driver_atmel_deauthenticate\n");
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DEAUTH,
+ reason_code);
+
+}
+
+
+static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ printf("wpa_driver_atmel_disassociate\n");
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DISASSOC,
+ reason_code);
+
+}
+
+
+#if 0
+/* Atmel driver uses specific values for each cipher suite */
+static int convertSuiteToDriver(wpa_cipher suite)
+{
+ u8 suite_type;
+
+ switch(suite) {
+ case CIPHER_NONE:
+ suite_type = 0;
+ break;
+ case CIPHER_WEP40:
+ suite_type = 1;
+ break;
+ case CIPHER_TKIP:
+ suite_type = 2;
+ break;
+ case CIPHER_WEP104:
+ suite_type = 5;
+ break;
+ case CIPHER_CCMP:
+ suite_type = 3;
+ break;
+ default:
+ suite_type = 2;
+ }
+
+ return suite_type;
+
+}
+#endif
+
+static int
+wpa_driver_atmel_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ int ret = 0;
+#if 0
+ u8 pairwise_suite_driver;
+ u8 group_suite_driver;
+ u8 key_mgmt_suite_driver;
+
+ pairwise_suite_driver = convertSuiteToDriver(params->pairwise_suite);
+ group_suite_driver = convertSuiteToDriver(params->group_suite);
+ key_mgmt_suite_driver = convertSuiteToDriver(params->key_mgmt_suite);
+
+ if (wpa_driver_atmel_set_suites(drv, pairwise_suite_driver,
+ group_suite_driver,
+ key_mgmt_suite_driver) < 0){
+ printf("wpa_driver_atmel_set_suites.\n");
+ ret = -1;
+ }
+ if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) {
+ printf("wpa_driver_atmel_set_freq.\n");
+ ret = -1;
+ }
+#endif
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
+ < 0) {
+ printf("FAILED : wpa_driver_atmel_set_ssid.\n");
+ ret = -1;
+ }
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) {
+ printf("FAILED : wpa_driver_atmel_set_bssid.\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_atmel_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_driver_atmel_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results * wpa_driver_atmel_get_scan_results(void *priv)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_atmel_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_atmel_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_atmel_deinit(void *priv)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_atmel_ops = {
+ .name = "atmel",
+ .desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
+ .get_bssid = wpa_driver_atmel_get_bssid,
+ .get_ssid = wpa_driver_atmel_get_ssid,
+ .set_wpa = wpa_driver_atmel_set_wpa,
+ .set_key = wpa_driver_atmel_set_key,
+ .init = wpa_driver_atmel_init,
+ .deinit = wpa_driver_atmel_deinit,
+ .set_countermeasures = wpa_driver_atmel_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_atmel_set_drop_unencrypted,
+ .scan = wpa_driver_atmel_scan,
+ .get_scan_results2 = wpa_driver_atmel_get_scan_results,
+ .deauthenticate = wpa_driver_atmel_deauthenticate,
+ .disassociate = wpa_driver_atmel_disassociate,
+ .associate = wpa_driver_atmel_associate,
+ .set_operstate = wpa_driver_atmel_set_operstate,
+};
diff --git a/contrib/wpa/src/drivers/driver_broadcom.c b/contrib/wpa/src/drivers/driver_broadcom.c
new file mode 100644
index 0000000..3600dae
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_broadcom.c
@@ -0,0 +1,604 @@
+/*
+ * WPA Supplicant - driver interaction with old Broadcom wl.o driver
+ * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+ * Linux wireless extensions and does not need (or even work) with this old
+ * driver wrapper. Use driver_wext.c with that driver.
+ */
+
+#include "includes.h"
+
+#include <sys/ioctl.h>
+
+#include "common.h"
+
+#if 0
+#include <netpacket/packet.h>
+#include <net/ethernet.h> /* the L2 protocols */
+#else
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#endif
+#include <net/if.h>
+#include <typedefs.h>
+
+/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
+ * WRT54G GPL tarball. */
+#include <wlioctl.h>
+
+#include "driver.h"
+#include "eloop.h"
+
+struct wpa_driver_broadcom_data {
+ void *ctx;
+ int ioctl_sock;
+ int event_sock;
+ char ifname[IFNAMSIZ + 1];
+};
+
+
+#ifndef WLC_DEAUTHENTICATE
+#define WLC_DEAUTHENTICATE 143
+#endif
+#ifndef WLC_DEAUTHENTICATE_WITH_REASON
+#define WLC_DEAUTHENTICATE_WITH_REASON 201
+#endif
+#ifndef WLC_SET_TKIP_COUNTERMEASURES
+#define WLC_SET_TKIP_COUNTERMEASURES 202
+#endif
+
+#if !defined(PSK_ENABLED) /* NEW driver interface */
+#define WL_VERSION 360130
+/* wireless authentication bit vector */
+#define WPA_ENABLED 1
+#define PSK_ENABLED 2
+
+#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
+#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
+#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
+
+#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
+
+typedef wl_wsec_key_t wsec_key_t;
+#endif
+
+typedef struct {
+ uint32 val;
+ struct ether_addr ea;
+ uint16 res;
+} wlc_deauth_t;
+
+
+static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+
+static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
+ void *buf, int len)
+{
+ struct ifreq ifr;
+ wl_ioctl_t ioc;
+ int ret = 0;
+
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
+ drv->ifname, cmd, len, buf);
+ /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
+
+ ioc.cmd = cmd;
+ ioc.buf = buf;
+ ioc.len = len;
+ os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
+ ifr.ifr_data = (caddr_t) &ioc;
+ if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
+ if (cmd != WLC_GET_MAGIC)
+ perror(ifr.ifr_name);
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
+ cmd, ret);
+ }
+
+ return ret;
+}
+
+static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
+ return 0;
+
+ os_memset(bssid, 0, ETH_ALEN);
+ return -1;
+}
+
+static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_ssid_t s;
+
+ if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
+ return -1;
+
+ os_memcpy(ssid, s.SSID, s.SSID_len);
+ return s.SSID_len;
+}
+
+static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ unsigned int wauth, wsec;
+ struct ether_addr ea;
+
+ os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
+ if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
+ -1 ||
+ broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
+ return -1;
+
+ if (enable) {
+ wauth = PSK_ENABLED;
+ wsec = TKIP_ENABLED;
+ } else {
+ wauth = 255;
+ wsec &= ~(TKIP_ENABLED | AES_ENABLED);
+ }
+
+ if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
+ -1 ||
+ broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
+ return -1;
+
+ /* FIX: magic number / error handling? */
+ broadcom_ioctl(drv, 122, &ea, sizeof(ea));
+
+ return 0;
+}
+
+static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ int ret;
+ wsec_key_t wkt;
+
+ os_memset(&wkt, 0, sizeof wkt);
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
+ set_tx ? "PRIMARY " : "", key_idx, alg);
+ if (key && key_len > 0)
+ wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ wkt.algo = CRYPTO_ALGO_OFF;
+ break;
+ case WPA_ALG_WEP:
+ wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
+ break;
+ case WPA_ALG_TKIP:
+ wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
+ break;
+ case WPA_ALG_CCMP:
+ wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
+ * AES_OCB_MSDU, AES_OCB_MPDU? */
+ break;
+ default:
+ wkt.algo = CRYPTO_ALGO_NALG;
+ break;
+ }
+
+ if (seq && seq_len > 0)
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
+
+ if (addr)
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
+
+ wkt.index = key_idx;
+ wkt.len = key_len;
+ if (key && key_len > 0) {
+ os_memcpy(wkt.data, key, key_len);
+ if (key_len == 32) {
+ /* hack hack hack XXX */
+ os_memcpy(&wkt.data[16], &key[24], 8);
+ os_memcpy(&wkt.data[24], &key[16], 8);
+ }
+ }
+ /* wkt.algo = CRYPTO_ALGO_...; */
+ wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
+ if (addr && set_tx)
+ os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
+ ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
+ if (addr && set_tx) {
+ /* FIX: magic number / error handling? */
+ broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
+ }
+ return ret;
+}
+
+
+static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ wl_wpa_header_t *wwh;
+ union wpa_event_data data;
+
+ if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
+ return;
+
+ wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
+
+ if ((size_t) left < sizeof(wl_wpa_header_t))
+ return;
+
+ wwh = (wl_wpa_header_t *) buf;
+
+ if (wwh->snap.type != WL_WPA_ETHER_TYPE)
+ return;
+ if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+
+ switch (wwh->type) {
+ case WLC_ASSOC_MSG:
+ left -= WL_WPA_HEADER_LEN;
+ wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
+ left);
+ if (left > 0) {
+ data.assoc_info.resp_ies = os_malloc(left);
+ if (data.assoc_info.resp_ies == NULL)
+ return;
+ os_memcpy(data.assoc_info.resp_ies,
+ buf + WL_WPA_HEADER_LEN, left);
+ data.assoc_info.resp_ies_len = left;
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
+ "into resp_ies",
+ data.assoc_info.resp_ies, left);
+ }
+ /* data.assoc_info.req_ies = NULL; */
+ /* data.assoc_info.req_ies_len = 0; */
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ break;
+ case WLC_DISASSOC_MSG:
+ wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
+ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+ break;
+ case WLC_PTK_MIC_MSG:
+ wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
+ data.michael_mic_failure.unicast = 1;
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ break;
+ case WLC_GTK_MIC_MSG:
+ wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
+ data.michael_mic_failure.unicast = 0;
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
+ wwh->type);
+ break;
+ }
+ os_free(data.assoc_info.resp_ies);
+}
+
+static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
+{
+ int s;
+ struct sockaddr_ll ll;
+ struct wpa_driver_broadcom_data *drv;
+ struct ifreq ifr;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return NULL;
+ }
+ /* do it */
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return NULL;
+ }
+
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->ioctl_sock = s;
+
+ s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
+ if (s < 0) {
+ perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_protocol = ntohs(ETH_P_802_2);
+ ll.sll_ifindex = ifr.ifr_ifindex;
+ ll.sll_hatype = 0;
+ ll.sll_pkttype = PACKET_HOST;
+ ll.sll_halen = 0;
+
+ if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
+ NULL);
+ drv->event_sock = s;
+
+ return drv;
+}
+
+static void wpa_driver_broadcom_deinit(void *priv)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
+ eloop_unregister_read_sock(drv->event_sock);
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv);
+}
+
+static int wpa_driver_broadcom_set_countermeasures(void *priv,
+ int enabled)
+{
+#if 0
+ struct wpa_driver_broadcom_data *drv = priv;
+ /* FIX: ? */
+ return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
+ sizeof(enabled));
+#else
+ return 0;
+#endif
+}
+
+static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
+ int restrict = (enabled ? 1 : 0);
+
+ if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
+ &restrict, sizeof(restrict)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
+ &restrict, sizeof(restrict)) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_ssid_t wst = { 0, "" };
+
+ if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
+ wst.SSID_len = ssid_len;
+ os_memcpy(wst.SSID, ssid, ssid_len);
+ }
+
+ if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
+ return -1;
+
+ eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static const int frequency_list[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+struct bss_ie_hdr {
+ u8 elem_id;
+ u8 len;
+ u8 oui[3];
+ /* u8 oui_type; */
+ /* u16 version; */
+} __attribute__ ((packed));
+
+static int
+wpa_driver_broadcom_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ char *buf;
+ wl_scan_results_t *wsr;
+ wl_bss_info_t *wbi;
+ size_t ap_num;
+
+ buf = os_malloc(WLC_IOCTL_MAXLEN);
+ if (buf == NULL)
+ return -1;
+
+ wsr = (wl_scan_results_t *) buf;
+
+ wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
+ wsr->version = 107;
+ wsr->count = 0;
+
+ if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+
+ for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
+ int left;
+ struct bss_ie_hdr *ie;
+
+ os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
+ os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
+ results[ap_num].ssid_len = wbi->SSID_len;
+ results[ap_num].freq = frequency_list[wbi->channel - 1];
+ /* get ie's */
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
+ (u8 *) wbi + sizeof(*wbi), wbi->ie_length);
+ ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
+ for (left = wbi->ie_length; left > 0;
+ left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
+ ((u8 *) ie + 2 + ie->len)) {
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
+ ie->elem_id, ie->len);
+ if (ie->len >= 3)
+ wpa_printf(MSG_MSGDUMP,
+ "BROADCOM: oui:%02x%02x%02x",
+ ie->oui[0], ie->oui[1], ie->oui[2]);
+ if (ie->elem_id != 0xdd ||
+ ie->len < 6 ||
+ os_memcmp(ie->oui, WPA_OUI, 3) != 0)
+ continue;
+ os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
+ results[ap_num].wpa_ie_len = ie->len + 2;
+ break;
+ }
+
+ wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
+ }
+
+ wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
+ "BSSes)",
+ wsr->buflen, (unsigned long) ap_num);
+
+ os_free(buf);
+ return ap_num;
+}
+
+static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_deauth_t wdt;
+ wdt.val = reason_code;
+ os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
+ wdt.res = 0x7fff;
+ return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
+ sizeof(wdt));
+}
+
+static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0);
+}
+
+static int
+wpa_driver_broadcom_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_ssid_t s;
+ int infra = 1;
+ int auth = 0;
+ int wsec = 4;
+ int dummy;
+ int wpa_auth;
+
+ s.SSID_len = params->ssid_len;
+ os_memcpy(s.SSID, params->ssid, params->ssid_len);
+
+ switch (params->pairwise_suite) {
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ wsec = 1;
+ break;
+
+ case CIPHER_TKIP:
+ wsec = 2;
+ break;
+
+ case CIPHER_CCMP:
+ wsec = 4;
+ break;
+
+ default:
+ wsec = 0;
+ break;
+ }
+
+ switch (params->key_mgmt_suite) {
+ case KEY_MGMT_802_1X:
+ wpa_auth = 1;
+ break;
+
+ case KEY_MGMT_PSK:
+ wpa_auth = 2;
+ break;
+
+ default:
+ wpa_auth = 255;
+ break;
+ }
+
+ /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
+ * group_suite, key_mgmt_suite);
+ * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
+ * wl join uses wlc_sec_wep here, not wlc_set_wsec */
+
+ if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
+ sizeof(wpa_auth)) < 0 ||
+ broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
+ return -1;
+
+ return 0;
+}
+
+const struct wpa_driver_ops wpa_driver_broadcom_ops = {
+ .name = "broadcom",
+ .desc = "Broadcom wl.o driver",
+ .get_bssid = wpa_driver_broadcom_get_bssid,
+ .get_ssid = wpa_driver_broadcom_get_ssid,
+ .set_wpa = wpa_driver_broadcom_set_wpa,
+ .set_key = wpa_driver_broadcom_set_key,
+ .init = wpa_driver_broadcom_init,
+ .deinit = wpa_driver_broadcom_deinit,
+ .set_countermeasures = wpa_driver_broadcom_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
+ .scan = wpa_driver_broadcom_scan,
+ .get_scan_results = wpa_driver_broadcom_get_scan_results,
+ .deauthenticate = wpa_driver_broadcom_deauthenticate,
+ .disassociate = wpa_driver_broadcom_disassociate,
+ .associate = wpa_driver_broadcom_associate,
+};
diff --git a/contrib/wpa/src/drivers/driver_bsd.c b/contrib/wpa/src/drivers/driver_bsd.c
new file mode 100644
index 0000000..da57852
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_bsd.c
@@ -0,0 +1,795 @@
+/*
+ * WPA Supplicant - driver interaction with BSD net80211 layer
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#include <net/if.h>
+
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#define COMPAT_FREEBSD_NET80211
+#else
+#include <net/ethernet.h>
+#endif
+
+#include <net80211/_ieee80211.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+struct wpa_driver_bsd_data {
+ int sock; /* open socket for 802.11 ioctls */
+ int route; /* routing socket for events */
+ char ifname[IFNAMSIZ+1]; /* interface name */
+ unsigned int ifindex; /* interface index */
+ void *ctx;
+ int prev_roaming; /* roaming state to restore on deinit */
+ int prev_privacy; /* privacy state to restore on deinit */
+ int prev_wpa; /* wpa state to restore on deinit */
+};
+
+static int
+set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = (void *) arg;
+
+ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
+ op, arg_len, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = arg;
+
+ if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
+ op, arg_len, strerror(errno));
+ return -1;
+ }
+ return ireq.i_len;
+}
+
+static int
+set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_val = arg;
+
+ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
+ op, arg, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get80211param(struct wpa_driver_bsd_data *drv, int op)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+
+ if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
+ op, strerror(errno));
+ return -1;
+ }
+ return ireq.i_val;
+}
+
+static int
+getifflags(struct wpa_driver_bsd_data *drv, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ perror("SIOCGIFFLAGS");
+ return errno;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+static int
+setifflags(struct wpa_driver_bsd_data *drv, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return errno;
+ }
+ return 0;
+}
+
+static int
+wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return get80211var(drv, IEEE80211_IOC_BSSID,
+ bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
+}
+
+#if 0
+static int
+wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return set80211var(drv, IEEE80211_IOC_BSSID,
+ bssid, IEEE80211_ADDR_LEN);
+}
+#endif
+
+static int
+wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return get80211var(drv, IEEE80211_IOC_SSID,
+ ssid, IEEE80211_NWID_LEN);
+}
+
+static int
+wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
+}
+
+static int
+wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ return set80211var(drv, IEEE80211_IOC_APPIE, wpa_ie, wpa_ie_len);
+}
+
+static int
+wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
+ __FUNCTION__, wpa, privacy);
+
+ if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+ ret = -1;
+ if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+wpa_driver_bsd_set_wpa(void *priv, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
+}
+
+static int
+wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
+ const unsigned char *addr)
+{
+ struct ieee80211req_del_key wk;
+
+ os_memset(&wk, 0, sizeof(wk));
+ if (addr != NULL &&
+ bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
+ struct ether_addr ea;
+
+ os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
+ wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
+ __func__, ether_ntoa(&ea), key_idx);
+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
+ wk.idk_keyix = key_idx;
+ }
+ return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
+}
+
+static int
+wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
+ const unsigned char *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_key wk;
+ struct ether_addr ea;
+ char *alg_name;
+ u_int8_t cipher;
+
+ if (alg == WPA_ALG_NONE)
+ return wpa_driver_bsd_del_key(drv, key_idx, addr);
+
+ switch (alg) {
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ cipher = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ cipher = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
+ __func__, alg);
+ return -1;
+ }
+
+ os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
+ wpa_printf(MSG_DEBUG,
+ "%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
+ __func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
+ seq_len, key_len);
+
+ if (seq_len > sizeof(u_int64_t)) {
+ wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
+ __func__, seq_len);
+ return -2;
+ }
+ if (key_len > sizeof(wk.ik_keydata)) {
+ wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
+ __func__, key_len);
+ return -3;
+ }
+
+ os_memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV;
+ if (set_tx)
+ wk.ik_flags |= IEEE80211_KEY_XMIT;
+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ /*
+ * Deduce whether group/global or unicast key by checking
+ * the address (yech). Note also that we can only mark global
+ * keys default; doing this for a unicast key is an error.
+ */
+ if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
+ wk.ik_flags |= IEEE80211_KEY_GROUP;
+ wk.ik_keyix = key_idx;
+ } else {
+ wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
+ }
+ if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ wk.ik_keylen = key_len;
+ os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+ os_memcpy(wk.ik_keydata, key, key_len);
+
+ return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
+}
+
+static int
+wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
+}
+
+
+static int
+wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
+}
+
+static int
+wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int privacy;
+
+ wpa_printf(MSG_DEBUG,
+ "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
+ , __func__
+ , params->ssid_len, params->ssid
+ , params->wpa_ie_len
+ , params->pairwise_suite
+ , params->group_suite
+ , params->key_mgmt_suite
+ );
+
+ /* XXX error handling is wrong but unclear what to do... */
+ if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
+ return -1;
+
+ privacy = !(params->pairwise_suite == CIPHER_NONE &&
+ params->group_suite == CIPHER_NONE &&
+ params->key_mgmt_suite == KEY_MGMT_NONE &&
+ params->wpa_ie_len == 0);
+ wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
+
+ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+ return -1;
+
+ if (params->wpa_ie_len &&
+ set80211param(drv, IEEE80211_IOC_WPA,
+ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
+ return -1;
+
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_ASSOC;
+ if (params->ssid != NULL)
+ os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
+ mlme.im_ssid_len = params->ssid_len;
+ if (params->bssid != NULL)
+ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
+ if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
+ return -1;
+ return 0;
+}
+
+static int
+wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int authmode;
+
+ if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
+ (auth_alg & AUTH_ALG_SHARED_KEY))
+ authmode = IEEE80211_AUTH_AUTO;
+ else if (auth_alg & AUTH_ALG_SHARED_KEY)
+ authmode = IEEE80211_AUTH_SHARED;
+ else
+ authmode = IEEE80211_AUTH_OPEN;
+
+ return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
+}
+
+static int
+wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int flags;
+
+ /* NB: interface must be marked UP to do a scan */
+ if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
+ return -1;
+
+ /* set desired ssid before scan */
+ if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
+ return -1;
+
+ /* NB: net80211 delivers a scan complete event so no need to poll */
+ return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
+}
+
+#include <net/route.h>
+#if __FreeBSD__
+#include <net80211/ieee80211_freebsd.h>
+#endif
+#if __NetBSD__
+#include <net80211/ieee80211_netbsd.h>
+#endif
+
+static void
+wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+ struct wpa_driver_bsd_data *drv = sock_ctx;
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct if_msghdr *ifm;
+ struct rt_msghdr *rtm;
+ union wpa_event_data event;
+ struct ieee80211_michael_event *mic;
+ int n;
+
+ n = read(sock, buf, sizeof(buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("read(PF_ROUTE)");
+ return;
+ }
+
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Routing message version %d not "
+ "understood\n", rtm->rtm_version);
+ return;
+ }
+ os_memset(&event, 0, sizeof(event));
+ switch (rtm->rtm_type) {
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *) rtm;
+ if (ifan->ifan_index != drv->ifindex)
+ break;
+ strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ switch (ifan->ifan_what) {
+ case IFAN_DEPARTURE:
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ default:
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+ event.interface_status.ifname,
+ ifan->ifan_what == IFAN_DEPARTURE ?
+ "removed" : "added");
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ break;
+ case RTM_IEEE80211:
+ ifan = (struct if_announcemsghdr *) rtm;
+ if (ifan->ifan_index != drv->ifindex)
+ break;
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ break;
+ case RTM_IEEE80211_DISASSOC:
+ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+ break;
+ case RTM_IEEE80211_SCAN:
+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+
+ os_memset(&event, 0, sizeof(event));
+ event.michael_mic_failure.unicast =
+ !IEEE80211_IS_MULTICAST(mic->iev_dst);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
+ &event);
+ break;
+ }
+ break;
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *) rtm;
+ if (ifm->ifm_index != drv->ifindex)
+ break;
+ if ((rtm->rtm_flags & RTF_UP) == 0) {
+ strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ event.interface_status.ifname);
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ }
+ break;
+ }
+}
+
+/* Compare function for sorting scan results. Return >0 if @b is consider
+ * better. */
+static int
+wpa_scan_result_compar(const void *a, const void *b)
+{
+ const struct wpa_scan_result *wa = a;
+ const struct wpa_scan_result *wb = b;
+
+ /* WPA/WPA2 support preferred */
+ if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
+ !(wa->wpa_ie_len || wa->rsn_ie_len))
+ return 1;
+ if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
+ (wa->wpa_ie_len || wa->rsn_ie_len))
+ return -1;
+
+ /* privacy support preferred */
+ if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
+ (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
+ return 1;
+ if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
+ (wb->caps & IEEE80211_CAPINFO_PRIVACY))
+ return -1;
+
+ /* best/max rate preferred if signal level close enough XXX */
+ if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
+ return wb->maxrate - wa->maxrate;
+
+ /* use freq for channel preference */
+
+ /* all things being equal, use signal level */
+ return wb->level - wa->level;
+}
+
+static int
+getmaxrate(uint8_t rates[15], uint8_t nrates)
+{
+ int i, maxrate = -1;
+
+ for (i = 0; i < nrates; i++) {
+ int rate = rates[i] & IEEE80211_RATE_VAL;
+ if (rate > maxrate)
+ rate = maxrate;
+ }
+ return maxrate;
+}
+
+/* unalligned little endian access */
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((const u_int8_t *)(p))[0] ) | \
+ (((const u_int8_t *)(p))[1] << 8) | \
+ (((const u_int8_t *)(p))[2] << 16) | \
+ (((const u_int8_t *)(p))[3] << 24)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int
+wpa_driver_bsd_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+#define min(a,b) ((a)>(b)?(b):(a))
+ struct wpa_driver_bsd_data *drv = priv;
+ uint8_t buf[24*1024];
+ uint8_t *cp, *vp;
+ struct ieee80211req_scan_result *sr;
+ struct wpa_scan_result *wsr;
+ int len, ielen;
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+
+ len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+ cp = buf;
+ wsr = results;
+ while (len >= sizeof(struct ieee80211req_scan_result)) {
+ sr = (struct ieee80211req_scan_result *) cp;
+ os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
+ wsr->ssid_len = sr->isr_ssid_len;
+ wsr->freq = sr->isr_freq;
+ wsr->noise = sr->isr_noise;
+ wsr->qual = sr->isr_rssi;
+ wsr->level = 0; /* XXX? */
+ wsr->caps = sr->isr_capinfo;
+ wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
+ vp = (u_int8_t *)(sr+1);
+ os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
+ if (sr->isr_ie_len > 0) {
+ vp += sr->isr_ssid_len;
+ ielen = sr->isr_ie_len;
+ while (ielen > 0) {
+ switch (vp[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (!iswpaoui(vp))
+ break;
+ wsr->wpa_ie_len =
+ min(2+vp[1], SSID_MAX_WPA_IE_LEN);
+ os_memcpy(wsr->wpa_ie, vp,
+ wsr->wpa_ie_len);
+ break;
+ case IEEE80211_ELEMID_RSN:
+ wsr->rsn_ie_len =
+ min(2+vp[1], SSID_MAX_WPA_IE_LEN);
+ os_memcpy(wsr->rsn_ie, vp,
+ wsr->rsn_ie_len);
+ break;
+ }
+ ielen -= 2+vp[1];
+ vp += 2+vp[1];
+ }
+ }
+
+ cp += sr->isr_len, len -= sr->isr_len;
+ wsr++;
+ }
+ qsort(results, wsr - results, sizeof(struct wpa_scan_result),
+ wpa_scan_result_compar);
+
+ wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
+ len, wsr - results);
+
+ return wsr - results;
+#undef min
+}
+
+static void *
+wpa_driver_bsd_init(void *ctx, const char *ifname)
+{
+#define GETPARAM(drv, param, v) \
+ (((v) = get80211param(drv, param)) != -1)
+ struct wpa_driver_bsd_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ /*
+ * NB: We require the interface name be mappable to an index.
+ * This implies we do not support having wpa_supplicant
+ * wait for an interface to appear. This seems ok; that
+ * doesn't belong here; it's really the job of devd.
+ */
+ drv->ifindex = if_nametoindex(ifname);
+ if (drv->ifindex == 0) {
+ wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+ __func__, ifname);
+ goto fail1;
+ }
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0)
+ goto fail1;
+ drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (drv->route < 0)
+ goto fail;
+ eloop_register_read_sock(drv->route,
+ wpa_driver_bsd_event_receive, ctx, drv);
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
+ "roaming: %s", __func__, strerror(errno));
+ goto fail;
+ }
+
+ if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ return drv;
+fail:
+ close(drv->sock);
+fail1:
+ os_free(drv);
+ return NULL;
+#undef GETPARAM
+}
+
+static void
+wpa_driver_bsd_deinit(void *priv)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int flags;
+
+ eloop_unregister_read_sock(drv->route);
+
+ /* NB: mark interface down */
+ if (getifflags(drv, &flags) == 0)
+ (void) setifflags(drv, flags &~ IFF_UP);
+
+ wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
+ if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
+ wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
+ __func__);
+
+ (void) close(drv->route); /* ioctl socket */
+ (void) close(drv->sock); /* event socket */
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_bsd_ops = {
+ .name = "bsd",
+ .desc = "BSD 802.11 support (Atheros, etc.)",
+ .init = wpa_driver_bsd_init,
+ .deinit = wpa_driver_bsd_deinit,
+ .get_bssid = wpa_driver_bsd_get_bssid,
+ .get_ssid = wpa_driver_bsd_get_ssid,
+ .set_wpa = wpa_driver_bsd_set_wpa,
+ .set_key = wpa_driver_bsd_set_key,
+ .set_countermeasures = wpa_driver_bsd_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted,
+ .scan = wpa_driver_bsd_scan,
+ .get_scan_results = wpa_driver_bsd_get_scan_results,
+ .deauthenticate = wpa_driver_bsd_deauthenticate,
+ .disassociate = wpa_driver_bsd_disassociate,
+ .associate = wpa_driver_bsd_associate,
+ .set_auth_alg = wpa_driver_bsd_set_auth_alg,
+};
diff --git a/contrib/wpa/src/drivers/driver_hostap.c b/contrib/wpa/src/drivers/driver_hostap.c
new file mode 100644
index 0000000..84ef3bd
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_hostap.c
@@ -0,0 +1,513 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Host AP driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "eloop.h"
+#include "driver_hostap.h"
+
+
+struct wpa_driver_hostap_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+ int current_mode; /* infra/adhoc */
+};
+
+
+static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
+ struct prism2_hostapd_param *param,
+ int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
+ int ret = errno;
+ if (show_err)
+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = wpa_ie_len;
+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
+ res = hostapd_ioctl(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int prism2param(struct wpa_driver_hostap_data *drv, int param,
+ int value)
+{
+ struct iwreq iwr;
+ int *i, ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+ if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
+ ret = -1;
+ if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static void show_set_key_error(struct prism2_hostapd_param *param)
+{
+ switch (param->u.crypt.err) {
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
+ param->u.crypt.alg);
+ wpa_printf(MSG_INFO, "You may need to load kernel module to "
+ "register that algorithm.");
+ wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
+ "WEP.");
+ break;
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
+ MAC2STR(param->sta_addr));
+ break;
+ case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "Key setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "TX key index setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
+ wpa_printf(MSG_INFO, "Card configuration failed.");
+ break;
+ }
+}
+
+
+static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_SET_ENCRYPTION;
+ /* TODO: In theory, STA in client mode can use five keys; four default
+ * keys for receiving (with keyidx 0..3) and one individual key for
+ * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
+ * keyidx 0 is reserved for this unicast use and default keys can only
+ * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
+ * This should be fine for more or less all cases, but for completeness
+ * sake, the driver could be enhanced to support the missing key. */
+#if 0
+ if (addr == NULL)
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
+#else
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+#endif
+ os_strlcpy((char *) param->u.crypt.alg, alg_name,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = key_idx;
+ os_memcpy(param->u.crypt.seq, seq, seq_len);
+ param->u.crypt.key_len = key_len;
+ os_memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ show_set_key_error(param);
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
+}
+
+
+static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled);
+}
+
+
+static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
+ int type)
+{
+ struct iwreq iwr;
+ int *i, ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = type;
+
+ if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_RESET]");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct prism2_hostapd_param param;
+ int ret;
+
+ /* There does not seem to be a better way of deauthenticating or
+ * disassociating with Prism2/2.5/3 than sending the management frame
+ * and then resetting the Port0 to make sure both the AP and the STA
+ * end up in disconnected state. */
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_MLME;
+ os_memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.mlme.cmd = cmd;
+ param.u.mlme.reason_code = reason_code;
+ ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
+ if (ret == 0) {
+ os_sleep(0, 100000);
+ ret = wpa_driver_hostap_reset(drv, 2);
+ }
+ return ret;
+}
+
+
+static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
+ reason_code);
+}
+
+
+static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
+ reason_code);
+}
+
+
+static int
+wpa_driver_hostap_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (params->mode != drv->current_mode) {
+ /* At the moment, Host AP driver requires host_roaming=2 for
+ * infrastructure mode and host_roaming=0 for adhoc. */
+ if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
+ params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
+ __func__);
+ }
+ drv->current_mode = params->mode;
+ }
+
+ if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
+ params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
+ ret = -1;
+ if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
+ params->wpa_ie_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
+ ret = -1;
+ if (params->freq &&
+ wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
+ < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
+ allow_unencrypted_eapol) < 0) {
+ wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
+ "ieee_802_1x param");
+ /* Ignore this error.. driver_hostap.c can also be used with
+ * other drivers that do not support this prism2_param. */
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ struct prism2_hostapd_param param;
+ int ret;
+
+ if (ssid == NULL) {
+ /* Use standard Linux Wireless Extensions ioctl if possible
+ * because some drivers using hostap code in wpa_supplicant
+ * might not support Host AP specific scan request (with SSID
+ * info). */
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+ }
+
+ if (ssid_len > 32)
+ ssid_len = 32;
+
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
+ param.u.scan_req.ssid_len = ssid_len;
+ os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
+ ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+ eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+
+ return ret;
+}
+
+
+static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ int algs = 0;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= 1;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= 2;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= 4;
+ if (algs == 0)
+ algs = 1; /* at least one algorithm should be set */
+
+ return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
+}
+
+
+static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_hostap_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_hostap_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ perror("socket");
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ if (os_strncmp(ifname, "wlan", 4) == 0) {
+ /*
+ * Host AP driver may use both wlan# and wifi# interface in
+ * wireless events.
+ */
+ char ifname2[IFNAMSIZ + 1];
+ os_strlcpy(ifname2, ifname, sizeof(ifname2));
+ os_memcpy(ifname2, "wifi", 4);
+ wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_hostap_deinit(void *priv)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_hostap_ops = {
+ .name = "hostap",
+ .desc = "Host AP driver (Intersil Prism2/2.5/3)",
+ .get_bssid = wpa_driver_hostap_get_bssid,
+ .get_ssid = wpa_driver_hostap_get_ssid,
+ .set_wpa = wpa_driver_hostap_set_wpa,
+ .set_key = wpa_driver_hostap_set_key,
+ .set_countermeasures = wpa_driver_hostap_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted,
+ .scan = wpa_driver_hostap_scan,
+ .get_scan_results2 = wpa_driver_hostap_get_scan_results,
+ .deauthenticate = wpa_driver_hostap_deauthenticate,
+ .disassociate = wpa_driver_hostap_disassociate,
+ .associate = wpa_driver_hostap_associate,
+ .set_auth_alg = wpa_driver_hostap_set_auth_alg,
+ .init = wpa_driver_hostap_init,
+ .deinit = wpa_driver_hostap_deinit,
+ .set_operstate = wpa_driver_hostap_set_operstate,
+};
diff --git a/contrib/wpa/src/drivers/driver_hostap.h b/contrib/wpa/src/drivers/driver_hostap.h
new file mode 100644
index 0000000..a2508ed
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_hostap.h
@@ -0,0 +1,153 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Host AP driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef HOSTAP_DRIVER_H
+#define HOSTAP_DRIVER_H
+
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_TXRATECTRL = 2,
+ PRISM2_PARAM_BEACON_INT = 3,
+ PRISM2_PARAM_PSEUDO_IBSS = 4,
+ PRISM2_PARAM_ALC = 5,
+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_DUMP = 7,
+ PRISM2_PARAM_OTHER_AP_POLICY = 8,
+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_DTIM_PERIOD = 11,
+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+ PRISM2_PARAM_MAX_WDS = 13,
+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+ PRISM2_PARAM_AP_AUTH_ALGS = 15,
+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+ PRISM2_PARAM_HOST_ENCRYPT = 17,
+ PRISM2_PARAM_HOST_DECRYPT = 18,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
+ PRISM2_PARAM_HOST_ROAMING = 21,
+ PRISM2_PARAM_BCRX_STA_KEY = 22,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+ PRISM2_PARAM_MONITOR_TYPE = 26,
+ PRISM2_PARAM_WDS_TYPE = 27,
+ PRISM2_PARAM_HOSTSCAN = 28,
+ PRISM2_PARAM_AP_SCAN = 29,
+ PRISM2_PARAM_ENH_SEC = 30,
+ PRISM2_PARAM_IO_DEBUG = 31,
+ PRISM2_PARAM_BASIC_RATES = 32,
+ PRISM2_PARAM_OPER_RATES = 33,
+ PRISM2_PARAM_HOSTAPD = 34,
+ PRISM2_PARAM_HOSTAPD_STA = 35,
+ PRISM2_PARAM_WPA = 36,
+ PRISM2_PARAM_PRIVACY_INVOKED = 37,
+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+ PRISM2_HOSTAPD_ADD_STA = 2,
+ PRISM2_HOSTAPD_REMOVE_STA = 3,
+ PRISM2_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_GET_ENCRYPTION = 7,
+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+ PRISM2_HOSTAPD_GET_RID = 9,
+ PRISM2_HOSTAPD_SET_RID = 10,
+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
+#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#endif /* HOSTAP_DRIVER_H */
diff --git a/contrib/wpa/src/drivers/driver_iphone.m b/contrib/wpa/src/drivers/driver_iphone.m
new file mode 100644
index 0000000..8e64ffd
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_iphone.m
@@ -0,0 +1,466 @@
+/*
+ * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#include "MobileApple80211.h"
+
+struct wpa_driver_iphone_data {
+ void *ctx;
+ Apple80211Ref wireless_ctx;
+ CFArrayRef scan_results;
+ int ctrl_power;
+};
+
+
+static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
+{
+ const void *res;
+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
+ kCFStringEncodingMacRoman);
+ if (str == NULL)
+ return NULL;
+
+ res = CFDictionaryGetValue(dict, str);
+ CFRelease(str);
+ return res;
+}
+
+
+static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ CFDataRef data;
+ int err, len;
+
+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
+ &data);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
+ "failed: %d", err);
+ return -1;
+ }
+
+ len = CFDataGetLength(data);
+ if (len > 32) {
+ CFRelease(data);
+ return -1;
+ }
+ os_memcpy(ssid, CFDataGetBytePtr(data), len);
+ CFRelease(data);
+
+ return len;
+}
+
+
+static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ CFStringRef data;
+ int err;
+ int a1, a2, a3, a4, a5, a6;
+
+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
+ &data);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
+ "failed: %d", err);
+ return -1;
+ }
+
+ sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
+ "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
+ bssid[0] = a1;
+ bssid[1] = a2;
+ bssid[2] = a3;
+ bssid[3] = a4;
+ bssid[4] = a5;
+ bssid[5] = a6;
+
+ CFRelease(data);
+
+ return 0;
+}
+
+
+static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int err;
+
+ if (drv->scan_results) {
+ CFRelease(drv->scan_results);
+ drv->scan_results = NULL;
+ }
+
+ err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
+ err);
+ return -1;
+ }
+
+ eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static int wpa_driver_iphone_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ size_t i, num;
+
+ if (drv->scan_results == NULL)
+ return 0;
+
+ num = CFArrayGetCount(drv->scan_results);
+ if (num > max_size)
+ num = max_size;
+ os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+ for (i = 0; i < num; i++) {
+ struct wpa_scan_result *res = &results[i];
+ CFDictionaryRef dict =
+ CFArrayGetValueAtIndex(drv->scan_results, i);
+ CFDataRef data;
+ CFStringRef str;
+ CFNumberRef num;
+ int val;
+
+ data = cfdict_get_key_str(dict, "SSID");
+ if (data) {
+ res->ssid_len = CFDataGetLength(data);
+ if (res->ssid_len > 32)
+ res->ssid_len = 32;
+ os_memcpy(res->ssid, CFDataGetBytePtr(data),
+ res->ssid_len);
+ }
+
+ str = cfdict_get_key_str(dict, "BSSID");
+ if (str) {
+ int a1, a2, a3, a4, a5, a6;
+ sscanf(CFStringGetCStringPtr(
+ str, kCFStringEncodingMacRoman),
+ "%x:%x:%x:%x:%x:%x",
+ &a1, &a2, &a3, &a4, &a5, &a6);
+ res->bssid[0] = a1;
+ res->bssid[1] = a2;
+ res->bssid[2] = a3;
+ res->bssid[3] = a4;
+ res->bssid[4] = a5;
+ res->bssid[5] = a6;
+ }
+
+ num = cfdict_get_key_str(dict, "CAPABILITIES");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->caps = val;
+ }
+
+ num = cfdict_get_key_str(dict, "CHANNEL");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->freq = 2407 + val * 5;
+ }
+
+ num = cfdict_get_key_str(dict, "RSSI");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->level = val;
+ }
+
+ num = cfdict_get_key_str(dict, "NOISE");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->noise = val;
+ }
+
+ data = cfdict_get_key_str(dict, "IE");
+ if (data) {
+ u8 *ptr = (u8 *) CFDataGetBytePtr(data);
+ int len = CFDataGetLength(data);
+ u8 *pos = ptr, *end = ptr + len;
+
+ while (pos + 2 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_RSN &&
+ pos[1] <= SSID_MAX_WPA_IE_LEN) {
+ os_memcpy(res->rsn_ie, pos,
+ 2 + pos[1]);
+ res->rsn_ie_len = 2 + pos[1];
+ }
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] > 4 && pos[2] == 0x00 &&
+ pos[3] == 0x50 && pos[4] == 0xf2 &&
+ pos[5] == 0x01) {
+ os_memcpy(res->wpa_ie, pos,
+ 2 + pos[1]);
+ res->wpa_ie_len = 2 + pos[1];
+ }
+
+ pos = pos + 2 + pos[1];
+ }
+ }
+ }
+
+ return num;
+}
+
+
+static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_iphone_data *drv = eloop_ctx;
+ u8 bssid[ETH_ALEN];
+
+ if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
+ eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
+ drv, drv->ctx);
+ return;
+ }
+
+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_iphone_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int i, num, err;
+ size_t ssid_len;
+ CFDictionaryRef bss = NULL;
+
+ /*
+ * TODO: Consider generating parameters instead of just using an entry
+ * from scan results in order to support ap_scan=2.
+ */
+
+ if (drv->scan_results == NULL) {
+ wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
+ "associate");
+ return -1;
+ }
+
+ num = CFArrayGetCount(drv->scan_results);
+
+ for (i = 0; i < num; i++) {
+ CFDictionaryRef dict =
+ CFArrayGetValueAtIndex(drv->scan_results, i);
+ CFDataRef data;
+
+ data = cfdict_get_key_str(dict, "SSID");
+ if (data == NULL)
+ continue;
+
+ ssid_len = CFDataGetLength(data);
+ if (ssid_len != params->ssid_len ||
+ os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
+ != 0)
+ continue;
+
+ bss = dict;
+ break;
+ }
+
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
+ "results - cannot associate");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
+ "from scan results");
+
+ err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
+ "%d", err);
+ return -1;
+ }
+
+ /*
+ * Driver is actually already associated; report association from an
+ * eloop callback.
+ */
+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+ eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
+ drv->ctx);
+
+ return 0;
+}
+
+
+static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key,
+ size_t key_len)
+{
+ /*
+ * TODO: Need to either support configuring PMK for 4-way handshake or
+ * PTK for TKIP/CCMP.
+ */
+ return -1;
+}
+
+
+static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ return 0;
+}
+
+
+static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_iphone_data *drv;
+ int err;
+ char power;
+ CFStringRef name;
+ CFDictionaryRef dict;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ err = Apple80211Open(&drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
+ err);
+ os_free(drv);
+ return NULL;
+ }
+
+ name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
+ kCFStringEncodingISOLatin1);
+ if (name == NULL) {
+ wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = Apple80211BindToInterface(drv->wireless_ctx, name);
+ CFRelease(name);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
+ "failed: %d", err);
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = Apple80211GetPower(drv->wireless_ctx, &power);
+ if (err)
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
+ err);
+
+ wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
+
+ if (!power) {
+ drv->ctrl_power = 1;
+ err = Apple80211SetPower(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
+ "failed: %d", err);
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
+ if (err == 0) {
+ CFShow(dict);
+ CFRelease(dict);
+ } else {
+ printf("Apple80211GetInfoCopy: %d\n", err);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_iphone_deinit(void *priv)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int err;
+
+ eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+
+ if (drv->ctrl_power) {
+ wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
+ err = Apple80211SetPower(drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
+ "failed: %d", err);
+ }
+ }
+
+ err = Apple80211Close(drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
+ err);
+ }
+
+ if (drv->scan_results)
+ CFRelease(drv->scan_results);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_iphone_ops = {
+ .name = "iphone",
+ .desc = "iPhone/iPod touch Apple80211 driver",
+ .get_ssid = wpa_driver_iphone_get_ssid,
+ .get_bssid = wpa_driver_iphone_get_bssid,
+ .init = wpa_driver_iphone_init,
+ .deinit = wpa_driver_iphone_deinit,
+ .scan = wpa_driver_iphone_scan,
+ .get_scan_results = wpa_driver_iphone_get_scan_results,
+ .associate = wpa_driver_iphone_associate,
+ .set_key = wpa_driver_iphone_set_key,
+ .get_capa = wpa_driver_iphone_get_capa,
+};
diff --git a/contrib/wpa/src/drivers/driver_ipw.c b/contrib/wpa/src/drivers/driver_ipw.c
new file mode 100644
index 0000000..3c19ccc
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_ipw.c
@@ -0,0 +1,463 @@
+/*
+ * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
+ * Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com>
+ * Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that ipw2100/2200 drivers change to use generic Linux wireless
+ * extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
+ * or newer). driver_wext.c should be used in those cases.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+struct wpa_driver_ipw_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+/* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
+
+#define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
+
+#define IPW_CMD_SET_WPA_PARAM 1
+#define IPW_CMD_SET_WPA_IE 2
+#define IPW_CMD_SET_ENCRYPTION 3
+#define IPW_CMD_MLME 4
+
+#define IPW_PARAM_WPA_ENABLED 1
+#define IPW_PARAM_TKIP_COUNTERMEASURES 2
+#define IPW_PARAM_DROP_UNENCRYPTED 3
+#define IPW_PARAM_PRIVACY_INVOKED 4
+#define IPW_PARAM_AUTH_ALGS 5
+#define IPW_PARAM_IEEE_802_1X 6
+
+#define IPW_MLME_STA_DEAUTH 1
+#define IPW_MLME_STA_DISASSOC 2
+
+#define IPW_CRYPT_ERR_UNKNOWN_ALG 2
+#define IPW_CRYPT_ERR_UNKNOWN_ADDR 3
+#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define IPW_CRYPT_ERR_KEY_SET_FAILED 5
+#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define IPW_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#define IPW_CRYPT_ALG_NAME_LEN 16
+
+struct ipw_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u8 name;
+ u32 value;
+ } wpa_param;
+ struct {
+ u32 len;
+ u8 reserved[32];
+ u8 data[0];
+ } wpa_ie;
+ struct{
+ u32 command;
+ u32 reason_code;
+ } mlme;
+ struct {
+ u8 alg[IPW_CRYPT_ALG_NAME_LEN];
+ u8 set_tx;
+ u32 err;
+ u8 idx;
+ u8 seq[8];
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+
+ } u;
+};
+
+/* end of ipw2100.c and ipw2200.c code */
+
+static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
+ struct ipw_param *param, int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
+ int ret = errno;
+ if (show_err)
+ perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static void ipw_show_set_key_error(struct ipw_param *param)
+{
+ switch (param->u.crypt.err) {
+ case IPW_CRYPT_ERR_UNKNOWN_ALG:
+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
+ param->u.crypt.alg);
+ wpa_printf(MSG_INFO, "You may need to load kernel module to "
+ "register that algorithm.");
+ wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
+ " WEP.");
+ break;
+ case IPW_CRYPT_ERR_UNKNOWN_ADDR:
+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
+ MAC2STR(param->sta_addr));
+ break;
+ case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
+ break;
+ case IPW_CRYPT_ERR_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "Key setting failed.");
+ break;
+ case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "TX key index setting failed.");
+ break;
+ case IPW_CRYPT_ERR_CARD_CONF_FAILED:
+ wpa_printf(MSG_INFO, "Card configuration failed.");
+ break;
+ }
+}
+
+
+static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ struct ipw_param *param;
+ int ret;
+ size_t blen = sizeof(*param) + wpa_ie_len;
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = IPW_CMD_SET_WPA_IE;
+ param->u.wpa_ie.len = wpa_ie_len;
+ os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
+
+ ret = ipw_ioctl(drv, param, blen, 1);
+
+ os_free(param);
+ return ret;
+}
+
+
+static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
+ u32 value)
+{
+ struct ipw_param param;
+
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = IPW_CMD_SET_WPA_PARAM;
+ param.u.wpa_param.name = name;
+ param.u.wpa_param.value = value;
+
+ return ipw_ioctl(drv, &param, sizeof(param), 1);
+}
+
+
+static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
+ int cmd, int reason)
+{
+ struct ipw_param param;
+
+ os_memset(&param, 0, sizeof(param));
+ os_memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.cmd = IPW_CMD_MLME;
+ param.u.mlme.command = cmd;
+ param.u.mlme.reason_code = reason;
+
+ return ipw_ioctl(drv, &param, sizeof(param), 1);
+}
+
+
+static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+
+ if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ struct ipw_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct ipw_param *) buf;
+ param->cmd = IPW_CMD_SET_ENCRYPTION;
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ os_strlcpy((char *) param->u.crypt.alg, alg_name,
+ IPW_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.set_tx = set_tx ? 1 : 0;
+ param->u.crypt.idx = key_idx;
+ os_memcpy(param->u.crypt.seq, seq, seq_len);
+ param->u.crypt.key_len = key_len;
+ os_memcpy((u8 *) (param + 1), key, key_len);
+
+ if (ipw_ioctl(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ ipw_show_set_key_error(param);
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
+ enabled);
+
+}
+
+
+static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
+}
+
+
+static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
+}
+
+
+static int
+wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ int ret = 0;
+ int unencrypted_eapol;
+
+ if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
+ ret = -1;
+
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ unencrypted_eapol = 0;
+ else
+ unencrypted_eapol = 1;
+
+ if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
+ unencrypted_eapol) < 0) {
+ wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
+ "ieee_802_1x param");
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ int algs = 0;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= 1;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= 2;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= 4;
+ if (algs == 0)
+ algs = 1; /* at least one algorithm should be set */
+
+ wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
+ return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
+}
+
+
+static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_ipw_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_ipw_data *drv;
+ int ver;
+
+ wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ ver = wpa_driver_wext_get_version(drv->wext);
+ if (ver >= 18) {
+ wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
+ "detected.", ver);
+ wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
+ "(-Dwext) instead of driver_ipw.");
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_ipw_deinit(void *priv)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_ipw_ops = {
+ .name = "ipw",
+ .desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
+ "or newer)",
+ .get_bssid = wpa_driver_ipw_get_bssid,
+ .get_ssid = wpa_driver_ipw_get_ssid,
+ .set_wpa = wpa_driver_ipw_set_wpa,
+ .set_key = wpa_driver_ipw_set_key,
+ .set_countermeasures = wpa_driver_ipw_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
+ .scan = wpa_driver_ipw_scan,
+ .get_scan_results2 = wpa_driver_ipw_get_scan_results,
+ .deauthenticate = wpa_driver_ipw_deauthenticate,
+ .disassociate = wpa_driver_ipw_disassociate,
+ .associate = wpa_driver_ipw_associate,
+ .set_auth_alg = wpa_driver_ipw_set_auth_alg,
+ .init = wpa_driver_ipw_init,
+ .deinit = wpa_driver_ipw_deinit,
+ .set_operstate = wpa_driver_ipw_set_operstate,
+};
diff --git a/contrib/wpa/src/drivers/driver_madwifi.c b/contrib/wpa/src/drivers/driver_madwifi.c
new file mode 100644
index 0000000..7521037
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_madwifi.c
@@ -0,0 +1,601 @@
+/*
+ * WPA Supplicant - driver interaction with MADWIFI 802.11 driver
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that madwifi supports WPA configuration via Linux wireless
+ * extensions and if the kernel includes support for this, driver_wext.c should
+ * be used instead of this driver wrapper.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+#include "wireless_copy.h"
+
+/*
+ * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
+ */
+#undef WME_OUI_TYPE
+
+#include <include/compat.h>
+#include <net80211/ieee80211.h>
+#ifdef WME_NUM_AC
+/* Assume this is built against BSD branch of madwifi driver. */
+#define MADWIFI_BSD
+#include <net80211/_ieee80211.h>
+#endif /* WME_NUM_AC */
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+
+#ifdef IEEE80211_IOCTL_SETWMMPARAMS
+/* Assume this is built against madwifi-ng */
+#define MADWIFI_NG
+#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
+
+struct wpa_driver_madwifi_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+static int
+set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
+ int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (len < IFNAMSIZ &&
+ op != IEEE80211_IOCTL_SET_APPIEBUF) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ os_memcpy(iwr.u.name, data, len);
+ } else {
+ /*
+ * Argument data too big for inline transfer; setup a
+ * parameter block instead; the kernel will transfer
+ * the data for the driver.
+ */
+ iwr.u.data.pointer = data;
+ iwr.u.data.length = len;
+ }
+
+ if (ioctl(drv->sock, op, &iwr) < 0) {
+ if (show_err) {
+#ifdef MADWIFI_NG
+ int first = IEEE80211_IOCTL_SETPARAM;
+ int last = IEEE80211_IOCTL_KICKMAC;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETMODE]",
+ "ioctl[IEEE80211_IOCTL_GETMODE]",
+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_KICKMAC]",
+ };
+#else /* MADWIFI_NG */
+ int first = IEEE80211_IOCTL_SETPARAM;
+ int last = IEEE80211_IOCTL_CHANLIST;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ "ioctl[IEEE80211_IOCTL_GETKEY]",
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_CHANLIST]",
+ };
+#endif /* MADWIFI_NG */
+ int idx = op - first;
+ if (first <= op && op <= last &&
+ idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
+ && opnames[idx])
+ perror(opnames[idx]);
+ else
+ perror("ioctl[unknown???]");
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
+ int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.mode = op;
+ os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ if (show_err)
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* NB: SETOPTIE is not fixed-size so must not be inlined */
+ iwr.u.data.pointer = (void *) wpa_ie;
+ iwr.u.data.length = wpa_ie_len;
+
+ if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
+ const u8 *addr)
+{
+ struct ieee80211req_del_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
+ os_memset(&wk, 0, sizeof(wk));
+ wk.idk_keyix = key_idx;
+ if (addr != NULL)
+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+
+ return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
+}
+
+static int
+wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_key wk;
+ char *alg_name;
+ u_int8_t cipher;
+
+ if (alg == WPA_ALG_NONE)
+ return wpa_driver_madwifi_del_key(drv, key_idx, addr);
+
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN) == 0) {
+ /*
+ * madwifi did not seem to like static WEP key
+ * configuration with IEEE80211_IOCTL_SETKEY, so use
+ * Linux wireless extensions ioctl for this.
+ */
+ return wpa_driver_wext_set_key(drv->wext, alg, addr,
+ key_idx, set_tx,
+ seq, seq_len,
+ key, key_len);
+ }
+ alg_name = "WEP";
+ cipher = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ cipher = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
+ __FUNCTION__, alg);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > sizeof(u_int64_t)) {
+ wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
+ __FUNCTION__, (unsigned long) seq_len);
+ return -2;
+ }
+ if (key_len > sizeof(wk.ik_keydata)) {
+ wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
+ __FUNCTION__, (unsigned long) key_len);
+ return -3;
+ }
+
+ os_memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV;
+ if (addr == NULL ||
+ os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ wk.ik_flags |= IEEE80211_KEY_GROUP;
+ if (set_tx) {
+ wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ } else
+ os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_keylen = key_len;
+#ifdef WORDS_BIGENDIAN
+#define WPA_KEY_RSC_LEN 8
+ {
+ size_t i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ os_memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < seq_len; i++)
+ tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+ os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
+ }
+#else /* WORDS_BIGENDIAN */
+ os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+ os_memcpy(wk.ik_keydata, key, key_len);
+
+ return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
+}
+
+static int
+wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
+}
+
+
+static int
+wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
+}
+
+static int
+wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
+}
+
+static int
+wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
+}
+
+static int
+wpa_driver_madwifi_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret = 0, privacy = 1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * NB: Don't need to set the freq or cipher-related state as
+ * this is implied by the bssid which is used to locate
+ * the scanned node state which holds it. The ssid is
+ * needed to disambiguate an AP that broadcasts multiple
+ * ssid's but uses the same bssid.
+ */
+ /* XXX error handling is wrong but unclear what to do... */
+ if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
+ params->wpa_ie_len) < 0)
+ ret = -1;
+
+ if (params->pairwise_suite == CIPHER_NONE &&
+ params->group_suite == CIPHER_NONE &&
+ params->key_mgmt_suite == KEY_MGMT_NONE &&
+ params->wpa_ie_len == 0)
+ privacy = 0;
+
+ if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
+ ret = -1;
+
+ if (params->wpa_ie_len &&
+ set80211param(drv, IEEE80211_PARAM_WPA,
+ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
+ ret = -1;
+
+ if (params->bssid == NULL) {
+ /* ap_scan=2 mode - driver takes care of AP selection and
+ * roaming */
+ /* FIX: this does not seem to work; would probably need to
+ * change something in the driver */
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
+ ret = -1;
+
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ } else {
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_ASSOC;
+ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme), 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
+ __func__);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+static int
+wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ int authmode;
+
+ if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
+ (auth_alg & AUTH_ALG_SHARED_KEY))
+ authmode = IEEE80211_AUTH_AUTO;
+ else if (auth_alg & AUTH_ALG_SHARED_KEY)
+ authmode = IEEE80211_AUTH_SHARED;
+ else
+ authmode = IEEE80211_AUTH_OPEN;
+
+ return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
+}
+
+static int
+wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ /* set desired ssid before scan */
+ /* FIX: scan should not break the current association, so using
+ * set_ssid may not be the best way of doing this.. */
+ if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
+ ret = -1;
+
+ if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /*
+ * madwifi delivers a scan complete event so no need to poll, but
+ * register a backup timeout anyway to make sure that we recover even
+ * if the driver does not send this event for any reason. This timeout
+ * will only be used if the event is not delivered (event handler will
+ * cancel the timeout).
+ */
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+ eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+
+ return ret;
+}
+
+static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_madwifi_get_scan_results(void *priv)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_madwifi_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct ieee80211req_getset_appiebuf *probe_req_ie;
+ int ret;
+
+ probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
+ if (probe_req_ie == NULL)
+ return -1;
+
+ probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
+ probe_req_ie->app_buflen = ies_len;
+ os_memcpy(probe_req_ie->app_buf, ies, ies_len);
+
+ ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) +
+ ies_len, 1);
+
+ os_free(probe_req_ie);
+
+ return ret;
+}
+
+
+static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_madwifi_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL)
+ goto fail;
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0)
+ goto fail2;
+
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
+ "roaming", __FUNCTION__);
+ goto fail3;
+ }
+
+ if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
+ __FUNCTION__);
+ goto fail3;
+ }
+
+ return drv;
+
+fail3:
+ close(drv->sock);
+fail2:
+ wpa_driver_wext_deinit(drv->wext);
+fail:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void wpa_driver_madwifi_deinit(void *priv)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+
+ if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
+ __FUNCTION__);
+ }
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
+ "roaming", __FUNCTION__);
+ }
+ if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
+ "flag", __FUNCTION__);
+ }
+ if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
+ __FUNCTION__);
+ }
+
+ wpa_driver_wext_deinit(drv->wext);
+
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_madwifi_ops = {
+ .name = "madwifi",
+ .desc = "MADWIFI 802.11 support (Atheros, etc.)",
+ .get_bssid = wpa_driver_madwifi_get_bssid,
+ .get_ssid = wpa_driver_madwifi_get_ssid,
+ .set_key = wpa_driver_madwifi_set_key,
+ .init = wpa_driver_madwifi_init,
+ .deinit = wpa_driver_madwifi_deinit,
+ .set_countermeasures = wpa_driver_madwifi_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
+ .scan = wpa_driver_madwifi_scan,
+ .get_scan_results2 = wpa_driver_madwifi_get_scan_results,
+ .deauthenticate = wpa_driver_madwifi_deauthenticate,
+ .disassociate = wpa_driver_madwifi_disassociate,
+ .associate = wpa_driver_madwifi_associate,
+ .set_auth_alg = wpa_driver_madwifi_set_auth_alg,
+ .set_operstate = wpa_driver_madwifi_set_operstate,
+ .set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,
+};
diff --git a/contrib/wpa/src/drivers/driver_ndis.c b/contrib/wpa/src/drivers/driver_ndis.c
index b22109b..0bda20a 100644
--- a/contrib/wpa/src/drivers/driver_ndis.c
+++ b/contrib/wpa/src/drivers/driver_ndis.c
@@ -56,9 +56,14 @@ static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
/* FIX: to be removed once this can be compiled with the complete NDIS
* header files */
#ifndef OID_802_11_BSSID
+#define OID_802_3_MULTICAST_LIST 0x01010103
#define OID_802_11_BSSID 0x0d010101
#define OID_802_11_SSID 0x0d010102
#define OID_802_11_INFRASTRUCTURE_MODE 0x0d010108
@@ -610,12 +615,7 @@ static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
* Report PAE group address as the "BSSID" for wired
* connection.
*/
- bssid[0] = 0x01;
- bssid[1] = 0x80;
- bssid[2] = 0xc2;
- bssid[3] = 0x00;
- bssid[4] = 0x00;
- bssid[5] = 0x03;
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
return 0;
}
@@ -2704,6 +2704,19 @@ static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
}
+static int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
+{
+ if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
+ (const char *) pae_group_addr, ETH_ALEN) < 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
+ "to the multicast list");
+ return -1;
+ }
+
+ return 0;
+}
+
+
static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
{
struct wpa_driver_ndis_data *drv;
@@ -2799,6 +2812,7 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
"any wireless capabilities - assume it is "
"a wired interface");
drv->wired = 1;
+ ndis_add_multicast(drv);
}
}
diff --git a/contrib/wpa/src/drivers/driver_ndis_.c b/contrib/wpa/src/drivers/driver_ndis_.c
new file mode 100644
index 0000000..4bee9aa
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_ndis_.c
@@ -0,0 +1,105 @@
+/*
+ * WPA Supplicant - Windows/NDIS driver interface - event processing
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+
+/* Keep this event processing in a separate file and without WinPcap headers to
+ * avoid conflicts with some of the header files. */
+struct _ADAPTER;
+typedef struct _ADAPTER * LPADAPTER;
+#include "driver_ndis.h"
+
+
+void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
+ const u8 *data, size_t data_len);
+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv);
+
+
+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT,
+ EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL,
+ EVENT_ADAPTER_REMOVAL };
+
+/* Event data:
+ * enum event_types (as int, i.e., 4 octets)
+ * data length (2 octets (big endian), optional)
+ * data (variable len, optional)
+ */
+
+
+static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv,
+ u8 *buf, size_t len)
+{
+ u8 *pos, *data = NULL;
+ enum event_types type;
+ size_t data_len = 0;
+
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len);
+ if (len < sizeof(int))
+ return;
+ type = *((int *) buf);
+ pos = buf + sizeof(int);
+ wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type);
+
+ if (buf + len - pos > 2) {
+ data_len = (int) *pos++ << 8;
+ data_len += *pos++;
+ if (data_len > (size_t) (buf + len - pos)) {
+ wpa_printf(MSG_DEBUG, "NDIS: event data overflow");
+ return;
+ }
+ data = pos;
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len);
+ }
+
+ switch (type) {
+ case EVENT_CONNECT:
+ wpa_driver_ndis_event_connect(drv);
+ break;
+ case EVENT_DISCONNECT:
+ wpa_driver_ndis_event_disconnect(drv);
+ break;
+ case EVENT_MEDIA_SPECIFIC:
+ wpa_driver_ndis_event_media_specific(drv, data, data_len);
+ break;
+ case EVENT_ADAPTER_ARRIVAL:
+ wpa_driver_ndis_event_adapter_arrival(drv);
+ break;
+ case EVENT_ADAPTER_REMOVAL:
+ wpa_driver_ndis_event_adapter_removal(drv);
+ break;
+ }
+}
+
+
+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data)
+{
+ struct wpa_driver_ndis_data *drv = eloop_data;
+ u8 buf[512];
+ DWORD len;
+
+ ResetEvent(drv->event_avail);
+ if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL))
+ wpa_driver_ndis_event_process(drv, buf, len);
+ else {
+ wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__,
+ (int) GetLastError());
+ }
+}
diff --git a/contrib/wpa/src/drivers/driver_ndiswrapper.c b/contrib/wpa/src/drivers/driver_ndiswrapper.c
new file mode 100644
index 0000000..b5c534a
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_ndiswrapper.c
@@ -0,0 +1,370 @@
+/*
+ * WPA Supplicant - driver interaction with Linux ndiswrapper
+ * Copyright (c) 2004-2006, Giridhar Pemmasani <giri@lmc.cs.sunysb.edu>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that ndiswrapper supports WPA configuration via Linux wireless
+ * extensions and if the kernel includes support for this, driver_wext.c should
+ * be used instead of this driver wrapper.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+struct wpa_driver_ndiswrapper_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+
+struct wpa_key
+{
+ wpa_alg alg;
+ const u8 *addr;
+ int key_index;
+ int set_tx;
+ const u8 *seq;
+ size_t seq_len;
+ const u8 *key;
+ size_t key_len;
+};
+
+struct wpa_assoc_info
+{
+ const u8 *bssid;
+ const u8 *ssid;
+ size_t ssid_len;
+ int freq;
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ wpa_cipher pairwise_suite;
+ wpa_cipher group_suite;
+ wpa_key_mgmt key_mgmt_suite;
+ int auth_alg;
+ int mode;
+};
+
+#define PRIV_RESET SIOCIWFIRSTPRIV+0
+#define WPA_SET_WPA SIOCIWFIRSTPRIV+1
+#define WPA_SET_KEY SIOCIWFIRSTPRIV+2
+#define WPA_ASSOCIATE SIOCIWFIRSTPRIV+3
+#define WPA_DISASSOCIATE SIOCIWFIRSTPRIV+4
+#define WPA_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+5
+#define WPA_SET_COUNTERMEASURES SIOCIWFIRSTPRIV+6
+#define WPA_DEAUTHENTICATE SIOCIWFIRSTPRIV+7
+#define WPA_SET_AUTH_ALG SIOCIWFIRSTPRIV+8
+#define WPA_INIT SIOCIWFIRSTPRIV+9
+#define WPA_DEINIT SIOCIWFIRSTPRIV+10
+#define WPA_GET_CAPA SIOCIWFIRSTPRIV+11
+
+static int get_socket(void)
+{
+ static const int families[] = {
+ AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
+ };
+ unsigned int i;
+ int sock;
+
+ for (i = 0; i < sizeof(families) / sizeof(int); ++i) {
+ sock = socket(families[i], SOCK_DGRAM, 0);
+ if (sock >= 0)
+ return sock;
+ }
+
+ return -1;
+}
+
+static int iw_set_ext(struct wpa_driver_ndiswrapper_data *drv, int request,
+ struct iwreq *pwrq)
+{
+ os_strlcpy(pwrq->ifr_name, drv->ifname, IFNAMSIZ);
+ return ioctl(drv->sock, request, pwrq);
+}
+
+static int wpa_ndiswrapper_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ struct iwreq priv_req;
+ int ret = 0;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.data.flags = enabled;
+ if (iw_set_ext(drv, WPA_SET_WPA, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ struct wpa_key wpa_key;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ wpa_key.alg = alg;
+ wpa_key.addr = addr;
+ wpa_key.key_index = key_idx;
+ wpa_key.set_tx = set_tx;
+ wpa_key.seq = seq;
+ wpa_key.seq_len = seq_len;
+ wpa_key.key = key;
+ wpa_key.key_len = key_len;
+
+ priv_req.u.data.pointer = (void *)&wpa_key;
+ priv_req.u.data.length = sizeof(wpa_key);
+
+ if (iw_set_ext(drv, WPA_SET_KEY, &priv_req) < 0)
+ ret = -1;
+
+ if (alg == WPA_ALG_NONE) {
+ /*
+ * ndiswrapper did not seem to be clearing keys properly in
+ * some cases with WPA_SET_KEY. For example, roaming from WPA
+ * enabled AP to plaintext one seemed to fail since the driver
+ * did not associate. Try to make sure the keys are cleared so
+ * that plaintext APs can be used in all cases.
+ */
+ wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx,
+ seq, seq_len, key, key_len);
+ }
+
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = enabled;
+ if (iw_set_ext(drv, WPA_SET_COUNTERMEASURES, &priv_req) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = enabled;
+ if (iw_set_ext(drv, WPA_DROP_UNENCRYPTED, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = reason_code;
+ os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
+ if (iw_set_ext(drv, WPA_DEAUTHENTICATE, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
+ if (iw_set_ext(drv, WPA_DISASSOCIATE, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int
+wpa_ndiswrapper_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct wpa_assoc_info wpa_assoc_info;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+ os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info));
+
+ wpa_assoc_info.bssid = params->bssid;
+ wpa_assoc_info.ssid = params->ssid;
+ wpa_assoc_info.ssid_len = params->ssid_len;
+ wpa_assoc_info.freq = params->freq;
+ wpa_assoc_info.wpa_ie = params->wpa_ie;
+ wpa_assoc_info.wpa_ie_len = params->wpa_ie_len;
+ wpa_assoc_info.pairwise_suite = params->pairwise_suite;
+ wpa_assoc_info.group_suite = params->group_suite;
+ wpa_assoc_info.key_mgmt_suite = params->key_mgmt_suite;
+ wpa_assoc_info.auth_alg = params->auth_alg;
+ wpa_assoc_info.mode = params->mode;
+
+ priv_req.u.data.pointer = (void *)&wpa_assoc_info;
+ priv_req.u.data.length = sizeof(wpa_assoc_info);
+
+ if (iw_set_ext(drv, WPA_ASSOCIATE, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = auth_alg;
+ if (iw_set_ext(drv, WPA_SET_AUTH_ALG, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_ndiswrapper_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results * wpa_ndiswrapper_get_scan_results(void *priv)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_ndiswrapper_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.data.pointer = (void *) capa;
+ priv_req.u.data.length = sizeof(*capa);
+ if (iw_set_ext(drv, WPA_GET_CAPA, &priv_req) < 0)
+ ret = -1;
+ return ret;
+
+}
+
+
+static int wpa_ndiswrapper_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_ndiswrapper_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = get_socket();
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_ndiswrapper_deinit(void *priv)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = {
+ .name = "ndiswrapper",
+ .desc = "Linux ndiswrapper (deprecated; use wext)",
+ .set_wpa = wpa_ndiswrapper_set_wpa,
+ .set_key = wpa_ndiswrapper_set_key,
+ .set_countermeasures = wpa_ndiswrapper_set_countermeasures,
+ .set_drop_unencrypted = wpa_ndiswrapper_set_drop_unencrypted,
+ .deauthenticate = wpa_ndiswrapper_deauthenticate,
+ .disassociate = wpa_ndiswrapper_disassociate,
+ .associate = wpa_ndiswrapper_associate,
+ .set_auth_alg = wpa_ndiswrapper_set_auth_alg,
+
+ .get_bssid = wpa_ndiswrapper_get_bssid,
+ .get_ssid = wpa_ndiswrapper_get_ssid,
+ .scan = wpa_ndiswrapper_scan,
+ .get_scan_results2 = wpa_ndiswrapper_get_scan_results,
+ .init = wpa_ndiswrapper_init,
+ .deinit = wpa_ndiswrapper_deinit,
+ .get_capa = wpa_ndiswrapper_get_capa,
+ .set_operstate = wpa_ndiswrapper_set_operstate,
+};
diff --git a/contrib/wpa/src/drivers/driver_nl80211.c b/contrib/wpa/src/drivers/driver_nl80211.c
new file mode 100644
index 0000000..9ab6d17
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211.c
@@ -0,0 +1,2766 @@
+/*
+ * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include "nl80211_copy.h"
+#ifdef CONFIG_CLIENT_MLME
+#include <netpacket/packet.h>
+#include <linux/if_ether.h>
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#endif /* CONFIG_CLIENT_MLME */
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+
+struct wpa_driver_nl80211_data {
+ void *ctx;
+ int wext_event_sock;
+ int ioctl_sock;
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ int if_removed;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+
+ struct nl_handle *nl_handle;
+ struct nl_cache *nl_cache;
+ struct nl_cb *nl_cb;
+ struct genl_family *nl80211;
+
+#ifdef CONFIG_CLIENT_MLME
+ int monitor_sock; /* socket for monitor */
+ int monitor_ifidx;
+#endif /* CONFIG_CLIENT_MLME */
+};
+
+
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_flush_pmkid(void *priv);
+static int wpa_driver_nl80211_get_range(void *priv);
+static void
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+
+
+/* nl80211 code */
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *err = arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ int *ret = arg;
+ *ret = err->error;
+ return NL_SKIP;
+}
+
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
+{
+ struct nl_cb *cb;
+ int err = -ENOMEM;
+
+ cb = nl_cb_clone(drv->nl_cb);
+ if (!cb)
+ goto out;
+
+ err = nl_send_auto_complete(drv->nl_handle, msg);
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+ if (valid_handler)
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ valid_handler, valid_data);
+
+ while (err > 0)
+ nl_recvmsgs(drv->nl_handle, cb);
+ out:
+ nl_cb_put(cb);
+ nlmsg_free(msg);
+ return err;
+}
+
+
+struct family_data {
+ const char *group;
+ int id;
+};
+
+
+static int family_handler(struct nl_msg *msg, void *arg)
+{
+ struct family_data *res = arg;
+ struct nlattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *mcgrp;
+ int i;
+
+ nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[CTRL_ATTR_MCAST_GROUPS])
+ return NL_SKIP;
+
+ nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
+ !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
+ os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
+ res->group,
+ nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
+ continue;
+ res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ };
+
+ return NL_SKIP;
+}
+
+
+static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+ const char *family, const char *group)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+ struct family_data res = { group, -ENOENT };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+ genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+ 0, 0, CTRL_CMD_GETFAMILY, 0);
+ NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+
+ ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+ msg = NULL;
+ if (ret == 0)
+ ret = res.id;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_send_oper_ifla(
+ struct wpa_driver_nl80211_data *drv,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = drv->ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = (struct rtattr *)
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
+ linkmode, operstate);
+
+ ret = send(drv->wext_event_sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
+ "%s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+static int wpa_driver_nl80211_set_auth_param(
+ struct wpa_driver_nl80211_data *drv, int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ else
+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCSIWAP]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ if (ret > 32)
+ ret = 32;
+ /* Some drivers include nul termination in the SSID, so let's
+ * remove it here before further processing. WE-21 changes this
+ * to explicitly require the length _not_ to include nul
+ * termination. */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ char buf[33];
+
+ if (ssid_len > 32)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+ iwr.u.essid.flags = (ssid_len != 0);
+ os_memset(buf, 0, sizeof(buf));
+ os_memcpy(buf, ssid, ssid_len);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ if (drv->we_version_compiled < 21) {
+ /* For historic reasons, set SSID length to include one extra
+ * character, C string nul termination, even though SSID is
+ * really an octet string that should not be presented as a C
+ * string. Some Linux drivers decrement the length by one and
+ * can thus end up missing the last octet of the SSID if the
+ * length is not incremented here. WE-21 changes this to
+ * explicitly require the length _not_ to include nul
+ * termination. */
+ if (ssid_len)
+ ssid_len++;
+ }
+ iwr.u.essid.length = ssid_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.freq.m = freq * 100000;
+ iwr.u.freq.e = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void
+wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+ custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast ") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ return;
+ bytes /= 2;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.req_ies, bytes);
+
+ spos += bytes * 2;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ spos += 9;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ goto done;
+ bytes /= 2;
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+#ifdef CONFIG_PEERKEY
+ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+ if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+ wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+ "STKSTART.request '%s'", custom + 17);
+ return;
+ }
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+ }
+}
+
+
+static int wpa_driver_nl80211_event_wireless_michaelmicfailure(
+ void *ctx, const char *ev, size_t len)
+{
+ const struct iw_michaelmicfailure *mic;
+ union wpa_event_data data;
+
+ if (len < sizeof(*mic))
+ return -1;
+
+ mic = (const struct iw_michaelmicfailure *) ev;
+
+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+ "flags=0x%x src_addr=" MACSTR, mic->flags,
+ MAC2STR(mic->src_addr.sa_data));
+
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_pmkidcand(
+ struct wpa_driver_nl80211_data *drv, const char *ev, size_t len)
+{
+ const struct iw_pmkid_cand *cand;
+ union wpa_event_data data;
+ const u8 *addr;
+
+ if (len < sizeof(*cand))
+ return -1;
+
+ cand = (const struct iw_pmkid_cand *) ev;
+ addr = (const u8 *) cand->bssid.sa_data;
+
+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+ cand->index, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+ data.pmkid_candidate.index = cand->index;
+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocreqie(
+ struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = os_malloc(len);
+ if (drv->assoc_req_ies == NULL) {
+ drv->assoc_req_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_req_ies, ev, len);
+ drv->assoc_req_ies_len = len;
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocrespie(
+ struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = os_malloc(len);
+ if (drv->assoc_resp_ies == NULL) {
+ drv->assoc_resp_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_resp_ies, ev, len);
+ drv->assoc_resp_ies_len = len;
+
+ return 0;
+}
+
+
+static void wpa_driver_nl80211_event_assoc_ies(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data;
+
+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ if (drv->assoc_req_ies) {
+ data.assoc_info.req_ies = drv->assoc_req_ies;
+ drv->assoc_req_ies = NULL;
+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+ }
+ if (drv->assoc_resp_ies) {
+ data.assoc_info.resp_ies = drv->assoc_resp_ies;
+ drv->assoc_resp_ies = NULL;
+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+ os_free(data.assoc_info.req_ies);
+ os_free(data.assoc_info.resp_ies);
+}
+
+
+static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version_compiled > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVASSOCRESPIE ||
+ iwe->cmd == IWEVPMKIDCAND)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+ MACSTR,
+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
+ os_memcmp(iwe->u.ap_addr.sa_data,
+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+ 0) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+
+ } else {
+ wpa_driver_nl80211_event_assoc_ies(drv);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ }
+ break;
+ case IWEVMICHAELMICFAILURE:
+ wpa_driver_nl80211_event_wireless_michaelmicfailure(
+ ctx, custom, iwe->u.data.length);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ wpa_driver_nl80211_event_wireless_custom(ctx, buf);
+ os_free(buf);
+ break;
+ case IWEVASSOCREQIE:
+ wpa_driver_nl80211_event_wireless_assocreqie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVASSOCRESPIE:
+ wpa_driver_nl80211_event_wireless_assocrespie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVPMKIDCAND:
+ wpa_driver_nl80211_event_wireless_pmkidcand(
+ drv, custom, iwe->u.data.length);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
+ void *ctx, char *buf, size_t len,
+ int del)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
+
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+ if (del)
+ drv->if_removed = 1;
+ else
+ drv->if_removed = 0;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
+ struct nlmsghdr *h)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr *attr;
+
+ ifi = NLMSG_DATA(h);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return 0;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+ == 0)
+ return 1;
+ else
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex, struct nlmsghdr *h)
+{
+ if (drv->ifindex == ifindex)
+ return 1;
+
+ if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) {
+ drv->ifindex = if_nametoindex(drv->ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
+ "interface");
+ wpa_driver_nl80211_finish_drv_init(drv);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) {
+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+ ifi->ifi_index);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_nl80211_event_wireless(
+ drv, ctx, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ } else if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(
+ drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(
+ drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_receive_wext(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ case RTM_DELLINK:
+ wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+
+static int process_event(struct nl_msg *msg, void *arg)
+{
+ struct wpa_driver_nl80211_data *drv = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX]) {
+ int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ if (ifindex != drv->ifindex) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+ " for foreign interface (ifindex %d)",
+ gnlh->cmd, ifindex);
+ return NL_SKIP;
+ }
+ }
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_TRIGGER_SCAN:
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+ break;
+ case NL80211_CMD_NEW_SCAN_RESULTS:
+ wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case NL80211_CMD_SCAN_ABORTED:
+ wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
+ /*
+ * Need to indicate that scan results are available in order
+ * not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl0211: Ignored unknown event (cmd=%d)",
+ gnlh->cmd);
+ break;
+ }
+
+ return NL_SKIP;
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct nl_cb *cb;
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+
+ cb = nl_cb_clone(drv->nl_cb);
+ if (!cb)
+ return;
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
+ nl_recvmsgs(drv->nl_handle, cb);
+ nl_cb_put(cb);
+}
+
+
+static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: Pointer to returned flags value
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv,
+ int *flags)
+{
+ return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+static int wpa_driver_nl80211_set_ifflags_ifname(
+ struct wpa_driver_nl80211_data *drv,
+ const char *ifname, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: New value for flags
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
+ int flags)
+{
+ return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+/**
+ * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
+ * @priv: driver_nl80211 private data
+ * @alpha2_arg: country to which to switch to
+ * Returns: 0 on success, -1 on failure
+ *
+ * This asks nl80211 to set the regulatory domain for given
+ * country ISO / IEC alpha2.
+ */
+static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ char alpha2[3];
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ alpha2[0] = alpha2_arg[0];
+ alpha2[1] = alpha2_arg[1];
+ alpha2[2] = '\0';
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_REQ_SET_REG, 0);
+
+ NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+ if (send_and_recv_msgs(drv, msg, NULL, NULL))
+ return -EINVAL;
+ return 0;
+nla_put_failure:
+ return -EINVAL;
+}
+
+
+static int wpa_driver_nl80211_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_MGMT_EXTRA_IE, 0);
+
+ NLA_PUT_U8(msg, NL80211_ATTR_MGMT_SUBTYPE, 4 /* ProbeReq */);
+ if (ies)
+ NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
+
+ ret = 0;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+
+static int nl80211_set_vif(struct wpa_driver_nl80211_data *drv,
+ int drop_unencrypted, int userspace_mlme)
+{
+#ifdef NL80211_CMD_SET_VIF
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_VIF, 0);
+
+ if (drop_unencrypted >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_VIF_DROP_UNENCRYPTED,
+ drop_unencrypted);
+ if (userspace_mlme >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_VIF_USERSPACE_MLME,
+ userspace_mlme);
+
+ ret = 0;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
+#else /* NL80211_CMD_SET_VIF */
+ return -1;
+#endif /* NL80211_CMD_SET_VIF */
+}
+
+
+static int wpa_driver_nl80211_set_userspace_mlme(
+ struct wpa_driver_nl80211_data *drv, int enabled)
+{
+ return nl80211_set_vif(drv, -1, enabled);
+}
+
+
+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
+ int ifidx)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return;
+nla_put_failure:
+ wpa_printf(MSG_ERROR, "nl80211: Failed to remove interface.");
+}
+
+
+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype)
+{
+ struct nl_msg *msg, *flags = NULL;
+ int ifidx, err;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+ if (iftype == NL80211_IFTYPE_MONITOR) {
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto nla_put_failure;
+
+ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+
+ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
+
+ nlmsg_free(flags);
+
+ if (err)
+ goto nla_put_failure;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ nla_put_failure:
+ wpa_printf(MSG_ERROR, "nl80211: Failed to create interface %d",
+ ret);
+ return ret;
+ }
+
+ ifidx = if_nametoindex(ifname);
+ if (ifidx <= 0)
+ return -1;
+
+ return ifidx;
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ int injected = 0, failed = 0, rxflags = 0;
+ struct ieee80211_rx_status rx_status;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len)) {
+ wpa_printf(MSG_DEBUG, "nl80211: received invalid radiotap "
+ "frame");
+ return;
+ }
+
+ os_memset(&rx_status, 0, sizeof(rx_status));
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: received invalid "
+ "radiotap frame (%d)", ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(u16 *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO convert from freq/flags to channel number
+ * rx_status.channel = XXX;
+ */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ break;
+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+ rx_status.ssi = *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected) {
+ wpa_supplicant_sta_rx(drv->ctx, buf + iter.max_length,
+ len - iter.max_length, &rx_status);
+ } else if (failed) {
+ /* TX failure callback */
+ } else {
+ /* TX success (ACK) callback */
+ }
+}
+
+
+static int wpa_driver_nl80211_create_monitor_interface(
+ struct wpa_driver_nl80211_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval, flags;
+ socklen_t optlen;
+
+ os_snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname);
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR);
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (wpa_driver_nl80211_get_ifflags_ifname(drv, buf, &flags) != 0 ||
+ wpa_driver_nl80211_set_ifflags_ifname(drv, buf, flags | IFF_UP) !=
+ 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not set interface '%s' "
+ "UP", buf);
+ goto error;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ goto error;
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll,
+ sizeof(ll)) < 0) {
+ perror("monitor socket bind");
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ perror("Failed to set socket priority");
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not register monitor "
+ "read socket");
+ goto error;
+ }
+
+ return 0;
+
+ error:
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ return -1;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+{
+ int s, ret;
+ struct sockaddr_nl local;
+ struct wpa_driver_nl80211_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (drv->nl_cb == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ goto err1;
+ }
+
+ drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
+ if (drv->nl_handle == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ goto err2;
+ }
+
+ if (genl_connect(drv->nl_handle)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink");
+ goto err3;
+ }
+
+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+ if (drv->nl_cache == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto err3;
+ }
+
+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+ if (drv->nl80211 == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+ "found");
+ goto err4;
+ }
+
+ ret = nl_get_multicast_id(drv, "nl80211", "scan");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(drv->nl_handle, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+ "membership for scan events: %d (%s)",
+ ret, strerror(-ret));
+ goto err4;
+ }
+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
+ wpa_driver_nl80211_event_receive, drv, ctx);
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket(PF_INET,SOCK_DGRAM)");
+ goto err5;
+ }
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ goto err6;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ goto err6;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_wext, drv,
+ ctx);
+ drv->wext_event_sock = s;
+
+ wpa_driver_nl80211_finish_drv_init(drv);
+
+ return drv;
+
+err6:
+ close(drv->ioctl_sock);
+err5:
+ genl_family_put(drv->nl80211);
+err4:
+ nl_cache_free(drv->nl_cache);
+err3:
+ nl_handle_destroy(drv->nl_handle);
+err2:
+ nl_cb_put(drv->nl_cb);
+err1:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+{
+ int flags;
+
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
+ printf("Could not configure driver to use managed mode\n");
+ }
+
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
+ printf("Could not get interface '%s' flags\n", drv->ifname);
+ else if (!(flags & IFF_UP)) {
+ if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
+ printf("Could not set interface '%s' UP\n",
+ drv->ifname);
+ }
+ }
+
+ /*
+ * Make sure that the driver does not have any obsolete PMKID entries.
+ */
+ wpa_driver_nl80211_flush_pmkid(drv);
+
+ wpa_driver_nl80211_get_range(drv);
+
+ wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+}
+
+
+/**
+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
+ * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_nl80211_init().
+ */
+static void wpa_driver_nl80211_deinit(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int flags;
+
+#ifdef CONFIG_CLIENT_MLME
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ }
+ if (drv->monitor_ifidx > 0)
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
+ wpa_driver_nl80211_set_userspace_mlme(drv, 0);
+#endif /* CONFIG_CLIENT_MLME */
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+ /*
+ * Clear possibly configured driver parameters in order to make it
+ * easier to use the driver after wpa_supplicant has been terminated.
+ */
+ (void) wpa_driver_nl80211_set_bssid(drv,
+ (u8 *) "\x00\x00\x00\x00\x00\x00");
+
+ wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
+
+ eloop_unregister_read_sock(drv->wext_event_sock);
+
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+ close(drv->wext_event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv->assoc_req_ies);
+ os_free(drv->assoc_resp_ies);
+
+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
+ genl_family_put(drv->nl80211);
+ nl_cache_free(drv->nl_cache);
+ nl_handle_destroy(drv->nl_handle);
+ nl_cb_put(drv->nl_cb);
+
+ os_free(drv);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
+ * all SSIDs (either active scan with broadcast SSID or passive
+ * scan
+ * @ssid_len: Length of the SSID
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = 0, timeout;
+ struct nl_msg *msg, *ssids;
+
+ msg = nlmsg_alloc();
+ ssids = nlmsg_alloc();
+ if (!msg || !ssids) {
+ nlmsg_free(msg);
+ nlmsg_free(ssids);
+ return -1;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_TRIGGER_SCAN, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (ssid && ssid_len) {
+ /* Request an active scan for a specific SSID */
+ NLA_PUT(ssids, 1, ssid_len, ssid);
+ } else {
+ /* Request an active scan for wildcard SSID */
+ NLA_PUT(ssids, 1, 0, "");
+ }
+ nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 10;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+
+nla_put_failure:
+ nlmsg_free(ssids);
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *res = arg;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ const u8 *ie;
+ size_t ie_len;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS])
+ return NL_SKIP;
+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy))
+ return NL_SKIP;
+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ } else {
+ ie = NULL;
+ ie_len = 0;
+ }
+
+ r = os_zalloc(sizeof(*r) + ie_len);
+ if (r == NULL)
+ return NL_SKIP;
+ if (bss[NL80211_BSS_BSSID])
+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+ ETH_ALEN);
+ if (bss[NL80211_BSS_FREQUENCY])
+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ if (bss[NL80211_BSS_BEACON_INTERVAL])
+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+ if (bss[NL80211_BSS_CAPABILITY])
+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+ if (bss[NL80211_BSS_SIGNAL_UNSPEC])
+ r->qual = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+ if (bss[NL80211_BSS_SIGNAL_MBM])
+ r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+ if (bss[NL80211_BSS_TSF])
+ r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ r->ie_len = ie_len;
+ if (ie)
+ os_memcpy(r + 1, ie, ie_len);
+
+ tmp = os_realloc(res->res,
+ (res->num + 1) * sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return NL_SKIP;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+
+ return NL_SKIP;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+static struct wpa_scan_results *
+wpa_driver_nl80211_get_scan_results(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ struct wpa_scan_results *res;
+ int ret;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return 0;
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
+ NL80211_CMD_GET_SCAN, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
+ msg = NULL;
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
+ (unsigned long) res->num);
+ return res;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+nla_put_failure:
+ nlmsg_free(msg);
+ wpa_scan_results_free(res);
+ return NULL;
+}
+
+
+static int wpa_driver_nl80211_get_range(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ os_free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->has_capability = 1;
+ drv->we_version_compiled = range->we_version_compiled;
+ if (range->enc_capa & IW_ENC_CAPA_WPA) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ }
+ if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ }
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x",
+ drv->capa.key_mgmt, drv->capa.enc);
+ } else {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+ "assuming WPA is not supported");
+ }
+
+ os_free(range);
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq,
+ size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int err;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
+ "seq_len=%lu key_len=%lu",
+ __func__, alg, addr, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -1;
+
+ if (alg == WPA_ALG_NONE) {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_DEL_KEY, 0);
+ } else {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_NEW_KEY, 0);
+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC01);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC05);
+ break;
+ case WPA_ALG_TKIP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ break;
+ case WPA_ALG_CCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ break;
+#ifdef CONFIG_IEEE80211W
+ case WPA_ALG_IGTK:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+ break;
+#endif /* CONFIG_IEEE80211W */
+ default:
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
+ if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+ {
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ }
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ err = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
+ return -1;
+ }
+
+ if (set_tx && alg != WPA_ALG_NONE) {
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_KEY, 0);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+ err = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "nl80211: set default key "
+ "failed; err=%d", err);
+ return -1;
+ }
+ }
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->use_crypt = enabled;
+ return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMLME]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+}
+
+
+static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DISASSOC,
+ reason_code);
+}
+
+
+static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWGENIE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+static int wpa_driver_nl80211_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case KEY_MGMT_802_1X:
+ case KEY_MGMT_802_1X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->auth_alg_fallback &&
+ wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_nl80211_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_cipher2wext(params->group_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+ params->pairwise_suite != CIPHER_NONE ||
+ params->group_suite != CIPHER_NONE ||
+ params->wpa_ie_len;
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+ if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = -1, flags;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
+ mode ? NL80211_IFTYPE_ADHOC : NL80211_IFTYPE_STATION);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (!ret)
+ return 0;
+ else
+ goto try_again;
+
+nla_put_failure:
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)",
+ ret, strerror(-ret));
+ return -1;
+
+try_again:
+ /* mac80211 doesn't allow mode changes while the device is up, so
+ * take the device down, try to set the mode again, and bring the
+ * device back up.
+ */
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
+ mode ? NL80211_IFTYPE_ADHOC :
+ NL80211_IFTYPE_STATION);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "Failed to set interface %s "
+ "mode(try_again): %d (%s)",
+ drv->ifname, ret, strerror(-ret));
+ }
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_nl80211_get_ifflags(drv, &flags);
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP);
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ perror("ioctl[SIOCSIWPMKSA]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_flush_pmkid(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+ __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return wpa_driver_nl80211_send_oper_ifla(
+ drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+static int wpa_driver_nl80211_open_mlme(struct wpa_driver_nl80211_data *drv)
+{
+ if (wpa_driver_nl80211_set_userspace_mlme(drv, 1) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to enable userspace "
+ "MLME");
+ return -1;
+ }
+ if (wpa_driver_nl80211_create_monitor_interface(drv)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to create monitor "
+ "interface");
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_CLIENT_MLME */
+
+
+static int wpa_driver_nl80211_set_param(void *priv, const char *param)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct wpa_driver_nl80211_data *drv = priv;
+
+ if (param == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+
+ if (os_strstr(param, "use_mlme=1")) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using user space MLME");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+
+ if (wpa_driver_nl80211_open_mlme(drv))
+ return -1;
+ }
+#endif /* CONFIG_CLIENT_MLME */
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct wpa_hw_modes *modes;
+};
+
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1]
+ = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ };
+
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+ { .type = NLA_FLAG },
+ };
+
+ struct nlattr *nl_band;
+ struct nlattr *nl_freq;
+ struct nlattr *nl_rate;
+ int rem_band, rem_freq, rem_rate;
+ struct wpa_hw_modes *mode;
+ int idx, mode_is_set;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS],
+ rem_band) {
+ mode = os_realloc(phy_info->modes,
+ (*phy_info->num_modes + 1) * sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode_is_set = 0;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ os_memset(mode, 0, sizeof(*mode));
+ *(phy_info->num_modes) += 1;
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+ rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq),
+ freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ mode->num_channels++;
+ }
+
+ mode->channels = os_zalloc(mode->num_channels *
+ sizeof(struct wpa_channel_data));
+ if (!mode->channels)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+ rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq),
+ freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+
+ mode->channels[idx].freq = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ mode->channels[idx].flag |= WPA_CHAN_W_SCAN |
+ WPA_CHAN_W_ACTIVE_SCAN |
+ WPA_CHAN_W_IBSS;
+
+ if (!mode_is_set) {
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000)
+ mode->mode = WPA_MODE_IEEE80211B;
+ else
+ mode->mode = WPA_MODE_IEEE80211A;
+ mode_is_set = 1;
+ }
+
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000) {
+ if (mode->channels[idx].freq == 2484)
+ mode->channels[idx].chan = 14;
+ else
+ mode->channels[idx].chan =
+ (mode->channels[idx].freq -
+ 2407) / 5;
+ } else
+ mode->channels[idx].chan =
+ mode->channels[idx].freq / 5 - 1000;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ mode->channels[idx].flag &= ~WPA_CHAN_W_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+ mode->channels[idx].flag &=
+ ~WPA_CHAN_W_ACTIVE_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+ mode->channels[idx].flag &= ~WPA_CHAN_W_IBSS;
+ idx++;
+ }
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES],
+ rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
+
+ mode->rates = os_zalloc(mode->num_rates *
+ sizeof(struct wpa_rate_data));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES],
+ rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx].rate = nla_get_u32(
+ tb_rate[NL80211_BITRATE_ATTR_RATE]);
+
+ /* crude heuristic */
+ if (mode->mode == WPA_MODE_IEEE80211B &&
+ mode->rates[idx].rate > 200)
+ mode->mode = WPA_MODE_IEEE80211G;
+
+ if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE])
+ mode->rates[idx].flags |= WPA_RATE_PREAMBLE2;
+
+ idx++;
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct wpa_hw_modes *
+wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_WIPHY, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
+ return result.modes;
+nla_put_failure:
+ return NULL;
+}
+
+
+static int wpa_driver_nl80211_set_channel(void *priv, wpa_hw_mode phymode,
+ int chan, int freq)
+{
+ return wpa_driver_nl80211_set_freq(priv, freq);
+}
+
+
+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = data_len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ if (sendmsg(drv->monitor_sock, &msg, 0) < 0) {
+ perror("send[MLME]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_mlme_add_sta(void *priv, const u8 *addr,
+ const u8 *supp_rates,
+ size_t supp_rates_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ /* TODO: Get proper Association ID and listen interval */
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
+ supp_rates);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 1);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ /* ignore EEXIST, this happens if a STA associates while associated */
+ if (ret == -EEXIST || ret >= 0)
+ ret = 0;
+
+nla_put_failure:
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_mlme_remove_sta(void *priv, const u8 *addr)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ ret = 0;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+ .desc = "Linux nl80211/cfg80211",
+ .get_bssid = wpa_driver_nl80211_get_bssid,
+ .get_ssid = wpa_driver_nl80211_get_ssid,
+ .set_wpa = wpa_driver_nl80211_set_wpa,
+ .set_key = wpa_driver_nl80211_set_key,
+ .set_countermeasures = wpa_driver_nl80211_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted,
+ .scan = wpa_driver_nl80211_scan,
+ .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
+ .deauthenticate = wpa_driver_nl80211_deauthenticate,
+ .disassociate = wpa_driver_nl80211_disassociate,
+ .set_mode = wpa_driver_nl80211_set_mode,
+ .associate = wpa_driver_nl80211_associate,
+ .set_auth_alg = wpa_driver_nl80211_set_auth_alg,
+ .init = wpa_driver_nl80211_init,
+ .deinit = wpa_driver_nl80211_deinit,
+ .set_param = wpa_driver_nl80211_set_param,
+ .add_pmkid = wpa_driver_nl80211_add_pmkid,
+ .remove_pmkid = wpa_driver_nl80211_remove_pmkid,
+ .flush_pmkid = wpa_driver_nl80211_flush_pmkid,
+ .get_capa = wpa_driver_nl80211_get_capa,
+ .set_operstate = wpa_driver_nl80211_set_operstate,
+ .set_country = wpa_driver_nl80211_set_country,
+ .set_probe_req_ie = wpa_driver_nl80211_set_probe_req_ie,
+#ifdef CONFIG_CLIENT_MLME
+ .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+ .set_channel = wpa_driver_nl80211_set_channel,
+ .set_ssid = wpa_driver_nl80211_set_ssid,
+ .set_bssid = wpa_driver_nl80211_set_bssid,
+ .send_mlme = wpa_driver_nl80211_send_mlme,
+ .mlme_add_sta = wpa_driver_nl80211_mlme_add_sta,
+ .mlme_remove_sta = wpa_driver_nl80211_mlme_remove_sta,
+#endif /* CONFIG_CLIENT_MLME */
+};
diff --git a/contrib/wpa/src/drivers/driver_osx.m b/contrib/wpa/src/drivers/driver_osx.m
new file mode 100644
index 0000000..93d7df0
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_osx.m
@@ -0,0 +1,432 @@
+/*
+ * WPA Supplicant - Mac OS X Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+
+#include "Apple80211.h"
+
+struct wpa_driver_osx_data {
+ void *ctx;
+ WirelessRef wireless_ctx;
+ CFArrayRef scan_results;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern int wpa_debug_level;
+
+static void dump_dict_cb(const void *key, const void *value, void *context)
+{
+ if (MSG_DEBUG < wpa_debug_level)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Key:");
+ CFShow(key);
+ wpa_printf(MSG_DEBUG, "Value:");
+ CFShow(value);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
+ title, (unsigned int) CFDictionaryGetCount(dict));
+ CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ WirelessInfo info;
+ int len;
+
+ err = WirelessGetInfo(drv->wireless_ctx, &info);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+ (int) err);
+ return -1;
+ }
+ if (!info.power) {
+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+ return -1;
+ }
+
+ for (len = 0; len < 32; len++)
+ if (info.ssid[len] == 0)
+ break;
+
+ os_memcpy(ssid, info.ssid, len);
+ return len;
+}
+
+
+static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ WirelessInfo info;
+
+ err = WirelessGetInfo(drv->wireless_ctx, &info);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+ (int) err);
+ return -1;
+ }
+ if (!info.power) {
+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+ return -1;
+ }
+
+ os_memcpy(bssid, info.bssID, ETH_ALEN);
+ return 0;
+}
+
+
+static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ if (drv->scan_results) {
+ CFRelease(drv->scan_results);
+ drv->scan_results = NULL;
+ }
+
+ if (ssid) {
+ CFStringRef data;
+ data = CFStringCreateWithBytes(kCFAllocatorDefault,
+ ssid, ssid_len,
+ kCFStringEncodingISOLatin1,
+ FALSE);
+ if (data == NULL) {
+ wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
+ "failed");
+ return -1;
+ }
+
+ err = WirelessDirectedScan(drv->wireless_ctx,
+ &drv->scan_results, 0, data);
+ CFRelease(data);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
+ "failed: 0x%08x", (unsigned int) err);
+ return -1;
+ }
+ } else {
+ err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+ }
+
+ eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static int wpa_driver_osx_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ size_t i, num;
+
+ if (drv->scan_results == NULL)
+ return 0;
+
+ num = CFArrayGetCount(drv->scan_results);
+ if (num > max_size)
+ num = max_size;
+ os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+ for (i = 0; i < num; i++) {
+ struct wpa_scan_result *res = &results[i];
+ WirelessNetworkInfo *info;
+ info = (WirelessNetworkInfo *)
+ CFDataGetBytePtr(CFArrayGetValueAtIndex(
+ drv->scan_results, i));
+
+ os_memcpy(res->bssid, info->bssid, ETH_ALEN);
+ if (info->ssid_len > 32) {
+ wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
+ "scan results", (int) info->ssid_len);
+ continue;
+ }
+ os_memcpy(res->ssid, info->ssid, info->ssid_len);
+ res->ssid_len = info->ssid_len;
+ res->caps = info->capability;
+ res->freq = 2407 + info->channel * 5;
+ res->level = info->signal;
+ res->noise = info->noise;
+ }
+
+ return num;
+}
+
+
+static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_osx_data *drv = eloop_ctx;
+ u8 bssid[ETH_ALEN];
+ CFDictionaryRef ai;
+
+ if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
+ eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
+ drv, drv->ctx);
+ return;
+ }
+
+ ai = WirelessGetAssociationInfo(drv->wireless_ctx);
+ if (ai) {
+ wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
+ CFRelease(ai);
+ } else {
+ wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
+ }
+
+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_osx_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ CFDataRef ssid;
+ CFStringRef key;
+ int assoc_type;
+
+ ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
+ params->ssid_len);
+ if (ssid == NULL)
+ return -1;
+
+ /* TODO: support for WEP */
+ if (params->key_mgmt_suite == KEY_MGMT_PSK) {
+ if (params->passphrase == NULL)
+ return -1;
+ key = CFStringCreateWithCString(kCFAllocatorDefault,
+ params->passphrase,
+ kCFStringEncodingISOLatin1);
+ if (key == NULL) {
+ CFRelease(ssid);
+ return -1;
+ }
+ } else
+ key = NULL;
+
+ if (params->key_mgmt_suite == KEY_MGMT_NONE)
+ assoc_type = 0;
+ else
+ assoc_type = 4;
+
+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
+ assoc_type, key);
+ err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
+ CFRelease(ssid);
+ if (key)
+ CFRelease(key);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
+ (unsigned int) err);
+ return -1;
+ }
+
+ /*
+ * Driver is actually already associated; report association from an
+ * eloop callback.
+ */
+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+ eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
+ drv->ctx);
+
+ return 0;
+}
+
+
+static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key,
+ size_t key_len)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ if (alg == WPA_ALG_WEP) {
+ err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
+ key);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ if (alg == WPA_ALG_PMK) {
+ err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
+ return -1;
+}
+
+
+static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ return 0;
+}
+
+
+static void * wpa_driver_osx_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_osx_data *drv;
+ WirelessError err;
+ u8 enabled, power;
+
+ if (!WirelessIsAvailable()) {
+ wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
+ return NULL;
+ }
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ err = WirelessAttach(&drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
+ (int) err);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
+ if (err)
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
+ (unsigned int) err);
+ err = WirelessGetPower(drv->wireless_ctx, &power);
+ if (err)
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
+ (unsigned int) err);
+
+ wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
+
+ if (!enabled) {
+ err = WirelessSetEnabled(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
+ " 0x%08x", (unsigned int) err);
+ WirelessDetach(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ if (!power) {
+ err = WirelessSetPower(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
+ "0x%08x", (unsigned int) err);
+ WirelessDetach(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_osx_deinit(void *priv)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+
+ err = WirelessSetPower(drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
+ "0x%08x", (unsigned int) err);
+ }
+
+ err = WirelessDetach(drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
+ (unsigned int) err);
+ }
+
+ if (drv->scan_results)
+ CFRelease(drv->scan_results);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_osx_ops = {
+ .name = "osx",
+ .desc = "Mac OS X Apple80211 driver",
+ .get_ssid = wpa_driver_osx_get_ssid,
+ .get_bssid = wpa_driver_osx_get_bssid,
+ .init = wpa_driver_osx_init,
+ .deinit = wpa_driver_osx_deinit,
+ .scan = wpa_driver_osx_scan,
+ .get_scan_results = wpa_driver_osx_get_scan_results,
+ .associate = wpa_driver_osx_associate,
+ .set_key = wpa_driver_osx_set_key,
+ .get_capa = wpa_driver_osx_get_capa,
+};
diff --git a/contrib/wpa/src/drivers/driver_prism54.c b/contrib/wpa/src/drivers/driver_prism54.c
new file mode 100644
index 0000000..e64e762
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_prism54.c
@@ -0,0 +1,381 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Prism54.org driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "driver_hostap.h"
+
+struct wpa_driver_prism54_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
+#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
+#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
+
+static void show_set_key_error(struct prism2_hostapd_param *);
+
+static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
+ struct prism2_hostapd_param *param,
+ int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
+ int ret = errno;
+ if (show_err)
+ perror("ioctl[PRISM54_HOSTAPD]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
+ const u8 *wpa_ie,
+ size_t wpa_ie_len)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = wpa_ie_len;
+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
+ res = hostapd_ioctl_prism54(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+/* This is called at wpa_supplicant daemon init time */
+static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM54_SET_WPA;
+ param->u.generic_elem.len = 0;
+ res = hostapd_ioctl_prism54(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ return -1;
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ return -1;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_SET_ENCRYPTION;
+ /* TODO: In theory, STA in client mode can use five keys; four default
+ * keys for receiving (with keyidx 0..3) and one individual key for
+ * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
+ * keyidx 0 is reserved for this unicast use and default keys can only
+ * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
+ * This should be fine for more or less all cases, but for completeness
+ * sake, the driver could be enhanced to support the missing key. */
+#if 0
+ if (addr == NULL)
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
+#else
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+#endif
+ os_strlcpy((char *) param->u.crypt.alg, alg_name,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = key_idx;
+ os_memcpy(param->u.crypt.seq, seq, seq_len);
+ param->u.crypt.key_len = key_len;
+ os_memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ show_set_key_error(param);
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_prism54_set_countermeasures(void *priv,
+ int enabled)
+{
+ /* FIX */
+ printf("wpa_driver_prism54_set_countermeasures - not yet "
+ "implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM54_DROP_UNENCRYPTED;
+ param->u.generic_elem.len = 0;
+ res = hostapd_ioctl_prism54(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ /* FIX */
+ printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ /* FIX */
+ printf("wpa_driver_prism54_disassociate - not yet implemented\n");
+ return 0;
+}
+
+
+static int
+wpa_driver_prism54_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ int ret = 0;
+
+ if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
+ params->wpa_ie_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static void show_set_key_error(struct prism2_hostapd_param *param)
+{
+ switch (param->u.crypt.err) {
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
+ param->u.crypt.alg);
+ wpa_printf(MSG_INFO, "You may need to load kernel module to "
+ "register that algorithm.");
+ wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
+ "WEP.");
+ break;
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
+ MAC2STR(param->sta_addr));
+ break;
+ case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "Key setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "TX key index setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
+ wpa_printf(MSG_INFO, "Card configuration failed.");
+ break;
+ }
+}
+
+
+static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_prism54_get_scan_results(void *priv)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_prism54_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_prism54_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_prism54_deinit(void *priv)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_prism54_ops = {
+ .name = "prism54",
+ .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
+ .get_bssid = wpa_driver_prism54_get_bssid,
+ .get_ssid = wpa_driver_prism54_get_ssid,
+ .set_wpa = wpa_driver_prism54_set_wpa,
+ .set_key = wpa_driver_prism54_set_key,
+ .set_countermeasures = wpa_driver_prism54_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
+ .scan = wpa_driver_prism54_scan,
+ .get_scan_results2 = wpa_driver_prism54_get_scan_results,
+ .deauthenticate = wpa_driver_prism54_deauthenticate,
+ .disassociate = wpa_driver_prism54_disassociate,
+ .associate = wpa_driver_prism54_associate,
+ .init = wpa_driver_prism54_init,
+ .deinit = wpa_driver_prism54_deinit,
+ .set_operstate = wpa_driver_prism54_set_operstate,
+};
diff --git a/contrib/wpa/src/drivers/driver_privsep.c b/contrib/wpa/src/drivers/driver_privsep.c
new file mode 100644
index 0000000..fdf299d
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_privsep.c
@@ -0,0 +1,820 @@
+/*
+ * WPA Supplicant - privilege separated driver interface
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "privsep_commands.h"
+
+
+struct wpa_driver_privsep_data {
+ void *ctx;
+ u8 own_addr[ETH_ALEN];
+ int priv_socket;
+ char *own_socket_path;
+ int cmd_socket;
+ char *own_cmd_path;
+ struct sockaddr_un priv_addr;
+ char ifname[16];
+};
+
+
+static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
+{
+ int res;
+
+ res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
+ (struct sockaddr *) &drv->priv_addr,
+ sizeof(drv->priv_addr));
+ if (res < 0)
+ perror("sendto");
+ return res < 0 ? -1 : 0;
+}
+
+
+static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
+ const void *data, size_t data_len,
+ void *reply, size_t *reply_len)
+{
+ struct msghdr msg;
+ struct iovec io[2];
+
+ io[0].iov_base = &cmd;
+ io[0].iov_len = sizeof(cmd);
+ io[1].iov_base = (u8 *) data;
+ io[1].iov_len = data_len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = data ? 2 : 1;
+ msg.msg_name = &drv->priv_addr;
+ msg.msg_namelen = sizeof(drv->priv_addr);
+
+ if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
+ perror("sendmsg(cmd_socket)");
+ return -1;
+ }
+
+ if (reply) {
+ fd_set rfds;
+ struct timeval tv;
+ int res;
+
+ FD_ZERO(&rfds);
+ FD_SET(drv->cmd_socket, &rfds);
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
+ if (res < 0 && errno != EINTR) {
+ perror("select");
+ return -1;
+ }
+
+ if (FD_ISSET(drv->cmd_socket, &rfds)) {
+ res = recv(drv->cmd_socket, reply, *reply_len, 0);
+ if (res < 0) {
+ perror("recv");
+ return -1;
+ }
+ *reply_len = res;
+ } else {
+ wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
+ "for reply (cmd=%d)", cmd);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_privsep_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled,
+ sizeof(enabled), NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
+ NULL, NULL);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_privsep_get_scan_results2(void *priv)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res, num;
+ u8 *buf, *pos, *end;
+ size_t reply_len = 60000;
+ struct wpa_scan_results *results;
+ struct wpa_scan_res *r;
+
+ buf = os_malloc(reply_len);
+ if (buf == NULL)
+ return NULL;
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
+ NULL, 0, buf, &reply_len);
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
+ (unsigned long) reply_len);
+ if (reply_len < sizeof(int)) {
+ wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
+ (unsigned long) reply_len);
+ os_free(buf);
+ return NULL;
+ }
+
+ pos = buf;
+ end = buf + reply_len;
+ os_memcpy(&num, pos, sizeof(int));
+ if (num < 0 || num > 1000) {
+ os_free(buf);
+ return NULL;
+ }
+ pos += sizeof(int);
+
+ results = os_zalloc(sizeof(*results));
+ if (results == NULL) {
+ os_free(buf);
+ return NULL;
+ }
+
+ results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
+ if (results->res == NULL) {
+ os_free(results);
+ os_free(buf);
+ return NULL;
+ }
+
+ while (results->num < (size_t) num && pos + sizeof(int) < end) {
+ int len;
+ os_memcpy(&len, pos, sizeof(int));
+ pos += sizeof(int);
+ if (len < 0 || len > 10000 || pos + len > end)
+ break;
+
+ r = os_malloc(len);
+ if (r == NULL)
+ break;
+ os_memcpy(r, pos, len);
+ pos += len;
+ if (sizeof(*r) + r->ie_len > (size_t) len) {
+ os_free(r);
+ break;
+ }
+
+ results->res[results->num++] = r;
+ }
+
+ os_free(buf);
+ return results;
+}
+
+
+static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ struct privsep_cmd_set_key cmd;
+
+ wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
+ __func__, priv, alg, key_idx, set_tx);
+
+ os_memset(&cmd, 0, sizeof(cmd));
+ cmd.alg = alg;
+ if (addr)
+ os_memcpy(cmd.addr, addr, ETH_ALEN);
+ else
+ os_memset(cmd.addr, 0xff, ETH_ALEN);
+ cmd.key_idx = key_idx;
+ cmd.set_tx = set_tx;
+ if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
+ os_memcpy(cmd.seq, seq, seq_len);
+ cmd.seq_len = seq_len;
+ }
+ if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
+ os_memcpy(cmd.key, key, key_len);
+ cmd.key_len = key_len;
+ }
+
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
+ NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ struct privsep_cmd_associate *data;
+ int res;
+ size_t buflen;
+
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+ "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
+ __func__, priv, params->freq, params->pairwise_suite,
+ params->group_suite, params->key_mgmt_suite,
+ params->auth_alg, params->mode);
+
+ buflen = sizeof(*data) + params->wpa_ie_len;
+ data = os_zalloc(buflen);
+ if (data == NULL)
+ return -1;
+
+ if (params->bssid)
+ os_memcpy(data->bssid, params->bssid, ETH_ALEN);
+ os_memcpy(data->ssid, params->ssid, params->ssid_len);
+ data->ssid_len = params->ssid_len;
+ data->freq = params->freq;
+ data->pairwise_suite = params->pairwise_suite;
+ data->group_suite = params->group_suite;
+ data->key_mgmt_suite = params->key_mgmt_suite;
+ data->auth_alg = params->auth_alg;
+ data->mode = params->mode;
+ data->wpa_ie_len = params->wpa_ie_len;
+ if (params->wpa_ie)
+ os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
+ /* TODO: add support for other assoc parameters */
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
+ NULL, NULL);
+ os_free(data);
+
+ return res;
+}
+
+
+static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res;
+ size_t len = ETH_ALEN;
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
+ if (res < 0 || len != ETH_ALEN)
+ return -1;
+ return 0;
+}
+
+
+static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res, ssid_len;
+ u8 reply[sizeof(int) + 32];
+ size_t len = sizeof(reply);
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
+ if (res < 0 || len < sizeof(int))
+ return -1;
+ os_memcpy(&ssid_len, reply, sizeof(int));
+ if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
+ wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
+ return -1;
+ }
+ os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
+ return ssid_len;
+}
+
+
+static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ //struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
+ return 0;
+}
+
+
+static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ //struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
+ return 0;
+}
+
+
+static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event,
+ u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+ int inc_data = 0;
+ u8 *pos, *end;
+ int ie_len;
+
+ os_memset(&data, 0, sizeof(data));
+
+ pos = buf;
+ end = buf + len;
+
+ if (end - pos < (int) sizeof(int))
+ return;
+ os_memcpy(&ie_len, pos, sizeof(int));
+ pos += sizeof(int);
+ if (ie_len < 0 || ie_len > end - pos)
+ return;
+ if (ie_len) {
+ data.assoc_info.req_ies = pos;
+ data.assoc_info.req_ies_len = ie_len;
+ pos += ie_len;
+ inc_data = 1;
+ }
+
+ wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
+}
+
+
+static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
+ size_t len)
+{
+ union wpa_event_data data;
+ int ievent;
+
+ if (len < sizeof(int) ||
+ len - sizeof(int) > sizeof(data.interface_status.ifname))
+ return;
+
+ os_memcpy(&ievent, buf, sizeof(int));
+
+ os_memset(&data, 0, sizeof(data));
+ data.interface_status.ievent = ievent;
+ os_memcpy(data.interface_status.ifname, buf + sizeof(int),
+ len - sizeof(int));
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
+}
+
+
+static void wpa_driver_privsep_event_michael_mic_failure(
+ void *ctx, u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+
+ if (len != sizeof(int))
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
+ size_t len)
+{
+ union wpa_event_data data;
+
+ if (len != sizeof(struct pmkid_candidate))
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(&data.pmkid_candidate, buf, len);
+ wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+
+ if (len != ETH_ALEN)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+}
+
+
+static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
+ size_t len)
+{
+ union wpa_event_data data;
+
+ if (len < sizeof(int) + ETH_ALEN)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
+ os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
+ data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
+ data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
+ wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
+{
+ if (len < ETH_ALEN)
+ return;
+
+ wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
+}
+
+
+static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct ieee80211_rx_status *rx_status;
+
+ if (len < sizeof(*rx_status))
+ return;
+ rx_status = (struct ieee80211_rx_status *) buf;
+ buf += sizeof(*rx_status);
+ len -= sizeof(*rx_status);
+
+ wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
+#endif /* CONFIG_CLIENT_MLME */
+}
+
+
+static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_driver_privsep_data *drv = eloop_ctx;
+ u8 *buf, *event_buf;
+ size_t event_len;
+ int res, event;
+ enum privsep_event e;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ const size_t buflen = 2000;
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ res = recvfrom(sock, buf, buflen, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(priv_socket)");
+ os_free(buf);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
+
+ if (res < (int) sizeof(int)) {
+ wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
+ return;
+ }
+
+ os_memcpy(&event, buf, sizeof(int));
+ event_buf = &buf[sizeof(int)];
+ event_len = res - sizeof(int);
+ wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
+ event, (unsigned long) event_len);
+
+ e = event;
+ switch (e) {
+ case PRIVSEP_EVENT_SCAN_RESULTS:
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case PRIVSEP_EVENT_ASSOC:
+ wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
+ event_buf, event_len);
+ break;
+ case PRIVSEP_EVENT_DISASSOC:
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ break;
+ case PRIVSEP_EVENT_ASSOCINFO:
+ wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
+ event_buf, event_len);
+ break;
+ case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
+ wpa_driver_privsep_event_michael_mic_failure(
+ drv->ctx, event_buf, event_len);
+ break;
+ case PRIVSEP_EVENT_INTERFACE_STATUS:
+ wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_PMKID_CANDIDATE:
+ wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_STKSTART:
+ wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_FT_RESPONSE:
+ wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_RX_EAPOL:
+ wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_STA_RX:
+ wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
+ event_len);
+ break;
+ }
+
+ os_free(buf);
+}
+
+
+static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_privsep_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ drv->priv_socket = -1;
+ drv->cmd_socket = -1;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ return drv;
+}
+
+
+static void wpa_driver_privsep_deinit(void *priv)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+
+ if (drv->priv_socket >= 0) {
+ wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
+ eloop_unregister_read_sock(drv->priv_socket);
+ close(drv->priv_socket);
+ }
+
+ if (drv->own_socket_path) {
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ }
+
+ if (drv->cmd_socket >= 0) {
+ eloop_unregister_read_sock(drv->cmd_socket);
+ close(drv->cmd_socket);
+ }
+
+ if (drv->own_cmd_path) {
+ unlink(drv->own_cmd_path);
+ os_free(drv->own_cmd_path);
+ }
+
+ os_free(drv);
+}
+
+
+static int wpa_driver_privsep_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ const char *pos;
+ char *own_dir, *priv_dir;
+ static unsigned int counter = 0;
+ size_t len;
+ struct sockaddr_un addr;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+ if (param == NULL)
+ pos = NULL;
+ else
+ pos = os_strstr(param, "own_dir=");
+ if (pos) {
+ char *end;
+ own_dir = os_strdup(pos + 8);
+ if (own_dir == NULL)
+ return -1;
+ end = os_strchr(own_dir, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ own_dir = os_strdup("/tmp");
+ if (own_dir == NULL)
+ return -1;
+ }
+
+ if (param == NULL)
+ pos = NULL;
+ else
+ pos = os_strstr(param, "priv_dir=");
+ if (pos) {
+ char *end;
+ priv_dir = os_strdup(pos + 9);
+ if (priv_dir == NULL) {
+ os_free(own_dir);
+ return -1;
+ }
+ end = os_strchr(priv_dir, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ priv_dir = os_strdup("/var/run/wpa_priv");
+ if (priv_dir == NULL) {
+ os_free(own_dir);
+ return -1;
+ }
+ }
+
+ len = os_strlen(own_dir) + 50;
+ drv->own_socket_path = os_malloc(len);
+ if (drv->own_socket_path == NULL) {
+ os_free(priv_dir);
+ os_free(own_dir);
+ return -1;
+ }
+ os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
+ own_dir, getpid(), counter++);
+
+ len = os_strlen(own_dir) + 50;
+ drv->own_cmd_path = os_malloc(len);
+ if (drv->own_cmd_path == NULL) {
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ os_free(priv_dir);
+ os_free(own_dir);
+ return -1;
+ }
+ os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
+ own_dir, getpid(), counter++);
+
+ os_free(own_dir);
+
+ drv->priv_addr.sun_family = AF_UNIX;
+ os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
+ "%s/%s", priv_dir, drv->ifname);
+ os_free(priv_dir);
+
+ drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (drv->priv_socket < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
+ if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ close(drv->priv_socket);
+ drv->priv_socket = -1;
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
+ drv, NULL);
+
+ drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (drv->cmd_socket < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(drv->own_cmd_path);
+ drv->own_cmd_path = NULL;
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
+ if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
+ perror("bind(PF_UNIX)");
+ close(drv->cmd_socket);
+ drv->cmd_socket = -1;
+ unlink(drv->own_cmd_path);
+ os_free(drv->own_cmd_path);
+ drv->own_cmd_path = NULL;
+ return -1;
+ }
+
+ if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_privsep_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res;
+ size_t len = sizeof(*capa);
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
+ if (res < 0 || len != sizeof(*capa))
+ return -1;
+ return 0;
+}
+
+
+static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ return drv->own_addr;
+}
+
+
+static int wpa_driver_privsep_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
+ NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
+ os_strlen(alpha2), NULL, NULL);
+}
+
+
+struct wpa_driver_ops wpa_driver_privsep_ops = {
+ "privsep",
+ "wpa_supplicant privilege separated driver",
+ wpa_driver_privsep_get_bssid,
+ wpa_driver_privsep_get_ssid,
+ wpa_driver_privsep_set_wpa,
+ wpa_driver_privsep_set_key,
+ wpa_driver_privsep_init,
+ wpa_driver_privsep_deinit,
+ wpa_driver_privsep_set_param,
+ NULL /* set_countermeasures */,
+ NULL /* set_drop_unencrypted */,
+ wpa_driver_privsep_scan,
+ NULL /* get_scan_results */,
+ wpa_driver_privsep_deauthenticate,
+ wpa_driver_privsep_disassociate,
+ wpa_driver_privsep_associate,
+ NULL /* set_auth_alg */,
+ NULL /* add_pmkid */,
+ NULL /* remove_pmkid */,
+ NULL /* flush_pmkid */,
+ wpa_driver_privsep_get_capa,
+ NULL /* poll */,
+ NULL /* get_ifname */,
+ wpa_driver_privsep_get_mac_addr,
+ NULL /* send_eapol */,
+ NULL /* set_operstate */,
+ NULL /* mlme_setprotection */,
+ NULL /* get_hw_feature_data */,
+ NULL /* set_channel */,
+ NULL /* set_ssid */,
+ NULL /* set_bssid */,
+ NULL /* send_mlme */,
+ NULL /* mlme_add_sta */,
+ NULL /* mlme_remove_sta */,
+ NULL /* update_ft_ies */,
+ NULL /* send_ft_action */,
+ wpa_driver_privsep_get_scan_results2,
+ NULL /* set_probe_req_ie */,
+ wpa_driver_privsep_set_mode,
+ wpa_driver_privsep_set_country,
+ NULL /* global_init */,
+ NULL /* global_deinit */,
+ NULL /* init2 */,
+ NULL /* get_interfaces */
+};
+
+
+struct wpa_driver_ops *wpa_supplicant_drivers[] =
+{
+ &wpa_driver_privsep_ops,
+ NULL
+};
diff --git a/contrib/wpa/src/drivers/driver_ps3.c b/contrib/wpa/src/drivers/driver_ps3.c
new file mode 100644
index 0000000..fde3425
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_ps3.c
@@ -0,0 +1,186 @@
+/*
+ * WPA Supplicant - PS3 Linux wireless extension driver interface
+ * Copyright 2007, 2008 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include "wireless_copy.h"
+#include "common.h"
+#include "wpa_common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+
+static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret, i;
+ struct iwreq iwr;
+ char *buf, *str;
+
+ if (!params->psk && !params->passphrase) {
+ wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
+ return -EINVAL;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ if (params->psk) {
+ /* includes null */
+ iwr.u.data.length = PMK_LEN * 2 + 1;
+ buf = os_malloc(iwr.u.data.length);
+ if (!buf)
+ return -ENOMEM;
+ str = buf;
+ for (i = 0; i < PMK_LEN; i++) {
+ str += snprintf(str, iwr.u.data.length - (str - buf),
+ "%02x", params->psk[i]);
+ }
+ } else if (params->passphrase) {
+ /* including quotations and null */
+ iwr.u.data.length = strlen(params->passphrase) + 3;
+ buf = os_malloc(iwr.u.data.length);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = '"';
+ os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
+ buf[iwr.u.data.length - 2] = '"';
+ buf[iwr.u.data.length - 1] = '\0';
+ } else
+ return -EINVAL;
+ iwr.u.data.pointer = (caddr_t) buf;
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
+ os_free(buf);
+
+ return ret;
+}
+
+static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret, i;
+ struct iwreq iwr;
+
+ for (i = 0; i < 4; i++) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = i + 1;
+ if (params->wep_key_len[i]) {
+ iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
+ iwr.u.encoding.length = params->wep_key_len[i];
+ } else
+ iwr.u.encoding.flags = IW_ENCODE_NOKEY |
+ IW_ENCODE_DISABLED;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+static int wpa_driver_ps3_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret, value;
+
+ wpa_printf(MSG_DEBUG, "%s: <-", __func__);
+
+ /* clear BSSID */
+ if (!params->bssid &&
+ wpa_driver_wext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->group_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+
+ /* set selected BSSID */
+ if (params->bssid &&
+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ switch (params->group_suite) {
+ case CIPHER_NONE:
+ ret = 0;
+ break;
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ ret = wpa_driver_ps3_set_wep_keys(drv, params);
+ break;
+ case CIPHER_TKIP:
+ case CIPHER_CCMP:
+ ret = wpa_driver_ps3_set_wpa_key(drv, params);
+ break;
+ }
+
+ /* start to associate */
+ ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
+
+ wpa_printf(MSG_DEBUG, "%s: ->", __func__);
+
+ return ret;
+}
+
+static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s:<-", __func__);
+
+ ret = wpa_driver_wext_get_capa(priv, capa);
+ if (ret) {
+ wpa_printf(MSG_INFO, "%s: base wext returns error %d",
+ __func__, ret);
+ return ret;
+ }
+ /* PS3 hypervisor does association and 4way handshake by itself */
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ wpa_printf(MSG_DEBUG, "%s:->", __func__);
+ return 0;
+}
+
+const struct wpa_driver_ops wpa_driver_ps3_ops = {
+ .name = "ps3",
+ .desc = "PLAYSTATION3 Linux wireless extension driver",
+ .get_bssid = wpa_driver_wext_get_bssid,
+ .get_ssid = wpa_driver_wext_get_ssid,
+ .scan = wpa_driver_wext_scan,
+ .get_scan_results2 = wpa_driver_wext_get_scan_results,
+ .associate = wpa_driver_ps3_associate, /* PS3 */
+ .init = wpa_driver_wext_init,
+ .deinit = wpa_driver_wext_deinit,
+ .get_capa = wpa_driver_ps3_get_capa, /* PS3 */
+};
diff --git a/contrib/wpa/src/drivers/driver_ralink.c b/contrib/wpa/src/drivers/driver_ralink.c
new file mode 100644
index 0000000..e9313cb
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_ralink.c
@@ -0,0 +1,1505 @@
+/*
+ * WPA Supplicant - driver interaction with Ralink Wireless Client
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+#include "priv_netlink.h"
+#include "driver_ralink.h"
+
+static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+#define MAX_SSID_LEN 32
+
+struct wpa_driver_ralink_data {
+ void *ctx;
+ int ioctl_sock;
+ int event_sock;
+ char ifname[IFNAMSIZ + 1];
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ int no_of_pmkid;
+ struct ndis_pmkid_entry *pmkid;
+ int we_version_compiled;
+ int ap_scan;
+ int scanning_done;
+ u8 g_driver_down;
+};
+
+static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
+ unsigned short oid, char *data, int len)
+{
+ char *buf;
+ struct iwreq iwr;
+
+ buf = os_zalloc(len);
+ if (buf == NULL)
+ return -1;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.flags = oid;
+ iwr.u.data.flags |= OID_GET_SET_TOGGLE;
+
+ if (data)
+ os_memcpy(buf, data, len);
+
+ iwr.u.data.pointer = (caddr_t) buf;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
+ __func__, oid, len);
+ os_free(buf);
+ return -1;
+ }
+ os_free(buf);
+ return 0;
+}
+
+static int
+ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
+{
+ struct iwreq iwr;
+ UCHAR enabled = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (UCHAR*) &enabled;
+ iwr.u.data.flags = RT_OID_NEW_DRIVER;
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed", __func__);
+ return 0;
+ }
+
+ return (enabled == 1) ? 1 : 0;
+}
+
+static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+#if 0
+ struct wpa_supplicant *wpa_s = drv->ctx;
+ struct wpa_ssid *entry;
+#endif
+ int ssid_len;
+ u8 bssid[ETH_ALEN];
+ u8 ssid_str[MAX_SSID_LEN];
+ struct iwreq iwr;
+#if 0
+ int result = 0;
+#endif
+ int ret = 0;
+#if 0
+ BOOLEAN ieee8021x_mode = FALSE;
+ BOOLEAN ieee8021x_required_key = FALSE;
+#endif
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ if (ret <= 0)
+ return ret;
+
+ ssid_len = ret;
+ os_memset(ssid_str, 0, MAX_SSID_LEN);
+ os_memcpy(ssid_str, ssid, ssid_len);
+
+ if (drv->ap_scan == 0) {
+ /* Read BSSID form driver */
+ if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
+ wpa_printf(MSG_WARNING, "Could not read BSSID from "
+ "driver.");
+ return ret;
+ }
+
+#if 0
+ entry = wpa_s->conf->ssid;
+ while (entry) {
+ if (!entry->disabled && ssid_len == entry->ssid_len &&
+ os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
+ (!entry->bssid_set ||
+ os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
+ /* match the config of driver */
+ result = 1;
+ break;
+ }
+ entry = entry->next;
+ }
+
+ if (result) {
+ wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
+ "ieee_required_keys parameters to driver");
+
+ /* set 802.1x mode and ieee_required_keys parameter */
+ if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
+ ieee8021x_required_key = TRUE;
+ ieee8021x_mode = TRUE;
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
+ }
+ else
+ {
+ wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
+ }
+ else
+ {
+ wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
+ entry->eapol_flags);
+ }
+ }
+#endif
+ }
+
+ return ret;
+}
+
+static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
+ const u8 *ssid, size_t ssid_len)
+{
+ NDIS_802_11_SSID *buf;
+ int ret = 0;
+ struct iwreq iwr;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ buf = os_zalloc(sizeof(NDIS_802_11_SSID));
+ if (buf == NULL)
+ return -1;
+ os_memset(buf, 0, sizeof(buf));
+ buf->SsidLength = ssid_len;
+ os_memcpy(buf->Ssid, ssid, ssid_len);
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ iwr.u.data.flags = OID_802_11_SSID;
+ iwr.u.data.flags |= OID_GET_SET_TOGGLE;
+ iwr.u.data.pointer = (caddr_t) buf;
+ iwr.u.data.length = sizeof(NDIS_802_11_SSID);
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
+ ret = -1;
+ }
+ os_free(buf);
+ return ret;
+}
+
+static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
+ const u8 *data, size_t data_len)
+{
+ NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
+ size_t i;
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (data_len < 8) {
+ wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
+ "Event (len=%lu)", (unsigned long) data_len);
+ return;
+ }
+ pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
+ wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
+ " NumCandidates %d",
+ (int) pmkid->Version, (int) pmkid->NumCandidates);
+
+ if (pmkid->Version != 1) {
+ wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
+ "List Version %d", (int) pmkid->Version);
+ return;
+ }
+
+ if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
+ wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
+ "underflow");
+
+ return;
+ }
+
+
+
+ os_memset(&event, 0, sizeof(event));
+ for (i = 0; i < pmkid->NumCandidates; i++) {
+ PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
+ wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
+ (unsigned long) i, MAC2STR(p->BSSID),
+ (int) p->Flags);
+ os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
+ event.pmkid_candidate.index = i;
+ event.pmkid_candidate.preauth =
+ p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
+ &event);
+ }
+}
+
+static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
+{
+ int len, count, i, ret;
+ struct ndis_pmkid_entry *entry;
+ NDIS_802_11_PMKID *p;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ count = 0;
+ entry = drv->pmkid;
+ while (entry) {
+ count++;
+ if (count >= drv->no_of_pmkid)
+ break;
+ entry = entry->next;
+ }
+ len = 8 + count * sizeof(BSSID_INFO);
+ p = os_zalloc(len);
+ if (p == NULL)
+ return -1;
+ p->Length = len;
+ p->BSSIDInfoCount = count;
+ entry = drv->pmkid;
+ for (i = 0; i < count; i++) {
+ os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
+ os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
+ entry = entry->next;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
+ (const u8 *) p, len);
+ ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
+ os_free(p);
+ return ret;
+}
+
+static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct ndis_pmkid_entry *entry, *prev;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->no_of_pmkid == 0)
+ return 0;
+
+ prev = NULL;
+ entry = drv->pmkid;
+ while (entry) {
+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
+ break;
+ prev = entry;
+ entry = entry->next;
+ }
+
+ if (entry) {
+ /* Replace existing entry for this BSSID and move it into the
+ * beginning of the list. */
+ os_memcpy(entry->pmkid, pmkid, 16);
+ if (prev) {
+ prev->next = entry->next;
+ entry->next = drv->pmkid;
+ drv->pmkid = entry;
+ }
+ } else {
+ entry = os_malloc(sizeof(*entry));
+ if (entry) {
+ os_memcpy(entry->bssid, bssid, ETH_ALEN);
+ os_memcpy(entry->pmkid, pmkid, 16);
+ entry->next = drv->pmkid;
+ drv->pmkid = entry;
+ }
+ }
+
+ return wpa_driver_ralink_set_pmkid(drv);
+}
+
+
+static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct ndis_pmkid_entry *entry, *prev;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->no_of_pmkid == 0)
+ return 0;
+
+ entry = drv->pmkid;
+ prev = NULL;
+ drv->pmkid = NULL;
+ while (entry) {
+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
+ os_memcmp(entry->pmkid, pmkid, 16) == 0) {
+ if (prev)
+ prev->next = entry->next;
+ else
+ drv->pmkid = entry->next;
+ os_free(entry);
+ break;
+ }
+ prev = entry;
+ entry = entry->next;
+ }
+ return wpa_driver_ralink_set_pmkid(drv);
+}
+
+
+static int wpa_driver_ralink_flush_pmkid(void *priv)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ NDIS_802_11_PMKID p;
+ struct ndis_pmkid_entry *pmkid, *prev;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->no_of_pmkid == 0)
+ return 0;
+
+ pmkid = drv->pmkid;
+ drv->pmkid = NULL;
+ while (pmkid) {
+ prev = pmkid;
+ pmkid = pmkid->next;
+ os_free(prev);
+ }
+
+ os_memset(&p, 0, sizeof(p));
+ p.Length = 8;
+ p.BSSIDInfoCount = 0;
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
+ (const u8 *) &p, 8);
+ return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
+}
+
+static void
+wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
+ void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ /* receive a MICFAILURE report */
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
+ /* receive assoc. req. IEs */
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+ /*get IE's length */
+ /*
+ * bytes = strlen(spos); ==> bug, bytes may less than original
+ * size by using this way to get size. snowpin 20070312
+ * if (!bytes)
+ * return;
+ */
+ bytes = drv->assoc_req_ies_len;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ os_memcpy(data.assoc_info.req_ies, spos, bytes);
+
+ /* skip the '\0' byte */
+ spos += bytes + 1;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ /* receive assoc. resp. IEs */
+ spos += 9;
+ /* get IE's length */
+ bytes = os_strlen(spos);
+ if (!bytes)
+ goto done;
+
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ os_memcpy(data.assoc_info.resp_ies, spos, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ /* free allocated memory */
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+ }
+}
+
+static void
+wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
+#if 0
+ BOOLEAN ieee8021x_required_key = FALSE;
+#endif
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ assoc_info_buf = info_pos = NULL;
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+
+ if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+
+ if (drv->ap_scan == 1) {
+ if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
+ || (iwe->u.data.flags ==
+ RT_REQIE_EVENT_FLAG) ||
+ (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
+ || (iwe->u.data.flags ==
+ RT_ASSOCINFO_EVENT_FLAG)) {
+ if (drv->scanning_done == 0) {
+ os_free(buf);
+ return;
+ }
+ }
+ }
+
+ if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive ASSOCIATED_EVENT !!!");
+ /* determine whether the dynamic-WEP is used or
+ * not */
+#if 0
+ if (wpa_s && wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt ==
+ WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ if ((wpa_s->current_ssid->eapol_flags &
+ (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
+ //wpa_printf(MSG_DEBUG, "The current ssid - (%s), eapol_flag = %d.\n",
+ // wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len),wpa_s->current_ssid->eapol_flags);
+ ieee8021x_required_key = TRUE;
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
+ (int) ieee8021x_required_key);
+ }
+
+ wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d).\n", ieee8021x_required_key ? "TRUE" : "FALSE",
+ wpa_s->current_ssid->eapol_flags);
+ }
+#endif
+
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive ReqIEs !!!");
+ drv->assoc_req_ies =
+ os_malloc(iwe->u.data.length);
+ if (drv->assoc_req_ies == NULL) {
+ os_free(buf);
+ return;
+ }
+
+ drv->assoc_req_ies_len = iwe->u.data.length;
+ os_memcpy(drv->assoc_req_ies, custom,
+ iwe->u.data.length);
+ } else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive RespIEs !!!");
+ drv->assoc_resp_ies =
+ os_malloc(iwe->u.data.length);
+ if (drv->assoc_resp_ies == NULL) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(buf);
+ return;
+ }
+
+ drv->assoc_resp_ies_len = iwe->u.data.length;
+ os_memcpy(drv->assoc_resp_ies, custom,
+ iwe->u.data.length);
+ } else if (iwe->u.data.flags ==
+ RT_ASSOCINFO_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive ASSOCINFO_EVENT !!!");
+
+ assoc_info_buf =
+ os_zalloc(drv->assoc_req_ies_len +
+ drv->assoc_resp_ies_len + 1);
+
+ if (assoc_info_buf == NULL) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ os_free(buf);
+ return;
+ }
+
+ if (drv->assoc_req_ies) {
+ os_memcpy(assoc_info_buf,
+ drv->assoc_req_ies,
+ drv->assoc_req_ies_len);
+ }
+ info_pos = assoc_info_buf +
+ drv->assoc_req_ies_len;
+ if (drv->assoc_resp_ies) {
+ os_memcpy(info_pos,
+ drv->assoc_resp_ies,
+ drv->assoc_resp_ies_len);
+ }
+ assoc_info_buf[drv->assoc_req_ies_len +
+ drv->assoc_resp_ies_len] = '\0';
+ wpa_driver_ralink_event_wireless_custom(
+ drv, ctx, assoc_info_buf);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ os_free(assoc_info_buf);
+ } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
+ {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive DISASSOCIATED_EVENT !!!");
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+ } else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive PMKIDCAND_EVENT !!!");
+ wpa_driver_ralink_event_pmkid(
+ drv, (const u8 *) custom,
+ iwe->u.data.length);
+ } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
+ drv->g_driver_down = 1;
+ eloop_terminate();
+ } else if (iwe->u.data.flags == RT_REPORT_AP_INFO) {
+ if (drv->ap_scan != 1) {
+ typedef struct PACKED {
+ UCHAR bssid[MAC_ADDR_LEN];
+ UCHAR ssid[MAX_LEN_OF_SSID];
+ INT ssid_len;
+ UCHAR wpa_ie[40];
+ INT wpa_ie_len;
+ UCHAR rsn_ie[40];
+ INT rsn_ie_len;
+ INT freq;
+ USHORT caps;
+ } *PAPINFO;
+
+ wpa_printf(MSG_DEBUG, "Custom wireless"
+ " event: receive "
+ "RT_REPORT_AP_INFO !!!");
+ //printf("iwe->u.data.length = %d\n", iwe->u.data.length);
+ //wpa_hexdump(MSG_DEBUG, "AP_Info: ", buf, iwe->u.data.length);
+#if 0
+ wpa_s->num_scan_results = 1;
+ if (wpa_s->scan_results)
+ os_free(wpa_s->scan_results);
+ wpa_s->scan_results = os_malloc(sizeof(struct wpa_scan_result) + 1);
+ if (wpa_s->scan_results) {
+ PAPINFO pApInfo = (PAPINFO)buf;
+ os_memcpy(wpa_s->scan_results[0].bssid, pApInfo->bssid, ETH_ALEN);
+ os_memcpy(wpa_s->scan_results[0].ssid, pApInfo->ssid, pApInfo->ssid_len);
+ wpa_s->scan_results[0].ssid_len = pApInfo->ssid_len;
+ if (pApInfo->wpa_ie_len > 0) {
+ os_memcpy(wpa_s->scan_results[0].wpa_ie, pApInfo->wpa_ie, pApInfo->wpa_ie_len);
+ wpa_s->scan_results[0].wpa_ie_len = pApInfo->wpa_ie_len;
+ } else if (pApInfo->rsn_ie_len > 0) {
+ os_memcpy(wpa_s->scan_results[0].rsn_ie, pApInfo->rsn_ie, pApInfo->rsn_ie_len);
+ wpa_s->scan_results[0].rsn_ie_len = pApInfo->rsn_ie_len;
+ }
+ wpa_s->scan_results[0].caps = pApInfo->caps;
+ wpa_s->scan_results[0].freq = pApInfo->freq;
+ } else {
+ wpa_printf("wpa_s->scan_"
+ "results fail to "
+ "os_malloc!!\n");
+ }
+#endif
+ }
+ } else {
+ wpa_driver_ralink_event_wireless_custom(
+ drv, ctx, buf);
+ }
+ os_free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+static void
+wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv,
+ void *ctx, struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+ wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
+ while (RTA_OK(attr, attrlen)) {
+ wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_ralink_event_wireless(
+ drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ wpa_hexdump(MSG_DEBUG, "attr3: ",
+ (u8 *) attr, sizeof(struct rtattr));
+ }
+}
+
+static void wpa_driver_ralink_event_receive(int sock, void *ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ wpa_hexdump(MSG_DEBUG, "h: ", (u8 *)h, h->nlmsg_len);
+
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d", len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_ralink_event_rtm_newlink(ctx, sock_ctx, h,
+ plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+}
+
+static int
+ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
+{
+ struct iwreq iwr;
+ UINT we_version_compiled = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) &we_version_compiled;
+ iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed", __func__);
+ return -1;
+ }
+
+ drv->we_version_compiled = we_version_compiled;
+
+ return 0;
+}
+
+static int
+ralink_set_iface_flags(void *priv, int dev_up)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->ifname);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
+{
+ int s;
+ struct wpa_driver_ralink_data *drv;
+ struct ifreq ifr;
+ struct sockaddr_nl local;
+ UCHAR enable_wpa_supplicant = 0;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return NULL;
+ }
+ /* do it */
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return NULL;
+ }
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+
+ drv->scanning_done = 1;
+ drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->ioctl_sock = s;
+ drv->g_driver_down = 0;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_ralink_event_receive, drv, ctx);
+ drv->event_sock = s;
+ drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
+
+ ralink_set_iface_flags(drv, 1); /* mark up during setup */
+ ralink_get_we_version_compiled(drv);
+ wpa_driver_ralink_flush_pmkid(drv);
+
+ if (drv->ap_scan == 1)
+ enable_wpa_supplicant = 1;
+ else
+ enable_wpa_supplicant = 2;
+ /* trigger driver support wpa_supplicant */
+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+ (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
+ (int) enable_wpa_supplicant);
+ wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
+ "wpa_supplicant");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ if (drv->ap_scan == 1)
+ drv->scanning_done = 0;
+
+ return drv;
+}
+
+static void wpa_driver_ralink_deinit(void *priv)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ UCHAR enable_wpa_supplicant;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ enable_wpa_supplicant = 0;
+
+ if (drv->g_driver_down == 0) {
+ /* trigger driver disable wpa_supplicant support */
+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+ (char *) &enable_wpa_supplicant,
+ sizeof(BOOLEAN)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
+ (int) enable_wpa_supplicant);
+ }
+
+ wpa_driver_ralink_flush_pmkid(drv);
+
+ sleep(1);
+ ralink_set_iface_flags(drv, 0);
+ }
+
+ eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
+ eloop_unregister_read_sock(drv->event_sock);
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv);
+}
+
+static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_ralink_data *drv = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+
+ drv->scanning_done = 1;
+
+}
+
+static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+ __FUNCTION__, (unsigned long) ssid_len);
+ return -1;
+ }
+
+ /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
+ drv->ctx);
+
+ drv->scanning_done = 0;
+
+ return ret;
+}
+
+static int
+wpa_driver_ralink_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ UCHAR *buf = NULL;
+ NDIS_802_11_BSSID_LIST_EX *wsr;
+ NDIS_WLAN_BSSID_EX *wbi;
+ struct iwreq iwr;
+ int rv = 0;
+ size_t ap_num;
+ u8 *pos, *end;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->we_version_compiled >= 17) {
+ buf = os_zalloc(8192);
+ iwr.u.data.length = 8192;
+ } else {
+ buf = os_zalloc(4096);
+ iwr.u.data.length = 4096;
+ }
+ if (buf == NULL)
+ return -1;
+
+ wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
+
+ wsr->NumberOfItems = 0;
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (void *) buf;
+ iwr.u.data.flags = OID_802_11_BSSID_LIST;
+
+ if ((rv = ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ioctl fail: rv = %d", rv);
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+
+ for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
+ ++ap_num) {
+ os_memcpy(results[ap_num].bssid, &wbi->MacAddress, ETH_ALEN);
+ os_memcpy(results[ap_num].ssid, wbi->Ssid.Ssid,
+ wbi->Ssid.SsidLength);
+ results[ap_num].ssid_len = wbi->Ssid.SsidLength;
+ results[ap_num].freq = (wbi->Configuration.DSConfig / 1000);
+
+ /* get ie's */
+ wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
+ (u8 *) wbi + sizeof(*wbi) - 1, wbi->IELength);
+
+ pos = (u8 *) wbi + sizeof(*wbi) - 1;
+ end = (u8 *) wbi + sizeof(*wbi) + wbi->IELength;
+
+ if (wbi->IELength < sizeof(NDIS_802_11_FIXED_IEs))
+ break;
+
+ pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
+ os_memcpy(&results[ap_num].caps, pos, 2);
+ pos += 2;
+
+ while (pos + 1 < end && pos + 2 + pos[1] <= end) {
+ u8 ielen = 2 + pos[1];
+
+ if (ielen > SSID_MAX_WPA_IE_LEN) {
+ pos += ielen;
+ continue;
+ }
+
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] >= 4 &&
+ os_memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
+ os_memcpy(results[ap_num].wpa_ie, pos, ielen);
+ results[ap_num].wpa_ie_len = ielen;
+ } else if (pos[0] == WLAN_EID_RSN) {
+ os_memcpy(results[ap_num].rsn_ie, pos, ielen);
+ results[ap_num].rsn_ie_len = ielen;
+ }
+ pos += ielen;
+ }
+
+ wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
+ }
+
+ os_free(buf);
+ return ap_num;
+}
+
+static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
+ NDIS_802_11_AUTHENTICATION_MODE mode)
+{
+ NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
+ (char *) &auth_mode, sizeof(auth_mode)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_AUTHENTICATION_MODE (%d)",
+ (int) auth_mode);
+ return -1;
+ }
+ return 0;
+}
+
+static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
+ int key_idx, const u8 *addr,
+ const u8 *bssid, int pairwise)
+{
+ NDIS_802_11_REMOVE_KEY rkey;
+ NDIS_802_11_KEY_INDEX _index;
+ int res, res2;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ os_memset(&rkey, 0, sizeof(rkey));
+
+ rkey.Length = sizeof(rkey);
+ rkey.KeyIndex = key_idx;
+
+ if (pairwise)
+ rkey.KeyIndex |= 1 << 30;
+
+ os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
+
+ res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
+ sizeof(rkey));
+
+ /* AlbertY@20060210 removed it */
+ if (0 /* !pairwise */) {
+ res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
+ (char *) &_index, sizeof(_index));
+ } else
+ res2 = 0;
+
+ if (res < 0 && res2 < 0)
+ return res;
+ return 0;
+}
+
+static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
+ int pairwise, int key_idx, int set_tx,
+ const u8 *key, size_t key_len)
+{
+ NDIS_802_11_WEP *wep;
+ size_t len;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ len = 12 + key_len;
+ wep = os_zalloc(len);
+ if (wep == NULL)
+ return -1;
+
+ wep->Length = len;
+ wep->KeyIndex = key_idx;
+
+ if (set_tx)
+ wep->KeyIndex |= 0x80000000;
+
+ wep->KeyLength = key_len;
+ os_memcpy(wep->KeyMaterial, key, key_len);
+
+ wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
+ (const u8 *) wep, len);
+ res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
+
+ os_free(wep);
+
+ return res;
+}
+
+static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ size_t len, i;
+ NDIS_802_11_KEY *nkey;
+ int res, pairwise;
+ u8 bssid[ETH_ALEN];
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN) == 0) {
+ /* Group Key */
+ pairwise = 0;
+ wpa_driver_ralink_get_bssid(drv, bssid);
+ } else {
+ /* Pairwise Key */
+ pairwise = 1;
+ os_memcpy(bssid, addr, ETH_ALEN);
+ }
+
+ if (alg == WPA_ALG_NONE || key_len == 0) {
+ return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
+ pairwise);
+ }
+
+ if (alg == WPA_ALG_WEP) {
+ return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
+ set_tx, key, key_len);
+ }
+
+ len = 12 + 6 + 6 + 8 + key_len;
+
+ nkey = os_zalloc(len);
+ if (nkey == NULL)
+ return -1;
+
+ nkey->Length = len;
+ nkey->KeyIndex = key_idx;
+
+ if (set_tx)
+ nkey->KeyIndex |= 1 << 31;
+
+ if (pairwise)
+ nkey->KeyIndex |= 1 << 30;
+
+ if (seq && seq_len)
+ nkey->KeyIndex |= 1 << 29;
+
+ nkey->KeyLength = key_len;
+ os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
+
+ if (seq && seq_len) {
+ for (i = 0; i < seq_len; i++)
+ nkey->KeyRSC |= seq[i] << (i * 8);
+ }
+ if (alg == WPA_ALG_TKIP && key_len == 32) {
+ os_memcpy(nkey->KeyMaterial, key, 16);
+ os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
+ os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
+ } else {
+ os_memcpy(nkey->KeyMaterial, key, key_len);
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
+ (const u8 *) nkey, len);
+ res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
+ os_free(nkey);
+
+ return res;
+}
+
+static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_DISASSOCIATE");
+ }
+
+ return 0;
+}
+
+static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ if (ralink_get_new_driver_flag(drv) == 0) {
+ return wpa_driver_ralink_disassociate(priv, addr, reason_code);
+ } else {
+ MLME_DEAUTH_REQ_STRUCT mlme;
+ os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
+ mlme.Reason = reason_code;
+ os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
+ return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
+ (char *) &mlme,
+ sizeof(MLME_DEAUTH_REQ_STRUCT));
+ }
+}
+
+static int
+wpa_driver_ralink_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+
+ NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
+ NDIS_802_11_AUTHENTICATION_MODE auth_mode;
+ NDIS_802_11_WEP_STATUS encr;
+ BOOLEAN ieee8021xMode;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (params->mode == IEEE80211_MODE_IBSS)
+ mode = Ndis802_11IBSS;
+ else
+ mode = Ndis802_11Infrastructure;
+
+ if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
+ (char *) &mode, sizeof(mode)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_INFRASTRUCTURE_MODE (%d)",
+ (int) mode);
+ /* Try to continue anyway */
+ }
+
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ auth_mode = Ndis802_11AuthModeAutoSwitch;
+ else
+ auth_mode = Ndis802_11AuthModeShared;
+ } else
+ auth_mode = Ndis802_11AuthModeOpen;
+ } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
+ if (params->key_mgmt_suite == KEY_MGMT_PSK)
+ auth_mode = Ndis802_11AuthModeWPA2PSK;
+ else
+ auth_mode = Ndis802_11AuthModeWPA2;
+ } else {
+ if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
+ auth_mode = Ndis802_11AuthModeWPANone;
+ else if (params->key_mgmt_suite == KEY_MGMT_PSK)
+ auth_mode = Ndis802_11AuthModeWPAPSK;
+ else
+ auth_mode = Ndis802_11AuthModeWPA;
+ }
+
+ switch (params->pairwise_suite) {
+ case CIPHER_CCMP:
+ encr = Ndis802_11Encryption3Enabled;
+ break;
+ case CIPHER_TKIP:
+ encr = Ndis802_11Encryption2Enabled;
+ break;
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ encr = Ndis802_11Encryption1Enabled;
+ break;
+ case CIPHER_NONE:
+ if (params->group_suite == CIPHER_CCMP)
+ encr = Ndis802_11Encryption3Enabled;
+ else if (params->group_suite == CIPHER_TKIP)
+ encr = Ndis802_11Encryption2Enabled;
+ else
+ encr = Ndis802_11EncryptionDisabled;
+ break;
+ default:
+ encr = Ndis802_11EncryptionDisabled;
+ break;
+ }
+
+ ralink_set_auth_mode(drv, auth_mode);
+
+ /* notify driver that IEEE8021x mode is enabled */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA)
+ ieee8021xMode = TRUE;
+ else
+ ieee8021xMode = FALSE;
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
+ (char *) &ieee8021xMode, sizeof(BOOLEAN)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_SET_IEEE8021X(%d)",
+ (int) ieee8021xMode);
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
+ (char *) &encr, sizeof(encr)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_WEP_STATUS(%d)",
+ (int) encr);
+ }
+
+ if ((ieee8021xMode == FALSE) &&
+ (encr == Ndis802_11Encryption1Enabled)) {
+ /* static WEP */
+ int enabled = 0;
+ if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
+ (char *) &enabled, sizeof(enabled)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_DROP_UNENCRYPTED(%d)",
+ (int) encr);
+ }
+ }
+
+ return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
+}
+
+static int
+wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
+ sizeof(int));
+}
+
+const struct wpa_driver_ops wpa_driver_ralink_ops = {
+ .name = "ralink",
+ .desc = "Ralink Wireless Client driver",
+ .get_bssid = wpa_driver_ralink_get_bssid,
+ .get_ssid = wpa_driver_ralink_get_ssid,
+ .set_key = wpa_driver_ralink_set_key,
+ .init = wpa_driver_ralink_init,
+ .deinit = wpa_driver_ralink_deinit,
+ .set_countermeasures = wpa_driver_ralink_set_countermeasures,
+ .scan = wpa_driver_ralink_scan,
+ .get_scan_results = wpa_driver_ralink_get_scan_results,
+ .deauthenticate = wpa_driver_ralink_deauthenticate,
+ .disassociate = wpa_driver_ralink_disassociate,
+ .associate = wpa_driver_ralink_associate,
+ .add_pmkid = wpa_driver_ralink_add_pmkid,
+ .remove_pmkid = wpa_driver_ralink_remove_pmkid,
+ .flush_pmkid = wpa_driver_ralink_flush_pmkid,
+};
diff --git a/contrib/wpa/src/drivers/driver_ralink.h b/contrib/wpa/src/drivers/driver_ralink.h
new file mode 100644
index 0000000..ddf44de
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_ralink.h
@@ -0,0 +1,382 @@
+/*
+ * WPA Supplicant - driver_ralink exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+// Ralink defined OIDs
+#if WIRELESS_EXT <= 11
+#ifndef SIOCDEVPRIVATE
+#define SIOCDEVPRIVATE 0x8BE0
+#endif
+#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
+#endif
+
+#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E)
+#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
+
+// IEEE 802.11 OIDs & Ralink defined OIDs ******
+
+// (RaConfig Set/QueryInform) ==>
+#define OID_GET_SET_TOGGLE 0x8000
+
+#define OID_802_11_ADD_WEP 0x0112
+#define OID_802_11_REMOVE_WEP 0x0113
+#define OID_802_11_DISASSOCIATE 0x0114
+#define OID_802_11_PRIVACY_FILTER 0x0118
+#define OID_802_11_ASSOCIATION_INFORMATION 0x011E
+#define OID_802_11_BSSID_LIST_SCAN 0x0508
+#define OID_802_11_SSID 0x0509
+#define OID_802_11_BSSID 0x050A
+#define OID_802_11_WEP_STATUS 0x0510
+#define OID_802_11_AUTHENTICATION_MODE 0x0511
+#define OID_802_11_INFRASTRUCTURE_MODE 0x0512
+#define OID_802_11_TX_POWER_LEVEL 0x0517
+#define OID_802_11_REMOVE_KEY 0x0519
+#define OID_802_11_ADD_KEY 0x0520
+#define OID_802_11_DEAUTHENTICATION 0x0526
+#define OID_802_11_DROP_UNENCRYPTED 0x0527
+#define OID_802_11_BSSID_LIST 0x0609
+#define OID_802_3_CURRENT_ADDRESS 0x060A
+#define OID_SET_COUNTERMEASURES 0x0616
+#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode
+#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode
+#define OID_802_11_PMKID 0x0620
+#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support
+#define RT_OID_WE_VERSION_COMPILED 0x0622
+#define RT_OID_NEW_DRIVER 0x0623
+
+#define PACKED __attribute__ ((packed))
+
+//wpa_supplicant event flags
+#define RT_ASSOC_EVENT_FLAG 0x0101
+#define RT_DISASSOC_EVENT_FLAG 0x0102
+#define RT_REQIE_EVENT_FLAG 0x0103
+#define RT_RESPIE_EVENT_FLAG 0x0104
+#define RT_ASSOCINFO_EVENT_FLAG 0x0105
+#define RT_PMKIDCAND_FLAG 0x0106
+#define RT_INTERFACE_DOWN 0x0107
+#define RT_REPORT_AP_INFO 0x0108
+
+//
+// IEEE 802.11 Structures and definitions
+//
+// new types for Media Specific Indications
+
+#ifndef ULONG
+#define CHAR char
+#define INT int
+#define SHORT int
+#define UINT u32
+#undef ULONG
+//#define ULONG u32
+#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
+#define USHORT unsigned short
+#define UCHAR unsigned char
+
+#define uint32 u32
+#define uint8 u8
+
+
+#define BOOLEAN u8
+//#define LARGE_INTEGER s64
+#define VOID void
+#define LONG long
+#define LONGLONG s64
+#define ULONGLONG u64
+typedef VOID *PVOID;
+typedef CHAR *PCHAR;
+typedef UCHAR *PUCHAR;
+typedef USHORT *PUSHORT;
+typedef LONG *PLONG;
+typedef ULONG *PULONG;
+
+typedef union _LARGE_INTEGER {
+ struct {
+ ULONG LowPart;
+ LONG HighPart;
+ }vv;
+ struct {
+ ULONG LowPart;
+ LONG HighPart;
+ } u;
+ s64 QuadPart;
+} LARGE_INTEGER;
+
+#endif
+
+#define NDIS_802_11_LENGTH_SSID 32
+#define NDIS_802_11_LENGTH_RATES 8
+#define NDIS_802_11_LENGTH_RATES_EX 16
+#define MAX_LEN_OF_SSID 32
+#define MAC_ADDR_LEN 6
+
+typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
+
+// mask for authentication/integrity fields
+#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
+
+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
+
+// Added new types for OFDM 5G and 2.4G
+typedef enum _NDIS_802_11_NETWORK_TYPE
+{
+ Ndis802_11FH,
+ Ndis802_11DS,
+ Ndis802_11OFDM5,
+ Ndis802_11OFDM24,
+ Ndis802_11Automode,
+ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
+} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
+
+//
+// Received Signal Strength Indication
+//
+typedef LONG NDIS_802_11_RSSI; // in dBm
+
+typedef struct _NDIS_802_11_CONFIGURATION_FH
+{
+ ULONG Length; // Length of structure
+ ULONG HopPattern; // As defined by 802.11, MSB set
+ ULONG HopSet; // to one if non-802.11
+ ULONG DwellTime; // units are Kusec
+} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
+
+typedef struct _NDIS_802_11_CONFIGURATION
+{
+ ULONG Length; // Length of structure
+ ULONG BeaconPeriod; // units are Kusec
+ ULONG ATIMWindow; // units are Kusec
+ ULONG DSConfig; // Frequency, units are kHz
+ NDIS_802_11_CONFIGURATION_FH FHConfig;
+} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
+
+typedef ULONG NDIS_802_11_KEY_INDEX;
+typedef ULONGLONG NDIS_802_11_KEY_RSC;
+
+// Key mapping keys require a BSSID
+typedef struct _NDIS_802_11_KEY
+{
+ UINT Length; // Length of this structure
+ UINT KeyIndex;
+ UINT KeyLength; // length of key in bytes
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ NDIS_802_11_KEY_RSC KeyRSC;
+ UCHAR KeyMaterial[1]; // variable length depending on above field
+} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
+
+typedef struct _NDIS_802_11_REMOVE_KEY
+{
+ UINT Length; // Length of this structure
+ UINT KeyIndex;
+ NDIS_802_11_MAC_ADDRESS BSSID;
+} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
+
+typedef struct PACKED _NDIS_802_11_WEP
+{
+ UINT Length; // Length of this structure
+ UINT KeyIndex; // 0 is the per-client key, 1-N are the
+ // global keys
+ UINT KeyLength; // length of key in bytes
+ UCHAR KeyMaterial[1];// variable length depending on above field
+} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
+
+
+typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
+{
+ Ndis802_11IBSS,
+ Ndis802_11Infrastructure,
+ Ndis802_11AutoUnknown,
+ Ndis802_11InfrastructureMax // Not a real value, defined as upper bound
+} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
+
+// PMKID Structures
+typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
+
+typedef struct _BSSID_INFO
+{
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ NDIS_802_11_PMKID_VALUE PMKID;
+} BSSID_INFO, *PBSSID_INFO;
+
+typedef struct _NDIS_802_11_PMKID
+{
+ ULONG Length;
+ ULONG BSSIDInfoCount;
+ BSSID_INFO BSSIDInfo[1];
+} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
+
+//Added new types for PMKID Candidate lists.
+typedef struct _PMKID_CANDIDATE {
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ ULONG Flags;
+} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
+
+typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
+{
+ ULONG Version; // Version of the structure
+ ULONG NumCandidates; // No. of pmkid candidates
+ PMKID_CANDIDATE CandidateList[1];
+} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
+
+//Flags for PMKID Candidate list structure
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
+
+// Add new authentication modes
+typedef enum _NDIS_802_11_AUTHENTICATION_MODE
+{
+ Ndis802_11AuthModeOpen,
+ Ndis802_11AuthModeShared,
+ Ndis802_11AuthModeAutoSwitch,
+ Ndis802_11AuthModeWPA,
+ Ndis802_11AuthModeWPAPSK,
+ Ndis802_11AuthModeWPANone,
+ Ndis802_11AuthModeWPA2,
+ Ndis802_11AuthModeWPA2PSK,
+ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound
+} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
+
+typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates
+typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates
+
+typedef struct PACKED _NDIS_802_11_SSID
+{
+ INT SsidLength; // length of SSID field below, in bytes;
+ // this can be zero.
+ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field
+} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
+
+
+typedef struct PACKED _NDIS_WLAN_BSSID
+{
+ ULONG Length; // Length of this structure
+ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
+ UCHAR Reserved[2];
+ NDIS_802_11_SSID Ssid; // SSID
+ ULONG Privacy; // WEP encryption requirement
+ NDIS_802_11_RSSI Rssi; // receive signal
+ // strength in dBm
+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+ NDIS_802_11_CONFIGURATION Configuration;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+ NDIS_802_11_RATES SupportedRates;
+} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
+
+typedef struct PACKED _NDIS_802_11_BSSID_LIST
+{
+ UINT NumberOfItems; // in list below, at least 1
+ NDIS_WLAN_BSSID Bssid[1];
+} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
+
+// Added Capabilities, IELength and IEs for each BSSID
+typedef struct PACKED _NDIS_WLAN_BSSID_EX
+{
+ ULONG Length; // Length of this structure
+ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
+ UCHAR Reserved[2];
+ NDIS_802_11_SSID Ssid; // SSID
+ UINT Privacy; // WEP encryption requirement
+ NDIS_802_11_RSSI Rssi; // receive signal
+ // strength in dBm
+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+ NDIS_802_11_CONFIGURATION Configuration;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+ NDIS_802_11_RATES_EX SupportedRates;
+ ULONG IELength;
+ UCHAR IEs[1];
+} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
+
+typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
+{
+ UINT NumberOfItems; // in list below, at least 1
+ NDIS_WLAN_BSSID_EX Bssid[1];
+} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
+
+typedef struct PACKED _NDIS_802_11_FIXED_IEs
+{
+ UCHAR Timestamp[8];
+ USHORT BeaconInterval;
+ USHORT Capabilities;
+} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
+
+// Added new encryption types
+// Also aliased typedef to new name
+typedef enum _NDIS_802_11_WEP_STATUS
+{
+ Ndis802_11WEPEnabled,
+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+ Ndis802_11WEPDisabled,
+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+ Ndis802_11WEPKeyAbsent,
+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+ Ndis802_11WEPNotSupported,
+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+ Ndis802_11Encryption2Enabled,
+ Ndis802_11Encryption2KeyAbsent,
+ Ndis802_11Encryption3Enabled,
+ Ndis802_11Encryption3KeyAbsent
+} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
+ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
+
+typedef enum _NDIS_802_11_RELOAD_DEFAULTS
+{
+ Ndis802_11ReloadWEPKeys
+} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
+
+#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
+#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
+#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
+
+#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
+#define NDIS_802_11_AI_RESFI_STATUSCODE 2
+#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
+
+typedef struct _NDIS_802_11_AI_REQFI
+{
+ USHORT Capabilities;
+ USHORT ListenInterval;
+ NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
+} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
+
+typedef struct _NDIS_802_11_AI_RESFI
+{
+ USHORT Capabilities;
+ USHORT StatusCode;
+ USHORT AssociationId;
+} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
+
+typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
+{
+ ULONG Length;
+ USHORT AvailableRequestFixedIEs;
+ NDIS_802_11_AI_REQFI RequestFixedIEs;
+ ULONG RequestIELength;
+ ULONG OffsetRequestIEs;
+ USHORT AvailableResponseFixedIEs;
+ NDIS_802_11_AI_RESFI ResponseFixedIEs;
+ ULONG ResponseIELength;
+ ULONG OffsetResponseIEs;
+} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
+
+struct ndis_pmkid_entry {
+ struct ndis_pmkid_entry *next;
+ u8 bssid[ETH_ALEN];
+ u8 pmkid[16];
+};
+
+typedef struct _MLME_DEAUTH_REQ_STRUCT {
+ UCHAR Addr[MAC_ADDR_LEN];
+ USHORT Reason;
+} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
diff --git a/contrib/wpa/src/drivers/driver_roboswitch.c b/contrib/wpa/src/drivers/driver_roboswitch.c
new file mode 100644
index 0000000..bc11a48
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_roboswitch.c
@@ -0,0 +1,476 @@
+/*
+ * WPA Supplicant - roboswitch driver interface
+ * Copyright (c) 2008-2009 Jouke Witteveen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/if_ether.h>
+#include <linux/mii.h>
+
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+
+#ifndef ETH_P_EAPOL
+#define ETH_P_EAPOL 0x888e
+#endif
+
+#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */
+
+/* MII access registers */
+#define ROBO_MII_PAGE 0x10 /* MII page register */
+#define ROBO_MII_ADDR 0x11 /* MII address register */
+#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */
+
+#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */
+#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */
+#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */
+#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */
+#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */
+
+/* Page numbers */
+#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */
+#define ROBO_VLAN_PAGE 0x34 /* VLAN page */
+
+/* ARL control page registers */
+#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */
+#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */
+#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */
+#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */
+#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */
+
+/* VLAN page registers */
+#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */
+#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */
+#define ROBO_VLAN_READ 0x0c /* VLAN read register */
+#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_roboswitch_data {
+ void *ctx;
+ struct l2_packet_data *l2;
+ char ifname[IFNAMSIZ + 1];
+ u8 own_addr[ETH_ALEN];
+ struct ifreq ifr;
+ int fd, is_5350;
+ u16 ports;
+};
+
+
+/* Copied from the kernel-only part of mii.h. */
+static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
+{
+ return (struct mii_ioctl_data *) &rq->ifr_ifru;
+}
+
+
+/*
+ * RoboSwitch uses 16-bit Big Endian addresses.
+ * The ordering of the words is reversed in the MII registers.
+ */
+static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
+{
+ int i;
+ for (i = 0; i < ETH_ALEN; i += 2)
+ be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
+}
+
+
+static u16 wpa_driver_roboswitch_mdio_read(
+ struct wpa_driver_roboswitch_data *drv, u8 reg)
+{
+ struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+ mii->phy_id = ROBO_PHY_ADDR;
+ mii->reg_num = reg;
+
+ if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
+ perror("ioctl[SIOCGMIIREG]");
+ return 0x00;
+ }
+ return mii->val_out;
+}
+
+
+static void wpa_driver_roboswitch_mdio_write(
+ struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
+{
+ struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+ mii->phy_id = ROBO_PHY_ADDR;
+ mii->reg_num = reg;
+ mii->val_in = val;
+
+ if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
+ perror("ioctl[SIOCSMIIREG");
+ }
+}
+
+
+static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u8 op)
+{
+ int i;
+
+ /* set page number */
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
+ (page << 8) | ROBO_MII_PAGE_ENABLE);
+ /* set register address */
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
+
+ /* check if operation completed */
+ for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
+ if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
+ == 0)
+ return 0;
+ }
+ /* timeout */
+ return -1;
+}
+
+
+static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u16 *val, int len)
+{
+ int i;
+
+ if (len > ROBO_MII_DATA_MAX ||
+ wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
+ return -1;
+
+ for (i = 0; i < len; ++i) {
+ val[i] = wpa_driver_roboswitch_mdio_read(
+ drv, ROBO_MII_DATA_OFFSET + i);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u16 *val, int len)
+{
+ int i;
+
+ if (len > ROBO_MII_DATA_MAX) return -1;
+ for (i = 0; i < len; ++i) {
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
+ val[i]);
+ }
+ return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
+}
+
+
+static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+
+ if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
+ os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) {
+ wpa_supplicant_rx_eapol(drv->ctx, src_addr, buf + 14,
+ len - 14);
+ }
+}
+
+
+static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+ char *sep;
+
+ if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
+ sep = drv->ifname + os_strlen(drv->ifname);
+ *sep = '.';
+ drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
+ wpa_driver_roboswitch_receive, drv,
+ 1);
+ if (drv->l2 == NULL) {
+ wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
+ __func__, drv->ifname);
+ return -1;
+ }
+ *sep = '\0';
+ l2_packet_get_own_addr(drv->l2, drv->own_addr);
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
+ drv->l2 = NULL;
+ }
+ return 0;
+}
+
+
+static const char * wpa_driver_roboswitch_get_ifname(void *priv)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+ return drv->ifname;
+}
+
+
+static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
+ u16 ports, const u8 *addr)
+{
+ u16 read1[3], read2[3], addr_be16[3];
+
+ wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, read1, 1) < 0)
+ return -1;
+ if (!(read1[0] & (1 << 4))) {
+ /* multiport addresses are not yet enabled */
+ read1[0] |= 1 << 4;
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, read1, 1);
+ } else {
+ /* if both multiport addresses are the same we can add */
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, read1, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, read2, 3);
+ if (os_memcmp(read1, read2, 6) != 0)
+ return -1;
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, read1, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, read2, 1);
+ if (read1[0] != read2[0])
+ return -1;
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports, 1);
+ }
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
+ u16 ports, const u8 *addr)
+{
+ u16 _read, addr_be16[3], addr_read[3], ports_read;
+
+ wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
+ &_read, 1);
+ /* If ARL control is disabled, there is nothing to leave. */
+ if (!(_read & (1 << 4))) return -1;
+
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ /* check if we occupy multiport address 1 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+ /* and multiport address 2 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+ ports_read == ports) {
+ _read &= ~(1 << 4);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, &_read,
+ 1);
+ } else {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1,
+ addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2,
+ addr_read, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2,
+ &ports_read, 1);
+ }
+ } else {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+ /* or multiport address 2 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+ ports_read == ports) {
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1,
+ addr_read, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ } else return -1;
+ }
+ return 0;
+}
+
+
+static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_roboswitch_data *drv;
+ char *sep;
+ u16 vlan = 0, _read[2];
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL) return NULL;
+ drv->ctx = ctx;
+ drv->own_addr[0] = '\0';
+
+ /* copy ifname and take a pointer to the second to last character */
+ sep = drv->ifname +
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
+ /* find the '.' seperating <interface> and <vlan> */
+ while (sep > drv->ifname && *sep != '.') sep--;
+ if (sep <= drv->ifname) {
+ wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
+ "interface name %s", __func__, drv->ifname);
+ os_free(drv);
+ return NULL;
+ }
+ *sep = '\0';
+ while (*++sep) {
+ if (*sep < '0' || *sep > '9') {
+ wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
+ "in interface name %s", __func__, ifname);
+ os_free(drv);
+ return NULL;
+ }
+ vlan *= 10;
+ vlan += *sep - '0';
+ if (vlan > ROBO_VLAN_MAX) {
+ wpa_printf(MSG_INFO, "%s: VLAN out of range in "
+ "interface name %s", __func__, ifname);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->fd < 0) {
+ wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&drv->ifr, 0, sizeof(drv->ifr));
+ os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
+ perror("ioctl[SIOCGMIIPHY]");
+ os_free(drv);
+ return NULL;
+ }
+ if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
+ wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
+ "RoboSwitch?)", __func__);
+ os_free(drv);
+ return NULL;
+ }
+
+ /* set and read back to see if the register can be used */
+ _read[0] = ROBO_VLAN_MAX;
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+ _read, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+ _read + 1, 1);
+ drv->is_5350 = _read[0] == _read[1];
+
+ /* set the read bit */
+ vlan |= 1 << 13;
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
+ drv->is_5350 ? ROBO_VLAN_ACCESS_5350
+ : ROBO_VLAN_ACCESS,
+ &vlan, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
+ drv->is_5350 ? 2 : 1);
+ if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
+ wpa_printf(MSG_INFO, "%s: Could not get port information for "
+ "VLAN %d", __func__, vlan & ~(1 << 13));
+ os_free(drv);
+ return NULL;
+ }
+ drv->ports = _read[0] & 0x001F;
+ /* add the MII port */
+ drv->ports |= 1 << 8;
+ if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
+ wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
+ os_free(drv);
+ return NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
+ "RoboSwitch ARL", __func__);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_roboswitch_deinit(void *priv)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+
+ if (drv->l2) {
+ l2_packet_deinit(drv->l2);
+ drv->l2 = NULL;
+ }
+ if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
+ __func__);
+ }
+
+ close(drv->fd);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
+ .name = "roboswitch",
+ .desc = "wpa_supplicant roboswitch driver",
+ .get_ssid = wpa_driver_roboswitch_get_ssid,
+ .get_bssid = wpa_driver_roboswitch_get_bssid,
+ .init = wpa_driver_roboswitch_init,
+ .deinit = wpa_driver_roboswitch_deinit,
+ .set_param = wpa_driver_roboswitch_set_param,
+ .get_ifname = wpa_driver_roboswitch_get_ifname,
+};
diff --git a/contrib/wpa/src/drivers/driver_test.c b/contrib/wpa/src/drivers/driver_test.c
new file mode 100644
index 0000000..2a41cf2
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_test.c
@@ -0,0 +1,1230 @@
+/*
+ * WPA Supplicant - testing driver interface
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+/* Make dure we get winsock2.h for Windows build to get sockaddr_storage */
+#include "build_config.h"
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock2.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/un.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#define DRIVER_TEST_UNIX
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+#include "eloop.h"
+#include "sha1.h"
+#include "ieee802_11_defs.h"
+
+
+struct wpa_driver_test_global {
+ int dummy;
+};
+
+struct wpa_driver_test_data {
+ struct wpa_driver_test_global *global;
+ void *ctx;
+ u8 own_addr[ETH_ALEN];
+ int test_socket;
+#ifdef DRIVER_TEST_UNIX
+ struct sockaddr_un hostapd_addr;
+#endif /* DRIVER_TEST_UNIX */
+ int hostapd_addr_set;
+ struct sockaddr_in hostapd_addr_udp;
+ int hostapd_addr_udp_set;
+ char *own_socket_path;
+ char *test_dir;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+#define MAX_SCAN_RESULTS 30
+ struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
+ size_t num_scanres;
+ int use_associnfo;
+ u8 assoc_wpa_ie[80];
+ size_t assoc_wpa_ie_len;
+ int use_mlme;
+ int associated;
+ u8 *probe_req_ie;
+ size_t probe_req_ie_len;
+};
+
+
+static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_test_data *drv = eloop_ctx;
+
+#ifdef DRIVER_TEST_UNIX
+ if (drv->associated && drv->hostapd_addr_set) {
+ struct stat st;
+ if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
+ __func__, strerror(errno));
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ }
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
+}
+
+
+static int wpa_driver_test_set_wpa(void *priv, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return 0;
+}
+
+
+static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+#ifdef DRIVER_TEST_UNIX
+static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
+ const char *path)
+{
+ struct dirent *dent;
+ DIR *dir;
+ struct sockaddr_un addr;
+ char cmd[512], *pos, *end;
+ int ret;
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
+ MAC2STR(drv->own_addr));
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ if (drv->probe_req_ie) {
+ ret = os_snprintf(pos, end - pos, " ");
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
+ drv->probe_req_ie_len);
+ }
+ end[-1] = '\0';
+
+ while ((dent = readdir(dir))) {
+ if (os_strncmp(dent->d_name, "AP-", 3) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+ path, dent->d_name);
+
+ if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+ (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("sendto(test_socket)");
+ }
+ }
+ closedir(dir);
+}
+#endif /* DRIVER_TEST_UNIX */
+
+
+static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+
+ drv->num_scanres = 0;
+
+#ifdef DRIVER_TEST_UNIX
+ if (drv->test_socket >= 0 && drv->test_dir)
+ wpa_driver_scan_dir(drv, drv->test_dir);
+
+ if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
+ sendto(drv->test_socket, "SCAN", 4, 0,
+ (struct sockaddr *) &drv->hostapd_addr,
+ sizeof(drv->hostapd_addr)) < 0) {
+ perror("sendto(test_socket)");
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+ sendto(drv->test_socket, "SCAN", 4, 0,
+ (struct sockaddr *) &drv->hostapd_addr_udp,
+ sizeof(drv->hostapd_addr_udp)) < 0) {
+ perror("sendto(test_socket)");
+ }
+
+ eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
+{
+ struct wpa_driver_test_data *drv = priv;
+ struct wpa_scan_results *res;
+ size_t i;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return NULL;
+
+ res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
+ if (res->res == NULL) {
+ os_free(res);
+ return NULL;
+ }
+
+ for (i = 0; i < drv->num_scanres; i++) {
+ struct wpa_scan_res *r;
+ if (drv->scanres[i] == NULL)
+ continue;
+ r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
+ if (r == NULL)
+ break;
+ os_memcpy(r, drv->scanres[i],
+ sizeof(*r) + drv->scanres[i]->ie_len);
+ res->res[res->num++] = r;
+ }
+
+ return res;
+}
+
+
+static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
+ __func__, priv, alg, key_idx, set_tx);
+ if (addr) {
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ }
+ if (seq) {
+ wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len);
+ }
+ if (key) {
+ wpa_hexdump(MSG_DEBUG, " key", key, key_len);
+ }
+ return 0;
+}
+
+
+static int wpa_driver_test_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+ "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
+ __func__, priv, params->freq, params->pairwise_suite,
+ params->group_suite, params->key_mgmt_suite,
+ params->auth_alg, params->mode);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ }
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " ssid",
+ params->ssid, params->ssid_len);
+ }
+ if (params->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG, " wpa_ie",
+ params->wpa_ie, params->wpa_ie_len);
+ drv->assoc_wpa_ie_len = params->wpa_ie_len;
+ if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
+ drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
+ os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
+ drv->assoc_wpa_ie_len);
+ } else
+ drv->assoc_wpa_ie_len = 0;
+
+#ifdef DRIVER_TEST_UNIX
+ if (drv->test_dir && params->bssid) {
+ os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
+ drv->hostapd_addr.sun_family = AF_UNIX;
+ os_snprintf(drv->hostapd_addr.sun_path,
+ sizeof(drv->hostapd_addr.sun_path),
+ "%s/AP-" MACSTR,
+ drv->test_dir, MAC2STR(params->bssid));
+ drv->hostapd_addr_set = 1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ if (drv->test_socket >= 0 &&
+ (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
+ char cmd[200], *pos, *end;
+ int ret;
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
+ MAC2STR(drv->own_addr));
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
+ params->ssid_len);
+ ret = os_snprintf(pos, end - pos, " ");
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
+ params->wpa_ie_len);
+ end[-1] = '\0';
+#ifdef DRIVER_TEST_UNIX
+ if (drv->hostapd_addr_set &&
+ sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+ (struct sockaddr *) &drv->hostapd_addr,
+ sizeof(drv->hostapd_addr)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+ if (drv->hostapd_addr_udp_set &&
+ sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+ (struct sockaddr *) &drv->hostapd_addr_udp,
+ sizeof(drv->hostapd_addr_udp)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+ } else {
+ drv->associated = 1;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_test_data *drv = priv;
+ os_memcpy(bssid, drv->bssid, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_test_data *drv = priv;
+ os_memcpy(ssid, drv->ssid, 32);
+ return drv->ssid_len;
+}
+
+
+static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
+{
+#ifdef DRIVER_TEST_UNIX
+ if (drv->test_socket >= 0 &&
+ sendto(drv->test_socket, "DISASSOC", 8, 0,
+ (struct sockaddr *) &drv->hostapd_addr,
+ sizeof(drv->hostapd_addr)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+ if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+ sendto(drv->test_socket, "DISASSOC", 8, 0,
+ (struct sockaddr *) &drv->hostapd_addr_udp,
+ sizeof(drv->hostapd_addr_udp)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ os_memset(drv->bssid, 0, ETH_ALEN);
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ return wpa_driver_test_send_disassoc(drv);
+}
+
+
+static int wpa_driver_test_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ os_memset(drv->bssid, 0, ETH_ALEN);
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ return wpa_driver_test_send_disassoc(drv);
+}
+
+
+static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const char *data)
+{
+ struct wpa_scan_res *res;
+ const char *pos, *pos2;
+ size_t len;
+ u8 *ie_pos, *ie_start, *ie_end;
+#define MAX_IE_LEN 1000
+
+ wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
+ if (drv->num_scanres >= MAX_SCAN_RESULTS) {
+ wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
+ "result");
+ return;
+ }
+
+ /* SCANRESP BSSID SSID IEs */
+
+ res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
+ if (res == NULL)
+ return;
+ ie_start = ie_pos = (u8 *) (res + 1);
+ ie_end = ie_pos + MAX_IE_LEN;
+
+ if (hwaddr_aton(data, res->bssid)) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
+ os_free(res);
+ return;
+ }
+
+ pos = data + 17;
+ while (*pos == ' ')
+ pos++;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
+ "in scanres");
+ os_free(res);
+ return;
+ }
+ len = (pos2 - pos) / 2;
+ if (len > 32)
+ len = 32;
+ /*
+ * Generate SSID IE from the SSID field since this IE is not included
+ * in the main IE field.
+ */
+ *ie_pos++ = WLAN_EID_SSID;
+ *ie_pos++ = len;
+ if (hexstr2bin(pos, ie_pos, len) < 0) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
+ os_free(res);
+ return;
+ }
+ ie_pos += len;
+
+ pos = pos2 + 1;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ len = os_strlen(pos) / 2;
+ else
+ len = (pos2 - pos) / 2;
+ if ((int) len > ie_end - ie_pos)
+ len = ie_end - ie_pos;
+ if (hexstr2bin(pos, ie_pos, len) < 0) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
+ os_free(res);
+ return;
+ }
+ ie_pos += len;
+ res->ie_len = ie_pos - ie_start;
+
+ if (pos2) {
+ pos = pos2 + 1;
+ while (*pos == ' ')
+ pos++;
+ if (os_strncmp(pos, "PRIVACY", 7) == 0)
+ res->caps |= IEEE80211_CAP_PRIVACY;
+ }
+
+ os_free(drv->scanres[drv->num_scanres]);
+ drv->scanres[drv->num_scanres++] = res;
+}
+
+
+static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const char *data)
+{
+ /* ASSOCRESP BSSID <res> */
+ if (hwaddr_aton(data, drv->bssid)) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
+ "assocresp");
+ }
+ if (drv->use_associnfo) {
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_info.req_ies = drv->assoc_wpa_ie;
+ event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
+ }
+ drv->associated = 1;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen)
+{
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+}
+
+
+static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const u8 *data, size_t data_len)
+{
+ const u8 *src = drv->bssid;
+
+ if (data_len > 14) {
+ /* Skip Ethernet header */
+ src = data + ETH_ALEN;
+ data += 14;
+ data_len -= 14;
+ }
+ wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len);
+}
+
+
+static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const u8 *data, size_t data_len)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct ieee80211_rx_status rx_status;
+ os_memset(&rx_status, 0, sizeof(rx_status));
+ wpa_supplicant_sta_rx(drv->ctx, data, data_len, &rx_status);
+#endif /* CONFIG_CLIENT_MLME */
+}
+
+
+static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_driver_test_data *drv = eloop_ctx;
+ char *buf;
+ int res;
+ struct sockaddr_storage from;
+ socklen_t fromlen = sizeof(from);
+ const size_t buflen = 2000;
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ res = recvfrom(sock, buf, buflen - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(test_socket)");
+ os_free(buf);
+ return;
+ }
+ buf[res] = '\0';
+
+ wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
+
+ if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
+ wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
+ fromlen, buf + 9);
+ } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
+ wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
+ fromlen, buf + 10);
+ } else if (os_strcmp(buf, "DISASSOC") == 0) {
+ wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+ fromlen);
+ } else if (os_strcmp(buf, "DEAUTH") == 0) {
+ wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+ fromlen);
+ } else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
+ wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
+ (const u8 *) buf + 6, res - 6);
+ } else if (os_strncmp(buf, "MLME ", 5) == 0) {
+ wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
+ (const u8 *) buf + 5, res - 5);
+ } else {
+ wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
+ (u8 *) buf, res);
+ }
+ os_free(buf);
+}
+
+
+static void * wpa_driver_test_init2(void *ctx, const char *ifname,
+ void *global_priv)
+{
+ struct wpa_driver_test_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->global = global_priv;
+ drv->ctx = ctx;
+ drv->test_socket = -1;
+
+ /* Set dummy BSSID and SSID for testing. */
+ drv->bssid[0] = 0x02;
+ drv->bssid[1] = 0x00;
+ drv->bssid[2] = 0x00;
+ drv->bssid[3] = 0x00;
+ drv->bssid[4] = 0x00;
+ drv->bssid[5] = 0x01;
+ os_memcpy(drv->ssid, "test", 5);
+ drv->ssid_len = 4;
+
+ /* Generate a MAC address to help testing with multiple STAs */
+ drv->own_addr[0] = 0x02; /* locally administered */
+ sha1_prf((const u8 *) ifname, os_strlen(ifname),
+ "wpa_supplicant test mac addr generation",
+ NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
+ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
+
+ return drv;
+}
+
+
+static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
+{
+ if (drv->test_socket >= 0) {
+ eloop_unregister_read_sock(drv->test_socket);
+ close(drv->test_socket);
+ drv->test_socket = -1;
+ }
+
+ if (drv->own_socket_path) {
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ }
+}
+
+
+static void wpa_driver_test_deinit(void *priv)
+{
+ struct wpa_driver_test_data *drv = priv;
+ int i;
+ wpa_driver_test_close_test_socket(drv);
+ eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
+ os_free(drv->test_dir);
+ for (i = 0; i < MAX_SCAN_RESULTS; i++)
+ os_free(drv->scanres[i]);
+ os_free(drv->probe_req_ie);
+ os_free(drv);
+}
+
+
+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
+ const char *dir)
+{
+#ifdef DRIVER_TEST_UNIX
+ static unsigned int counter = 0;
+ struct sockaddr_un addr;
+ size_t len;
+
+ os_free(drv->own_socket_path);
+ if (dir) {
+ len = os_strlen(dir) + 30;
+ drv->own_socket_path = os_malloc(len);
+ if (drv->own_socket_path == NULL)
+ return -1;
+ os_snprintf(drv->own_socket_path, len, "%s/STA-" MACSTR,
+ dir, MAC2STR(drv->own_addr));
+ } else {
+ drv->own_socket_path = os_malloc(100);
+ if (drv->own_socket_path == NULL)
+ return -1;
+ os_snprintf(drv->own_socket_path, 100,
+ "/tmp/wpa_supplicant_test-%d-%d",
+ getpid(), counter++);
+ }
+
+ drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (drv->test_socket < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
+ if (bind(drv->test_socket, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ close(drv->test_socket);
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ eloop_register_read_sock(drv->test_socket,
+ wpa_driver_test_receive_unix, drv, NULL);
+
+ return 0;
+#else /* DRIVER_TEST_UNIX */
+ return -1;
+#endif /* DRIVER_TEST_UNIX */
+}
+
+
+static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
+ char *dst)
+{
+ char *pos;
+
+ pos = os_strchr(dst, ':');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
+
+ drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->test_socket < 0) {
+ perror("socket(PF_INET)");
+ return -1;
+ }
+
+ os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
+ drv->hostapd_addr_udp.sin_family = AF_INET;
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
+ {
+ int a[4];
+ u8 *pos;
+ sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+ pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
+ *pos++ = a[0];
+ *pos++ = a[1];
+ *pos++ = a[2];
+ *pos++ = a[3];
+ }
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+ inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+ drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
+
+ drv->hostapd_addr_udp_set = 1;
+
+ eloop_register_read_sock(drv->test_socket,
+ wpa_driver_test_receive_unix, drv, NULL);
+
+ return 0;
+}
+
+
+static int wpa_driver_test_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_test_data *drv = priv;
+ const char *pos;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+ if (param == NULL)
+ return 0;
+
+ wpa_driver_test_close_test_socket(drv);
+
+#ifdef DRIVER_TEST_UNIX
+ pos = os_strstr(param, "test_socket=");
+ if (pos) {
+ const char *pos2;
+ size_t len;
+
+ pos += 12;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ len = pos2 - pos;
+ else
+ len = os_strlen(pos);
+ if (len > sizeof(drv->hostapd_addr.sun_path))
+ return -1;
+ os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
+ drv->hostapd_addr.sun_family = AF_UNIX;
+ os_memcpy(drv->hostapd_addr.sun_path, pos, len);
+ drv->hostapd_addr_set = 1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ pos = os_strstr(param, "test_dir=");
+ if (pos) {
+ char *end;
+ os_free(drv->test_dir);
+ drv->test_dir = os_strdup(pos + 9);
+ if (drv->test_dir == NULL)
+ return -1;
+ end = os_strchr(drv->test_dir, ' ');
+ if (end)
+ *end = '\0';
+ if (wpa_driver_test_attach(drv, drv->test_dir))
+ return -1;
+ } else {
+ pos = os_strstr(param, "test_udp=");
+ if (pos) {
+ char *dst, *epos;
+ dst = os_strdup(pos + 9);
+ if (dst == NULL)
+ return -1;
+ epos = os_strchr(dst, ' ');
+ if (epos)
+ *epos = '\0';
+ if (wpa_driver_test_attach_udp(drv, dst))
+ return -1;
+ os_free(dst);
+ } else if (wpa_driver_test_attach(drv, NULL))
+ return -1;
+ }
+
+ if (os_strstr(param, "use_associnfo=1")) {
+ wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
+ drv->use_associnfo = 1;
+ }
+
+#ifdef CONFIG_CLIENT_MLME
+ if (os_strstr(param, "use_mlme=1")) {
+ wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
+ drv->use_mlme = 1;
+ }
+#endif /* CONFIG_CLIENT_MLME */
+
+ return 0;
+}
+
+
+static const u8 * wpa_driver_test_get_mac_addr(void *priv)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ return drv->own_addr;
+}
+
+
+static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
+ const u8 *data, size_t data_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+ char *msg;
+ size_t msg_len;
+ struct l2_ethhdr eth;
+ struct sockaddr *addr;
+ socklen_t alen;
+#ifdef DRIVER_TEST_UNIX
+ struct sockaddr_un addr_un;
+#endif /* DRIVER_TEST_UNIX */
+
+ wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
+
+ os_memset(&eth, 0, sizeof(eth));
+ os_memcpy(eth.h_dest, dest, ETH_ALEN);
+ os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
+ eth.h_proto = host_to_be16(proto);
+
+ msg_len = 6 + sizeof(eth) + data_len;
+ msg = os_malloc(msg_len);
+ if (msg == NULL)
+ return -1;
+ os_memcpy(msg, "EAPOL ", 6);
+ os_memcpy(msg + 6, &eth, sizeof(eth));
+ os_memcpy(msg + 6 + sizeof(eth), data, data_len);
+
+ if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
+ drv->test_dir == NULL) {
+ if (drv->hostapd_addr_udp_set) {
+ addr = (struct sockaddr *) &drv->hostapd_addr_udp;
+ alen = sizeof(drv->hostapd_addr_udp);
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ addr = (struct sockaddr *) &drv->hostapd_addr;
+ alen = sizeof(drv->hostapd_addr);
+#else /* DRIVER_TEST_UNIX */
+ os_free(msg);
+ return -1;
+#endif /* DRIVER_TEST_UNIX */
+ }
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ struct stat st;
+ os_memset(&addr_un, 0, sizeof(addr_un));
+ addr_un.sun_family = AF_UNIX;
+ os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
+ "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
+ if (stat(addr_un.sun_path, &st) < 0) {
+ os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
+ "%s/AP-" MACSTR,
+ drv->test_dir, MAC2STR(dest));
+ }
+ addr = (struct sockaddr *) &addr_un;
+ alen = sizeof(addr_un);
+#else /* DRIVER_TEST_UNIX */
+ os_free(msg);
+ return -1;
+#endif /* DRIVER_TEST_UNIX */
+ }
+
+ if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
+ perror("sendmsg(test_socket)");
+ os_free(msg);
+ return -1;
+ }
+
+ os_free(msg);
+ return 0;
+}
+
+
+static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_test_data *drv = priv;
+ os_memset(capa, 0, sizeof(*capa));
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP |
+ WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ if (drv->use_mlme)
+ capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+
+ return 0;
+}
+
+
+static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
+ int protect_type,
+ int key_type)
+{
+ wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
+ __func__, protect_type, key_type);
+
+ if (addr) {
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
+ __func__, MAC2STR(addr));
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+static struct wpa_hw_modes *
+wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ struct wpa_hw_modes *modes;
+
+ *num_modes = 1;
+ *flags = 0;
+ modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes));
+ if (modes == NULL)
+ return NULL;
+ modes[0].mode = WPA_MODE_IEEE80211G;
+ modes[0].num_channels = 1;
+ modes[0].num_rates = 1;
+ modes[0].channels = os_zalloc(sizeof(struct wpa_channel_data));
+ modes[0].rates = os_zalloc(sizeof(struct wpa_rate_data));
+ if (modes[0].channels == NULL || modes[0].rates == NULL) {
+ wpa_supplicant_sta_free_hw_features(modes, *num_modes);
+ return NULL;
+ }
+ modes[0].channels[0].chan = 1;
+ modes[0].channels[0].freq = 2412;
+ modes[0].channels[0].flag = WPA_CHAN_W_SCAN | WPA_CHAN_W_ACTIVE_SCAN;
+ modes[0].rates[0].rate = 10;
+ modes[0].rates[0].flags = WPA_RATE_BASIC | WPA_RATE_SUPPORTED |
+ WPA_RATE_CCK | WPA_RATE_MANDATORY;
+
+ return modes;
+}
+
+
+static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode,
+ int chan, int freq)
+{
+ wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
+ __func__, phymode, chan, freq);
+ return 0;
+}
+
+
+static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
+ size_t data_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+ struct msghdr msg;
+ struct iovec io[2];
+ struct sockaddr_un addr;
+ const u8 *dest;
+ struct dirent *dent;
+ DIR *dir;
+
+ wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
+ if (data_len < 10)
+ return -1;
+ dest = data + 4;
+
+ io[0].iov_base = "MLME ";
+ io[0].iov_len = 5;
+ io[1].iov_base = (u8 *) data;
+ io[1].iov_len = data_len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+ if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
+ drv->test_dir == NULL) {
+ if (drv->hostapd_addr_udp_set) {
+ msg.msg_name = &drv->hostapd_addr_udp;
+ msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ msg.msg_name = &drv->hostapd_addr;
+ msg.msg_namelen = sizeof(drv->hostapd_addr);
+#endif /* DRIVER_TEST_UNIX */
+ }
+ } else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ {
+ dir = opendir(drv->test_dir);
+ if (dir == NULL)
+ return -1;
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (os_strcmp(dent->d_name, ".") == 0 ||
+ os_strcmp(dent->d_name, "..") == 0)
+ continue;
+ wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
+ __func__, dent->d_name);
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/%s", drv->test_dir, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+
+ if (sendmsg(drv->test_socket, &msg, 0) < 0)
+ perror("sendmsg(test_socket)");
+ }
+ closedir(dir);
+ return 0;
+ } else {
+ struct stat st;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
+ if (stat(addr.sun_path, &st) < 0) {
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/STA-" MACSTR,
+ drv->test_dir, MAC2STR(dest));
+ }
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ }
+
+ if (sendmsg(drv->test_socket, &msg, 0) < 0) {
+ perror("sendmsg(test_socket)");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
+ const u8 *supp_rates,
+ size_t supp_rates_len)
+{
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
+ return 0;
+}
+
+
+static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
+{
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
+ return 0;
+}
+
+
+static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ return 0;
+}
+
+
+static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
+{
+ wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
+ return 0;
+}
+#endif /* CONFIG_CLIENT_MLME */
+
+
+static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+
+ os_free(drv->probe_req_ie);
+ if (ies) {
+ drv->probe_req_ie = os_malloc(ies_len);
+ if (drv->probe_req_ie == NULL) {
+ drv->probe_req_ie_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->probe_req_ie, ies, ies_len);
+ drv->probe_req_ie_len = ies_len;
+ } else {
+ drv->probe_req_ie = NULL;
+ drv->probe_req_ie_len = 0;
+ }
+ return 0;
+}
+
+
+static void * wpa_driver_test_global_init(void)
+{
+ struct wpa_driver_test_global *global;
+
+ global = os_zalloc(sizeof(*global));
+ return global;
+}
+
+
+static void wpa_driver_test_global_deinit(void *priv)
+{
+ struct wpa_driver_test_global *global = priv;
+ os_free(global);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_test_get_interfaces(void *global_priv)
+{
+ /* struct wpa_driver_test_global *global = priv; */
+ struct wpa_interface_info *iface;
+
+ iface = os_zalloc(sizeof(*iface));
+ if (iface == NULL)
+ return iface;
+ iface->ifname = os_strdup("sta0");
+ iface->desc = os_strdup("test interface 0");
+ iface->drv_name = "test";
+ iface->next = os_zalloc(sizeof(*iface));
+ if (iface->next) {
+ iface->next->ifname = os_strdup("sta1");
+ iface->next->desc = os_strdup("test interface 1");
+ iface->next->drv_name = "test";
+ }
+
+ return iface;
+}
+
+
+const struct wpa_driver_ops wpa_driver_test_ops = {
+ "test",
+ "wpa_supplicant test driver",
+ wpa_driver_test_get_bssid,
+ wpa_driver_test_get_ssid,
+ wpa_driver_test_set_wpa,
+ wpa_driver_test_set_key,
+ NULL /* init */,
+ wpa_driver_test_deinit,
+ wpa_driver_test_set_param,
+ NULL /* set_countermeasures */,
+ NULL /* set_drop_unencrypted */,
+ wpa_driver_test_scan,
+ NULL /* get_scan_results */,
+ wpa_driver_test_deauthenticate,
+ wpa_driver_test_disassociate,
+ wpa_driver_test_associate,
+ NULL /* set_auth_alg */,
+ NULL /* add_pmkid */,
+ NULL /* remove_pmkid */,
+ NULL /* flush_pmkid */,
+ wpa_driver_test_get_capa,
+ NULL /* poll */,
+ NULL /* get_ifname */,
+ wpa_driver_test_get_mac_addr,
+ wpa_driver_test_send_eapol,
+ NULL /* set_operstate */,
+ wpa_driver_test_mlme_setprotection,
+#ifdef CONFIG_CLIENT_MLME
+ wpa_driver_test_get_hw_feature_data,
+ wpa_driver_test_set_channel,
+ wpa_driver_test_set_ssid,
+ wpa_driver_test_set_bssid,
+ wpa_driver_test_send_mlme,
+ wpa_driver_test_mlme_add_sta,
+ wpa_driver_test_mlme_remove_sta,
+#else /* CONFIG_CLIENT_MLME */
+ NULL /* get_hw_feature_data */,
+ NULL /* set_channel */,
+ NULL /* set_ssid */,
+ NULL /* set_bssid */,
+ NULL /* send_mlme */,
+ NULL /* mlme_add_sta */,
+ NULL /* mlme_remove_sta */,
+#endif /* CONFIG_CLIENT_MLME */
+ NULL /* update_ft_ies */,
+ NULL /* send_ft_action */,
+ wpa_driver_test_get_scan_results2,
+ wpa_driver_test_set_probe_req_ie,
+ NULL /* set_mode */,
+ NULL /* set_country */,
+ wpa_driver_test_global_init,
+ wpa_driver_test_global_deinit,
+ wpa_driver_test_init2,
+ wpa_driver_test_get_interfaces
+};
diff --git a/contrib/wpa/src/drivers/driver_wext.c b/contrib/wpa/src/drivers/driver_wext.c
new file mode 100644
index 0000000..e771d37
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wext.c
@@ -0,0 +1,2375 @@
+/*
+ * WPA Supplicant - driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file implements a driver interface for the Linux Wireless Extensions.
+ * When used with WE-18 or newer, this interface can be used as-is with number
+ * of drivers. In addition to this, some of the common functions in this file
+ * can be used by other driver interface implementations that use generic WE
+ * ioctls, but require private ioctls for some of the functionality.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+#include "wpa_common.h"
+
+
+static int wpa_driver_wext_flush_pmkid(void *priv);
+static int wpa_driver_wext_get_range(void *priv);
+static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
+
+
+static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = drv->ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = (struct rtattr *)
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
+ linkmode, operstate);
+
+ ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
+ "%s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: Buffer for BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ else
+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCSIWAP]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: Buffer for the SSID; must be at least 32 bytes long
+ * Returns: SSID length on success, -1 on failure
+ */
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ if (ret > 32)
+ ret = 32;
+ /* Some drivers include nul termination in the SSID, so let's
+ * remove it here before further processing. WE-21 changes this
+ * to explicitly require the length _not_ to include nul
+ * termination. */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: SSID
+ * @ssid_len: Length of SSID (0..32)
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ char buf[33];
+
+ if (ssid_len > 32)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+ iwr.u.essid.flags = (ssid_len != 0);
+ os_memset(buf, 0, sizeof(buf));
+ os_memcpy(buf, ssid, ssid_len);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ if (drv->we_version_compiled < 21) {
+ /* For historic reasons, set SSID length to include one extra
+ * character, C string nul termination, even though SSID is
+ * really an octet string that should not be presented as a C
+ * string. Some Linux drivers decrement the length by one and
+ * can thus end up missing the last octet of the SSID if the
+ * length is not incremented here. WE-21 changes this to
+ * explicitly require the length _not_ to include nul
+ * termination. */
+ if (ssid_len)
+ ssid_len++;
+ }
+ iwr.u.essid.length = ssid_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @freq: Frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.freq.m = freq * 100000;
+ iwr.u.freq.e = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void
+wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+ custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast ") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ return;
+ bytes /= 2;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.req_ies, bytes);
+
+ spos += bytes * 2;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ spos += 9;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ goto done;
+ bytes /= 2;
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+#ifdef CONFIG_PEERKEY
+ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+ if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+ wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+ "STKSTART.request '%s'", custom + 17);
+ return;
+ }
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+ }
+}
+
+
+static int wpa_driver_wext_event_wireless_michaelmicfailure(
+ void *ctx, const char *ev, size_t len)
+{
+ const struct iw_michaelmicfailure *mic;
+ union wpa_event_data data;
+
+ if (len < sizeof(*mic))
+ return -1;
+
+ mic = (const struct iw_michaelmicfailure *) ev;
+
+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+ "flags=0x%x src_addr=" MACSTR, mic->flags,
+ MAC2STR(mic->src_addr.sa_data));
+
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_pmkidcand(
+ struct wpa_driver_wext_data *drv, const char *ev, size_t len)
+{
+ const struct iw_pmkid_cand *cand;
+ union wpa_event_data data;
+ const u8 *addr;
+
+ if (len < sizeof(*cand))
+ return -1;
+
+ cand = (const struct iw_pmkid_cand *) ev;
+ addr = (const u8 *) cand->bssid.sa_data;
+
+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+ cand->index, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+ data.pmkid_candidate.index = cand->index;
+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocreqie(
+ struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = os_malloc(len);
+ if (drv->assoc_req_ies == NULL) {
+ drv->assoc_req_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_req_ies, ev, len);
+ drv->assoc_req_ies_len = len;
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocrespie(
+ struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = os_malloc(len);
+ if (drv->assoc_resp_ies == NULL) {
+ drv->assoc_resp_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_resp_ies, ev, len);
+ drv->assoc_resp_ies_len = len;
+
+ return 0;
+}
+
+
+static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
+{
+ union wpa_event_data data;
+
+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ if (drv->assoc_req_ies) {
+ data.assoc_info.req_ies = drv->assoc_req_ies;
+ drv->assoc_req_ies = NULL;
+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+ }
+ if (drv->assoc_resp_ies) {
+ data.assoc_info.resp_ies = drv->assoc_resp_ies;
+ drv->assoc_resp_ies = NULL;
+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+ os_free(data.assoc_info.req_ies);
+ os_free(data.assoc_info.resp_ies);
+}
+
+
+static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version_compiled > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVASSOCRESPIE ||
+ iwe->cmd == IWEVPMKIDCAND)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+ MACSTR,
+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
+ os_memcmp(iwe->u.ap_addr.sa_data,
+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+ 0) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+
+ } else {
+ wpa_driver_wext_event_assoc_ies(drv);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ }
+ break;
+ case IWEVMICHAELMICFAILURE:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVMICHAELMICFAILURE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_michaelmicfailure(
+ ctx, custom, iwe->u.data.length);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVCUSTOM length");
+ return;
+ }
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ wpa_driver_wext_event_wireless_custom(ctx, buf);
+ os_free(buf);
+ break;
+ case SIOCGIWSCAN:
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
+ drv, ctx);
+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case IWEVASSOCREQIE:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVASSOCREQIE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_assocreqie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVASSOCRESPIE:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVASSOCRESPIE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_assocrespie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVPMKIDCAND:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVPMKIDCAND length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_pmkidcand(
+ drv, custom, iwe->u.data.length);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
+ void *ctx, char *buf, size_t len,
+ int del)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
+
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+ if (del)
+ drv->if_removed = 1;
+ else
+ drv->if_removed = 0;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
+ struct nlmsghdr *h)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr *attr;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return 0;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+ == 0)
+ return 1;
+ else
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
+ int ifindex, struct nlmsghdr *h)
+{
+ if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
+ return 1;
+
+ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) {
+ drv->ifindex = if_nametoindex(drv->ifname);
+ wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
+ "interface");
+ wpa_driver_wext_finish_drv_init(drv);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) {
+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+ ifi->ifi_index);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_wext_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_wext_event_wireless(
+ drv, ctx, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ } else if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_wext_event_link(drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_wext_event_link(drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ case RTM_DELLINK:
+ wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+/**
+ * wpa_driver_wext_get_ifflags - Get interface flags (SIOCGIFFLAGS)
+ * @drv: driver_wext private data
+ * @flags: Pointer to returned flags value
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags)
+{
+ return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_driver_wext_set_ifflags - Set interface flags (SIOCSIFFLAGS)
+ * @drv: driver_wext private data
+ * @flags: New value for flags
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
+{
+ return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+/**
+ * wpa_driver_wext_init - Initialize WE driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+void * wpa_driver_wext_init(void *ctx, const char *ifname)
+{
+ int s;
+ struct sockaddr_nl local;
+ struct wpa_driver_wext_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket(PF_INET,SOCK_DGRAM)");
+ os_free(drv);
+ return NULL;
+ }
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
+ drv->event_sock = s;
+
+ drv->mlme_sock = -1;
+
+ wpa_driver_wext_finish_drv_init(drv);
+
+ return drv;
+}
+
+
+static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+{
+ int flags;
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) != 0)
+ printf("Could not get interface '%s' flags\n", drv->ifname);
+ else if (!(flags & IFF_UP)) {
+ if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
+ printf("Could not set interface '%s' UP\n",
+ drv->ifname);
+ } else {
+ /*
+ * Wait some time to allow driver to initialize before
+ * starting configuring the driver. This seems to be
+ * needed at least some drivers that load firmware etc.
+ * when the interface is set up.
+ */
+ wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
+ "a second for the driver to complete "
+ "initialization", drv->ifname);
+ sleep(1);
+ }
+ }
+
+ /*
+ * Make sure that the driver does not have any obsolete PMKID entries.
+ */
+ wpa_driver_wext_flush_pmkid(drv);
+
+ if (wpa_driver_wext_set_mode(drv, 0) < 0) {
+ printf("Could not configure driver to use managed mode\n");
+ }
+
+ wpa_driver_wext_get_range(drv);
+
+ /*
+ * Unlock the driver's BSSID and force to a random SSID to clear any
+ * previous association the driver might have when the supplicant
+ * starts up.
+ */
+ wpa_driver_wext_disconnect(drv);
+
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
+ /*
+ * Host AP driver may use both wlan# and wifi# interface in
+ * wireless events. Since some of the versions included WE-18
+ * support, let's add the alternative ifindex also from
+ * driver_wext.c for the time being. This may be removed at
+ * some point once it is believed that old versions of the
+ * driver are not in use anymore.
+ */
+ char ifname2[IFNAMSIZ + 1];
+ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
+ os_memcpy(ifname2, "wifi", 4);
+ wpa_driver_wext_alternative_ifindex(drv, ifname2);
+ }
+
+ wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+}
+
+
+/**
+ * wpa_driver_wext_deinit - Deinitialize WE driver interface
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_wext_init().
+ */
+void wpa_driver_wext_deinit(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int flags;
+
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+
+ /*
+ * Clear possibly configured driver parameters in order to make it
+ * easier to use the driver after wpa_supplicant has been terminated.
+ */
+ wpa_driver_wext_disconnect(drv);
+
+ wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
+
+ eloop_unregister_read_sock(drv->event_sock);
+ if (drv->mlme_sock >= 0)
+ eloop_unregister_read_sock(drv->mlme_sock);
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ if (drv->mlme_sock >= 0)
+ close(drv->mlme_sock);
+ os_free(drv->assoc_req_ies);
+ os_free(drv->assoc_resp_ies);
+ os_free(drv);
+}
+
+
+/**
+ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_wext_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
+ * all SSIDs (either active scan with broadcast SSID or passive
+ * scan
+ * @ssid_len: Length of the SSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0, timeout;
+ struct iw_scan_req req;
+
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+ __FUNCTION__, (unsigned long) ssid_len);
+ return -1;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ssid && ssid_len) {
+ os_memset(&req, 0, sizeof(req));
+ req.essid_len = ssid_len;
+ req.bssid.sa_family = ARPHRD_ETHER;
+ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
+ os_memcpy(req.essid, ssid, ssid_len);
+ iwr.u.data.pointer = (caddr_t) &req;
+ iwr.u.data.length = sizeof(req);
+ iwr.u.data.flags = IW_SCAN_THIS_ESSID;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 5;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
+ drv->ctx);
+
+ return ret;
+}
+
+
+static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
+ size_t *len)
+{
+ struct iwreq iwr;
+ u8 *res_buf;
+ size_t res_buf_len;
+
+ res_buf_len = IW_SCAN_MAX_DATA;
+ for (;;) {
+ res_buf = os_malloc(res_buf_len);
+ if (res_buf == NULL)
+ return NULL;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = res_buf;
+ iwr.u.data.length = res_buf_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
+ break;
+
+ if (errno == E2BIG && res_buf_len < 65535) {
+ os_free(res_buf);
+ res_buf = NULL;
+ res_buf_len *= 2;
+ if (res_buf_len > 65535)
+ res_buf_len = 65535; /* 16-bit length field */
+ wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+ "trying larger buffer (%lu bytes)",
+ (unsigned long) res_buf_len);
+ } else {
+ perror("ioctl[SIOCGIWSCAN]");
+ os_free(res_buf);
+ return NULL;
+ }
+ }
+
+ if (iwr.u.data.length > res_buf_len) {
+ os_free(res_buf);
+ return NULL;
+ }
+ *len = iwr.u.data.length;
+
+ return res_buf;
+}
+
+
+/*
+ * Data structure for collecting WEXT scan results. This is needed to allow
+ * the various methods of reporting IEs to be combined into a single IE buffer.
+ */
+struct wext_scan_data {
+ struct wpa_scan_res res;
+ u8 *ie;
+ size_t ie_len;
+ u8 ssid[32];
+ size_t ssid_len;
+ int maxrate;
+};
+
+
+static void wext_get_scan_mode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (iwe->u.mode == IW_MODE_ADHOC)
+ res->res.caps |= IEEE80211_CAP_IBSS;
+ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
+ res->res.caps |= IEEE80211_CAP_ESS;
+}
+
+
+static void wext_get_scan_ssid(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ int ssid_len = iwe->u.essid.length;
+ if (custom + ssid_len > end)
+ return;
+ if (iwe->u.essid.flags &&
+ ssid_len > 0 &&
+ ssid_len <= IW_ESSID_MAX_SIZE) {
+ os_memcpy(res->ssid, custom, ssid_len);
+ res->ssid_len = ssid_len;
+ }
+}
+
+
+static void wext_get_scan_freq(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ int divi = 1000000, i;
+
+ if (iwe->u.freq.e == 0) {
+ /*
+ * Some drivers do not report frequency, but a channel.
+ * Try to map this to frequency by assuming they are using
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
+ */
+
+ if (res->res.freq)
+ return;
+
+ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
+ res->res.freq = 2407 + 5 * iwe->u.freq.m;
+ return;
+ } else if (iwe->u.freq.m == 14) {
+ res->res.freq = 2484;
+ return;
+ }
+ }
+
+ if (iwe->u.freq.e > 6) {
+ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
+ MACSTR " m=%d e=%d)",
+ MAC2STR(res->res.bssid), iwe->u.freq.m,
+ iwe->u.freq.e);
+ return;
+ }
+
+ for (i = 0; i < iwe->u.freq.e; i++)
+ divi /= 10;
+ res->res.freq = iwe->u.freq.m / divi;
+}
+
+
+static void wext_get_scan_qual(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ res->res.qual = iwe->u.qual.qual;
+ res->res.noise = iwe->u.qual.noise;
+ res->res.level = iwe->u.qual.level;
+}
+
+
+static void wext_get_scan_encode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
+ res->res.caps |= IEEE80211_CAP_PRIVACY;
+}
+
+
+static void wext_get_scan_rate(struct iw_event *iwe,
+ struct wext_scan_data *res, char *pos,
+ char *end)
+{
+ int maxrate;
+ char *custom = pos + IW_EV_LCP_LEN;
+ struct iw_param p;
+ size_t clen;
+
+ clen = iwe->len;
+ if (custom + clen > end)
+ return;
+ maxrate = 0;
+ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
+ /* Note: may be misaligned, make a local, aligned copy */
+ os_memcpy(&p, custom, sizeof(struct iw_param));
+ if (p.value > maxrate)
+ maxrate = p.value;
+ clen -= sizeof(struct iw_param);
+ custom += sizeof(struct iw_param);
+ }
+
+ /* Convert the maxrate from WE-style (b/s units) to
+ * 802.11 rates (500000 b/s units).
+ */
+ res->maxrate = maxrate / 500000;
+}
+
+
+static void wext_get_scan_iwevgenie(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ char *genie, *gpos, *gend;
+ u8 *tmp;
+
+ if (iwe->u.data.length == 0)
+ return;
+
+ gpos = genie = custom;
+ gend = genie + iwe->u.data.length;
+ if (gend > end) {
+ wpa_printf(MSG_INFO, "IWEVGENIE overflow");
+ return;
+ }
+
+ tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
+ if (tmp == NULL)
+ return;
+ os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
+ res->ie = tmp;
+ res->ie_len += gend - gpos;
+}
+
+
+static void wext_get_scan_custom(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ size_t clen;
+ u8 *tmp;
+
+ clen = iwe->u.data.length;
+ if (custom + clen > end)
+ return;
+
+ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1 || bytes == 0)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ hexstr2bin(spos, tmp + res->ie_len, bytes);
+ res->ie = tmp;
+ res->ie_len += bytes;
+ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1 || bytes == 0)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ hexstr2bin(spos, tmp + res->ie_len, bytes);
+ res->ie = tmp;
+ res->ie_len += bytes;
+ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
+ char *spos;
+ int bytes;
+ u8 bin[8];
+ spos = custom + 4;
+ bytes = custom + clen - spos;
+ if (bytes != 16) {
+ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
+ return;
+ }
+ bytes /= 2;
+ hexstr2bin(spos, bin, bytes);
+ res->res.tsf += WPA_GET_BE64(bin);
+ }
+}
+
+
+static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
+{
+ return drv->we_version_compiled > 18 &&
+ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
+ cmd == IWEVGENIE || cmd == IWEVCUSTOM);
+}
+
+
+static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
+ struct wext_scan_data *data)
+{
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ size_t extra_len;
+ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
+
+ /* Figure out whether we need to fake any IEs */
+ pos = data->ie;
+ end = pos + data->ie_len;
+ while (pos && pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_SSID)
+ ssid_ie = pos;
+ else if (pos[0] == WLAN_EID_SUPP_RATES)
+ rate_ie = pos;
+ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
+ rate_ie = pos;
+ pos += 2 + pos[1];
+ }
+
+ extra_len = 0;
+ if (ssid_ie == NULL)
+ extra_len += 2 + data->ssid_len;
+ if (rate_ie == NULL && data->maxrate)
+ extra_len += 3;
+
+ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+ if (r == NULL)
+ return;
+ os_memcpy(r, &data->res, sizeof(*r));
+ r->ie_len = extra_len + data->ie_len;
+ pos = (u8 *) (r + 1);
+ if (ssid_ie == NULL) {
+ /*
+ * Generate a fake SSID IE since the driver did not report
+ * a full IE list.
+ */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = data->ssid_len;
+ os_memcpy(pos, data->ssid, data->ssid_len);
+ pos += data->ssid_len;
+ }
+ if (rate_ie == NULL && data->maxrate) {
+ /*
+ * Generate a fake Supported Rates IE since the driver did not
+ * report a full IE list.
+ */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = 1;
+ *pos++ = data->maxrate;
+ }
+ if (data->ie)
+ os_memcpy(pos, data->ie, data->ie_len);
+
+ tmp = os_realloc(res->res,
+ (res->num + 1) * sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+}
+
+
+/**
+ * wpa_driver_wext_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ size_t ap_num = 0, len;
+ int first;
+ u8 *res_buf;
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom;
+ struct wpa_scan_results *res;
+ struct wext_scan_data data;
+
+ res_buf = wpa_driver_wext_giwscan(drv, &len);
+ if (res_buf == NULL)
+ return NULL;
+
+ ap_num = 0;
+ first = 1;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL) {
+ os_free(res_buf);
+ return NULL;
+ }
+
+ pos = (char *) res_buf;
+ end = (char *) res_buf + len;
+ os_memset(&data, 0, sizeof(data));
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ break;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (wext_19_iw_point(drv, iwe->cmd)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ if (!first)
+ wpa_driver_wext_add_scan_entry(res, &data);
+ first = 0;
+ os_free(data.ie);
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.res.bssid,
+ iwe->u.ap_addr.sa_data, ETH_ALEN);
+ break;
+ case SIOCGIWMODE:
+ wext_get_scan_mode(iwe, &data);
+ break;
+ case SIOCGIWESSID:
+ wext_get_scan_ssid(iwe, &data, custom, end);
+ break;
+ case SIOCGIWFREQ:
+ wext_get_scan_freq(iwe, &data);
+ break;
+ case IWEVQUAL:
+ wext_get_scan_qual(iwe, &data);
+ break;
+ case SIOCGIWENCODE:
+ wext_get_scan_encode(iwe, &data);
+ break;
+ case SIOCGIWRATE:
+ wext_get_scan_rate(iwe, &data, pos, end);
+ break;
+ case IWEVGENIE:
+ wext_get_scan_iwevgenie(iwe, &data, custom, end);
+ break;
+ case IWEVCUSTOM:
+ wext_get_scan_custom(iwe, &data, custom, end);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+ os_free(res_buf);
+ res_buf = NULL;
+ if (!first)
+ wpa_driver_wext_add_scan_entry(res, &data);
+ os_free(data.ie);
+
+ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
+ (unsigned long) len, (unsigned long) res->num);
+
+ return res;
+}
+
+
+static int wpa_driver_wext_get_range(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ os_free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->has_capability = 1;
+ drv->we_version_compiled = range->we_version_compiled;
+ if (range->enc_capa & IW_ENC_CAPA_WPA) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ }
+ if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ }
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
+ "flags 0x%x",
+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ } else {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+ "assuming WPA is not supported");
+ }
+
+ os_free(range);
+ return 0;
+}
+
+
+static int wpa_driver_wext_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
+ enabled);
+}
+
+
+static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
+ const u8 *psk)
+{
+ struct iw_encode_ext *ext;
+ struct iwreq iwr;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ return 0;
+
+ if (!psk)
+ return 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ ext = os_zalloc(sizeof(*ext) + PMK_LEN);
+ if (ext == NULL)
+ return -1;
+
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
+ ext->key_len = PMK_LEN;
+ os_memcpy(&ext->key, psk, ext->key_len);
+ ext->alg = IW_ENCODE_ALG_PMK;
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
+ if (ret < 0)
+ perror("ioctl[SIOCSIWENCODEEXT] PMK");
+ os_free(ext);
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq,
+ size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ struct iw_encode_ext *ext;
+
+ if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
+ __FUNCTION__, (unsigned long) seq_len);
+ return -1;
+ }
+
+ ext = os_zalloc(sizeof(*ext) + key_len);
+ if (ext == NULL)
+ return -1;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ if (alg == WPA_ALG_NONE)
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + key_len;
+
+ if (addr == NULL ||
+ os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
+ if (set_tx)
+ ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
+
+ ext->addr.sa_family = ARPHRD_ETHER;
+ if (addr)
+ os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
+ else
+ os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
+ if (key && key_len) {
+ os_memcpy(ext + 1, key, key_len);
+ ext->key_len = key_len;
+ }
+ switch (alg) {
+ case WPA_ALG_NONE:
+ ext->alg = IW_ENCODE_ALG_NONE;
+ break;
+ case WPA_ALG_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ break;
+ case WPA_ALG_PMK:
+ ext->alg = IW_ENCODE_ALG_PMK;
+ break;
+#ifdef CONFIG_IEEE80211W
+ case WPA_ALG_IGTK:
+ ext->alg = IW_ENCODE_ALG_AES_CMAC;
+ break;
+#endif /* CONFIG_IEEE80211W */
+ default:
+ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+ __FUNCTION__, alg);
+ os_free(ext);
+ return -1;
+ }
+
+ if (seq && seq_len) {
+ ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
+ os_memcpy(ext->rx_seq, seq, seq_len);
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ if (errno == ENODEV) {
+ /*
+ * ndiswrapper seems to be returning incorrect error
+ * code.. */
+ ret = -2;
+ }
+
+ perror("ioctl[SIOCSIWENCODEEXT]");
+ }
+
+ os_free(ext);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_key - Configure encryption key
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @priv: Private driver interface data
+ * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
+ * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
+ * broadcast/default keys
+ * @key_idx: key index (0..3), usually 0 for unicast keys
+ * @set_tx: Configure this key as the default Tx key (only used when
+ * driver does not support separate unicast/individual key
+ * @seq: Sequence number/packet number, seq_len octets, the next
+ * packet number to be used for in replay protection; configured
+ * for Rx keys (in most cases, this is only used with broadcast
+ * keys and set to zero for unicast keys)
+ * @seq_len: Length of the seq, depends on the algorithm:
+ * TKIP: 6 octets, CCMP: 6 octets
+ * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+ * 8-byte Rx Mic Key
+ * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
+ * TKIP: 32, CCMP: 16)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function uses SIOCSIWENCODEEXT by default, but tries to use
+ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
+ */
+int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu",
+ __FUNCTION__, alg, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
+ seq, seq_len, key, key_len);
+ if (ret == 0)
+ return 0;
+
+ if (ret == -2 &&
+ (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
+ wpa_printf(MSG_DEBUG, "Driver did not support "
+ "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
+ ret = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "Driver did not support "
+ "SIOCSIWENCODEEXT");
+ return ret;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ if (alg == WPA_ALG_NONE)
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ iwr.u.encoding.pointer = (caddr_t) key;
+ iwr.u.encoding.length = key_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ if (set_tx && alg != WPA_ALG_NONE) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE] (set_tx)");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+
+static int wpa_driver_wext_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->use_crypt = enabled;
+ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMLME]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
+{
+ struct iwreq iwr;
+ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 ssid[32];
+ int i;
+
+ /*
+ * Only force-disconnect when the card is in infrastructure mode,
+ * otherwise the driver might interpret the cleared BSSID and random
+ * SSID as an attempt to create a new ad-hoc network.
+ */
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ iwr.u.mode = IW_MODE_INFRA;
+ }
+
+ if (iwr.u.mode == IW_MODE_INFRA) {
+ /*
+ * Clear the BSSID selection and set a random SSID to make sure
+ * the driver will not be trying to associate with something
+ * even if it does not understand SIOCSIWMLME commands (or
+ * tries to associate automatically after deauth/disassoc).
+ */
+ wpa_driver_wext_set_bssid(drv, null_bssid);
+
+ for (i = 0; i < 32; i++)
+ ssid[i] = rand() & 0xFF;
+ wpa_driver_wext_set_ssid(drv, ssid, 32);
+ }
+}
+
+
+static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
+}
+
+
+static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWGENIE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int wpa_driver_wext_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case KEY_MGMT_802_1X:
+ case KEY_MGMT_802_1X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->auth_alg_fallback &&
+ wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_wext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->group_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+ params->pairwise_suite != CIPHER_NONE ||
+ params->group_suite != CIPHER_NONE ||
+ params->wpa_ie_len;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+#ifdef CONFIG_IEEE80211W
+ switch (params->mgmt_frame_protection) {
+ case NO_MGMT_FRAME_PROTECTION:
+ value = IW_AUTH_MFP_DISABLED;
+ break;
+ case MGMT_FRAME_PROTECTION_OPTIONAL:
+ value = IW_AUTH_MFP_OPTIONAL;
+ break;
+ case MGMT_FRAME_PROTECTION_REQUIRED:
+ value = IW_AUTH_MFP_REQUIRED;
+ break;
+ };
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
+ ret = -1;
+#endif /* CONFIG_IEEE80211W */
+ if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
+/**
+ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = -1, flags;
+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+ ret = 0;
+ goto done;
+ }
+
+ if (errno != EBUSY) {
+ perror("ioctl[SIOCSIWMODE]");
+ goto done;
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so if
+ * the device isn't in the mode we're about to change to, take device
+ * down, try to set the mode again, and bring it back up.
+ */
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ goto done;
+ }
+
+ if (iwr.u.mode == new_mode) {
+ ret = 0;
+ goto done;
+ }
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+ perror("ioctl[SIOCSIWMODE]");
+ else
+ ret = 0;
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_wext_get_ifflags(drv, &flags);
+ (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
+ }
+
+done:
+ return ret;
+}
+
+
+static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ perror("ioctl[SIOCSIWPMKSA]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_wext_flush_pmkid(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+ const char *ifname)
+{
+ if (ifname == NULL) {
+ drv->ifindex2 = -1;
+ return 0;
+ }
+
+ drv->ifindex2 = if_nametoindex(ifname);
+ if (drv->ifindex2 <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
+ "wireless events", drv->ifindex2, ifname);
+
+ return 0;
+}
+
+
+int wpa_driver_wext_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_wext_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+ __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return wpa_driver_wext_send_oper_ifla(
+ drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
+{
+ return drv->we_version_compiled;
+}
+
+
+const struct wpa_driver_ops wpa_driver_wext_ops = {
+ .name = "wext",
+ .desc = "Linux wireless extensions (generic)",
+ .get_bssid = wpa_driver_wext_get_bssid,
+ .get_ssid = wpa_driver_wext_get_ssid,
+ .set_wpa = wpa_driver_wext_set_wpa,
+ .set_key = wpa_driver_wext_set_key,
+ .set_countermeasures = wpa_driver_wext_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
+ .scan = wpa_driver_wext_scan,
+ .get_scan_results2 = wpa_driver_wext_get_scan_results,
+ .deauthenticate = wpa_driver_wext_deauthenticate,
+ .disassociate = wpa_driver_wext_disassociate,
+ .set_mode = wpa_driver_wext_set_mode,
+ .associate = wpa_driver_wext_associate,
+ .set_auth_alg = wpa_driver_wext_set_auth_alg,
+ .init = wpa_driver_wext_init,
+ .deinit = wpa_driver_wext_deinit,
+ .add_pmkid = wpa_driver_wext_add_pmkid,
+ .remove_pmkid = wpa_driver_wext_remove_pmkid,
+ .flush_pmkid = wpa_driver_wext_flush_pmkid,
+ .get_capa = wpa_driver_wext_get_capa,
+ .set_operstate = wpa_driver_wext_set_operstate,
+};
diff --git a/contrib/wpa/src/drivers/driver_wext.h b/contrib/wpa/src/drivers/driver_wext.h
new file mode 100644
index 0000000..b89c2cb
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wext.h
@@ -0,0 +1,82 @@
+/*
+ * WPA Supplicant - driver_wext exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DRIVER_WEXT_H
+#define DRIVER_WEXT_H
+
+#include <net/if.h>
+
+struct wpa_driver_wext_data {
+ void *ctx;
+ int event_sock;
+ int ioctl_sock;
+ int mlme_sock;
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ int ifindex2;
+ int if_removed;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+};
+
+int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
+int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_wext_set_freq(void *priv, int freq);
+int wpa_driver_wext_set_mode(void *priv, int mode);
+int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len);
+int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len);
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
+
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+ const char *ifname);
+
+void * wpa_driver_wext_init(void *ctx, const char *ifname);
+void wpa_driver_wext_deinit(void *priv);
+
+int wpa_driver_wext_set_operstate(void *priv, int state);
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
+
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params);
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value);
+int wpa_driver_wext_cipher2wext(int cipher);
+int wpa_driver_wext_keymgmt2wext(int keymgmt);
+
+#endif /* DRIVER_WEXT_H */
diff --git a/contrib/wpa/src/drivers/driver_wired.c b/contrib/wpa/src/drivers/driver_wired.c
new file mode 100644
index 0000000..098991a
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wired.c
@@ -0,0 +1,286 @@
+/*
+ * WPA Supplicant - wired Ethernet driver interface
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifdef __linux__
+#include <netpacket/packet.h>
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <net/if_dl.h>
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
+
+#include "common.h"
+#include "driver.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_wired_data {
+ void *ctx;
+ int pf_sock;
+ char ifname[IFNAMSIZ + 1];
+ int membership, multi, iff_allmulti, iff_up;
+};
+
+
+static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ {
+ struct sockaddr_dl *dlp;
+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETH_ALEN;
+ dlp->sdl_slen = 0;
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+ {
+ struct sockaddr *sap;
+ sap = (struct sockaddr *) &ifr.ifr_addr;
+ sap->sa_len = sizeof(struct sockaddr);
+ sap->sa_family = AF_UNSPEC;
+ os_memcpy(sap->sa_data, addr, ETH_ALEN);
+ }
+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
+
+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
+ const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (drv->pf_sock == -1)
+ return -1;
+
+ os_memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = if_nametoindex(drv->ifname);
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+ if (setsockopt(drv->pf_sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static void * wpa_driver_wired_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_wired_data *drv;
+ int flags;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->ctx = ctx;
+
+#ifdef __linux__
+ drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (drv->pf_sock < 0)
+ perror("socket(PF_PACKET)");
+#else /* __linux__ */
+ drv->pf_sock = -1;
+#endif /* __linux__ */
+
+ if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
+ !(flags & IFF_UP) &&
+ wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
+ drv->iff_up = 1;
+ }
+
+ if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+ "packet socket", __func__);
+ drv->membership = 1;
+ } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+ "SIOCADDMULTI", __func__);
+ drv->multi = 1;
+ } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
+ wpa_printf(MSG_INFO, "%s: Could not get interface "
+ "flags", __func__);
+ os_free(drv);
+ return NULL;
+ } else if (flags & IFF_ALLMULTI) {
+ wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
+ "for multicast", __func__);
+ } else if (wpa_driver_wired_set_ifflags(ifname,
+ flags | IFF_ALLMULTI) < 0) {
+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
+ __func__);
+ os_free(drv);
+ return NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
+ __func__);
+ drv->iff_allmulti = 1;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_wired_deinit(void *priv)
+{
+ struct wpa_driver_wired_data *drv = priv;
+ int flags;
+
+ if (drv->membership &&
+ wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+ "group (PACKET)", __func__);
+ }
+
+ if (drv->multi &&
+ wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+ "group (SIOCDELMULTI)", __func__);
+ }
+
+ if (drv->iff_allmulti &&
+ (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
+ wpa_driver_wired_set_ifflags(drv->ifname,
+ flags & ~IFF_ALLMULTI) < 0)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+ __func__);
+ }
+
+ if (drv->iff_up &&
+ wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
+ (flags & IFF_UP) &&
+ wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+ __func__);
+ }
+
+ if (drv->pf_sock != -1)
+ close(drv->pf_sock);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_wired_ops = {
+ .name = "wired",
+ .desc = "wpa_supplicant wired Ethernet driver",
+ .get_ssid = wpa_driver_wired_get_ssid,
+ .get_bssid = wpa_driver_wired_get_bssid,
+ .init = wpa_driver_wired_init,
+ .deinit = wpa_driver_wired_deinit,
+};
diff --git a/contrib/wpa/src/drivers/ndis_events.c b/contrib/wpa/src/drivers/ndis_events.c
new file mode 100644
index 0000000..f6eaa7c
--- /dev/null
+++ b/contrib/wpa/src/drivers/ndis_events.c
@@ -0,0 +1,808 @@
+/*
+ * ndis_events - Receive NdisMIndicateStatus() events using WMI
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#define _WIN32_WINNT 0x0400
+
+#include "includes.h"
+
+#ifndef COBJMACROS
+#define COBJMACROS
+#endif /* COBJMACROS */
+#include <wbemidl.h>
+
+#include "common.h"
+
+
+static int wmi_refcnt = 0;
+static int wmi_first = 1;
+
+struct ndis_events_data {
+ IWbemObjectSink sink;
+ IWbemObjectSinkVtbl sink_vtbl;
+
+ IWbemServices *pSvc;
+ IWbemLocator *pLoc;
+
+ HANDLE read_pipe, write_pipe, event_avail;
+ UINT ref;
+ int terminating;
+ char *ifname; /* {GUID..} */
+ WCHAR *adapter_desc;
+};
+
+#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
+#define BstrFree(x) if (x) SysFreeString(x)
+
+/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
+ * BSTRs */
+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
+ IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
+ long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
+{
+ BSTR bsQueryLanguage, bsQuery;
+ HRESULT hr;
+
+ bsQueryLanguage = BstrAlloc(strQueryLanguage);
+ bsQuery = BstrAlloc(strQuery);
+
+ hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
+ pCtx, ppEnum);
+
+ BstrFree(bsQueryLanguage);
+ BstrFree(bsQuery);
+
+ return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
+ IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
+ long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
+{
+ BSTR bsQueryLanguage, bsQuery;
+ HRESULT hr;
+
+ bsQueryLanguage = BstrAlloc(strQueryLanguage);
+ bsQuery = BstrAlloc(strQuery);
+
+ hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
+ bsQuery, lFlags, pCtx,
+ pResponseHandler);
+
+ BstrFree(bsQueryLanguage);
+ BstrFree(bsQuery);
+
+ return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
+ IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
+ LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
+ LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
+{
+ BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
+ HRESULT hr;
+
+ bsNetworkResource = BstrAlloc(strNetworkResource);
+ bsUser = BstrAlloc(strUser);
+ bsPassword = BstrAlloc(strPassword);
+ bsLocale = BstrAlloc(strLocale);
+ bsAuthority = BstrAlloc(strAuthority);
+
+ hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
+ bsPassword, bsLocale, lSecurityFlags,
+ bsAuthority, pCtx, ppNamespace);
+
+ BstrFree(bsNetworkResource);
+ BstrFree(bsUser);
+ BstrFree(bsPassword);
+ BstrFree(bsLocale);
+ BstrFree(bsAuthority);
+
+ return hr;
+}
+
+
+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
+ EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
+
+static int ndis_events_get_adapter(struct ndis_events_data *events,
+ const char *ifname, const char *desc);
+
+
+static int ndis_events_constructor(struct ndis_events_data *events)
+{
+ events->ref = 1;
+
+ if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
+ wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+ events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (events->event_avail == NULL) {
+ wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
+ (int) GetLastError());
+ CloseHandle(events->read_pipe);
+ CloseHandle(events->write_pipe);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void ndis_events_destructor(struct ndis_events_data *events)
+{
+ CloseHandle(events->read_pipe);
+ CloseHandle(events->write_pipe);
+ CloseHandle(events->event_avail);
+ IWbemServices_Release(events->pSvc);
+ IWbemLocator_Release(events->pLoc);
+ if (--wmi_refcnt == 0)
+ CoUninitialize();
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
+{
+ *obj = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IWbemObjectSink)) {
+ *obj = this;
+ IWbemObjectSink_AddRef(this);
+ return NOERROR;
+ }
+
+ return E_NOINTERFACE;
+}
+
+
+static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
+{
+ struct ndis_events_data *events = (struct ndis_events_data *) this;
+ return ++events->ref;
+}
+
+
+static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
+{
+ struct ndis_events_data *events = (struct ndis_events_data *) this;
+
+ if (--events->ref != 0)
+ return events->ref;
+
+ ndis_events_destructor(events);
+ wpa_printf(MSG_DEBUG, "ndis_events: terminated");
+ os_free(events->adapter_desc);
+ os_free(events->ifname);
+ os_free(events);
+ return 0;
+}
+
+
+static int ndis_events_send_event(struct ndis_events_data *events,
+ enum event_types type,
+ char *data, size_t data_len)
+{
+ char buf[512], *pos, *end;
+ int _type;
+ DWORD written;
+
+ end = buf + sizeof(buf);
+ _type = (int) type;
+ os_memcpy(buf, &_type, sizeof(_type));
+ pos = buf + sizeof(_type);
+
+ if (data) {
+ if (2 + data_len > (size_t) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "Not enough room for send_event "
+ "data (%d)", data_len);
+ return -1;
+ }
+ *pos++ = data_len >> 8;
+ *pos++ = data_len & 0xff;
+ os_memcpy(pos, data, data_len);
+ pos += data_len;
+ }
+
+ if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
+ SetEvent(events->event_avail);
+ return 0;
+ }
+ wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
+ return -1;
+}
+
+
+static void ndis_events_media_connect(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
+ ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
+}
+
+
+static void ndis_events_media_disconnect(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
+ ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
+}
+
+
+static void ndis_events_media_specific(struct ndis_events_data *events,
+ IWbemClassObject *pObj)
+{
+ VARIANT vt;
+ HRESULT hr;
+ LONG lower, upper, k;
+ UCHAR ch;
+ char *data, *pos;
+ size_t data_len;
+
+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
+
+ /* This is the StatusBuffer from NdisMIndicateStatus() call */
+ hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
+ 0, &vt, NULL, NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "Could not get "
+ "NdisStatusMediaSpecificIndication from "
+ "the object?!");
+ return;
+ }
+
+ SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
+ SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
+ data_len = upper - lower + 1;
+ data = os_malloc(data_len);
+ if (data == NULL) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
+ "data");
+ VariantClear(&vt);
+ return;
+ }
+
+ pos = data;
+ for (k = lower; k <= upper; k++) {
+ SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
+ *pos++ = ch;
+ }
+ wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
+
+ VariantClear(&vt);
+
+ ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
+
+ os_free(data);
+}
+
+
+static void ndis_events_adapter_arrival(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
+ ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
+}
+
+
+static void ndis_events_adapter_removal(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
+ ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
+ IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
+{
+ struct ndis_events_data *events = (struct ndis_events_data *) this;
+ long i;
+
+ if (events->terminating) {
+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
+ "indication - terminating");
+ return WBEM_NO_ERROR;
+ }
+ /* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
+ lObjectCount); */
+
+ for (i = 0; i < lObjectCount; i++) {
+ IWbemClassObject *pObj = ppObjArray[i];
+ HRESULT hr;
+ VARIANT vtClass, vt;
+
+ hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
+ NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
+ "event.");
+ break;
+ }
+ /* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
+
+ hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
+ NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
+ "from event.");
+ VariantClear(&vtClass);
+ break;
+ }
+
+ if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_NotifyAdapterArrival") == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
+ "update adapter description since it may "
+ "have changed with new adapter instance");
+ ndis_events_get_adapter(events, events->ifname, NULL);
+ }
+
+ if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
+ "indication for foreign adapter: "
+ "InstanceName: '%S' __CLASS: '%S'",
+ vt.bstrVal, vtClass.bstrVal);
+ VariantClear(&vtClass);
+ VariantClear(&vt);
+ continue;
+ }
+ VariantClear(&vt);
+
+ if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_StatusMediaSpecificIndication") == 0) {
+ ndis_events_media_specific(events, pObj);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_StatusMediaConnect") == 0) {
+ ndis_events_media_connect(events);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_StatusMediaDisconnect") == 0) {
+ ndis_events_media_disconnect(events);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_NotifyAdapterArrival") == 0) {
+ ndis_events_adapter_arrival(events);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_NotifyAdapterRemoval") == 0) {
+ ndis_events_adapter_removal(events);
+ } else {
+ wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
+ "'%S'", vtClass.bstrVal);
+ }
+
+ VariantClear(&vtClass);
+ }
+
+ return WBEM_NO_ERROR;
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
+ BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
+{
+ return WBEM_NO_ERROR;
+}
+
+
+static int notification_query(IWbemObjectSink *pDestSink,
+ IWbemServices *pSvc, const char *class_name)
+{
+ HRESULT hr;
+ WCHAR query[256];
+
+ _snwprintf(query, 256,
+ L"SELECT * FROM %S", class_name);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+ hr = call_IWbemServices_ExecNotificationQueryAsync(
+ pSvc, L"WQL", query, 0, 0, pDestSink);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
+ "failed with hresult of 0x%x",
+ class_name, (int) hr);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int register_async_notification(IWbemObjectSink *pDestSink,
+ IWbemServices *pSvc)
+{
+ int i;
+ const char *class_list[] = {
+ "MSNdis_StatusMediaConnect",
+ "MSNdis_StatusMediaDisconnect",
+ "MSNdis_StatusMediaSpecificIndication",
+ "MSNdis_NotifyAdapterArrival",
+ "MSNdis_NotifyAdapterRemoval",
+ NULL
+ };
+
+ for (i = 0; class_list[i]; i++) {
+ if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void ndis_events_deinit(struct ndis_events_data *events)
+{
+ events->terminating = 1;
+ IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
+ IWbemObjectSink_Release(&events->sink);
+ /*
+ * Rest of deinitialization is done in ndis_events_destructor() once
+ * all reference count drops to zero.
+ */
+}
+
+
+static int ndis_events_use_desc(struct ndis_events_data *events,
+ const char *desc)
+{
+ char *tmp, *pos;
+ size_t len;
+
+ if (desc == NULL) {
+ if (events->adapter_desc == NULL)
+ return -1;
+ /* Continue using old description */
+ return 0;
+ }
+
+ tmp = os_strdup(desc);
+ if (tmp == NULL)
+ return -1;
+
+ pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
+ if (pos)
+ *pos = '\0';
+
+ len = os_strlen(tmp);
+ events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
+ if (events->adapter_desc == NULL) {
+ os_free(tmp);
+ return -1;
+ }
+ _snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
+ os_free(tmp);
+ return 0;
+}
+
+
+static int ndis_events_get_adapter(struct ndis_events_data *events,
+ const char *ifname, const char *desc)
+{
+ HRESULT hr;
+ IWbemServices *pSvc;
+#define MAX_QUERY_LEN 256
+ WCHAR query[MAX_QUERY_LEN];
+ IEnumWbemClassObject *pEnumerator;
+ IWbemClassObject *pObj;
+ ULONG uReturned;
+ VARIANT vt;
+ int len, pos;
+
+ /*
+ * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
+ * to have better probability of matching with InstanceName from
+ * MSNdis events. If this fails, use the provided description.
+ */
+
+ os_free(events->adapter_desc);
+ events->adapter_desc = NULL;
+
+ hr = call_IWbemLocator_ConnectServer(
+ events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
+ "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
+ return ndis_events_use_desc(events, desc);
+ }
+ wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
+
+ _snwprintf(query, MAX_QUERY_LEN,
+ L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
+ L"WHERE SettingID='%S'", ifname);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+
+ hr = call_IWbemServices_ExecQuery(
+ pSvc, L"WQL", query,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+ "GUID from Win32_NetworkAdapterConfiguration: "
+ "0x%x", (int) hr);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ uReturned = 0;
+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+ &pObj, &uReturned);
+ if (!SUCCEEDED(hr) || uReturned == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+ "GUID from Win32_NetworkAdapterConfiguration: "
+ "0x%x", (int) hr);
+ IEnumWbemClassObject_Release(pEnumerator);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+ IEnumWbemClassObject_Release(pEnumerator);
+
+ VariantInit(&vt);
+ hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
+ "Win32_NetworkAdapterConfiguration: 0x%x",
+ (int) hr);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ _snwprintf(query, MAX_QUERY_LEN,
+ L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
+ L"Index=%d",
+ vt.uintVal);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+ VariantClear(&vt);
+ IWbemClassObject_Release(pObj);
+
+ hr = call_IWbemServices_ExecQuery(
+ pSvc, L"WQL", query,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+ "from Win32_NetworkAdapter: 0x%x", (int) hr);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ uReturned = 0;
+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+ &pObj, &uReturned);
+ if (!SUCCEEDED(hr) || uReturned == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+ "from Win32_NetworkAdapter: 0x%x", (int) hr);
+ IEnumWbemClassObject_Release(pEnumerator);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+ IEnumWbemClassObject_Release(pEnumerator);
+
+ hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
+ "Win32_NetworkAdapter: 0x%x", (int) hr);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
+ vt.bstrVal);
+ events->adapter_desc = _wcsdup(vt.bstrVal);
+ VariantClear(&vt);
+
+ /*
+ * Try to get even better candidate for matching with InstanceName
+ * from Win32_PnPEntity. This is needed at least for some USB cards
+ * that can change the InstanceName whenever being unplugged and
+ * plugged again.
+ */
+
+ hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
+ "from Win32_NetworkAdapter: 0x%x", (int) hr);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
+ "'%S'", vt.bstrVal);
+
+ len = _snwprintf(query, MAX_QUERY_LEN,
+ L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
+ if (len < 0 || len >= MAX_QUERY_LEN - 1) {
+ VariantClear(&vt);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ /* Escape \ as \\ */
+ for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
+ if (vt.bstrVal[pos] == '\\') {
+ if (len >= MAX_QUERY_LEN - 3)
+ break;
+ query[len++] = '\\';
+ }
+ query[len++] = vt.bstrVal[pos];
+ }
+ query[len++] = L'\'';
+ query[len] = L'\0';
+ VariantClear(&vt);
+ IWbemClassObject_Release(pObj);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+
+ hr = call_IWbemServices_ExecQuery(
+ pSvc, L"WQL", query,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+ "Name from Win32_PnPEntity: 0x%x", (int) hr);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ uReturned = 0;
+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+ &pObj, &uReturned);
+ if (!SUCCEEDED(hr) || uReturned == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+ "from Win32_PnPEntity: 0x%x", (int) hr);
+ IEnumWbemClassObject_Release(pEnumerator);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+ IEnumWbemClassObject_Release(pEnumerator);
+
+ hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
+ "Win32_PnPEntity: 0x%x", (int) hr);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
+ vt.bstrVal);
+ os_free(events->adapter_desc);
+ events->adapter_desc = _wcsdup(vt.bstrVal);
+ VariantClear(&vt);
+
+ IWbemClassObject_Release(pObj);
+
+ IWbemServices_Release(pSvc);
+
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+
+ return 0;
+}
+
+
+struct ndis_events_data *
+ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
+ const char *ifname, const char *desc)
+{
+ HRESULT hr;
+ IWbemObjectSink *pSink;
+ struct ndis_events_data *events;
+
+ events = os_zalloc(sizeof(*events));
+ if (events == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
+ return NULL;
+ }
+ events->ifname = os_strdup(ifname);
+ if (events->ifname == NULL) {
+ os_free(events);
+ return NULL;
+ }
+
+ if (wmi_refcnt++ == 0) {
+ hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
+ "returned 0x%x", (int) hr);
+ os_free(events);
+ return NULL;
+ }
+ }
+
+ if (wmi_first) {
+ /* CoInitializeSecurity() must be called once and only once
+ * per process, so let's use wmi_first flag to protect against
+ * multiple calls. */
+ wmi_first = 0;
+
+ hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL, EOAC_SECURE_REFS, NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
+ "- returned 0x%x", (int) hr);
+ os_free(events);
+ return NULL;
+ }
+ }
+
+ hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
+ &IID_IWbemLocator,
+ (LPVOID *) (void *) &events->pLoc);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
+ "0x%x", (int) hr);
+ CoUninitialize();
+ os_free(events);
+ return NULL;
+ }
+
+ if (ndis_events_get_adapter(events, ifname, desc) < 0) {
+ CoUninitialize();
+ os_free(events);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
+ events->adapter_desc);
+
+ hr = call_IWbemLocator_ConnectServer(
+ events->pLoc, L"ROOT\\WMI", NULL, NULL,
+ 0, 0, 0, 0, &events->pSvc);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "Could not connect to server - error "
+ "0x%x", (int) hr);
+ CoUninitialize();
+ os_free(events->adapter_desc);
+ os_free(events);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
+
+ ndis_events_constructor(events);
+ pSink = &events->sink;
+ pSink->lpVtbl = &events->sink_vtbl;
+ events->sink_vtbl.QueryInterface = ndis_events_query_interface;
+ events->sink_vtbl.AddRef = ndis_events_add_ref;
+ events->sink_vtbl.Release = ndis_events_release;
+ events->sink_vtbl.Indicate = ndis_events_indicate;
+ events->sink_vtbl.SetStatus = ndis_events_set_status;
+
+ if (register_async_notification(pSink, events->pSvc) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to register async "
+ "notifications");
+ ndis_events_destructor(events);
+ os_free(events->adapter_desc);
+ os_free(events);
+ return NULL;
+ }
+
+ *read_pipe = events->read_pipe;
+ *event_avail = events->event_avail;
+
+ return events;
+}
diff --git a/contrib/wpa/src/drivers/priv_netlink.h b/contrib/wpa/src/drivers/priv_netlink.h
new file mode 100644
index 0000000..2a31e25
--- /dev/null
+++ b/contrib/wpa/src/drivers/priv_netlink.h
@@ -0,0 +1,104 @@
+/*
+ * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef PRIV_NETLINK_H
+#define PRIV_NETLINK_H
+
+/*
+ * This should be replaced with user space header once one is available with C
+ * library, etc..
+ */
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IFLA_IFNAME
+#define IFLA_IFNAME 3
+#endif
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS 11
+#endif
+#ifndef IFLA_OPERSTATE
+#define IFLA_OPERSTATE 16
+#endif
+#ifndef IFLA_LINKMODE
+#define IFLA_LINKMODE 17
+#define IF_OPER_DORMANT 5
+#define IF_OPER_UP 6
+#endif
+
+#define NLM_F_REQUEST 1
+
+#define NETLINK_ROUTE 0
+#define RTMGRP_LINK 1
+#define RTM_BASE 0x10
+#define RTM_NEWLINK (RTM_BASE + 0)
+#define RTM_DELLINK (RTM_BASE + 1)
+#define RTM_SETLINK (RTM_BASE + 3)
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
+#define RTA_OK(rta,len) \
+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+(rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) \
+((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
+
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family;
+ unsigned short nl_pad;
+ u32 nl_pid;
+ u32 nl_groups;
+};
+
+struct nlmsghdr
+{
+ u32 nlmsg_len;
+ u16 nlmsg_type;
+ u16 nlmsg_flags;
+ u32 nlmsg_seq;
+ u32 nlmsg_pid;
+};
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type;
+ int ifi_index;
+ unsigned ifi_flags;
+ unsigned ifi_change;
+};
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+#endif /* PRIV_NETLINK_H */
diff --git a/contrib/wpa/src/drivers/radiotap.c b/contrib/wpa/src/drivers/radiotap.c
new file mode 100644
index 0000000..804473f
--- /dev/null
+++ b/contrib/wpa/src/drivers/radiotap.c
@@ -0,0 +1,287 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ *
+ * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
+ * I only modified some things on top to ease syncing should bugs be found.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "radiotap_iter.h"
+
+#define le16_to_cpu le_to_host16
+#define le32_to_cpu le_to_host32
+#define __le32 uint32_t
+#define ulong unsigned long
+#define unlikely(cond) (cond)
+#define get_unaligned(p) \
+({ \
+ struct packed_dummy_struct { \
+ typeof(*(p)) __val; \
+ } __attribute__((packed)) *__ptr = (void *) (p); \
+ \
+ __ptr->__val; \
+})
+
+/* function prototypes and related defs are in radiotap_iter.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader)
+ > (ulong)iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < (int) sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ (ulong) iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
diff --git a/contrib/wpa/src/drivers/radiotap.h b/contrib/wpa/src/drivers/radiotap.h
new file mode 100644
index 0000000..508264c
--- /dev/null
+++ b/contrib/wpa/src/drivers/radiotap.h
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004 David Young. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn@kismetwireless.net)
+ */
+
+#ifndef IEEE80211RADIOTAP_H
+#define IEEE80211RADIOTAP_H
+
+#include <stdint.h>
+
+/* Base version of the radiotap packet header data */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ */
+
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header {
+ uint8_t it_version; /* Version 0. Only increases
+ * for drastic changes,
+ * introduction of compatible
+ * new fields does not count.
+ */
+ uint8_t it_pad;
+ uint16_t it_len; /* length of the whole
+ * header in bytes, including
+ * it_version, it_pad,
+ * it_len, and data fields.
+ */
+ uint32_t it_present; /* A bitmap telling which
+ * fields are present. Set bit 31
+ * (0x80000000) to extend the
+ * bitmap by another 32 bits.
+ * Additional extensions are made
+ * by setting bit 31.
+ */
+};
+
+/* Name Data type Units
+ * ---- --------- -----
+ *
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
+ *
+ * Value in microseconds of the MAC's 64-bit 802.11 Time
+ * Synchronization Function timer when the first bit of the
+ * MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
+ *
+ * Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS uint16_t see below
+ *
+ * For frequency-hopping radios, the hop set (first byte)
+ * and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE u8 500kb/s
+ *
+ * Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF signal power at the antenna, decibel difference from
+ * one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF noise power at the antenna, decibel difference from one
+ * milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
+ *
+ * RF signal power at the antenna, decibel difference from an
+ * arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
+ *
+ * RF noise power at the antenna, decibel difference from an
+ * arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
+ *
+ * Quality of Barker code lock. Unitless. Monotonically
+ * nondecreasing with "better" lock strength. Called "Signal
+ * Quality" in datasheets. (Is there a standard way to measure
+ * this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
+ *
+ * Transmit power expressed as unitless distance from max
+ * power set at factory calibration. 0 is max power.
+ * Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
+ *
+ * Transmit power expressed as decibel distance from max power
+ * set at factory calibration. 0 is max power. Monotonically
+ * nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * Transmit power expressed as dBm (decibels from a 1 milliwatt
+ * reference). This is the absolute power level measured at
+ * the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS u8 bitmap
+ *
+ * Properties of transmitted and received frames. See flags
+ * defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
+ *
+ * Unitless indication of the Rx/Tx antenna for this packet.
+ * The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
+ *
+ * Number of unicast retries a transmitted frame used.
+ *
+ */
+enum ieee80211_radiotap_type {
+ IEEE80211_RADIOTAP_TSFT = 0,
+ IEEE80211_RADIOTAP_FLAGS = 1,
+ IEEE80211_RADIOTAP_RATE = 2,
+ IEEE80211_RADIOTAP_CHANNEL = 3,
+ IEEE80211_RADIOTAP_FHSS = 4,
+ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+ IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+ IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+ IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+ IEEE80211_RADIOTAP_ANTENNA = 11,
+ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+ IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* Channel flags. */
+#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
+#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
+#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
+#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
+#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
+#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
+#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
+#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
+ * during CFP
+ */
+#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
+ * with short
+ * preamble
+ */
+#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
+ * with WEP encryption
+ */
+#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
+ * with fragmentation
+ */
+#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
+#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
+ * 802.11 header and payload
+ * (to 32-bit boundary)
+ */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+
+#endif /* IEEE80211_RADIOTAP_H */
diff --git a/contrib/wpa/src/drivers/radiotap_iter.h b/contrib/wpa/src/drivers/radiotap_iter.h
new file mode 100644
index 0000000..92a798a
--- /dev/null
+++ b/contrib/wpa/src/drivers/radiotap_iter.h
@@ -0,0 +1,41 @@
+#ifndef __RADIOTAP_ITER_H
+#define __RADIOTAP_ITER_H
+
+#include "radiotap.h"
+
+/* Radiotap header iteration
+ * implemented in radiotap.c
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ unsigned char *this_arg;
+
+ int arg_index;
+ unsigned char *arg;
+ uint32_t *next_bitmap;
+ uint32_t bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+#endif /* __RADIOTAP_ITER_H */
OpenPOWER on IntegriCloud