diff options
Diffstat (limited to 'src/drivers')
29 files changed, 5047 insertions, 7449 deletions
diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h deleted file mode 100644 index 2a612e7..0000000 --- a/src/drivers/Apple80211.h +++ /dev/null @@ -1,156 +0,0 @@ -#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/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c deleted file mode 100644 index ce004fe..0000000 --- a/src/drivers/MobileApple80211.c +++ /dev/null @@ -1,189 +0,0 @@ -#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/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h deleted file mode 100644 index 64d439d..0000000 --- a/src/drivers/MobileApple80211.h +++ /dev/null @@ -1,43 +0,0 @@ -#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/src/drivers/android_drv.h b/src/drivers/android_drv.h new file mode 100644 index 0000000..6df7160 --- /dev/null +++ b/src/drivers/android_drv.h @@ -0,0 +1,62 @@ +/* + * Android driver interface + * + * 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. + */ + +#ifndef ANDROID_DRV_H +#define ANDROID_DRV_H + +#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE " + +#define WEXT_CSCAN_AMOUNT 9 + +#define MAX_SSID_LEN 32 + +#define MAX_DRV_CMD_SIZE 248 +#define DRV_NUMBER_SEQUENTIAL_ERRORS 4 + +#define WEXT_PNOSETUP_HEADER "PNOSETUP " +#define WEXT_PNOSETUP_HEADER_SIZE 9 +#define WEXT_PNO_TLV_PREFIX 'S' +#define WEXT_PNO_TLV_VERSION '1' +#define WEXT_PNO_TLV_SUBVERSION '2' +#define WEXT_PNO_TLV_RESERVED '0' +#define WEXT_PNO_VERSION_SIZE 4 +#define WEXT_PNO_AMOUNT 16 +#define WEXT_PNO_SSID_SECTION 'S' +/* SSID header size is SSID section type above + SSID length */ +#define WEXT_PNO_SSID_HEADER_SIZE 2 +#define WEXT_PNO_SCAN_INTERVAL_SECTION 'T' +#define WEXT_PNO_SCAN_INTERVAL_LENGTH 2 +#define WEXT_PNO_SCAN_INTERVAL 30 +/* Scan interval size is scan interval section type + scan interval length + * above */ +#define WEXT_PNO_SCAN_INTERVAL_SIZE (1 + WEXT_PNO_SCAN_INTERVAL_LENGTH) +#define WEXT_PNO_REPEAT_SECTION 'R' +#define WEXT_PNO_REPEAT_LENGTH 1 +#define WEXT_PNO_REPEAT 4 +/* Repeat section size is Repeat section type + Repeat value length above */ +#define WEXT_PNO_REPEAT_SIZE (1 + WEXT_PNO_REPEAT_LENGTH) +#define WEXT_PNO_MAX_REPEAT_SECTION 'M' +#define WEXT_PNO_MAX_REPEAT_LENGTH 1 +#define WEXT_PNO_MAX_REPEAT 3 +/* Max Repeat section size is Max Repeat section type + Max Repeat value length + * above */ +#define WEXT_PNO_MAX_REPEAT_SIZE (1 + WEXT_PNO_MAX_REPEAT_LENGTH) +/* This corresponds to the size of all sections expect SSIDs */ +#define WEXT_PNO_NONSSID_SECTIONS_SIZE \ +(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE) +/* PNO Max command size is total of header, version, ssid and other sections + + * Null termination */ +#define WEXT_PNO_MAX_COMMAND_SIZE \ + (WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \ + + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \ + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) + +#endif /* ANDROID_DRV_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 19f732d..ceed531 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -35,14 +35,6 @@ #define HOSTAPD_CHAN_HT40MINUS 0x00000020 #define HOSTAPD_CHAN_HT40 0x00000040 -#ifdef ANDROID_BRCM_P2P_PATCH -/** - * Monitor interface name is derived from p2p interface name - * We need to reset p2p interface name early to take care of extra character in - */ -#define WPA_MONITOR_IFNAME_PREFIX "m." -#endif - /** * struct hostapd_channel_data - Channel information */ @@ -68,6 +60,8 @@ struct hostapd_channel_data { u8 max_tx_power; }; +#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) + /** * struct hostapd_hw_modes - Supported hardware mode information */ @@ -111,6 +105,8 @@ struct hostapd_hw_modes { * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters */ u8 a_mpdu_params; + + unsigned int flags; /* HOSTAPD_MODE_FLAG_* */ }; @@ -203,7 +199,7 @@ struct wpa_interface_info { const char *drv_name; }; -#define WPAS_MAX_SCAN_SSIDS 10 +#define WPAS_MAX_SCAN_SSIDS 16 /** * struct wpa_driver_scan_params - Scan parameters @@ -272,6 +268,15 @@ struct wpa_driver_scan_params { * num_filter_ssids - Number of entries in filter_ssids array */ size_t num_filter_ssids; + + /** + * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes + * + * When set, the driver is expected to remove rates 1, 2, 5.5, and 11 + * Mbps from the support rates element(s) in the Probe Request frames + * and not to transmit the frames at any of those rates. + */ + u8 p2p_probe; }; /** @@ -290,6 +295,12 @@ struct wpa_driver_auth_params { size_t wep_key_len[4]; int wep_tx_keyidx; int local_state_change; + + /** + * p2p - Whether this connection is a P2P group + */ + int p2p; + }; enum wps_mode { @@ -353,6 +364,11 @@ struct wpa_driver_associate_params { size_t wpa_ie_len; /** + * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2 + */ + unsigned int wpa_proto; + + /** * pairwise_suite - Selected pairwise cipher suite * * This is usually ignored if @wpa_ie is used. @@ -502,6 +518,183 @@ struct wpa_driver_associate_params { int uapsd; }; +enum hide_ssid { + NO_SSID_HIDING, + HIDDEN_SSID_ZERO_LEN, + HIDDEN_SSID_ZERO_CONTENTS +}; + +struct wpa_driver_ap_params { + /** + * head - Beacon head from IEEE 802.11 header to IEs before TIM IE + */ + const u8 *head; + + /** + * head_len - Length of the head buffer in octets + */ + size_t head_len; + + /** + * tail - Beacon tail following TIM IE + */ + const u8 *tail; + + /** + * tail_len - Length of the tail buffer in octets + */ + size_t tail_len; + + /** + * dtim_period - DTIM period + */ + int dtim_period; + + /** + * beacon_int - Beacon interval + */ + int beacon_int; + + /** + * basic_rates: -1 terminated array of basic rates in 100 kbps + * + * This parameter can be used to set a specific basic rate set for the + * BSS. If %NULL, default basic rate set is used. + */ + int *basic_rates; + + /** + * proberesp - Probe Response template + * + * This is used by drivers that reply to Probe Requests internally in + * AP mode and require the full Probe Response template. + */ + const u8 *proberesp; + + /** + * proberesp_len - Length of the proberesp buffer in octets + */ + size_t proberesp_len; + + /** + * ssid - The SSID to use in Beacon/Probe Response frames + */ + const u8 *ssid; + + /** + * ssid_len - Length of the SSID (1..32) + */ + size_t ssid_len; + + /** + * hide_ssid - Whether to hide the SSID + */ + enum hide_ssid hide_ssid; + + /** + * pairwise_ciphers - WPA_CIPHER_* bitfield + */ + unsigned int pairwise_ciphers; + + /** + * group_cipher - WPA_CIPHER_* + */ + unsigned int group_cipher; + + /** + * key_mgmt_suites - WPA_KEY_MGMT_* bitfield + */ + unsigned int key_mgmt_suites; + + /** + * auth_algs - WPA_AUTH_ALG_* bitfield + */ + unsigned int auth_algs; + + /** + * wpa_version - WPA_PROTO_* bitfield + */ + unsigned int wpa_version; + + /** + * privacy - Whether privacy is used in the BSS + */ + int privacy; + + /** + * beacon_ies - WPS/P2P IE(s) for Beacon frames + * + * This is used to add IEs like WPS IE and P2P IE by drivers that do + * not use the full Beacon template. + */ + const struct wpabuf *beacon_ies; + + /** + * proberesp_ies - P2P/WPS IE(s) for Probe Response frames + * + * This is used to add IEs like WPS IE and P2P IE by drivers that + * reply to Probe Request frames internally. + */ + const struct wpabuf *proberesp_ies; + + /** + * assocresp_ies - WPS IE(s) for (Re)Association Response frames + * + * This is used to add IEs like WPS IE by drivers that reply to + * (Re)Association Request frames internally. + */ + const struct wpabuf *assocresp_ies; + + /** + * isolate - Whether to isolate frames between associated stations + * + * If this is non-zero, the AP is requested to disable forwarding of + * frames between associated stations. + */ + int isolate; + + /** + * cts_protect - Whether CTS protection is enabled + */ + int cts_protect; + + /** + * preamble - Whether short preamble is enabled + */ + int preamble; + + /** + * short_slot_time - Whether short slot time is enabled + * + * 0 = short slot time disable, 1 = short slot time enabled, -1 = do + * not set (e.g., when 802.11g mode is not in use) + */ + int short_slot_time; + + /** + * ht_opmode - HT operation mode or -1 if HT not in use + */ + int ht_opmode; + + /** + * interworking - Whether Interworking is enabled + */ + int interworking; + + /** + * hessid - Homogeneous ESS identifier or %NULL if not set + */ + const u8 *hessid; + + /** + * access_network_type - Access Network Type (0..15) + * + * This is used for filtering Probe Request frames when Interworking is + * enabled. + */ + u8 access_network_type; +}; + /** * struct wpa_driver_capa - Driver capability information */ @@ -530,7 +723,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001 /* Driver needs static WEP key setup after association command */ #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002 -#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004 +/* unused: 0x00000004 */ /* Driver takes care of RSN 4-way handshake internally; PMK is configured with * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */ #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008 @@ -571,9 +764,24 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000 /* Driver indicates TX status events for EAPOL Data frames */ #define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000 +/* Driver indicates TX status events for Deauth/Disassoc frames */ +#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000 +/* Driver supports roaming (BSS selection) in firmware */ +#define WPA_DRIVER_FLAGS_BSS_SELECTION 0x00040000 +/* Driver supports operating as a TDLS peer */ +#define WPA_DRIVER_FLAGS_TDLS_SUPPORT 0x00080000 +/* Driver requires external TDLS setup/teardown/discovery */ +#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP 0x00100000 +/* Driver indicates support for Probe Response offloading in AP mode */ +#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000 +/* Driver supports U-APSD in AP mode */ +#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000 unsigned int flags; int max_scan_ssids; + int max_sched_scan_ssids; + int sched_scan_supported; + int max_match_sets; /** * max_remain_on_chan - Maximum remain-on-channel duration in msec @@ -585,6 +793,20 @@ struct wpa_driver_capa { * supports in AP mode */ unsigned int max_stations; + + /** + * probe_resp_offloads - Bitmap of supported protocols by the driver + * for Probe Response offloading. + */ +/* Driver Probe Response offloading support for WPS ver. 1 */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS 0x00000001 +/* Driver Probe Response offloading support for WPS ver. 2 */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2 0x00000002 +/* Driver Probe Response offloading support for P2P */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P 0x00000004 +/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008 + unsigned int probe_resp_offloads; }; @@ -610,6 +832,9 @@ struct hostapd_sta_add_params { size_t supp_rates_len; u16 listen_interval; const struct ieee80211_ht_capabilities *ht_capabilities; + u32 flags; /* bitmask of WPA_STA_* flags */ + int set; /* Set STA parameters instead of add */ + u8 qosinfo; }; struct hostapd_freq_params { @@ -661,6 +886,7 @@ enum wpa_driver_if_type { }; struct wpa_init_params { + void *global_priv; const u8 *bssid; const char *ifname; const u8 *ssid; @@ -693,6 +919,7 @@ struct wpa_bss_params { #define WPA_STA_WMM BIT(1) #define WPA_STA_SHORT_PREAMBLE BIT(2) #define WPA_STA_MFP BIT(3) +#define WPA_STA_TDLS_PEER BIT(4) /** * struct p2p_params - P2P parameters for driver-based P2P management @@ -1079,91 +1306,21 @@ struct wpa_driver_ops { * flags: Variable for returning hardware feature flags * Returns: Pointer to allocated hardware data on success or %NULL on * failure. Caller is responsible for freeing this. - * - * This function is only needed for drivers that export MLME - * (management frame processing) to %wpa_supplicant or hostapd. */ struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv, u16 *num_modes, u16 *flags); /** - * set_channel - Set channel - * @priv: Private driver interface data - * @phymode: HOSTAPD_MODE_IEEE80211B, .. - * @chan: IEEE 802.11 channel number - * @freq: Frequency of the channel in MHz - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan, - int freq); - - /** - * set_ssid - Set SSID - * @priv: Private driver interface data - * @ssid: SSID - * @ssid_len: SSID length - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len); - - /** - * set_bssid - Set BSSID - * @priv: Private driver interface data - * @bssid: BSSID - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*set_bssid)(void *priv, const u8 *bssid); - - /** * send_mlme - Send management frame from MLME * @priv: Private driver interface data * @data: IEEE 802.11 management frame with IEEE 802.11 header * @data_len: Size of the management frame + * @noack: Do not wait for this frame to be acked (disable retries) * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. */ - int (*send_mlme)(void *priv, const u8 *data, size_t data_len); - - /** - * mlme_add_sta - Add a STA entry into the driver/netstack - * @priv: Private driver interface data - * @addr: MAC address of the STA (e.g., BSSID of the AP) - * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11 - * format (one octet per rate, 1 = 0.5 Mbps) - * @supp_rates_len: Number of entries in supp_rates - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. When the MLME code - * completes association with an AP, this function is called to - * configure the driver/netstack with a STA entry for data frame - * processing (TX rate control, encryption/decryption). - */ - int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates, - size_t supp_rates_len); - - /** - * mlme_remove_sta - Remove a STA entry from the driver/netstack - * @priv: Private driver interface data - * @addr: MAC address of the STA (e.g., BSSID of the AP) - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*mlme_remove_sta)(void *priv, const u8 *addr); + int (*send_mlme)(void *priv, const u8 *data, size_t data_len, + int noack); /** * update_ft_ies - Update FT (IEEE 802.11r) IEs @@ -1292,24 +1449,25 @@ struct wpa_driver_ops { struct wpa_driver_auth_params *params); /** - * set_beacon - Set Beacon frame template + * set_ap - Set Beacon and Probe Response information for AP mode * @priv: Private driver interface data - * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE - * @head_len: Length of the head buffer in octets - * @tail: Beacon tail following TIM IE - * @tail_len: Length of the tail buffer in octets - * @dtim_period: DTIM period - * @beacon_int: Beacon interval - * Returns: 0 on success, -1 on failure + * @params: Parameters to use in AP mode * - * This function is used to configure Beacon template for the driver in + * This function is used to configure Beacon template and/or extra IEs + * to add for Beacon and Probe Response frames for the driver in * AP mode. The driver is responsible for building the full Beacon * frame by concatenating the head part with TIM IE generated by the - * driver/firmware and finishing with the tail part. + * driver/firmware and finishing with the tail part. Depending on the + * driver architectue, this can be done either by using the full + * template or the set of additional IEs (e.g., WPS and P2P IE). + * Similarly, Probe Response processing depends on the driver design. + * If the driver (or firmware) takes care of replying to Probe Request + * frames, the extra IEs provided here needs to be added to the Probe + * Response frames. + * + * Returns: 0 on success, -1 on failure */ - int (*set_beacon)(void *priv, const u8 *head, size_t head_len, - const u8 *tail, size_t tail_len, int dtim_period, - int beacon_int); + int (*set_ap)(void *priv, struct wpa_driver_ap_params *params); /** * hapd_init - Initialize driver interface (hostapd only) @@ -1318,7 +1476,7 @@ struct wpa_driver_ops { * Returns: Pointer to private data, %NULL on failure * * This function is used instead of init() or init2() when the driver - * wrapper is used withh hostapd. + * wrapper is used with hostapd. */ void * (*hapd_init)(struct hostapd_data *hapd, struct wpa_init_params *params); @@ -1338,8 +1496,10 @@ struct wpa_driver_ops { * This is an optional function to configure the kernel driver to * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This * can be left undefined (set to %NULL) if IEEE 802.1X support is - * always enabled and the driver uses set_beacon() to set WPA/RSN IE + * always enabled and the driver uses set_ap() to set WPA/RSN IE * for Beacon frames. + * + * DEPRECATED - use set_ap() instead */ int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params); @@ -1351,7 +1511,9 @@ struct wpa_driver_ops { * * This is an optional function to configure privacy field in the * kernel driver for Beacon frames. This can be left undefined (set to - * %NULL) if the driver uses the Beacon template from set_beacon(). + * %NULL) if the driver uses the Beacon template from set_ap(). + * + * DEPRECATED - use set_ap() instead */ int (*set_privacy)(void *priv, int enabled); @@ -1393,7 +1555,9 @@ struct wpa_driver_ops { * This is an optional function to add information elements in the * kernel driver for Beacon and Probe Response frames. This can be left * undefined (set to %NULL) if the driver uses the Beacon template from - * set_beacon(). + * set_ap(). + * + * DEPRECATED - use set_ap() instead */ int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len); @@ -1467,8 +1631,7 @@ struct wpa_driver_ops { * Returns: Length of the SSID on success, -1 on failure * * This function need not be implemented if the driver uses Beacon - * template from set_beacon() and does not reply to Probe Request - * frames. + * template from set_ap() and does not reply to Probe Request frames. */ int (*hapd_get_ssid)(void *priv, u8 *buf, int len); @@ -1478,6 +1641,8 @@ struct wpa_driver_ops { * @buf: SSID * @len: Length of the SSID in octets * Returns: 0 on success, -1 on failure + * + * DEPRECATED - use set_ap() instead */ int (*hapd_set_ssid)(void *priv, const u8 *buf, int len); @@ -1501,6 +1666,9 @@ struct wpa_driver_ops { * This function is used to add a station entry to the driver once the * station has completed association. This is only used if the driver * does not take care of association processing. + * + * With TDLS, this function is also used to add or set (params->set 1) + * TDLS peer entries. */ int (*sta_add)(void *priv, struct hostapd_sta_add_params *params); @@ -1557,41 +1725,6 @@ struct wpa_driver_ops { int total_flags, int flags_or, int flags_and); /** - * set_rate_sets - Set supported and basic rate sets (AP only) - * @priv: Private driver interface data - * @supp_rates: -1 terminated array of supported rates in 100 kbps - * @basic_rates: -1 terminated array of basic rates in 100 kbps - * @mode: hardware mode (HOSTAPD_MODE_*) - * Returns: 0 on success, -1 on failure - */ - int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates, - int mode); - - /** - * set_cts_protect - Set CTS protection mode (AP only) - * @priv: Private driver interface data - * @value: Whether CTS protection is enabled - * Returns: 0 on success, -1 on failure - */ - int (*set_cts_protect)(void *priv, int value); - - /** - * set_preamble - Set preamble mode (AP only) - * @priv: Private driver interface data - * @value: Whether short preamble is enabled - * Returns: 0 on success, -1 on failure - */ - int (*set_preamble)(void *priv, int value); - - /** - * set_short_slot_time - Set short slot time (AP only) - * @priv: Private driver interface data - * @value: Whether short slot time is enabled - * Returns: 0 on success, -1 on failure - */ - int (*set_short_slot_time)(void *priv, int value); - - /** * set_tx_queue_params - Set TX queue parameters * @priv: Private driver interface data * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK) @@ -1604,17 +1737,6 @@ struct wpa_driver_ops { int cw_max, int burst_time); /** - * valid_bss_mask - Validate BSSID mask - * @priv: Private driver interface data - * @addr: Address - * @mask: Mask - * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can - * be used, but the main interface address must be the first address in - * the block if mask is applied - */ - int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask); - - /** * if_add - Add a virtual interface * @priv: Private driver interface data * @type: Interface type @@ -1709,19 +1831,6 @@ struct wpa_driver_ops { int (*set_radius_acl_expire)(void *priv, const u8 *mac); /** - * set_ht_params - Set HT parameters (AP only) - * @priv: Private driver interface data - * @ht_capab: HT Capabilities IE - * @ht_capab_len: Length of ht_capab in octets - * @ht_oper: HT Operation IE - * @ht_oper_len: Length of ht_oper in octets - * Returns: 0 on success, -1 on failure - */ - int (*set_ht_params)(void *priv, - const u8 *ht_capab, size_t ht_capab_len, - const u8 *ht_oper, size_t ht_oper_len); - - /** * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP) * @priv: Private driver interface data * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s) @@ -1733,7 +1842,7 @@ struct wpa_driver_ops { * * This is an optional function to add WPS IE in the kernel driver for * Beacon and Probe Response frames. This can be left undefined (set - * to %NULL) if the driver uses the Beacon template from set_beacon() + * to %NULL) if the driver uses the Beacon template from set_ap() * and does not process Probe Request frames. If the driver takes care * of (Re)Association frame processing, the assocresp buffer includes * WPS IE(s) that need to be added to (Re)Association Response frames @@ -1746,6 +1855,8 @@ struct wpa_driver_ops { * also used to provide Probe Response IEs for P2P Listen state * operations for drivers that generate the Probe Response frames * internally. + * + * DEPRECATED - use set_ap() instead */ int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon, const struct wpabuf *proberesp, @@ -1782,6 +1893,7 @@ struct wpa_driver_ops { * @bssid: BSSID (Address 3) * @data: Frame body * @data_len: data length in octets + @ @no_cck: Whether CCK rates must not be used to transmit this frame * Returns: 0 on success, -1 on failure * * This command can be used to request the driver to transmit an action @@ -1799,7 +1911,7 @@ struct wpa_driver_ops { */ int (*send_action)(void *priv, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *src, const u8 *bssid, - const u8 *data, size_t data_len); + const u8 *data, size_t data_len, int no_cck); /** * send_action_cancel_wait - Cancel action frame TX wait @@ -1866,19 +1978,6 @@ struct wpa_driver_ops { int (*probe_req_report)(void *priv, int report); /** - * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX - * @priv: Private driver interface data - * @disabled: Whether IEEE 802.11b rates are disabled - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and - * 11 Mbps) as TX rates for data and management frames. This can be - * used to optimize channel use when there is no need to support IEEE - * 802.11b-only devices. - */ - int (*disable_11b_rates)(void *priv, int disabled); - - /** * deinit_ap - Deinitialize AP mode * @priv: Private driver interface data * Returns: 0 on success, -1 on failure (or if not supported) @@ -1990,11 +2089,6 @@ struct wpa_driver_ops { int (*ampdu)(void *priv, int ampdu); /** - * set_intra_bss - Enables/Disables intra BSS bridging - */ - int (*set_intra_bss)(void *priv, int enabled); - - /** * get_radio_name - Get physical radio name for the device * @priv: Private driver interface data * Returns: Radio name or %NULL if not known @@ -2132,7 +2226,7 @@ struct wpa_driver_ops { * struct wpa_driver_capa. */ int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr, - u16 config_methods); + u16 config_methods, int join); /** * p2p_sd_request - Schedule a service discovery query @@ -2232,7 +2326,7 @@ struct wpa_driver_ops { * @status_code: Status Code or Reason Code to use (if needed) * @buf: TDLS IEs to add to the message * @len: Length of buf in octets - * Returns: 0 on success, -1 on failure + * Returns: 0 on success, negative (<0) on failure * * This optional function can be used to send packet to driver which is * responsible for receiving and sending all TDLS packets. @@ -2241,6 +2335,16 @@ struct wpa_driver_ops { u8 dialog_token, u16 status_code, const u8 *buf, size_t len); + /** + * tdls_oper - Ask the driver to perform high-level TDLS operations + * @priv: Private driver interface data + * @oper: TDLS high-level operation. See %enum tdls_oper + * @peer: Destination (peer) MAC address + * Returns: 0 on success, negative (<0) on failure + * + * This optional function can be used to send high-level TDLS commands + * to the driver. + */ int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer); /** @@ -2259,9 +2363,11 @@ struct wpa_driver_ops { * This function can be used to set authentication algorithms for AP * mode when static WEP is used. If the driver uses user space MLME/SME * implementation, there is no need to implement this function. + * + * DEPRECATED - use set_ap() instead */ int (*set_authmode)(void *priv, int authmode); - +#ifdef ANDROID /** * driver_cmd - execute driver-specific command * @priv: private driver interface data @@ -2272,6 +2378,135 @@ struct wpa_driver_ops { * Returns: 0 on success, -1 on failure */ int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len); +#endif + /** + * set_rekey_info - Set rekey information + * @priv: Private driver interface data + * @kek: Current KEK + * @kck: Current KCK + * @replay_ctr: Current EAPOL-Key Replay Counter + * + * This optional function can be used to provide information for the + * driver/firmware to process EAPOL-Key frames in Group Key Handshake + * while the host (including wpa_supplicant) is sleeping. + */ + void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck, + const u8 *replay_ctr); + + /** + * sta_assoc - Station association indication + * @priv: Private driver interface data + * @own_addr: Source address and BSSID for association frame + * @addr: MAC address of the station to associate + * @reassoc: flag to indicate re-association + * @status: association response status code + * @ie: assoc response ie buffer + * @len: ie buffer length + * Returns: 0 on success, -1 on failure + * + * This function indicates the driver to send (Re)Association + * Response frame to the station. + */ + int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr, + int reassoc, u16 status, const u8 *ie, size_t len); + + /** + * sta_auth - Station authentication indication + * @priv: Private driver interface data + * @own_addr: Source address and BSSID for authentication frame + * @addr: MAC address of the station to associate + * @seq: authentication sequence number + * @status: authentication response status code + * @ie: authentication frame ie buffer + * @len: ie buffer length + * + * This function indicates the driver to send Authentication frame + * to the station. + */ + int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr, + u16 seq, u16 status, const u8 *ie, size_t len); + + /** + * add_tspec - Add traffic stream + * @priv: Private driver interface data + * @addr: MAC address of the station to associate + * @tspec_ie: tspec ie buffer + * @tspec_ielen: tspec ie length + * Returns: 0 on success, -1 on failure + * + * This function adds the traffic steam for the station + * and fills the medium_time in tspec_ie. + */ + int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie, + size_t tspec_ielen); + + /** + * add_sta_node - Add a station node in the driver + * @priv: Private driver interface data + * @addr: MAC address of the station to add + * @auth_alg: authentication algorithm used by the station + * Returns: 0 on success, -1 on failure + * + * This function adds the station node in the driver, when + * the station gets added by FT-over-DS. + */ + int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg); + + /** + * sched_scan - Request the driver to initiate scheduled scan + * @priv: Private driver interface data + * @params: Scan parameters + * @interval: Interval between scan cycles in milliseconds + * Returns: 0 on success, -1 on failure + * + * This operation should be used for scheduled scan offload to + * the hardware. Every time scan results are available, the + * driver should report scan results event for wpa_supplicant + * which will eventually request the results with + * wpa_driver_get_scan_results2(). This operation is optional + * and if not provided or if it returns -1, we fall back to + * normal host-scheduled scans. + */ + int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params, + u32 interval); + + /** + * stop_sched_scan - Request the driver to stop a scheduled scan + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + * + * This should cause the scheduled scan to be stopped and + * results should stop being sent. Must be supported if + * sched_scan is supported. + */ + int (*stop_sched_scan)(void *priv); + + /** + * poll_client - Probe (null data or such) the given station + * @priv: Private driver interface data + * @own_addr: MAC address of sending interface + * @addr: MAC address of the station to probe + * @qos: Indicates whether station is QoS station + * + * This function is used to verify whether an associated station is + * still present. This function does not need to be implemented if the + * driver provides such inactivity polling mechanism. + */ + void (*poll_client)(void *priv, const u8 *own_addr, + const u8 *addr, int qos); +#ifdef ANDROID_P2P + /** + * go_switch_channel - Announce channel switch and migrate the GO to a + * given frequency. + * @priv: Private driver interface data + * @freq: frequency in MHz + * Returns: 0 on success, -1 on failure + * + * This function is used to move the GO to the legacy STA channel to avoid + * frequency conflict in single channel concurrency. + */ + int (*go_switch_channel)(void *priv, unsigned int freq); +#endif }; @@ -2674,7 +2909,35 @@ enum wpa_event_type { /** * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore */ - EVENT_IBSS_PEER_LOST + EVENT_IBSS_PEER_LOST, + + /** + * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey + * + * This event carries the new replay counter to notify wpa_supplicant + * of the current EAPOL-Key Replay Counter in case the driver/firmware + * completed Group Key Handshake while the host (including + * wpa_supplicant was sleeping). + */ + EVENT_DRIVER_GTK_REKEY, + + /** + * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped + */ + EVENT_SCHED_SCAN_STOPPED, + + /** + * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll + * + * This event indicates that the station responded to the poll + * initiated with @poll_client. + */ + EVENT_DRIVER_CLIENT_POLL_OK, + + /** + * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status + */ + EVENT_EAPOL_TX_STATUS }; @@ -2898,7 +3161,9 @@ union wpa_event_data { */ struct auth_info { u8 peer[ETH_ALEN]; + u8 bssid[ETH_ALEN]; u16 auth_type; + u16 auth_transaction; u16 status_code; const u8 *ies; size_t ies_len; @@ -2966,8 +3231,9 @@ union wpa_event_data { * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events */ struct rx_from_unknown { - const u8 *frame; - size_t len; + const u8 *bssid; + const u8 *addr; + int wds; } rx_from_unknown; /** @@ -3075,6 +3341,18 @@ union wpa_event_data { const u8 *sa; /** + * da - Destination address of the received Probe Request frame + * or %NULL if not available + */ + const u8 *da; + + /** + * bssid - BSSID of the received Probe Request frame or %NULL + * if not available + */ + const u8 *bssid; + + /** * ie - IEs from the Probe Request body */ const u8 *ie; @@ -3206,6 +3484,39 @@ union wpa_event_data { struct ibss_peer_lost { u8 peer[ETH_ALEN]; } ibss_peer_lost; + + /** + * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY + */ + struct driver_gtk_rekey { + const u8 *bssid; + const u8 *replay_ctr; + } driver_gtk_rekey; + + /** + * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events + * @addr: station address + */ + struct client_poll { + u8 addr[ETH_ALEN]; + } client_poll; + + /** + * struct eapol_tx_status + * @dst: Original destination + * @data: Data starting with IEEE 802.1X header (!) + * @data_len: Length of data + * @ack: Indicates ack or lost frame + * + * This corresponds to hapd_send_eapol if the frame sent + * there isn't just reported as EVENT_TX_STATUS. + */ + struct eapol_tx_status { + const u8 *dst; + const u8 *data; + int data_len; + int ack; + } eapol_tx_status; }; /** @@ -3258,4 +3569,10 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event); } +/* driver_common.c */ +void wpa_scan_results_free(struct wpa_scan_results *res); + +/* Convert wpa_event_type to a string for logging */ +const char * event_to_string(enum wpa_event_type event); + #endif /* DRIVER_H */ diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 1e78f6e..b17d1a6 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -34,7 +34,7 @@ */ #define ATH_WPS_IE -#include "os/linux/include/ieee80211_external.h" +#include "ieee80211_external.h" #ifdef CONFIG_WPS @@ -45,7 +45,7 @@ #endif #endif /* CONFIG_WPS */ -#include "wireless_copy.h" +#include "linux_wext.h" #include "driver.h" #include "eloop.h" @@ -641,6 +641,7 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, (unsigned long) ie_len); + wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len); wpabuf_free(drv->wpa_ie); drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); @@ -658,6 +659,8 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) wpabuf_len(drv->wps_beacon_ie)); app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); } + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)", + app_ie->app_buf, app_ie->app_buflen); set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, sizeof(struct ieee80211req_getset_appiebuf) + app_ie->app_buflen); @@ -672,6 +675,8 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) wpabuf_len(drv->wps_probe_resp_ie); } else app_ie->app_buflen = ie_len; + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)", + app_ie->app_buf, app_ie->app_buflen); set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, sizeof(struct ieee80211req_getset_appiebuf) + app_ie->app_buflen); @@ -748,6 +753,8 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, os_memset(&event, 0, sizeof(event)); event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; event.rx_probe_req.ie = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); @@ -785,8 +792,9 @@ atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) u8 buf[512]; struct ieee80211req_getset_appiebuf *beac_ie; - wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, - (unsigned long) len); + wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__, + (unsigned long) len, frametype); + wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len); beac_ie = (struct ieee80211req_getset_appiebuf *) buf; beac_ie->app_frmtype = frametype; @@ -797,11 +805,15 @@ atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && (drv->wpa_ie != NULL)) { + wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE", + drv->wpa_ie); os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), wpabuf_len(drv->wpa_ie)); beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); } + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF", + beac_ie->app_buf, beac_ie->app_buflen); return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, sizeof(struct ieee80211req_getset_appiebuf) + beac_ie->app_buflen); @@ -814,6 +826,11 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, { struct atheros_driver_data *drv = priv; + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon); + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp", + proberesp); + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp", + assocresp); wpabuf_free(drv->wps_beacon_ie); drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; wpabuf_free(drv->wps_probe_resp_ie); @@ -1332,6 +1349,8 @@ atheros_get_ssid(void *priv, u8 *buf, int len) os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.pointer = (caddr_t) buf; iwr.u.essid.length = len; + iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? + IW_ESSID_MAX_SIZE : len; if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { perror("ioctl[SIOCGIWESSID]"); @@ -1374,6 +1393,34 @@ static int atheros_set_authmode(void *priv, int auth_algs) return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode); } +static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) +{ + /* + * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x, + * set_generic_elem, and hapd_set_ssid. + */ + + wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x " + "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x " + "wpa_version=0x%x privacy=%d interworking=%d", + params->pairwise_ciphers, params->group_cipher, + params->key_mgmt_suites, params->auth_algs, + params->wpa_version, params->privacy, params->interworking); + wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID", + params->ssid, params->ssid_len); + if (params->hessid) + wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR, + MAC2STR(params->hessid)); + wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies", + params->beacon_ies); + wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies", + params->proberesp_ies); + wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", + params->assocresp_ies); + + return 0; +} + const struct wpa_driver_ops wpa_driver_atheros_ops = { .name = "atheros", .hapd_init = atheros_init, @@ -1396,4 +1443,5 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = { .commit = atheros_commit, .set_ap_wps_ie = atheros_set_ap_wps_ie, .set_authmode = atheros_set_authmode, + .set_ap = atheros_set_ap, }; diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c deleted file mode 100644 index cb88543..0000000 --- a/src/drivers/driver_broadcom.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * 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(const char *ifname, void *priv, - enum 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; - u8 *resp_ies = NULL; - - 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) { - resp_ies = os_malloc(left); - if (resp_ies == NULL) - return; - os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left); - data.assoc_info.resp_ies = resp_ies; - data.assoc_info.resp_ies_len = left; - } - - wpa_supplicant_event(ctx, EVENT_ASSOC, &data); - os_free(resp_ies); - 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; - } -} - -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; - wpa_driver_broadcom_set_wpa(drv, 1); - - return drv; -} - -static void wpa_driver_broadcom_deinit(void *priv) -{ - struct wpa_driver_broadcom_data *drv = priv; - wpa_driver_broadcom_set_wpa(drv, 0); - 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, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_broadcom_data *drv = priv; - wlc_ssid_t wst = { 0, "" }; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - 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 struct wpa_scan_results * -wpa_driver_broadcom_get_scan_results(void *priv) -{ - struct wpa_driver_broadcom_data *drv = priv; - char *buf; - wl_scan_results_t *wsr; - wl_bss_info_t *wbi; - size_t ap_num; - struct wpa_scan_results *res; - - buf = os_malloc(WLC_IOCTL_MAXLEN); - if (buf == NULL) - return NULL; - - 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 NULL; - } - - res = os_zalloc(sizeof(*res)); - if (res == NULL) { - os_free(buf); - return NULL; - } - - res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *)); - if (res->res == NULL) { - os_free(res); - os_free(buf); - return NULL; - } - - for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) { - struct wpa_scan_res *r; - r = os_malloc(sizeof(*r) + wbi->ie_length); - if (r == NULL) - break; - res->res[res->num++] = r; - - os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN); - r->freq = frequency_list[wbi->channel - 1]; - /* get ie's */ - os_memcpy(r + 1, wbi + 1, wbi->ie_length); - r->ie_len = wbi->ie_length; - - 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 res; - } - -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, NULL, 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; - int ret; - - ret = wpa_driver_broadcom_set_drop_unencrypted( - drv, params->drop_unencrypted); - - 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 ret; -} - -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_key = wpa_driver_broadcom_set_key, - .init = wpa_driver_broadcom_init, - .deinit = wpa_driver_broadcom_deinit, - .set_countermeasures = wpa_driver_broadcom_set_countermeasures, - .scan2 = wpa_driver_broadcom_scan, - .get_scan_results2 = wpa_driver_broadcom_get_scan_results, - .deauthenticate = wpa_driver_broadcom_deauthenticate, - .disassociate = wpa_driver_broadcom_disassociate, - .associate = wpa_driver_broadcom_associate, -}; diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c new file mode 100644 index 0000000..26ca8d6 --- /dev/null +++ b/src/drivers/driver_common.c @@ -0,0 +1,90 @@ +/* + * Common driver-related functions + * Copyright (c) 2003-2011, 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 "utils/common.h" +#include "driver.h" + +void wpa_scan_results_free(struct wpa_scan_results *res) +{ + size_t i; + + if (res == NULL) + return; + + for (i = 0; i < res->num; i++) + os_free(res->res[i]); + os_free(res->res); + os_free(res); +} + + +const char * event_to_string(enum wpa_event_type event) +{ +#define E2S(n) case EVENT_ ## n: return #n + switch (event) { + E2S(ASSOC); + E2S(DISASSOC); + E2S(MICHAEL_MIC_FAILURE); + E2S(SCAN_RESULTS); + E2S(ASSOCINFO); + E2S(INTERFACE_STATUS); + E2S(PMKID_CANDIDATE); + E2S(STKSTART); + E2S(TDLS); + E2S(FT_RESPONSE); + E2S(IBSS_RSN_START); + E2S(AUTH); + E2S(DEAUTH); + E2S(ASSOC_REJECT); + E2S(AUTH_TIMED_OUT); + E2S(ASSOC_TIMED_OUT); + E2S(FT_RRB_RX); + E2S(WPS_BUTTON_PUSHED); + E2S(TX_STATUS); + E2S(RX_FROM_UNKNOWN); + E2S(RX_MGMT); + E2S(RX_ACTION); + E2S(REMAIN_ON_CHANNEL); + E2S(CANCEL_REMAIN_ON_CHANNEL); + E2S(MLME_RX); + E2S(RX_PROBE_REQ); + E2S(NEW_STA); + E2S(EAPOL_RX); + E2S(SIGNAL_CHANGE); + E2S(INTERFACE_ENABLED); + E2S(INTERFACE_DISABLED); + E2S(CHANNEL_LIST_CHANGED); + E2S(INTERFACE_UNAVAILABLE); + E2S(BEST_CHANNEL); + E2S(UNPROT_DEAUTH); + E2S(UNPROT_DISASSOC); + E2S(STATION_LOW_ACK); + E2S(P2P_DEV_FOUND); + E2S(P2P_GO_NEG_REQ_RX); + E2S(P2P_GO_NEG_COMPLETED); + E2S(P2P_PROV_DISC_REQUEST); + E2S(P2P_PROV_DISC_RESPONSE); + E2S(P2P_SD_REQUEST); + E2S(P2P_SD_RESPONSE); + E2S(IBSS_PEER_LOST); + E2S(DRIVER_GTK_REKEY); + E2S(SCHED_SCAN_STOPPED); + E2S(DRIVER_CLIENT_POLL_OK); + E2S(EAPOL_TX_STATUS); + } + + return "UNKNOWN"; +#undef E2S +} diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c index e855c1b..8fc0efd 100644 --- a/src/drivers/driver_hostap.c +++ b/src/drivers/driver_hostap.c @@ -15,7 +15,7 @@ #include "includes.h" #include <sys/ioctl.h> -#include "wireless_copy.h" +#include "linux_wext.h" #include "common.h" #include "driver.h" #include "driver_wext.h" @@ -23,8 +23,6 @@ #include "driver_hostap.h" -#ifdef HOSTAPD - #include <net/if_arp.h> #include <netpacket/packet.h> @@ -32,6 +30,7 @@ #include "netlink.h" #include "linux_ioctl.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" /* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X @@ -84,8 +83,8 @@ static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len, sa = hdr->addr2; os_memset(&event, 0, sizeof(event)); - event.rx_from_unknown.frame = buf; - event.rx_from_unknown.len = len; + event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); + event.rx_from_unknown.addr = sa; wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event); pos = (u8 *) (hdr + 1); @@ -148,7 +147,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) { struct ieee80211_hdr *hdr; u16 fc, extra_len, type, stype; - unsigned char *extra = NULL; size_t data_len = len; int ver; union wpa_event_data event; @@ -185,7 +183,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) return; } len -= extra_len + 2; - extra = buf + len; } else if (ver == 1 || ver == 2) { handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); return; @@ -273,7 +270,7 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) } -static int hostap_send_mlme(void *priv, const u8 *msg, size_t len) +static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; @@ -322,7 +319,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, pos += 2; memcpy(pos, data, data_len); - res = hostap_send_mlme(drv, (u8 *) hdr, len); + res = hostap_send_mlme(drv, (u8 *) hdr, len, 0); if (res < 0) { wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " "failed: %d (%s)", @@ -1054,7 +1051,26 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth)); + sizeof(mgmt.u.deauth), 0); +} + + +static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.freq.m = freq->channel; + iwr.u.freq.e = 0; + + if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { + perror("ioctl[SIOCSIWFREQ]"); + return -1; + } + + return 0; } @@ -1072,7 +1088,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc)); + sizeof(mgmt.u.disassoc), 0); } @@ -1126,492 +1142,38 @@ static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, return mode; } -#else /* HOSTAPD */ - -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 wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg); - - -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(const char *ifname, void *priv, - enum 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; - if (seq) - 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_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(¶m, 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, ¶m, 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) +static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr, + const u8 *addr, int qos) { - struct wpa_driver_hostap_data *drv = priv; - int ret = 0; - int allow_unencrypted_eapol; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + struct ieee80211_hdr hdr; - if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, - params->drop_unencrypted) < 0) - ret = -1; - if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0) - ret = -1; - 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; + os_memset(&hdr, 0, sizeof(hdr)); - /* 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, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_hostap_data *drv = priv; - struct prism2_hostapd_param param; - int ret; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - 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, params); - } - - if (ssid_len > 32) - ssid_len = 32; - - os_memset(¶m, 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, ¶m, 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 & WPA_AUTH_ALG_OPEN) - algs |= 1; - if (auth_alg & WPA_AUTH_ALG_SHARED) - algs |= 2; - if (auth_alg & WPA_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); - } - - wpa_driver_hostap_set_wpa(drv, 1); - - return drv; -} + /* + * WLAN_FC_STYPE_NULLFUNC would be more appropriate, + * but it is apparently not retried so TX Exc events + * are not received for it. + * This is the reason the driver overrides the default + * handling. + */ + hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_DATA); + hdr.frame_control |= + host_to_le16(WLAN_FC_FROMDS); + os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); + os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); -static void wpa_driver_hostap_deinit(void *priv) -{ - struct wpa_driver_hostap_data *drv = priv; - wpa_driver_hostap_set_wpa(drv, 0); - wpa_driver_wext_deinit(drv->wext); - close(drv->sock); - os_free(drv); + hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0); } -#endif /* HOSTAPD */ - const struct wpa_driver_ops wpa_driver_hostap_ops = { .name = "hostap", .desc = "Host AP driver (Intersil Prism2/2.5/3)", .set_key = wpa_driver_hostap_set_key, -#ifdef HOSTAPD .hapd_init = hostap_init, .hapd_deinit = hostap_driver_deinit, .set_ieee8021x = hostap_set_ieee8021x, @@ -1632,17 +1194,6 @@ const struct wpa_driver_ops wpa_driver_hostap_ops = { .sta_clear_stats = hostap_sta_clear_stats, .get_hw_feature_data = hostap_get_hw_feature_data, .set_ap_wps_ie = hostap_set_ap_wps_ie, -#else /* HOSTAPD */ - .get_bssid = wpa_driver_hostap_get_bssid, - .get_ssid = wpa_driver_hostap_get_ssid, - .set_countermeasures = wpa_driver_hostap_set_countermeasures, - .scan2 = 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, - .init = wpa_driver_hostap_init, - .deinit = wpa_driver_hostap_deinit, - .set_operstate = wpa_driver_hostap_set_operstate, -#endif /* HOSTAPD */ + .set_freq = hostap_set_freq, + .poll_client = wpa_driver_hostap_poll_client, }; diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m deleted file mode 100644 index 8213fda..0000000 --- a/src/drivers/driver_iphone.m +++ /dev/null @@ -1,466 +0,0 @@ -/* - * 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 "common/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/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c index 630fbf4..edb086f 100644 --- a/src/drivers/driver_madwifi.c +++ b/src/drivers/driver_madwifi.c @@ -27,7 +27,7 @@ #include "driver_wext.h" #include "eloop.h" #include "common/ieee802_11_defs.h" -#include "wireless_copy.h" +#include "linux_wext.h" /* * Avoid conflicts with wpa_supplicant definitions by undefining a definition. @@ -71,8 +71,6 @@ #define WPA_KEY_RSC_LEN 8 -#ifdef HOSTAPD - #include "priv_netlink.h" #include "netlink.h" #include "linux_ioctl.h" @@ -734,6 +732,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, os_memset(&event, 0, sizeof(event)); event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; event.rx_probe_req.ie = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); @@ -804,6 +804,24 @@ madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, #define madwifi_set_ap_wps_ie NULL #endif /* CONFIG_WPS */ +static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + struct madwifi_driver_data *drv = priv; + struct iwreq iwr; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.freq.m = freq->channel; + iwr.u.freq.e = 0; + + if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { + perror("ioctl[SIOCSIWFREQ]"); + return -1; + } + + return 0; +} + static void madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { @@ -1274,554 +1292,11 @@ madwifi_commit(void *priv) return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); } -#else /* HOSTAPD */ - -struct wpa_driver_madwifi_data { - void *wext; /* private data for driver_wext */ - void *ctx; - char ifname[IFNAMSIZ + 1]; - int sock; -}; - -static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg); -static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies, - size_t ies_len); - - -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(const char *ifname, void *priv, enum 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(ifname, 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 - if (seq) { - 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 */ - if (seq) - 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_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__); - - if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, - params->drop_unencrypted, 1) < 0) - ret = -1; - if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0) - ret = -1; - - /* - * 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 & WPA_AUTH_ALG_OPEN) && - (auth_alg & WPA_AUTH_ALG_SHARED)) - authmode = IEEE80211_AUTH_AUTO; - else if (auth_alg & WPA_AUTH_ALG_SHARED) - 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, struct wpa_driver_scan_params *params) -{ - struct wpa_driver_madwifi_data *drv = priv; - struct iwreq iwr; - int ret = 0; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies, - params->extra_ies_len); - - 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); -} - -#endif /* HOSTAPD */ - const struct wpa_driver_ops wpa_driver_madwifi_ops = { .name = "madwifi", .desc = "MADWIFI 802.11 support (Atheros, etc.)", .set_key = wpa_driver_madwifi_set_key, -#ifdef HOSTAPD .hapd_init = madwifi_init, .hapd_deinit = madwifi_deinit, .set_ieee8021x = madwifi_set_ieee8021x, @@ -1840,17 +1315,5 @@ const struct wpa_driver_ops wpa_driver_madwifi_ops = { .sta_clear_stats = madwifi_sta_clear_stats, .commit = madwifi_commit, .set_ap_wps_ie = madwifi_set_ap_wps_ie, -#else /* HOSTAPD */ - .get_bssid = wpa_driver_madwifi_get_bssid, - .get_ssid = wpa_driver_madwifi_get_ssid, - .init = wpa_driver_madwifi_init, - .deinit = wpa_driver_madwifi_deinit, - .set_countermeasures = wpa_driver_madwifi_set_countermeasures, - .scan2 = 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_operstate = wpa_driver_madwifi_set_operstate, -#endif /* HOSTAPD */ + .set_freq = madwifi_set_freq, }; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index aeb7304..dbe9a28 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -3213,119 +3213,33 @@ wpa_driver_ndis_get_interfaces(void *global_priv) } -const struct wpa_driver_ops wpa_driver_ndis_ops = { - "ndis", - "Windows NDIS driver", - wpa_driver_ndis_get_bssid, - wpa_driver_ndis_get_ssid, - wpa_driver_ndis_set_key, - wpa_driver_ndis_init, - wpa_driver_ndis_deinit, - NULL /* set_param */, - NULL /* set_countermeasures */, - wpa_driver_ndis_deauthenticate, - wpa_driver_ndis_disassociate, - wpa_driver_ndis_associate, - wpa_driver_ndis_add_pmkid, - wpa_driver_ndis_remove_pmkid, - wpa_driver_ndis_flush_pmkid, - wpa_driver_ndis_get_capa, - wpa_driver_ndis_poll, - wpa_driver_ndis_get_ifname, - wpa_driver_ndis_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_ndis_get_scan_results, - NULL /* set_country */, - NULL /* global_init */, - NULL /* global_deinit */, - NULL /* init2 */, - wpa_driver_ndis_get_interfaces, - wpa_driver_ndis_scan, - NULL /* authenticate */, - NULL /* set_beacon */, - NULL /* hapd_init */, - NULL /* hapd_deinit */, - NULL /* set_ieee8021x */, - NULL /* set_privacy */, - NULL /* get_seqnum */, - NULL /* flush */, - NULL /* set_generic_elem */, - NULL /* read_sta_data */, - NULL /* hapd_send_eapol */, - NULL /* sta_deauth */, - NULL /* sta_disassoc */, - NULL /* sta_remove */, - NULL /* hapd_get_ssid */, - NULL /* hapd_set_ssid */, - NULL /* hapd_set_countermeasures */, - NULL /* sta_add */, - NULL /* get_inact_sec */, - NULL /* sta_clear_stats */, - NULL /* set_freq */, - NULL /* set_rts */, - NULL /* set_frag */, - NULL /* sta_set_flags */, - NULL /* set_rate_sets */, - NULL /* set_cts_protect */, - NULL /* set_preamble */, - NULL /* set_short_slot_time */, - NULL /* set_tx_queue_params */, - NULL /* valid_bss_mask */, - NULL /* if_add */, - NULL /* if_remove */, - NULL /* set_sta_vlan */, - NULL /* commit */, - NULL /* send_ether */, - NULL /* set_radius_acl_auth */, - NULL /* set_radius_acl_expire */, - NULL /* set_ht_params */, - NULL /* set_ap_wps_ie */, - NULL /* set_supp_port */, - NULL /* set_wds_sta */, - NULL /* send_action */, - NULL /* send_action_cancel_wait */, - NULL /* remain_on_channel */, - NULL /* cancel_remain_on_channel */, - NULL /* probe_req_report */, - NULL /* disable_11b_rates */, - NULL /* deinit_ap */, - NULL /* suspend */, - NULL /* resume */, - NULL /* signal_monitor */, - NULL /* send_frame */, - NULL /* shared_freq */, - NULL /* get_noa */, - NULL /* set_noa */, - NULL /* set_p2p_powersave */, - NULL /* ampdu */, - NULL /* set_intra_bss */, - NULL /* get_radio_name */, - NULL /* p2p_find */, - NULL /* p2p_stop_find */, - NULL /* p2p_listen */, - NULL /* p2p_connect */, - NULL /* wps_success_cb */, - NULL /* p2p_group_formation_failed */, - NULL /* p2p_set_params */, - NULL /* p2p_prov_disc_req */, - NULL /* p2p_sd_request */, - NULL /* p2p_sd_cancel_request */, - NULL /* p2p_sd_response */, - NULL /* p2p_service_update */, - NULL /* p2p_reject */, - NULL /* p2p_invite */, - NULL /* send_tdls_mgmt */, - NULL /* tdls_oper */, - NULL /* signal_poll */ -}; +static const char *ndis_drv_name = "ndis"; +static const char *ndis_drv_desc = "Windows NDIS driver"; + +struct wpa_driver_ops wpa_driver_ndis_ops; + +void driver_ndis_init_ops(void) +{ + os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops)); + wpa_driver_ndis_ops.name = ndis_drv_name; + wpa_driver_ndis_ops.desc = ndis_drv_desc; + wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid; + wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid; + wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key; + wpa_driver_ndis_ops.init = wpa_driver_ndis_init; + wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit; + wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate; + wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate; + wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate; + wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid; + wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid; + wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid; + wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa; + wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll; + wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname; + wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr; + wpa_driver_ndis_ops.get_scan_results2 = + wpa_driver_ndis_get_scan_results; + wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces; + wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan; +} diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index df309c5..a00f703 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -28,21 +28,47 @@ #include <linux/rtnetlink.h> #include <netpacket/packet.h> #include <linux/filter.h> +#include <linux/errqueue.h> #include "nl80211_copy.h" #include "common.h" #include "eloop.h" #include "utils/list.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "l2_packet/l2_packet.h" #include "netlink.h" #include "linux_ioctl.h" #include "radiotap.h" #include "radiotap_iter.h" #include "rfkill.h" #include "driver.h" -#if defined(ANDROID_BRCM_P2P_PATCH) && !defined(HOSTAPD) +#if defined(ANDROID_P2P) && !defined(HOSTAPD) #include "wpa_supplicant_i.h" #endif +#ifndef SO_WIFI_STATUS +# if defined(__sparc__) +# define SO_WIFI_STATUS 0x0025 +# elif defined(__parisc__) +# define SO_WIFI_STATUS 0x4022 +# else +# define SO_WIFI_STATUS 41 +# endif + +# define SCM_WIFI_STATUS SO_WIFI_STATUS +#endif + +#ifndef SO_EE_ORIGIN_TXSTATUS +#define SO_EE_ORIGIN_TXSTATUS 4 +#endif + +#ifndef PACKET_TX_TIMESTAMP +#define PACKET_TX_TIMESTAMP 16 +#endif + +#ifdef ANDROID +#include "android_drv.h" +#endif /* ANDROID */ #ifdef CONFIG_LIBNL20 /* libnl 2.0 compatibility code */ #define nl_handle nl_sock @@ -91,6 +117,37 @@ static void nl80211_handle_destroy(struct nl_handle *handle) #endif /* CONFIG_LIBNL20 */ +static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg) +{ + struct nl_handle *handle; + + handle = nl80211_handle_alloc(cb); + if (handle == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " + "callbacks (%s)", dbg); + return NULL; + } + + if (genl_connect(handle)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " + "netlink (%s)", dbg); + nl80211_handle_destroy(handle); + return NULL; + } + + return handle; +} + + +static void nl_destroy_handles(struct nl_handle **handle) +{ + if (*handle == NULL) + return; + nl80211_handle_destroy(*handle); + *handle = NULL; +} + + #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ #endif @@ -107,8 +164,30 @@ static void nl80211_handle_destroy(struct nl_handle *handle) struct nl80211_global { struct dl_list interfaces; + int if_add_ifindex; + struct netlink_data *netlink; + struct nl_cb *nl_cb; + struct nl_handle *nl; + int nl80211_id; + int ioctl_sock; /* socket for ioctl() use */ + + struct nl_handle *nl_event; }; +struct nl80211_wiphy_data { + struct dl_list list; + struct dl_list bsss; + struct dl_list drvs; + + struct nl_handle *nl_beacons; + struct nl_cb *nl_cb; + + int wiphy_idx; +}; + +static void nl80211_global_deinit(void *priv); +static void wpa_driver_nl80211_deinit(void *priv); + struct i802_bss { struct wpa_driver_nl80211_data *drv; struct i802_bss *next; @@ -118,19 +197,28 @@ struct i802_bss { unsigned int beacon_set:1; unsigned int added_if_into_bridge:1; unsigned int added_bridge:1; + + u8 addr[ETH_ALEN]; + + int freq; + + struct nl_handle *nl_preq, *nl_mgmt; + struct nl_cb *nl_cb; + + struct nl80211_wiphy_data *wiphy_data; + struct dl_list wiphy_list; }; struct wpa_driver_nl80211_data { struct nl80211_global *global; struct dl_list list; - u8 addr[ETH_ALEN]; + struct dl_list wiphy_list; char phyname[32]; void *ctx; - struct netlink_data *netlink; - int ioctl_sock; /* socket for ioctl() use */ int ifindex; int if_removed; int if_disabled; + int ignore_if_down_event; struct rfkill_data *rfkill; struct wpa_driver_capa capa; int has_capability; @@ -139,42 +227,43 @@ struct wpa_driver_nl80211_data { int scan_complete_events; - struct nl_handle *nl_handle; - struct nl_handle *nl_handle_event; - struct nl_handle *nl_handle_preq; - struct nl_cache *nl_cache; - struct nl_cache *nl_cache_event; - struct nl_cache *nl_cache_preq; struct nl_cb *nl_cb; - struct genl_family *nl80211; u8 auth_bssid[ETH_ALEN]; u8 bssid[ETH_ALEN]; int associated; u8 ssid[32]; size_t ssid_len; - int nlmode; - int ap_scan_as_station; + enum nl80211_iftype nlmode; + enum nl80211_iftype ap_scan_as_station; unsigned int assoc_freq; int monitor_sock; int monitor_ifidx; - int no_monitor_iface_capab; - int disable_11b_rates; + int monitor_refcount; + unsigned int disabled_11b_rates:1; unsigned int pending_remain_on_chan:1; + unsigned int in_interface_list:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int scan_for_auth:1; + unsigned int retry_auth:1; + unsigned int use_monitor:1; u64 remain_on_chan_cookie; u64 send_action_cookie; unsigned int last_mgmt_freq; - unsigned int ap_oper_freq; struct wpa_driver_scan_filter *filter_ssids; size_t num_filter_ssids; struct i802_bss first_bss; + int eapol_tx_sock; + #ifdef HOSTAPD int eapol_sock; /* socket for EAPOL frames */ @@ -185,12 +274,27 @@ struct wpa_driver_nl80211_data { int last_freq; int last_freq_ht; #endif /* HOSTAPD */ + + /* From failed authentication command */ + int auth_freq; + u8 auth_bssid_[ETH_ALEN]; + u8 auth_ssid[32]; + size_t auth_ssid_len; + int auth_alg; + u8 *auth_ie; + size_t auth_ie_len; + u8 auth_wep_key[4][16]; + size_t auth_wep_key_len[4]; + int auth_wep_tx_keyidx; + int auth_local_state_change; + int auth_p2p; }; 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_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode); static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, @@ -198,22 +302,28 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, int local_state_change); static void nl80211_remove_monitor_interface( struct wpa_driver_nl80211_data *drv); -static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, +static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, - const u8 *buf, size_t buf_len, u64 *cookie); + const u8 *buf, size_t buf_len, u64 *cookie, + int no_cck, int no_ack, int offchanok); static int wpa_driver_nl80211_probe_req_report(void *priv, int report); -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID +static int android_pno_start(struct i802_bss *bss, + struct wpa_driver_scan_params *params); +static int android_pno_stop(struct i802_bss *bss); +#endif /* ANDROID */ +#ifdef ANDROID_P2P static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, enum wpa_event_type type, const u8 *frame, size_t len); -int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len); int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration); +int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len); int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow); int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, const struct wpabuf *proberesp, const struct wpabuf *assocresp); -#endif +#endif #ifdef HOSTAPD static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); @@ -222,12 +332,19 @@ static int wpa_driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type, const char *ifname); #else /* HOSTAPD */ -static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ +} + +static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ +} + +static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) { return 0; } #endif /* HOSTAPD */ - #ifdef ANDROID extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len); @@ -238,12 +355,36 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, int ifindex, int disabled); static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv); +static int wpa_driver_nl80211_authenticate_retry( + struct wpa_driver_nl80211_data *drv); + + +static int is_ap_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_AP || + nlmode == NL80211_IFTYPE_P2P_GO); +} + + +static int is_sta_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_STATION || + nlmode == NL80211_IFTYPE_P2P_CLIENT); +} + + +static int is_p2p_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_P2P_CLIENT || + nlmode == NL80211_IFTYPE_P2P_GO); +} struct nl80211_bss_info_arg { struct wpa_driver_nl80211_data *drv; struct wpa_scan_results *res; unsigned int assoc_freq; + u8 assoc_bssid[ETH_ALEN]; }; static int bss_info_handler(struct nl_msg *msg, void *arg); @@ -279,7 +420,7 @@ static int no_seq_check(struct nl_msg *msg, void *arg) } -static int send_and_recv(struct wpa_driver_nl80211_data *drv, +static int send_and_recv(struct nl80211_global *global, struct nl_handle *nl_handle, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) @@ -287,7 +428,7 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv, struct nl_cb *cb; int err = -ENOMEM; - cb = nl_cb_clone(drv->nl_cb); + cb = nl_cb_clone(global->nl_cb); if (!cb) goto out; @@ -314,13 +455,22 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv, } +static int send_and_recv_msgs_global(struct nl80211_global *global, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + return send_and_recv(global, global->nl, msg, valid_handler, + valid_data); +} + 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) { - return send_and_recv(drv, drv->nl_handle, msg, valid_handler, - valid_data); + return send_and_recv(drv->global, drv->global->nl, msg, + valid_handler, valid_data); } @@ -361,7 +511,7 @@ static int family_handler(struct nl_msg *msg, void *arg) } -static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv, +static int nl_get_multicast_id(struct nl80211_global *global, const char *family, const char *group) { struct nl_msg *msg; @@ -371,11 +521,11 @@ static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv, msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"), + genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "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); + ret = send_and_recv_msgs_global(global, msg, family_handler, &res); msg = NULL; if (ret == 0) ret = res.id; @@ -386,6 +536,235 @@ nla_put_failure: } +static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg, int flags, uint8_t cmd) +{ + return genlmsg_put(msg, 0, 0, drv->global->nl80211_id, + 0, flags, cmd, 0); +} + + +struct wiphy_idx_data { + int wiphy_idx; +}; + + +static int netdev_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wiphy_idx_data *info = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_WIPHY]) + info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + + return NL_SKIP; +} + + +static int nl80211_get_wiphy_index(struct i802_bss *bss) +{ + struct nl_msg *msg; + struct wiphy_idx_data data = { + .wiphy_idx = -1, + }; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0) + return data.wiphy_idx; + msg = NULL; +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv, + struct nl80211_wiphy_data *w) +{ + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS); + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx); + + ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Register beacons command " + "failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle) +{ + struct nl80211_wiphy_data *w = eloop_ctx; + + wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available"); + + nl_recvmsgs(handle, w->nl_cb); +} + + +static int process_beacon_event(struct nl_msg *msg, void *arg) +{ + struct nl80211_wiphy_data *w = arg; + struct wpa_driver_nl80211_data *drv; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + union wpa_event_data event; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (gnlh->cmd != NL80211_CMD_FRAME) { + wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)", + gnlh->cmd); + return NL_SKIP; + } + + if (!tb[NL80211_ATTR_FRAME]) + return NL_SKIP; + + dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data, + wiphy_list) { + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]); + event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]); + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + } + + return NL_SKIP; +} + + +static struct nl80211_wiphy_data * +nl80211_get_wiphy_data_ap(struct i802_bss *bss) +{ + static DEFINE_DL_LIST(nl80211_wiphys); + struct nl80211_wiphy_data *w; + int wiphy_idx, found = 0; + struct i802_bss *tmp_bss; + + if (bss->wiphy_data != NULL) + return bss->wiphy_data; + + wiphy_idx = nl80211_get_wiphy_index(bss); + + dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) { + if (w->wiphy_idx == wiphy_idx) + goto add; + } + + /* alloc new one */ + w = os_zalloc(sizeof(*w)); + if (w == NULL) + return NULL; + w->wiphy_idx = wiphy_idx; + dl_list_init(&w->bsss); + dl_list_init(&w->drvs); + + w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!w->nl_cb) { + os_free(w); + return NULL; + } + nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); + nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event, + w); + + w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb, + "wiphy beacons"); + if (w->nl_beacons == NULL) { + os_free(w); + return NULL; + } + + if (nl80211_register_beacons(bss->drv, w)) { + nl_destroy_handles(&w->nl_beacons); + os_free(w); + return NULL; + } + + eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons), + nl80211_recv_beacons, w, w->nl_beacons); + + dl_list_add(&nl80211_wiphys, &w->list); + +add: + /* drv entry for this bss already there? */ + dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) { + if (tmp_bss->drv == bss->drv) { + found = 1; + break; + } + } + /* if not add it */ + if (!found) + dl_list_add(&w->drvs, &bss->drv->wiphy_list); + + dl_list_add(&w->bsss, &bss->wiphy_list); + bss->wiphy_data = w; + return w; +} + + +static void nl80211_put_wiphy_data_ap(struct i802_bss *bss) +{ + struct nl80211_wiphy_data *w = bss->wiphy_data; + struct i802_bss *tmp_bss; + int found = 0; + + if (w == NULL) + return; + bss->wiphy_data = NULL; + dl_list_del(&bss->wiphy_list); + + /* still any for this drv present? */ + dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) { + if (tmp_bss->drv == bss->drv) { + found = 1; + break; + } + } + /* if not remove it */ + if (!found) + dl_list_del(&bss->drv->wiphy_list); + + if (!dl_list_empty(&w->bsss)) + return; + + eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons)); + + nl_cb_put(w->nl_cb); + nl_destroy_handles(&w->nl_beacons); + dl_list_del(&w->list); + os_free(w); +} + + static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) { struct i802_bss *bss = priv; @@ -479,17 +858,33 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, } +static struct wpa_driver_nl80211_data * +nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len) +{ + struct wpa_driver_nl80211_data *drv; + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) || + have_ifidx(drv, idx)) + return drv; + } + return NULL; +} + + static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { - struct wpa_driver_nl80211_data *drv = ctx; + struct nl80211_global *global = ctx; + struct wpa_driver_nl80211_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; + char namebuf[IFNAMSIZ]; - if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) && - !have_ifidx(drv, ifi->ifi_index)) { + drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) { wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign " "ifindex %d", ifi->ifi_index); return; @@ -504,15 +899,38 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { + if (if_indextoname(ifi->ifi_index, namebuf) && + linux_iface_up(drv->global->ioctl_sock, + drv->first_bss.ifname) > 0) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " + "event since interface %s is up", namebuf); + return; + } wpa_printf(MSG_DEBUG, "nl80211: Interface down"); - drv->if_disabled = 1; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); + if (drv->ignore_if_down_event) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " + "event generated by mode change"); + drv->ignore_if_down_event = 0; + } else { + drv->if_disabled = 1; + wpa_supplicant_event(drv->ctx, + EVENT_INTERFACE_DISABLED, NULL); + } } if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { - wpa_printf(MSG_DEBUG, "nl80211: Interface up"); - drv->if_disabled = 0; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); + if (if_indextoname(ifi->ifi_index, namebuf) && + linux_iface_up(drv->global->ioctl_sock, + drv->first_bss.ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " + "event since interface %s is down", + namebuf); + } else { + wpa_printf(MSG_DEBUG, "nl80211: Interface up"); + drv->if_disabled = 0; + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); + } } /* @@ -524,7 +942,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) - netlink_send_oper_ifla(drv->netlink, drv->ifindex, + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, IF_OPER_UP); attrlen = len; @@ -541,16 +959,13 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, attr = RTA_NEXT(attr, attrlen); } -#ifdef HOSTAPD if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been added to bridge */ - char namebuf[IFNAMSIZ]; if_indextoname(brid, namebuf); wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s", brid, namebuf); add_ifidx(drv, brid); } -#endif /* HOSTAPD */ } @@ -558,11 +973,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { - struct wpa_driver_nl80211_data *drv = ctx; + struct nl80211_global *global = ctx; + struct wpa_driver_nl80211_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; + drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for " + "foreign ifindex %d", ifi->ifi_index); + return; + } + attrlen = len; attr = (struct rtattr *) buf; @@ -578,7 +1001,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, attr = RTA_NEXT(attr, attrlen); } -#ifdef HOSTAPD if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; @@ -587,7 +1009,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, "%s", brid, namebuf); del_ifidx(drv, brid); } -#endif /* HOSTAPD */ } @@ -629,8 +1050,7 @@ static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) 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); + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; @@ -656,12 +1076,12 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 status; -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P struct wpa_supplicant *wpa_s = drv->ctx; #endif mgmt = (const struct ieee80211_mgmt *) frame; -#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_BRCM_P2P_PATCH) +#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_P2P) if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { if (len < 24 + sizeof(mgmt->u.assoc_req)) { wpa_printf(MSG_DEBUG, "nl80211: Too short association event " @@ -674,7 +1094,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req); event.assoc_info.addr = mgmt->sa; } else { -#endif +#endif if (len < 24 + sizeof(mgmt->u.assoc_resp)) { wpa_printf(MSG_DEBUG, "nl80211: Too short association event " "frame"); @@ -708,7 +1128,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, } event.assoc_info.freq = drv->assoc_freq; -#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_BRCM_P2P_PATCH) +#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_P2P) } #endif wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); @@ -765,6 +1185,29 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } +static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, + struct nlattr *reason, struct nlattr *addr) +{ + union wpa_event_data data; + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + /* + * Avoid reporting two disassociation events that could + * confuse the core code. + */ + wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " + "event when using userspace SME"); + return; + } + + drv->associated = 0; + os_memset(&data, 0, sizeof(data)); + if (reason) + data.disassoc_info.reason_code = nla_get_u16(reason); + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); +} + + static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, enum nl80211_commands cmd, struct nlattr *addr) { @@ -819,7 +1262,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, event.rx_action.data = &mgmt->u.action.category + 1; event.rx_action.len = frame + len - event.rx_action.data; wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P } else if (stype == WLAN_FC_STYPE_ASSOC_REQ) { mlme_event_assoc(drv, frame, len); } else if (stype == WLAN_FC_STYPE_DISASSOC) { @@ -835,26 +1278,29 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, } -static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv, - struct nlattr *cookie, const u8 *frame, - size_t len, struct nlattr *ack) +static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, + struct nlattr *cookie, const u8 *frame, + size_t len, struct nlattr *ack) { union wpa_event_data event; const struct ieee80211_hdr *hdr; u16 fc; - u64 cookie_val; - if (!cookie) - return; + if (!is_ap_interface(drv->nlmode)) { + u64 cookie_val; - cookie_val = nla_get_u64(cookie); - wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s " - "(ack=%d)", - (long long unsigned int) cookie_val, - cookie_val == drv->send_action_cookie ? - " (match)" : " (unknown)", ack != NULL); - if (cookie_val != drv->send_action_cookie) - return; + if (!cookie) + return; + + cookie_val = nla_get_u64(cookie); + wpa_printf(MSG_DEBUG, "nl80211: Action TX status:" + " cookie=0%llx%s (ack=%d)", + (long long unsigned int) cookie_val, + cookie_val == drv->send_action_cookie ? + " (match)" : " (unknown)", ack != NULL); + if (cookie_val != drv->send_action_cookie) + return; + } hdr = (const struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); @@ -906,7 +1352,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, reason_code = le_to_host16(mgmt->u.deauth.reason_code); if (type == EVENT_DISASSOC) { -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { event.disassoc_info.addr = mgmt->sa; @@ -920,7 +1366,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, mgmt->u.disassoc.variable; } } else { -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { event.deauth_info.addr = mgmt->sa; @@ -1011,8 +1457,8 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv, mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME_TX_STATUS: - mlme_event_action_tx_status(drv, cookie, nla_data(frame), - nla_len(frame), ack); + mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), + nla_len(frame), ack); break; case NL80211_CMD_UNPROT_DEAUTHENTICATE: mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, @@ -1117,7 +1563,8 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, if (cookie != drv->remain_on_chan_cookie) return; /* not for us */ - drv->pending_remain_on_chan = !cancel_event; + if (cancel_event) + drv->pending_remain_on_chan = 0; os_memset(&data, 0, sizeof(data)); data.remain_on_channel.freq = freq; @@ -1139,6 +1586,14 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; + if (drv->scan_for_auth) { + drv->scan_for_auth = 0; + wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing " + "cfg80211 BSS entry"); + wpa_driver_nl80211_authenticate_retry(drv); + return; + } + os_memset(&event, 0, sizeof(event)); info = &event.scan_info; info->aborted = aborted; @@ -1228,14 +1683,14 @@ static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); return send_and_recv_msgs(drv, msg, get_link_signal, sig); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -1296,13 +1751,88 @@ static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0); + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, get_link_noise, sig_change); nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; + static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, + }; + struct wpa_scan_results *scan_results = arg; + struct wpa_scan_res *scan_res; + size_t i; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_SURVEY_INFO]) { + wpa_printf(MSG_DEBUG, "nl80211: Survey data missing"); + return NL_SKIP; + } + + if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, + tb[NL80211_ATTR_SURVEY_INFO], + survey_policy)) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested " + "attributes"); + return NL_SKIP; + } + + if (!sinfo[NL80211_SURVEY_INFO_NOISE]) + return NL_SKIP; + + if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) + return NL_SKIP; + + for (i = 0; i < scan_results->num; ++i) { + scan_res = scan_results->res[i]; + if (!scan_res) + continue; + if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != + scan_res->freq) + continue; + if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID)) + continue; + scan_res->noise = (s8) + nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); + scan_res->flags &= ~WPA_SCAN_NOISE_INVALID; + } + + return NL_SKIP; +} + + +static int nl80211_get_noise_for_scan_results( + struct wpa_driver_nl80211_data *drv, + struct wpa_scan_results *scan_res) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, + scan_res); + nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -1385,8 +1915,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, addr = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); - if (drv->nlmode == NL80211_IFTYPE_AP && - drv->no_monitor_iface_capab) { + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { u8 *ies = NULL; size_t ies_len = 0; if (tb[NL80211_ATTR_IE]) { @@ -1419,8 +1948,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, MAC2STR(addr)); - if (drv->nlmode == NL80211_IFTYPE_AP && - drv->no_monitor_iface_capab) { + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { drv_event_disassoc(drv->ctx, addr); return; } @@ -1434,38 +1962,138 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, } -static int process_event(struct nl_msg *msg, void *arg) +static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) { - struct wpa_driver_nl80211_data *drv = arg; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; + static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { + [NL80211_REKEY_DATA_KEK] = { + .minlen = NL80211_KEK_LEN, + .maxlen = NL80211_KEK_LEN, + }, + [NL80211_REKEY_DATA_KCK] = { + .minlen = NL80211_KCK_LEN, + .maxlen = NL80211_KCK_LEN, + }, + [NL80211_REKEY_DATA_REPLAY_CTR] = { + .minlen = NL80211_REPLAY_CTR_LEN, + .maxlen = NL80211_REPLAY_CTR_LEN, + }, + }; union wpa_event_data data; - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_MAC]) + return; + if (!tb[NL80211_ATTR_REKEY_DATA]) + return; + if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, + tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) + return; + if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) + return; + + os_memset(&data, 0, sizeof(data)); + data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR, + MAC2STR(data.driver_gtk_rekey.bssid)); + data.driver_gtk_rekey.replay_ctr = + nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); + wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter", + data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); +} + + +static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; + static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { + [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, + [NL80211_PMKSA_CANDIDATE_BSSID] = { + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN, + }, + [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, + }; + union wpa_event_data data; + + if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) + return; + if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, + tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) + return; + if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || + !cand[NL80211_PMKSA_CANDIDATE_BSSID]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.pmkid_candidate.bssid, + nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); + data.pmkid_candidate.index = + nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); + data.pmkid_candidate.preauth = + cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; + wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); +} - if (tb[NL80211_ATTR_IFINDEX]) { - int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { - wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)" - " for foreign interface (ifindex %d)", - gnlh->cmd, ifindex); - return NL_SKIP; - } - } - if (drv->ap_scan_as_station && - (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || - gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { +static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.client_poll.addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); +} + + +static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, + int wds) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + union wpa_event_data event; + + if (!tb[NL80211_ATTR_MAC]) + return; + + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.bssid = bss->addr; + event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]); + event.rx_from_unknown.wds = wds; + + wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); +} + + +static void do_process_drv_event(struct wpa_driver_nl80211_data *drv, + int cmd, struct nlattr **tb) +{ + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && + (cmd == NL80211_CMD_NEW_SCAN_RESULTS || + cmd == NL80211_CMD_SCAN_ABORTED)) { wpa_driver_nl80211_set_mode(&drv->first_bss, - IEEE80211_MODE_AP); - drv->ap_scan_as_station = 0; + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } - switch (gnlh->cmd) { + switch (cmd) { case NL80211_CMD_TRIGGER_SCAN: wpa_printf(MSG_DEBUG, "nl80211: Scan trigger"); break; + case NL80211_CMD_START_SCHED_SCAN: + wpa_printf(MSG_DEBUG, "nl80211: Sched scan started"); + break; + case NL80211_CMD_SCHED_SCAN_STOPPED: + wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped"); + wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); + break; case NL80211_CMD_NEW_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "nl80211: New scan results available"); drv->scan_complete_events = 1; @@ -1473,6 +2101,11 @@ static int process_event(struct nl_msg *msg, void *arg) drv->ctx); send_scan_event(drv, 0, tb); break; + case NL80211_CMD_SCHED_SCAN_RESULTS: + wpa_printf(MSG_DEBUG, + "nl80211: New sched scan results available"); + send_scan_event(drv, 0, tb); + break; case NL80211_CMD_SCAN_ABORTED: wpa_printf(MSG_DEBUG, "nl80211: Scan aborted"); /* @@ -1487,39 +2120,25 @@ static int process_event(struct nl_msg *msg, void *arg) case NL80211_CMD_ASSOCIATE: case NL80211_CMD_DEAUTHENTICATE: case NL80211_CMD_DISASSOCIATE: - case NL80211_CMD_FRAME: case NL80211_CMD_FRAME_TX_STATUS: case NL80211_CMD_UNPROT_DEAUTHENTICATE: case NL80211_CMD_UNPROT_DISASSOCIATE: - mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], + mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; case NL80211_CMD_CONNECT: case NL80211_CMD_ROAM: - mlme_event_connect(drv, gnlh->cmd, + mlme_event_connect(drv, cmd, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_RESP_IE]); break; case NL80211_CMD_DISCONNECT: - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { - /* - * Avoid reporting two disassociation events that could - * confuse the core code. - */ - wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " - "event when using userspace SME"); - break; - } - drv->associated = 0; - os_memset(&data, 0, sizeof(data)); - if (tb[NL80211_ATTR_REASON_CODE]) - data.disassoc_info.reason_code = - nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); + mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], + tb[NL80211_ATTR_MAC]); break; case NL80211_CMD_MICHAEL_MIC_FAILURE: mlme_event_michael_mic_failure(drv, tb); @@ -1552,6 +2171,95 @@ static int process_event(struct nl_msg *msg, void *arg) case NL80211_CMD_DEL_STATION: nl80211_del_station_event(drv, tb); break; + case NL80211_CMD_SET_REKEY_OFFLOAD: + nl80211_rekey_offload_event(drv, tb); + break; + case NL80211_CMD_PMKSA_CANDIDATE: + nl80211_pmksa_candidate_event(drv, tb); + break; + case NL80211_CMD_PROBE_CLIENT: + nl80211_client_probe_event(drv, tb); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " + "(cmd=%d)", cmd); + break; + } +} + + +static int process_drv_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 && !have_ifidx(drv, ifindex)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)" + " for foreign interface (ifindex %d)", + gnlh->cmd, ifindex); + return NL_SKIP; + } + } + + do_process_drv_event(drv, gnlh->cmd, tb); + return NL_SKIP; +} + + +static int process_global_event(struct nl_msg *msg, void *arg) +{ + struct nl80211_global *global = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct wpa_driver_nl80211_data *drv; + int ifidx = -1; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) + ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (ifidx == -1 || ifidx == drv->ifindex || + have_ifidx(drv, ifidx)) + do_process_drv_event(drv, gnlh->cmd, tb); + } + + return NL_SKIP; +} + + +static int process_bss_event(struct nl_msg *msg, void *arg) +{ + struct i802_bss *bss = 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); + + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: + case NL80211_CMD_FRAME_TX_STATUS: + mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE]); + break; + case NL80211_CMD_UNEXPECTED_FRAME: + nl80211_spurious_frame(bss, tb, 0); + break; + case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: + nl80211_spurious_frame(bss, tb, 1); + break; default: wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", gnlh->cmd); @@ -1565,18 +2273,11 @@ static int process_event(struct nl_msg *msg, void *arg) static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx, void *handle) { - struct nl_cb *cb; - struct wpa_driver_nl80211_data *drv = eloop_ctx; + struct nl_cb *cb = 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(handle, cb); - nl_cb_put(cb); } @@ -1604,43 +2305,82 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg) 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); + nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG); 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: + nlmsg_free(msg); return -EINVAL; } struct wiphy_info_data { - int max_scan_ssids; - int ap_supported; - int p2p_supported; - int auth_supported; - int connect_supported; - int offchan_tx_supported; - int max_remain_on_chan; + struct wpa_driver_capa *capa; + + unsigned int error:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int monitor_supported:1; }; +static unsigned int probe_resp_offload_support(int supp_protocols) +{ + unsigned int prot = 0; + + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING; + + return prot; +} + + static int wiphy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct wiphy_info_data *info = arg; int p2p_go_supported = 0, p2p_client_supported = 0; + int p2p_concurrent = 0; + int auth_supported = 0, connect_supported = 0; + struct wpa_driver_capa *capa = info->capa; + static struct nla_policy + iface_combination_policy[NUM_NL80211_IFACE_COMB] = { + [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, + [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, + [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, + [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, + }, + iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { + [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, + [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, + }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) - info->max_scan_ssids = + capa->max_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); + if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) + capa->max_sched_scan_ssids = + nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); + + if (tb[NL80211_ATTR_MAX_MATCH_SETS]) + capa->max_match_sets = + nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); + if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { struct nlattr *nl_mode; int i; @@ -1648,7 +2388,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { switch (nla_type(nl_mode)) { case NL80211_IFTYPE_AP: - info->ap_supported = 1; + capa->flags |= WPA_DRIVER_FLAGS_AP; break; case NL80211_IFTYPE_P2P_GO: p2p_go_supported = 1; @@ -1656,11 +2396,69 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case NL80211_IFTYPE_P2P_CLIENT: p2p_client_supported = 1; break; + case NL80211_IFTYPE_MONITOR: + info->monitor_supported = 1; + break; } } } - info->p2p_supported = p2p_go_supported && p2p_client_supported; + if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) { + struct nlattr *nl_combi; + int rem_combi; + + nla_for_each_nested(nl_combi, + tb[NL80211_ATTR_INTERFACE_COMBINATIONS], + rem_combi) { + struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; + struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; + struct nlattr *nl_limit, *nl_mode; + int err, rem_limit, rem_mode; + int combination_has_p2p = 0, combination_has_mgd = 0; + + err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, + nl_combi, + iface_combination_policy); + if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || + !tb_comb[NL80211_IFACE_COMB_MAXNUM] || + !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) + goto broken_combination; + + nla_for_each_nested(nl_limit, + tb_comb[NL80211_IFACE_COMB_LIMITS], + rem_limit) { + err = nla_parse_nested(tb_limit, + MAX_NL80211_IFACE_LIMIT, + nl_limit, + iface_limit_policy); + if (err || + !tb_limit[NL80211_IFACE_LIMIT_TYPES]) + goto broken_combination; + + nla_for_each_nested( + nl_mode, + tb_limit[NL80211_IFACE_LIMIT_TYPES], + rem_mode) { + int ift = nla_type(nl_mode); + if (ift == NL80211_IFTYPE_P2P_GO || + ift == NL80211_IFTYPE_P2P_CLIENT) + combination_has_p2p = 1; + if (ift == NL80211_IFTYPE_STATION) + combination_has_mgd = 1; + } + if (combination_has_p2p && combination_has_mgd) + break; + } + + if (combination_has_p2p && combination_has_mgd) { + p2p_concurrent = 1; + break; + } + +broken_combination: + ; + } + } if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { struct nlattr *nl_cmd; @@ -1668,21 +2466,92 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) nla_for_each_nested(nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { - u32 cmd = nla_get_u32(nl_cmd); - if (cmd == NL80211_CMD_AUTHENTICATE) - info->auth_supported = 1; - else if (cmd == NL80211_CMD_CONNECT) - info->connect_supported = 1; + switch (nla_get_u32(nl_cmd)) { + case NL80211_CMD_AUTHENTICATE: + auth_supported = 1; + break; + case NL80211_CMD_CONNECT: + connect_supported = 1; + break; + case NL80211_CMD_START_SCHED_SCAN: + capa->sched_scan_supported = 1; + break; + case NL80211_CMD_PROBE_CLIENT: + info->poll_command_supported = 1; + break; + } } } - if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) - info->offchan_tx_supported = 1; + if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { + wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " + "off-channel TX"); + capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; + } + + if (tb[NL80211_ATTR_ROAM_SUPPORT]) { + wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming"); + capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; + } + + /* default to 5000 since early versions of mac80211 don't set it */ + capa->max_remain_on_chan = 5000; + + if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD]) + capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD; if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]) - info->max_remain_on_chan = + capa->max_remain_on_chan = nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); + if (auth_supported) + capa->flags |= WPA_DRIVER_FLAGS_SME; + else if (!connect_supported) { + wpa_printf(MSG_INFO, "nl80211: Driver does not support " + "authentication/association or connect commands"); + info->error = 1; + } + + if (p2p_go_supported && p2p_client_supported) + capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; + if (p2p_concurrent) { + wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group " + "interface (driver advertised support)"); + capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; + capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; + } + + if (tb[NL80211_ATTR_TDLS_SUPPORT]) { + wpa_printf(MSG_DEBUG, "nl80211: TDLS supported"); + capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; + + if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) { + wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup"); + capa->flags |= + WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; + } + } + + if (tb[NL80211_ATTR_DEVICE_AP_SME]) + info->device_ap_sme = 1; + + if (tb[NL80211_ATTR_FEATURE_FLAGS]) { + u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]); + + if (flags & NL80211_FEATURE_SK_TX_STATUS) + info->data_tx_status = 1; + } + + if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) { + int protocols = + nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]); + wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response " + "offload in AP mode"); + capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD; + capa->probe_resp_offloads = + probe_resp_offload_support(protocols); + } + return NL_SKIP; } @@ -1693,16 +2562,13 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg; os_memset(info, 0, sizeof(*info)); - - /* default to 5000 since early versions of mac80211 don't set it */ - info->max_remain_on_chan = 5000; + info->capa = &drv->capa; msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex); @@ -1720,6 +2586,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) struct wiphy_info_data info; if (wpa_driver_nl80211_get_info(drv, &info)) return -1; + + if (info.error) + return -1; + drv->has_capability = 1; /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | @@ -1734,131 +2604,132 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; - drv->capa.max_scan_ssids = info.max_scan_ssids; - if (info.ap_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_AP; + drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; + drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; + drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; - if (info.auth_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_SME; - else if (!info.connect_supported) { - wpa_printf(MSG_INFO, "nl80211: Driver does not support " - "authentication/association or connect commands"); - return -1; - } + drv->device_ap_sme = info.device_ap_sme; + drv->poll_command_supported = info.poll_command_supported; + drv->data_tx_status = info.data_tx_status; - if (info.offchan_tx_supported) { - wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " - "off-channel TX"); - drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; + /* + * If poll command is supported mac80211 is new enough to + * have everything we need to not need monitor interfaces. + */ + drv->use_monitor = !info.poll_command_supported; + + if (drv->device_ap_sme && drv->use_monitor) { + /* + * Non-mac80211 drivers may not support monitor interface. + * Make sure we do not get stuck with incorrect capability here + * by explicitly testing this. + */ + if (!info.monitor_supported) { + wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor " + "with device_ap_sme since no monitor mode " + "support detected"); + drv->use_monitor = 0; + } } - drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; - drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; - if (info.p2p_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; - drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; - drv->capa.max_remain_on_chan = info.max_remain_on_chan; + /* + * If we aren't going to use monitor interfaces, but the + * driver doesn't support data TX status, we won't get TX + * status for EAPOL frames. + */ + if (!drv->use_monitor && !info.data_tx_status) + drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; return 0; } -static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) +#ifdef ANDROID +static int android_genl_ctrl_resolve(struct nl_handle *handle, + const char *name) { - int ret; - - /* Initialize generic netlink and nl80211 */ + /* + * Android ICS has very minimal genl_ctrl_resolve() implementation, so + * need to work around that. + */ + struct nl_cache *cache = NULL; + struct genl_family *nl80211 = NULL; + int id = -1; - 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; + if (genl_ctrl_alloc_cache(handle, &cache) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " + "netlink cache"); + goto fail; } - drv->nl_handle = nl80211_handle_alloc(drv->nl_cb); - if (drv->nl_handle == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " - "callbacks"); - goto err2; - } + nl80211 = genl_ctrl_search_by_name(cache, name); + if (nl80211 == NULL) + goto fail; - drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb); - if (drv->nl_handle_event == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " - "callbacks (event)"); - goto err2b; - } + id = genl_family_get_id(nl80211); - if (genl_connect(drv->nl_handle)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " - "netlink"); - goto err3; - } +fail: + if (nl80211) + genl_family_put(nl80211); + if (cache) + nl_cache_free(cache); - if (genl_connect(drv->nl_handle_event)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " - "netlink (event)"); - goto err3; - } + return id; +} +#define genl_ctrl_resolve android_genl_ctrl_resolve +#endif /* ANDROID */ -#ifdef CONFIG_LIBNL20 - if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache"); - goto err3; - } - if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) < - 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (event)"); - goto err3b; - } -#else /* CONFIG_LIBNL20 */ - 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->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event); - if (drv->nl_cache_event == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (event)"); - goto err3b; + +static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) +{ + int ret; + + global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (global->nl_cb == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " + "callbacks"); + return -1; } -#endif /* CONFIG_LIBNL20 */ - drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); - if (drv->nl80211 == NULL) { + global->nl = nl_create_handle(global->nl_cb, "nl"); + if (global->nl == NULL) + goto err; + + global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211"); + if (global->nl80211_id < 0) { wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not " "found"); - goto err4; + goto err; } - ret = nl_get_multicast_id(drv, "nl80211", "scan"); + global->nl_event = nl_create_handle(global->nl_cb, "event"); + if (global->nl_event == NULL) + goto err; + + ret = nl_get_multicast_id(global, "nl80211", "scan"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle_event, ret); + ret = nl_socket_add_membership(global->nl_event, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for scan events: %d (%s)", ret, strerror(-ret)); - goto err4; + goto err; } - ret = nl_get_multicast_id(drv, "nl80211", "mlme"); + ret = nl_get_multicast_id(global, "nl80211", "mlme"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle_event, ret); + ret = nl_socket_add_membership(global->nl_event, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for mlme events: %d (%s)", ret, strerror(-ret)); - goto err4; + goto err; } - ret = nl_get_multicast_id(drv, "nl80211", "regulatory"); + ret = nl_get_multicast_id(global, "nl80211", "regulatory"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle_event, ret); + ret = nl_socket_add_membership(global->nl_event, ret); if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " "membership for regulatory events: %d (%s)", @@ -1866,27 +2737,43 @@ static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) /* Continue without regulatory events */ } - eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event), - wpa_driver_nl80211_event_receive, drv, - drv->nl_handle_event); + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_global_event, global); + + eloop_register_read_sock(nl_socket_get_fd(global->nl_event), + wpa_driver_nl80211_event_receive, + global->nl_cb, global->nl_event); return 0; -err4: - nl_cache_free(drv->nl_cache_event); -err3b: - nl_cache_free(drv->nl_cache); -err3: - nl80211_handle_destroy(drv->nl_handle_event); -err2b: - nl80211_handle_destroy(drv->nl_handle); -err2: - nl_cb_put(drv->nl_cb); -err1: +err: + nl_destroy_handles(&global->nl_event); + nl_destroy_handles(&global->nl); + nl_cb_put(global->nl_cb); + global->nl_cb = NULL; return -1; } +static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) +{ + drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!drv->nl_cb) { + wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct"); + return -1; + } + + nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_drv_event, drv); + + return 0; +} + + static void wpa_driver_nl80211_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); @@ -1901,7 +2788,8 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) { struct wpa_driver_nl80211_data *drv = ctx; wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked"); - if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, + drv->first_bss.ifname, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " "after rfkill unblock"); return; @@ -1943,6 +2831,90 @@ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv) } +static void wpa_driver_nl80211_handle_eapol_tx_status(int sock, + void *eloop_ctx, + void *handle) +{ + struct wpa_driver_nl80211_data *drv = eloop_ctx; + u8 data[2048]; + struct msghdr msg; + struct iovec entry; + struct { + struct cmsghdr cm; + char control[512]; + } control; + struct cmsghdr *cmsg; + int res, found_ee = 0, found_wifi = 0, acked = 0; + union wpa_event_data event; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &entry; + msg.msg_iovlen = 1; + entry.iov_base = data; + entry.iov_len = sizeof(data); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + res = recvmsg(sock, &msg, MSG_ERRQUEUE); + /* if error or not fitting 802.3 header, return */ + if (res < 14) + return; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_WIFI_STATUS) { + int *ack; + + found_wifi = 1; + ack = (void *)CMSG_DATA(cmsg); + acked = *ack; + } + + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_TX_TIMESTAMP) { + struct sock_extended_err *err = + (struct sock_extended_err *)CMSG_DATA(cmsg); + + if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS) + found_ee = 1; + } + } + + if (!found_ee || !found_wifi) + return; + + memset(&event, 0, sizeof(event)); + event.eapol_tx_status.dst = data; + event.eapol_tx_status.data = data + 14; + event.eapol_tx_status.data_len = res - 14; + event.eapol_tx_status.ack = acked; + wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event); +} + + +static int nl80211_init_bss(struct i802_bss *bss) +{ + bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!bss->nl_cb) + return -1; + + nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_bss_event, bss); + + return 0; +} + + +static void nl80211_destroy_bss(struct i802_bss *bss) +{ + nl_cb_put(bss->nl_cb); + bss->nl_cb = NULL; +} + + /** * wpa_driver_nl80211_init - Initialize nl80211 driver interface * @ctx: context to be used when calling wpa_supplicant functions, @@ -1955,10 +2927,11 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, void *global_priv) { struct wpa_driver_nl80211_data *drv; - struct netlink_config *cfg; struct rfkill_config *rcfg; struct i802_bss *bss; + if (global_priv == NULL) + return NULL; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) return NULL; @@ -1969,32 +2942,18 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); drv->monitor_ifidx = -1; drv->monitor_sock = -1; - drv->ioctl_sock = -1; + drv->eapol_tx_sock = -1; + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; if (wpa_driver_nl80211_init_nl(drv)) { os_free(drv); return NULL; } - nl80211_get_phy_name(drv); - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket(PF_INET,SOCK_DGRAM)"); + if (nl80211_init_bss(bss)) goto failed; - } - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) - goto failed; - cfg->ctx = drv; - cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; - cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - goto failed; - } + nl80211_get_phy_name(drv); rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL) @@ -2012,32 +2971,46 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, if (wpa_driver_nl80211_finish_drv_init(drv)) goto failed; - if (drv->global) + drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0); + if (drv->eapol_tx_sock < 0) + goto failed; + + if (drv->data_tx_status) { + int enabled = 1; + + if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS, + &enabled, sizeof(enabled)) < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: wifi status sockopt failed\n"); + drv->data_tx_status = 0; + if (!drv->use_monitor) + drv->capa.flags &= + ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + } else { + eloop_register_read_sock(drv->eapol_tx_sock, + wpa_driver_nl80211_handle_eapol_tx_status, + drv, NULL); + } + } + + if (drv->global) { dl_list_add(&drv->global->interfaces, &drv->list); + drv->in_interface_list = 1; + } return bss; failed: - rfkill_deinit(drv->rfkill); - netlink_deinit(drv->netlink); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl80211_handle_destroy(drv->nl_handle); - nl_cb_put(drv->nl_cb); - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); - - os_free(drv); + wpa_driver_nl80211_deinit(bss); return NULL; } -static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv, +static int nl80211_register_frame(struct i802_bss *bss, struct nl_handle *nl_handle, u16 type, const u8 *match, size_t match_len) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; int ret = -1; @@ -2045,14 +3018,18 @@ static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_REGISTER_ACTION, 0); + wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p", + type, nl_handle); + wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match", + match, match_len); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); - ret = send_and_recv(drv, nl_handle, msg, NULL, NULL); + ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Register frame command " @@ -2069,58 +3046,213 @@ nla_put_failure: } -static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv, +static int nl80211_alloc_mgmt_handle(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (bss->nl_mgmt) { + wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting " + "already on! (nl_mgmt=%p)", bss->nl_mgmt); + return -1; + } + + bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt"); + if (bss->nl_mgmt == NULL) + return -1; + + eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt), + wpa_driver_nl80211_event_receive, bss->nl_cb, + bss->nl_mgmt); + + return 0; +} + + +static int nl80211_register_action_frame(struct i802_bss *bss, const u8 *match, size_t match_len) { u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); - return nl80211_register_frame(drv, drv->nl_handle_event, + return nl80211_register_frame(bss, bss->nl_mgmt, type, match, match_len); } -static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv) +static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) { -#ifdef CONFIG_P2P + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP " + "handle %p", bss->nl_mgmt); + +#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) /* GAS Initial Request */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0) return -1; /* GAS Initial Response */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0) return -1; /* GAS Comeback Request */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0) return -1; /* GAS Comeback Response */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0) return -1; +#endif /* CONFIG_P2P || CONFIG_INTERWORKING */ +#ifdef CONFIG_P2P /* P2P Public Action */ - if (nl80211_register_action_frame(drv, + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x09\x50\x6f\x9a\x09", 6) < 0) return -1; /* P2P Action */ - if (nl80211_register_action_frame(drv, + if (nl80211_register_action_frame(bss, (u8 *) "\x7f\x50\x6f\x9a\x09", 5) < 0) return -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211W /* SA Query Response */ - if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0) return -1; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_TDLS + if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) { + /* TDLS Discovery Response */ + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) < + 0) + return -1; + } +#endif /* CONFIG_TDLS */ /* FT Action frames */ - if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) return -1; else drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; + /* WNM - BSS Transition Management Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0) + return -1; + return 0; } +static int nl80211_register_spurious_class3(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 " + "failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) +{ + static const int stypes[] = { + WLAN_FC_STYPE_AUTH, + WLAN_FC_STYPE_ASSOC_REQ, + WLAN_FC_STYPE_REASSOC_REQ, + WLAN_FC_STYPE_DISASSOC, + WLAN_FC_STYPE_DEAUTH, + WLAN_FC_STYPE_ACTION, + WLAN_FC_STYPE_PROBE_REQ, +/* Beacon doesn't work as mac80211 doesn't currently allow + * it, but it wouldn't really be the right thing anyway as + * it isn't per interface ... maybe just dump the scan + * results periodically for OLBC? + */ +// WLAN_FC_STYPE_BEACON, + }; + unsigned int i; + + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP " + "handle %p", bss->nl_mgmt); + + for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { + if (nl80211_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (stypes[i] << 4), + NULL, 0) < 0) { + goto out_err; + } + } + + if (nl80211_register_spurious_class3(bss)) + goto out_err; + + if (nl80211_get_wiphy_data_ap(bss) == NULL) + goto out_err; + + return 0; + +out_err: + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_handles(&bss->nl_mgmt); + return -1; +} + + +static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss) +{ + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP " + "handle %p (device SME)", bss->nl_mgmt); + + if (nl80211_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ACTION << 4), + NULL, 0) < 0) + goto out_err; + + return 0; + +out_err: + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_handles(&bss->nl_mgmt); + return -1; +} + + +static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason) +{ + if (bss->nl_mgmt == NULL) + return; + wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p " + "(%s)", bss->nl_mgmt, reason); + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_handles(&bss->nl_mgmt); + + nl80211_put_wiphy_data_ap(bss); +} + + static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx) { wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); @@ -2137,12 +3269,19 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) drv->first_bss.ifindex = drv->ifindex; #ifndef HOSTAPD - if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) { - wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " + /* + * Make sure the interface starts up in station mode unless this is a + * dynamically added interface (e.g., P2P) that was already configured + * with proper iftype. + */ + if (drv->ifindex != drv->global->if_add_ifindex && + wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to " "use managed mode"); + return -1; } - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { if (rfkill_is_blocked(drv->rfkill)) { wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " "interface '%s' due to rfkill", @@ -2156,26 +3295,17 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) } } - netlink_send_oper_ifla(drv->netlink, drv->ifindex, + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT); #endif /* HOSTAPD */ if (wpa_driver_nl80211_capa(drv)) return -1; - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr)) + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + bss->addr)) return -1; - if (nl80211_register_action_frames(drv) < 0) { - wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " - "frame processing - ignore for now"); - /* - * Older kernel versions did not support this, so ignore the - * error for now. Some functionality may not be available - * because of this. - */ - } - if (send_rfkill_event) { eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, drv, drv->ctx); @@ -2193,12 +3323,12 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_BEACON, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -2215,17 +3345,22 @@ static void wpa_driver_nl80211_deinit(void *priv) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nl_handle_preq) + if (drv->data_tx_status) + eloop_unregister_read_sock(drv->eapol_tx_sock); + if (drv->eapol_tx_sock >= 0) + close(drv->eapol_tx_sock); + + if (bss->nl_preq) wpa_driver_nl80211_probe_req_report(bss, 0); if (bss->added_if_into_bridge) { - if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname) - < 0) + if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, + bss->ifname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { - if (linux_br_del(drv->ioctl_sock, bss->brname) < 0) + if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); @@ -2233,7 +3368,7 @@ static void wpa_driver_nl80211_deinit(void *priv) nl80211_remove_monitor_interface(drv); - if (drv->nlmode == NL80211_IFTYPE_AP) + if (is_ap_interface(drv->nlmode)) wpa_driver_nl80211_del_beacon(drv); #ifdef HOSTAPD @@ -2254,32 +3389,28 @@ static void wpa_driver_nl80211_deinit(void *priv) os_free(drv->if_indices); #endif /* HOSTAPD */ - if (drv->disable_11b_rates) + if (drv->disabled_11b_rates) nl80211_disable_11b_rates(drv, drv->ifindex, 0); - netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); - netlink_deinit(drv->netlink); + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, + IF_OPER_UP); rfkill_deinit(drv->rfkill); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); - wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA); - - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); + (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); + wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION); + nl80211_mgmt_unsubscribe(bss, "deinit"); - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl_cache_free(drv->nl_cache_event); - nl80211_handle_destroy(drv->nl_handle); - nl80211_handle_destroy(drv->nl_handle_event); nl_cb_put(drv->nl_cb); + nl80211_destroy_bss(&drv->first_bss); + os_free(drv->filter_ssids); - if (drv->global) + os_free(drv->auth_ie); + + if (drv->in_interface_list) dl_list_del(&drv->list); os_free(drv); @@ -2297,10 +3428,10 @@ static void wpa_driver_nl80211_deinit(void *priv) static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_nl80211_data *drv = eloop_ctx; - if (drv->ap_scan_as_station) { + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { wpa_driver_nl80211_set_mode(&drv->first_bss, - IEEE80211_MODE_AP); - drv->ap_scan_as_station = 0; + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); @@ -2319,16 +3450,20 @@ static int wpa_driver_nl80211_scan(void *priv, struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; int ret = 0, timeout; - struct nl_msg *msg, *ssids, *freqs; + struct nl_msg *msg, *ssids, *freqs, *rates; size_t i; + drv->scan_for_auth = 0; + msg = nlmsg_alloc(); ssids = nlmsg_alloc(); freqs = nlmsg_alloc(); - if (!msg || !ssids || !freqs) { + rates = nlmsg_alloc(); + if (!msg || !ssids || !freqs || !rates) { nlmsg_free(msg); nlmsg_free(ssids); nlmsg_free(freqs); + nlmsg_free(rates); return -1; } @@ -2337,8 +3472,7 @@ static int wpa_driver_nl80211_scan(void *priv, params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_TRIGGER_SCAN, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); @@ -2353,8 +3487,8 @@ static int wpa_driver_nl80211_scan(void *priv, nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); if (params->extra_ies) { - wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs", - params->extra_ies, params->extra_ies_len); + wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", + params->extra_ies, params->extra_ies_len); NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies); } @@ -2368,29 +3502,42 @@ static int wpa_driver_nl80211_scan(void *priv, nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } + if (params->p2p_probe) { + /* + * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates + * by masking out everything else apart from the OFDM rates 6, + * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz + * rates are left enabled. + */ + NLA_PUT(rates, NL80211_BAND_2GHZ, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates); + + NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); + } + 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)); #ifdef HOSTAPD - if (drv->nlmode == NL80211_IFTYPE_AP) { + if (is_ap_interface(drv->nlmode)) { /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ - if (wpa_driver_nl80211_set_mode(bss, - IEEE80211_MODE_INFRA)) + if (wpa_driver_nl80211_set_mode( + bss, NL80211_IFTYPE_STATION)) goto nla_put_failure; if (wpa_driver_nl80211_scan(drv, params)) { - wpa_driver_nl80211_set_mode(bss, - IEEE80211_MODE_AP); + wpa_driver_nl80211_set_mode(bss, drv->nlmode); goto nla_put_failure; } /* Restore AP mode when processing scan results */ - drv->ap_scan_as_station = 1; + drv->ap_scan_as_station = drv->nlmode; ret = 0; } else goto nla_put_failure; @@ -2420,6 +3567,165 @@ nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); nlmsg_free(freqs); + nlmsg_free(rates); + return ret; +} + + +/** + * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() + * @params: Scan parameters + * @interval: Interval between scan cycles in milliseconds + * Returns: 0 on success, -1 on failure or if not supported + */ +static int wpa_driver_nl80211_sched_scan(void *priv, + struct wpa_driver_scan_params *params, + u32 interval) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = 0; + struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets; + size_t i; + +#ifdef ANDROID + if (!drv->capa.sched_scan_supported) + return android_pno_start(bss, params); +#endif /* ANDROID */ + + msg = nlmsg_alloc(); + ssids = nlmsg_alloc(); + freqs = nlmsg_alloc(); + if (!msg || !ssids || !freqs) { + nlmsg_free(msg); + nlmsg_free(ssids); + nlmsg_free(freqs); + return -1; + } + + os_free(drv->filter_ssids); + drv->filter_ssids = params->filter_ssids; + params->filter_ssids = NULL; + drv->num_filter_ssids = params->num_filter_ssids; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval); + + if (drv->num_filter_ssids && + (int) drv->num_filter_ssids <= drv->capa.max_match_sets) { + match_sets = nlmsg_alloc(); + + for (i = 0; i < drv->num_filter_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, + "nl80211: Sched scan filter SSID", + drv->filter_ssids[i].ssid, + drv->filter_ssids[i].ssid_len); + + match_set_ssid = nlmsg_alloc(); + nla_put(match_set_ssid, + NL80211_ATTR_SCHED_SCAN_MATCH_SSID, + drv->filter_ssids[i].ssid_len, + drv->filter_ssids[i].ssid); + + nla_put_nested(match_sets, i + 1, match_set_ssid); + + nlmsg_free(match_set_ssid); + } + + nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, + match_sets); + nlmsg_free(match_sets); + } + + for (i = 0; i < params->num_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, + params->ssids[i].ssid); + } + if (params->num_ssids) + nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); + + if (params->extra_ies) { + wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs", + params->extra_ies, params->extra_ies_len); + NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, + params->extra_ies); + } + + if (params->freqs) { + for (i = 0; params->freqs[i]; i++) { + wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " + "MHz", params->freqs[i]); + NLA_PUT_U32(freqs, i + 1, params->freqs[i]); + } + nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + + /* TODO: if we get an error here, we should fall back to normal scan */ + + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: " + "ret=%d (%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - " + "scan interval %d msec", ret, interval); + +nla_put_failure: + nlmsg_free(ssids); + nlmsg_free(msg); + nlmsg_free(freqs); + return ret; +} + + +/** + * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() + * Returns: 0 on success, -1 on failure or if not supported + */ +static int wpa_driver_nl80211_stop_sched_scan(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = 0; + struct nl_msg *msg; + +#ifdef ANDROID + if (!drv->capa.sched_scan_supported) + return android_pno_stop(bss); +#endif /* ANDROID */ + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: " + "ret=%d (%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret); + +nla_put_failure: + nlmsg_free(msg); return ret; } @@ -2514,6 +3820,13 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz", _arg->assoc_freq); } + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_BSSID]) { + os_memcpy(_arg->assoc_bssid, + nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: Associated with " + MACSTR, MAC2STR(_arg->assoc_bssid)); + } } if (!res) return NL_SKIP; @@ -2555,7 +3868,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); - r->flags |= WPA_SCAN_LEVEL_INVALID; + r->flags |= WPA_SCAN_QUAL_INVALID; } else r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; if (bss[NL80211_BSS_TSF]) @@ -2657,7 +3970,7 @@ static void wpa_driver_nl80211_check_bss_status( "indicates BSS status with " MACSTR " as authenticated", MAC2STR(r->bssid)); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != 0) { @@ -2675,13 +3988,13 @@ static void wpa_driver_nl80211_check_bss_status( "indicate BSS status with " MACSTR " as associated", MAC2STR(r->bssid)); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && !drv->associated) { wpa_printf(MSG_DEBUG, "nl80211: Local state " "(not associated) does not match " "with BSS state"); clear_state_mismatch(drv, r->bssid); - } else if (drv->nlmode == NL80211_IFTYPE_STATION && + } else if (is_sta_interface(drv->nlmode) && os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "nl80211: Local state " @@ -2696,20 +4009,6 @@ static void wpa_driver_nl80211_check_bss_status( } -static void wpa_scan_results_free(struct wpa_scan_results *res) -{ - size_t i; - - if (res == NULL) - return; - - for (i = 0; i < res->num; i++) - os_free(res->res[i]); - os_free(res->res); - os_free(res); -} - - static struct wpa_scan_results * nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) { @@ -2725,8 +4024,7 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) 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); + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; @@ -2734,8 +4032,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { - wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)", - (unsigned long) res->num); + wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu " + "BSSes)", (unsigned long) res->num); + nl80211_get_noise_for_scan_results(drv, res); return res; } wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " @@ -2806,17 +4105,19 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, "set_tx=%d seq_len=%lu key_len=%lu", __func__, ifindex, alg, addr, key_idx, set_tx, (unsigned long) seq_len, (unsigned long) key_len); +#ifdef CONFIG_TDLS + if (key_idx == -1) + key_idx = 0; +#endif /* CONFIG_TDLS */ msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (alg == WPA_ALG_NONE) { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY); } else { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); switch (alg) { case WPA_ALG_WEP: @@ -2889,7 +4190,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, */ if (ret || !set_tx || alg == WPA_ALG_NONE) return ret; - if (drv->nlmode == NL80211_IFTYPE_AP && addr && + if (is_ap_interface(drv->nlmode) && addr && !is_broadcast_ether_addr(addr)) return ret; @@ -2897,8 +4198,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (alg == WPA_ALG_IGTK) @@ -2940,6 +4240,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, return ret; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -3069,7 +4370,7 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0); + nl80211_cmd(drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); @@ -3080,8 +4381,9 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " - "(%s)", ret, strerror(-ret)); + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: MLME command failed: reason=%u ret=%d (%s)", + reason_code, ret, strerror(-ret)); goto nla_put_failure; } ret = 0; @@ -3134,6 +4436,52 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr, } +static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_auth_params *params) +{ + int i; + + drv->auth_freq = params->freq; + drv->auth_alg = params->auth_alg; + drv->auth_wep_tx_keyidx = params->wep_tx_keyidx; + drv->auth_local_state_change = params->local_state_change; + drv->auth_p2p = params->p2p; + + if (params->bssid) + os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN); + else + os_memset(drv->auth_bssid_, 0, ETH_ALEN); + + if (params->ssid) { + os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len); + drv->auth_ssid_len = params->ssid_len; + } else + drv->auth_ssid_len = 0; + + + os_free(drv->auth_ie); + drv->auth_ie = NULL; + drv->auth_ie_len = 0; + if (params->ie) { + drv->auth_ie = os_malloc(params->ie_len); + if (drv->auth_ie) { + os_memcpy(drv->auth_ie, params->ie, params->ie_len); + drv->auth_ie_len = params->ie_len; + } + } + + for (i = 0; i < 4; i++) { + if (params->wep_key[i] && params->wep_key_len[i] && + params->wep_key_len[i] <= 16) { + os_memcpy(drv->auth_wep_key[i], params->wep_key[i], + params->wep_key_len[i]); + drv->auth_wep_key_len[i] = params->wep_key_len[i]; + } else + drv->auth_wep_key_len[i] = 0; + } +} + + static int wpa_driver_nl80211_authenticate( void *priv, struct wpa_driver_auth_params *params) { @@ -3142,13 +4490,20 @@ static int wpa_driver_nl80211_authenticate( int ret = -1, i; struct nl_msg *msg; enum nl80211_auth_type type; + enum nl80211_iftype nlmode; int count = 0; + int is_retry; + + is_retry = drv->retry_auth; + drv->retry_auth = 0; drv->associated = 0; os_memset(drv->auth_bssid, 0, ETH_ALEN); /* FIX: IBSS mode */ - if (drv->nlmode != NL80211_IFTYPE_STATION && - wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0) + nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + if (drv->nlmode != nlmode && + wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; retry: @@ -3159,8 +4514,7 @@ retry: wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)", drv->ifindex); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_AUTHENTICATE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE); for (i = 0; i < 4; i++) { if (!params->wep_key[i]) @@ -3218,8 +4572,9 @@ retry: ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " - "(%s)", ret, strerror(-ret)); + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: MLME command failed (auth): ret=%d (%s)", + ret, strerror(-ret)); count++; if (ret == -EALREADY && count == 1 && params->bssid && !params->local_state_change) { @@ -3236,6 +4591,49 @@ retry: nlmsg_free(msg); goto retry; } + + if (ret == -ENOENT && params->freq && !is_retry) { + /* + * cfg80211 has likely expired the BSS entry even + * though it was previously available in our internal + * BSS table. To recover quickly, start a single + * channel scan on the specified channel. + */ + struct wpa_driver_scan_params scan; + int freqs[2]; + + os_memset(&scan, 0, sizeof(scan)); + scan.num_ssids = 1; + if (params->ssid) { + scan.ssids[0].ssid = params->ssid; + scan.ssids[0].ssid_len = params->ssid_len; + } + freqs[0] = params->freq; + freqs[1] = 0; + scan.freqs = freqs; + wpa_printf(MSG_DEBUG, "nl80211: Trigger single " + "channel scan to refresh cfg80211 BSS " + "entry"); + ret = wpa_driver_nl80211_scan(bss, &scan); + if (ret == 0) { + nl80211_copy_auth_params(drv, params); + drv->scan_for_auth = 1; + } + } else if (is_retry) { + /* + * Need to indicate this with an event since the return + * value from the retry is not delivered to core code. + */ + union wpa_event_data event; + wpa_printf(MSG_DEBUG, "nl80211: Authentication retry " + "failed"); + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.timeout_event.addr, drv->auth_bssid_, + ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT, + &event); + } + goto nla_put_failure; } ret = 0; @@ -3248,6 +4646,45 @@ nla_put_failure: } +static int wpa_driver_nl80211_authenticate_retry( + struct wpa_driver_nl80211_data *drv) +{ + struct wpa_driver_auth_params params; + struct i802_bss *bss = &drv->first_bss; + int i; + + wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again"); + + os_memset(¶ms, 0, sizeof(params)); + params.freq = drv->auth_freq; + params.auth_alg = drv->auth_alg; + params.wep_tx_keyidx = drv->auth_wep_tx_keyidx; + params.local_state_change = drv->auth_local_state_change; + params.p2p = drv->auth_p2p; + + if (!is_zero_ether_addr(drv->auth_bssid_)) + params.bssid = drv->auth_bssid_; + + if (drv->auth_ssid_len) { + params.ssid = drv->auth_ssid; + params.ssid_len = drv->auth_ssid_len; + } + + params.ie = drv->auth_ie; + params.ie_len = drv->auth_ie_len; + + for (i = 0; i < 4; i++) { + if (drv->auth_wep_key_len[i]) { + params.wep_key[i] = drv->auth_wep_key[i]; + params.wep_key_len[i] = drv->auth_wep_key_len[i]; + } + } + + drv->retry_auth = 1; + return wpa_driver_nl80211_authenticate(bss, ¶ms); +} + + struct phy_info_arg { u16 *num_modes; struct hostapd_hw_modes *modes; @@ -3300,6 +4737,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) mode = &phy_info->modes[*(phy_info->num_modes)]; memset(mode, 0, sizeof(*mode)); + mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN; *(phy_info->num_modes) += 1; nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), @@ -3640,8 +5078,7 @@ static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_REG, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); return send_and_recv_msgs(drv, msg, nl80211_get_reg, results); } @@ -3664,8 +5101,7 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) if (!msg) return NULL; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); @@ -3673,14 +5109,16 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) nl80211_set_ht40_flags(drv, &result); return wpa_driver_nl80211_add_11b(result.modes, num_modes); } + msg = NULL; nla_put_failure: + nlmsg_free(msg); return NULL; } -static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, - const void *data, size_t len, - int encrypt) +static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv, + const void *data, size_t len, + int encrypt, int noack) { __u8 rtap_hdr[] = { 0x00, 0x00, /* radiotap version */ @@ -3711,6 +5149,7 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, .msg_flags = 0, }; int res; + u16 txflags = 0; if (encrypt) rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; @@ -3721,6 +5160,10 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, return -1; } + if (noack) + txflags |= IEEE80211_RADIOTAP_F_TX_NOACK; + *(le16 *) &rtap_hdr[12] = host_to_le16(txflags); + res = sendmsg(drv->monitor_sock, &msg, 0); if (res < 0) { wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno)); @@ -3730,8 +5173,24 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, } +static int wpa_driver_nl80211_send_frame(struct i802_bss *bss, + const void *data, size_t len, + int encrypt, int noack) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + u64 cookie; + + if (drv->use_monitor) + return wpa_driver_nl80211_send_mntr(drv, data, len, + encrypt, noack); + + return nl80211_send_frame_cmd(bss, bss->freq, 0, data, len, + &cookie, 0, noack, 0); +} + + static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, - size_t data_len) + size_t data_len, int noack) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -3741,7 +5200,8 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); - if (drv->nlmode == NL80211_IFTYPE_STATION && + + if (is_sta_interface(drv->nlmode) && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { /* @@ -3749,19 +5209,21 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, * but it works due to the single-threaded nature * of wpa_supplicant. */ - return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0, - data, data_len, NULL); + return nl80211_send_frame_cmd(bss, drv->last_mgmt_freq, 0, + data, data_len, NULL, 1, noack, + 1); } -#ifdef ANDROID_BRCM_P2P_PATCH - if (drv->nlmode == NL80211_IFTYPE_AP) { - wpa_printf(MSG_DEBUG, "%s: Sending frame on ap_oper_freq %d using nl80211_send_frame_cmd", __func__, drv->ap_oper_freq); - return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0, - data, data_len, &drv->send_action_cookie); +#ifdef ANDROID_P2P + if (is_ap_interface(drv->nlmode)) { + return nl80211_send_frame_cmd(bss, bss->freq, 0, + data, data_len, &drv->send_action_cookie, 0, noack, 1); } #else - if (drv->no_monitor_iface_capab && drv->nlmode == NL80211_IFTYPE_AP ) { - return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0, - data, data_len, NULL); + + if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { + return nl80211_send_frame_cmd(bss, bss->freq, 0, + data, data_len, NULL, + 0, noack, 0); } #endif if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && @@ -3777,15 +5239,59 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) encrypt = 0; } - wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/l2 socket", __func__); - return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); + + return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, + noack); } -static int wpa_driver_nl80211_set_beacon(void *priv, - const u8 *head, size_t head_len, - const u8 *tail, size_t tail_len, - int dtim_period, int beacon_int) +static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble, + int slot, int ht_opmode, int ap_isolate, + int *basic_rates) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); + + if (cts >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); + if (preamble >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); + if (slot >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); + if (ht_opmode >= 0) + NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); + if (ap_isolate >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate); + + if (basic_rates) { + u8 rates[NL80211_MAX_SUPP_RATES]; + u8 rates_len = 0; + int i; + + for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; + i++) + rates[rates_len++] = basic_rates[i] / 5; + + NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int wpa_driver_nl80211_set_ap(void *priv, + struct wpa_driver_ap_params *params) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -3794,6 +5300,10 @@ static int wpa_driver_nl80211_set_beacon(void *priv, int ret; int beacon_set; int ifindex = if_nametoindex(bss->ifname); + int num_suites; + u32 suites[10]; + u32 ver; + beacon_set = bss->beacon_set; msg = nlmsg_alloc(); @@ -3805,13 +5315,112 @@ static int wpa_driver_nl80211_set_beacon(void *priv, if (beacon_set) cmd = NL80211_CMD_SET_BEACON; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, cmd, 0); - NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); - NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); + nl80211_cmd(drv, msg, 0, cmd); + NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head); + NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int); - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int); + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->proberesp && params->proberesp_len) + NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len, + params->proberesp); + switch (params->hide_ssid) { + case NO_SSID_HIDING: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_NOT_IN_USE); + break; + case HIDDEN_SSID_ZERO_LEN: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_LEN); + break; + case HIDDEN_SSID_ZERO_CONTENTS: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_CONTENTS); + break; + } + if (params->privacy) + NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); + if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == + (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { + /* Leave out the attribute */ + } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_SHARED_KEY); + else + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_OPEN_SYSTEM); + + ver = 0; + if (params->wpa_version & WPA_PROTO_WPA) + ver |= NL80211_WPA_VERSION_1; + if (params->wpa_version & WPA_PROTO_RSN) + ver |= NL80211_WPA_VERSION_2; + if (ver) + NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); + + num_suites = 0; + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X) + suites[num_suites++] = WLAN_AKM_SUITE_8021X; + if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK) + suites[num_suites++] = WLAN_AKM_SUITE_PSK; + if (num_suites) { + NLA_PUT(msg, NL80211_ATTR_AKM_SUITES, + num_suites * sizeof(u32), suites); + } + + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X && + params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); + + num_suites = 0; + if (params->pairwise_ciphers & WPA_CIPHER_CCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; + if (params->pairwise_ciphers & WPA_CIPHER_TKIP) + suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; + if (params->pairwise_ciphers & WPA_CIPHER_WEP104) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; + if (params->pairwise_ciphers & WPA_CIPHER_WEP40) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + if (num_suites) { + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + num_suites * sizeof(u32), suites); + } + + switch (params->group_cipher) { + case WPA_CIPHER_CCMP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_CCMP); + break; + case WPA_CIPHER_TKIP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_TKIP); + break; + case WPA_CIPHER_WEP104: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_WEP104); + break; + case WPA_CIPHER_WEP40: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_WEP40); + break; + } + + if (params->beacon_ies) { + NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies), + wpabuf_head(params->beacon_ies)); + } + if (params->proberesp_ies) { + NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP, + wpabuf_len(params->proberesp_ies), + wpabuf_head(params->proberesp_ies)); + } + if (params->assocresp_ies) { + NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP, + wpabuf_len(params->assocresp_ies), + wpabuf_head(params->assocresp_ies)); + } ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { @@ -3819,29 +5428,36 @@ static int wpa_driver_nl80211_set_beacon(void *priv, ret, strerror(-ret)); } else { bss->beacon_set = 1; + nl80211_set_bss(bss, params->cts_protect, params->preamble, + params->short_slot_time, params->ht_opmode, + params->isolate, params->basic_rates); } -#if defined(ANDROID_BRCM_P2P_PATCH) && defined(HOSTAPD) +#if defined(ANDROID_P2P) && defined(HOSTAPD) wpa_driver_nl80211_probe_req_report(priv, 1); #endif return ret; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } -static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, +static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, int freq, int ht_enabled, int sec_channel_offset) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; int ret; + wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d " + "sec_channel_offset=%d)", + freq, ht_enabled, sec_channel_offset); msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); @@ -3856,7 +5472,7 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, NL80211_CHAN_HT40PLUS); break; default: -#ifndef ANDROID_BRCM_P2P_PATCH +#ifndef ANDROID_P2P /* Should be change to HT20 as a default value because P2P firmware does not support 11n for BCM4329 */ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); @@ -3869,50 +5485,102 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, } ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == 0) + msg = NULL; + if (ret == 0) { + bss->freq = freq; return 0; + } wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): " "%d (%s)", freq, ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } +static u32 sta_flags_nl80211(int flags) +{ + u32 f = 0; + + if (flags & WPA_STA_AUTHORIZED) + f |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (flags & WPA_STA_WMM) + f |= BIT(NL80211_STA_FLAG_WME); + if (flags & WPA_STA_SHORT_PREAMBLE) + f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (flags & WPA_STA_MFP) + f |= BIT(NL80211_STA_FLAG_MFP); + if (flags & WPA_STA_TDLS_PEER) + f |= BIT(NL80211_STA_FLAG_TDLS_PEER); + + return f; +} + + static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params *params) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; + struct nl_msg *msg, *wme = NULL; + struct nl80211_sta_flag_update upd; int ret = -ENOBUFS; + if ((params->flags & WPA_STA_TDLS_PEER) && + !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + 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); + nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION : + NL80211_CMD_NEW_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, params->supp_rates); - NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, - params->listen_interval); + if (!params->set) { + NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); + NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, + params->listen_interval); + } if (params->ht_capabilities) { NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sizeof(*params->ht_capabilities), params->ht_capabilities); } + os_memset(&upd, 0, sizeof(upd)); + upd.mask = sta_flags_nl80211(params->flags); + upd.set = upd.mask; + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + if (params->flags & WPA_STA_WMM) { + wme = nlmsg_alloc(); + if (!wme) + goto nla_put_failure; + + NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES, + params->qosinfo & WMM_QOSINFO_STA_AC_MASK); + NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP, + (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) & + WMM_QOSINFO_STA_SP_MASK); + nla_put_nested(msg, NL80211_ATTR_STA_WME, wme); + } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret) - wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION " - "result: %d (%s)", ret, strerror(-ret)); + wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION " + "result: %d (%s)", params->set ? "SET" : "NEW", ret, + strerror(-ret)); if (ret == -EEXIST) ret = 0; nla_put_failure: + nlmsg_free(wme); + nlmsg_free(msg); return ret; } @@ -3928,8 +5596,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr) if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -3940,6 +5607,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr) return 0; return ret; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -3951,26 +5619,46 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx); -#ifdef HOSTAPD /* stop listening for EAPOL on this interface */ del_ifidx(drv, ifidx); -#endif /* HOSTAPD */ 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); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return; + msg = NULL; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); } +static const char * nl80211_iftype_str(enum nl80211_iftype mode) +{ + switch (mode) { + case NL80211_IFTYPE_ADHOC: + return "ADHOC"; + case NL80211_IFTYPE_STATION: + return "STATION"; + case NL80211_IFTYPE_AP: + return "AP"; + case NL80211_IFTYPE_MONITOR: + return "MONITOR"; + case NL80211_IFTYPE_P2P_CLIENT: + return "P2P_CLIENT"; + case NL80211_IFTYPE_P2P_GO: + return "P2P_GO"; + default: + return "unknown"; + } +} + + static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, const char *ifname, enum nl80211_iftype iftype, @@ -3980,12 +5668,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, int ifidx; int ret = -ENOBUFS; + wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)", + iftype, nl80211_iftype_str(iftype)); + 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); + nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); @@ -4010,8 +5700,10 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, } ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret) { nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", ifname, ret, strerror(-ret)); return ret; @@ -4024,13 +5716,11 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, if (ifidx <= 0) return -1; -#ifdef HOSTAPD /* start listening for EAPOL on this interface */ add_ifidx(drv, ifidx); -#endif /* HOSTAPD */ if (addr && iftype != NL80211_IFTYPE_MONITOR && - linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) { + linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) { nl80211_remove_iface(drv, ifidx); return -1; } @@ -4047,7 +5737,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds); - /* if error occured and interface exists already */ + /* if error occurred and interface exists already */ if (ret == -ENFILE && if_nametoindex(ifname)) { wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); @@ -4059,7 +5749,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, wds); } - if (ret >= 0 && drv->disable_11b_rates) + if (ret >= 0 && is_p2p_interface(iftype)) nl80211_disable_11b_rates(drv, ret, 1); return ret; @@ -4089,10 +5779,20 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) static void from_unknown_sta(struct wpa_driver_nl80211_data *drv, u8 *buf, size_t len) { + struct ieee80211_hdr *hdr = (void *)buf; + u16 fc; union wpa_event_data event; + + if (len < sizeof(*hdr)) + return; + + fc = le_to_host16(hdr->frame_control); + os_memset(&event, 0, sizeof(event)); - event.rx_from_unknown.frame = buf; - event.rx_from_unknown.len = len; + event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); + event.rx_from_unknown.addr = hdr->addr2; + event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) == + (WLAN_FC_FROMDS | WLAN_FC_TODS); wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); } @@ -4350,6 +6050,10 @@ static int add_monitor_filter(int s) static void nl80211_remove_monitor_interface( struct wpa_driver_nl80211_data *drv) { + drv->monitor_refcount--; + if (drv->monitor_refcount > 0) + return; + if (drv->monitor_ifidx >= 0) { nl80211_remove_iface(drv, drv->monitor_ifidx); drv->monitor_ifidx = -1; @@ -4369,11 +6073,25 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) struct sockaddr_ll ll; int optval; socklen_t optlen; -#ifdef ANDROID_BRCM_P2P_PATCH - snprintf(buf, IFNAMSIZ, "%s%s", WPA_MONITOR_IFNAME_PREFIX, drv->first_bss.ifname); -#else - snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); -#endif + + if (drv->monitor_ifidx >= 0) { + drv->monitor_refcount++; + return 0; + } + + if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) { + /* + * P2P interface name is of the format p2p-%s-%d. For monitor + * interface name corresponding to P2P GO, replace "p2p-" with + * "mon-" to retain the same interface name length and to + * indicate that it is a monitor interface. + */ + snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4); + } else { + /* Non-P2P interface with AP functionality. */ + snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); + } + buf[IFNAMSIZ - 1] = '\0'; drv->monitor_ifidx = @@ -4381,15 +6099,21 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) 0); if (drv->monitor_ifidx == -EOPNOTSUPP) { + /* + * This is backward compatibility for a few versions of + * the kernel only that didn't advertise the right + * attributes for the only driver that then supported + * AP mode w/o monitor -- ath6kl. + */ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support " "monitor interface type - try to run without it"); - drv->no_monitor_iface_capab = 1; + drv->device_ap_sme = 1; } if (drv->monitor_ifidx < 0) return -1; - if (linux_set_iface_flags(drv->ioctl_sock, buf, 1)) + if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1)) goto error; memset(&ll, 0, sizeof(ll)); @@ -4433,6 +6157,98 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) } +static int nl80211_setup_ap(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + + wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d " + "use_monitor=%d", drv->device_ap_sme, drv->use_monitor); + + /* + * Disable Probe Request reporting unless we need it in this way for + * devices that include the AP SME, in the other case (unless using + * monitor iface) we'll get it through the nl_mgmt socket instead. + */ + if (!drv->device_ap_sme) + wpa_driver_nl80211_probe_req_report(bss, 0); + + if (!drv->device_ap_sme && !drv->use_monitor) + if (nl80211_mgmt_subscribe_ap(bss)) + return -1; + + if (drv->device_ap_sme && !drv->use_monitor) + if (nl80211_mgmt_subscribe_ap_dev_sme(bss)) + return -1; + + if (!drv->device_ap_sme && drv->use_monitor && + nl80211_create_monitor_interface(drv) && + !drv->device_ap_sme) + return -1; + + if (drv->device_ap_sme && + wpa_driver_nl80211_probe_req_report(bss, 1) < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to enable " + "Probe Request frame reporting in AP mode"); + /* Try to survive without this */ + } + +#ifdef ANDROID_P2P + /* For AP mode, enable probe req report even if device_ap_sme + * is not enabled + */ + wpa_printf(MSG_DEBUG, "nl80211: Enabling probe req report"); + wpa_driver_nl80211_probe_req_report(bss, 1); +#endif + + return 0; +} + + +static void nl80211_teardown_ap(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (drv->device_ap_sme) { + wpa_driver_nl80211_probe_req_report(bss, 0); + if (!drv->use_monitor) + nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)"); + } else if (drv->use_monitor) + nl80211_remove_monitor_interface(drv); + else + nl80211_mgmt_unsubscribe(bss, "AP teardown"); + + bss->beacon_set = 0; +} + + +static int nl80211_send_eapol_data(struct i802_bss *bss, + const u8 *addr, const u8 *data, + size_t data_len) +{ + struct sockaddr_ll ll; + int ret; + + if (bss->drv->eapol_tx_sock < 0) { + wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL"); + return -1; + } + + os_memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + ll.sll_ifindex = bss->ifindex; + ll.sll_protocol = htons(ETH_P_PAE); + ll.sll_halen = ETH_ALEN; + os_memcpy(ll.sll_addr, addr, ETH_ALEN); + ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0, + (struct sockaddr *) &ll, sizeof(ll)); + if (ret < 0) + wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s", + strerror(errno)); + + return ret; +} + + static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; static int wpa_driver_nl80211_hapd_send_eapol( @@ -4447,6 +6263,9 @@ static int wpa_driver_nl80211_hapd_send_eapol( int res; int qos = flags & WPA_STA_WMM; + if (drv->device_ap_sme || !drv->use_monitor) + return nl80211_send_eapol_data(bss, addr, data, data_len); + len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + data_len; hdr = os_zalloc(len); @@ -4484,7 +6303,7 @@ static int wpa_driver_nl80211_hapd_send_eapol( pos += 2; memcpy(pos, data, data_len); - res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt); + res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0); if (res < 0) { wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " "failed: %d (%s)", @@ -4496,23 +6315,6 @@ static int wpa_driver_nl80211_hapd_send_eapol( } -static u32 sta_flags_nl80211(int flags) -{ - u32 f = 0; - - if (flags & WPA_STA_AUTHORIZED) - f |= BIT(NL80211_STA_FLAG_AUTHORIZED); - if (flags & WPA_STA_WMM) - f |= BIT(NL80211_STA_FLAG_WME); - if (flags & WPA_STA_SHORT_PREAMBLE) - f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); - if (flags & WPA_STA_MFP) - f |= BIT(NL80211_STA_FLAG_MFP); - - return f; -} - - static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, int flags_and) @@ -4532,8 +6334,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, return -ENOMEM; } - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -4555,6 +6356,9 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, if (total_flags & WPA_STA_MFP) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); + if (total_flags & WPA_STA_TDLS_PEER) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER); + if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) goto nla_put_failure; @@ -4567,6 +6371,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); nlmsg_free(flags); return -ENOBUFS; } @@ -4575,20 +6380,21 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) { - if (params->p2p) + enum nl80211_iftype nlmode; + + if (params->p2p) { wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P " "group (GO)"); - if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) || - wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) { + nlmode = NL80211_IFTYPE_P2P_GO; + } else + nlmode = NL80211_IFTYPE_AP; + + if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) || + wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) { nl80211_remove_monitor_interface(drv); return -1; } - /* TODO: setup monitor interface (and add code somewhere to remove this - * when AP mode is stopped; associate with mode != 2 or drv_deinit) */ - wpa_printf(MSG_DEBUG, "nl80211: Update ap_oper_freq with params->freq %d", params->freq); - drv->ap_oper_freq = params->freq; - return 0; } @@ -4602,8 +6408,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv) if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_LEAVE_IBSS, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; @@ -4631,7 +6436,8 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); - if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) { + if (wpa_driver_nl80211_set_mode(&drv->first_bss, + NL80211_IFTYPE_ADHOC)) { wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " "IBSS mode"); return -1; @@ -4642,8 +6448,7 @@ retry: if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_JOIN_IBSS, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid)) @@ -4696,6 +6501,55 @@ nla_put_failure: } +static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv, + u8 *bssid) +{ + struct nl_msg *msg; + int ret; + struct nl80211_bss_info_arg arg; + + os_memset(&arg, 0, sizeof(arg)); + msg = nlmsg_alloc(); + if (!msg) + goto nla_put_failure; + + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + arg.drv = drv; + ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + msg = NULL; + if (ret == 0) { + if (is_zero_ether_addr(arg.assoc_bssid)) + return -ENOTCONN; + os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN); + return 0; + } + wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " + "(%s)", ret, strerror(-ret)); +nla_put_failure: + nlmsg_free(msg); + return drv->assoc_freq; +} + + +static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv, + const u8 *bssid) +{ + u8 addr[ETH_ALEN]; + + if (bssid == NULL) { + int res = nl80211_get_assoc_bssid(drv, addr); + if (res) + return res; + bssid = addr; + } + + return wpa_driver_nl80211_disconnect(drv, bssid, + WLAN_REASON_PREV_AUTH_NOT_VALID); +} + + static int wpa_driver_nl80211_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) @@ -4710,8 +6564,7 @@ static int wpa_driver_nl80211_connect( return -1; wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_CONNECT, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { @@ -4766,15 +6619,15 @@ static int wpa_driver_nl80211_connect( NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); skip_auth_type: - if (params->wpa_ie && params->wpa_ie_len) { - enum nl80211_wpa_versions ver; + if (params->wpa_proto) { + enum nl80211_wpa_versions ver = 0; - if (params->wpa_ie[0] == WLAN_EID_RSN) - ver = NL80211_WPA_VERSION_2; - else - ver = NL80211_WPA_VERSION_1; + if (params->wpa_proto & WPA_PROTO_WPA) + ver |= NL80211_WPA_VERSION_1; + if (params->wpa_proto & WPA_PROTO_RSN) + ver |= NL80211_WPA_VERSION_2; - wpa_printf(MSG_DEBUG, " * WPA Version %d", ver); + wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver); NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); } @@ -4845,6 +6698,14 @@ skip_auth_type: if (ret) { wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " "(%s)", ret, strerror(-ret)); + /* + * cfg80211 does not currently accept new connection if we are + * already connected. As a workaround, force disconnection and + * try again once the driver indicates it completed + * disconnection. + */ + if (ret == -EALREADY) + nl80211_disconnect(drv, params->bssid); goto nla_put_failure; } ret = 0; @@ -4872,7 +6733,10 @@ static int wpa_driver_nl80211_associate( return wpa_driver_nl80211_ibss(drv, params); if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0) + enum nl80211_iftype nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + + if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; return wpa_driver_nl80211_connect(drv, params); } @@ -4885,8 +6749,7 @@ static int wpa_driver_nl80211_associate( wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)", drv->ifindex); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_ASSOCIATE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { @@ -4979,8 +6842,9 @@ static int wpa_driver_nl80211_associate( ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " - "(%s)", ret, strerror(-ret)); + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: MLME command failed (assoc): ret=%d (%s)", + ret, strerror(-ret)); nl80211_dump_scan(drv); goto nla_put_failure; } @@ -4995,58 +6859,53 @@ nla_put_failure: static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, - int ifindex, int mode) + int ifindex, enum nl80211_iftype mode) { struct nl_msg *msg; int ret = -ENOBUFS; + wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)", + ifindex, mode, nl80211_iftype_str(mode)); + msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (!ret) return 0; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:" " %d (%s)", ifindex, mode, ret, strerror(-ret)); return ret; } -static int wpa_driver_nl80211_set_mode(void *priv, int mode) +static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode) { - struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; int ret = -1; - int nlmode; int i; + int was_ap = is_ap_interface(drv->nlmode); + int res; - switch (mode) { - case 0: - nlmode = NL80211_IFTYPE_STATION; - break; - case 1: - nlmode = NL80211_IFTYPE_ADHOC; - break; - case 2: - nlmode = NL80211_IFTYPE_AP; - break; - default: - return -1; - } - - if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) { + res = nl80211_set_mode(drv, drv->ifindex, nlmode); + if (res == 0) { drv->nlmode = nlmode; ret = 0; goto done; } + if (res == -ENODEV) + return -1; + if (nlmode == drv->nlmode) { wpa_printf(MSG_DEBUG, "nl80211: Interface already in " "requested mode - ignore error"); @@ -5061,15 +6920,21 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting " "interface down"); for (i = 0; i < 10; i++) { - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == - 0) { + res = linux_set_iface_flags(drv->global->ioctl_sock, + bss->ifname, 0); + if (res == -EACCES || res == -ENODEV) + break; + if (res == 0) { /* Try to set the mode again while the interface is * down */ ret = nl80211_set_mode(drv, drv->ifindex, nlmode); - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, - 1)) + if (ret == -EACCES) + break; + res = linux_set_iface_flags(drv->global->ioctl_sock, + bss->ifname, 1); + if (res && !ret) ret = -1; - if (!ret) + else if (ret != -EBUSY) break; } else wpa_printf(MSG_DEBUG, "nl80211: Failed to set " @@ -5081,26 +6946,34 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while " "interface is down"); drv->nlmode = nlmode; + drv->ignore_if_down_event = 1; } done: - if (!ret && nlmode == NL80211_IFTYPE_AP) { + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " + "from %d failed", nlmode, drv->nlmode); + return ret; + } + + if (is_ap_interface(nlmode)) { + nl80211_mgmt_unsubscribe(bss, "start AP"); /* Setup additional AP mode functionality if needed */ - if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 && - nl80211_create_monitor_interface(drv) && - !drv->no_monitor_iface_capab) + if (nl80211_setup_ap(bss)) return -1; - } else if (!ret && nlmode != NL80211_IFTYPE_AP) { + } else if (was_ap) { /* Remove additional AP mode functionality */ - nl80211_remove_monitor_interface(drv); - bss->beacon_set = 0; + nl80211_teardown_ap(bss); + } else { + nl80211_mgmt_unsubscribe(bss, "mode change"); } - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " - "from %d failed", nlmode, drv->nlmode); + if (!is_ap_interface(nlmode) && + nl80211_mgmt_subscribe_non_ap(bss) < 0) + wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " + "frame processing - ignore for now"); - return ret; + return 0; } @@ -5124,7 +6997,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state) wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; - return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, + return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); } @@ -5140,8 +7013,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -5155,6 +7027,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5163,8 +7036,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) { struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled, + return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled, freq->sec_channel_offset); } @@ -5211,8 +7083,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY); if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); @@ -5223,36 +7094,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, - int mode) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - u8 rates[NL80211_MAX_SUPP_RATES]; - u8 rates_len = 0; - int i; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); - - for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) - rates[rates_len++] = basic_rates[i] / 5; - - NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5274,15 +7116,16 @@ static int i802_set_rts(void *priv, int rts) else val = rts; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (!ret) return 0; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: " "%d (%s)", rts, ret, strerror(-ret)); return ret; @@ -5306,15 +7149,16 @@ static int i802_set_frag(void *priv, int frag) else val = frag; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (!ret) return 0; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold " "%d: %d (%s)", frag, ret, strerror(-ret)); return ret; @@ -5326,13 +7170,13 @@ static int i802_flush(void *priv) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; + int res; msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); /* * XXX: FIX! this needs to flush all VLANs too @@ -5340,8 +7184,14 @@ static int i802_flush(void *priv) NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - return send_and_recv_msgs(drv, msg, NULL, NULL); + res = send_and_recv_msgs(drv, msg, NULL, NULL); + if (res) { + wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d " + "(%s)", res, strerror(-res)); + } + return res; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5409,14 +7259,14 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, get_sta_handler, data); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5433,8 +7283,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -5474,59 +7323,13 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs, if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; + msg = NULL; nla_put_failure: + nlmsg_free(msg); return -1; } -static int i802_set_bss(void *priv, int cts, int preamble, int slot, - int ht_opmode) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); - - if (cts >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); - if (preamble >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); - if (slot >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); - if (ht_opmode >= 0) - NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_cts_protect(void *priv, int value) -{ - return i802_set_bss(priv, value, -1, -1, -1); -} - - -static int i802_set_preamble(void *priv, int value) -{ - return i802_set_bss(priv, -1, value, -1, -1); -} - - -static int i802_set_short_slot_time(void *priv, int value) -{ - return i802_set_bss(priv, -1, -1, value, -1); -} - - static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname, int vlan_id) { @@ -5539,8 +7342,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -5549,6 +7351,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, if_nametoindex(ifname)); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr=" MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", @@ -5556,23 +7359,11 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, strerror(-ret)); } nla_put_failure: + nlmsg_free(msg); return ret; } -static int i802_set_ht_params(void *priv, const u8 *ht_capab, - size_t ht_capab_len, const u8 *ht_oper, - size_t ht_oper_len) -{ - if (ht_oper_len >= 6) { - /* ht opmode uses 16bit in octet 5 & 6 */ - u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]); - return i802_set_bss(priv, -1, -1, -1, ht_opmode); - } else - return -1; -} - - static int i802_get_inact_sec(void *priv, const u8 *addr) { struct hostap_sta_driver_data data; @@ -5610,7 +7401,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, mgmt.u.deauth.reason_code = host_to_le16(reason); return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth)); + sizeof(mgmt.u.deauth), 0); } @@ -5629,7 +7420,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, mgmt.u.disassoc.reason_code = host_to_le16(reason); return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc)); + sizeof(mgmt.u.disassoc), 0); } #endif /* HOSTAPD || CONFIG_AP */ @@ -5716,11 +7507,11 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, NULL, 1) < 0) return -1; if (bridge_ifname && - linux_br_add_if(drv->ioctl_sock, bridge_ifname, - name) < 0) + linux_br_add_if(drv->global->ioctl_sock, + bridge_ifname, name) < 0) return -1; } - linux_set_iface_flags(drv->ioctl_sock, name, 1); + linux_set_iface_flags(drv->global->ioctl_sock, name, 1); return i802_set_sta_vlan(priv, addr, name, 0); } else { i802_set_sta_vlan(priv, addr, bss->ifname, 0); @@ -5764,7 +7555,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, * Bridge was configured, but the bridge device does * not exist. Try to add it now. */ - if (linux_br_add(drv->ioctl_sock, brname) < 0) { + if (linux_br_add(drv->global->ioctl_sock, brname) < 0) { wpa_printf(MSG_ERROR, "nl80211: Failed to add the " "bridge interface %s: %s", brname, strerror(errno)); @@ -5780,7 +7571,8 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from " "bridge %s", ifname, in_br); - if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) { + if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) < + 0) { wpa_printf(MSG_ERROR, "nl80211: Failed to " "remove interface %s from bridge " "%s: %s", @@ -5791,7 +7583,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s", ifname, brname); - if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) { + if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) { wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s " "into bridge %s: %s", ifname, brname, strerror(errno)); @@ -5813,12 +7605,15 @@ static void *i802_init(struct hostapd_data *hapd, int ifindex, br_ifindex; int br_added = 0; - bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL); + bss = wpa_driver_nl80211_init(hapd, params->ifname, + params->global_priv); if (bss == NULL) return NULL; drv = bss->drv; drv->nlmode = NL80211_IFTYPE_AP; + drv->eapol_sock = -1; + if (linux_br_get(brname, params->ifname) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s", params->ifname, brname); @@ -5846,16 +7641,16 @@ static void *i802_init(struct hostapd_data *hapd, /* start listening for EAPOL on the default AP interface */ add_ifidx(drv, drv->ifindex); - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0)) + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0)) goto failed; if (params->bssid) { - if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname, + if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->bssid)) goto failed; } - if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) { + if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) { wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s " "into AP mode", bss->ifname); goto failed; @@ -5865,7 +7660,7 @@ static void *i802_init(struct hostapd_data *hapd, i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) goto failed; - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) goto failed; drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); @@ -5880,25 +7675,16 @@ static void *i802_init(struct hostapd_data *hapd, goto failed; } - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr)) + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + params->own_addr)) goto failed; + memcpy(bss->addr, params->own_addr, ETH_ALEN); + return bss; failed: - nl80211_remove_monitor_interface(drv); - rfkill_deinit(drv->rfkill); - netlink_deinit(drv->netlink); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl80211_handle_destroy(drv->nl_handle); - nl_cb_put(drv->nl_cb); - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); - - os_free(drv); + wpa_driver_nl80211_deinit(bss); return NULL; } @@ -5938,7 +7724,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr) struct wpa_driver_nl80211_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_nl80211_data, list) { - if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0) + if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0) return 1; } return 0; @@ -5953,9 +7739,9 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv, if (!drv->global) return -1; - os_memcpy(new_addr, drv->addr, ETH_ALEN); + os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN); for (idx = 0; idx < 64; idx++) { - new_addr[0] = drv->addr[0] | 0x02; + new_addr[0] = drv->first_bss.addr[0] | 0x02; new_addr[0] ^= idx << 2; if (!nl80211_addr_in_use(drv->global, new_addr)) break; @@ -6004,7 +7790,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } if (!addr && - linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) { + linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + if_addr) < 0) { nl80211_remove_iface(drv, ifidx); return -1; } @@ -6016,10 +7803,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, /* Enforce unique P2P Interface Address */ u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN]; - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) - < 0 || - linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0) - { + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + own_addr) < 0 || + linux_get_ifhwaddr(drv->global->ioctl_sock, ifname, + new_addr) < 0) { nl80211_remove_iface(drv, ifidx); return -1; } @@ -6030,7 +7817,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, nl80211_remove_iface(drv, ifidx); return -1; } - if (linux_set_ifhwaddr(drv->ioctl_sock, ifname, + if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, new_addr) < 0) { nl80211_remove_iface(drv, ifidx); return -1; @@ -6051,21 +7838,27 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } if (type == WPA_IF_AP_BSS) { - if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1)) + { nl80211_remove_iface(drv, ifidx); os_free(new_bss); return -1; } os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); + os_memcpy(new_bss->addr, if_addr, ETH_ALEN); new_bss->ifindex = ifidx; new_bss->drv = drv; new_bss->next = drv->first_bss.next; drv->first_bss.next = new_bss; if (drv_priv) *drv_priv = new_bss; + nl80211_init_bss(new_bss); } #endif /* HOSTAPD */ + if (drv->global) + drv->global->if_add_ifindex = ifidx; + return 0; } @@ -6085,14 +7878,14 @@ static int wpa_driver_nl80211_if_remove(void *priv, #ifdef HOSTAPD if (bss->added_if_into_bridge) { - if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname) - < 0) + if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, + bss->ifname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { - if (linux_br_del(drv->ioctl_sock, bss->brname) < 0) + if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); @@ -6111,6 +7904,7 @@ static int wpa_driver_nl80211_if_remove(void *priv, for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { if (tbss->next == bss) { tbss->next = bss->next; + nl80211_destroy_bss(bss); os_free(bss); bss = NULL; break; @@ -6139,11 +7933,13 @@ static int cookie_handler(struct nl_msg *msg, void *arg) } -static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, +static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, - u64 *cookie_out) + u64 *cookie_out, int no_cck, int no_ack, + int offchanok) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; u64 cookie; int ret = -1; @@ -6152,16 +7948,21 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_FRAME, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); -#ifndef ANDROID_BRCM_P2P_PATCH +#ifndef ANDROID_P2P if (wait) NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); #endif - NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + if (offchanok) + NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + if (no_cck) + NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); + if (no_ack) + NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK); + NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf); cookie = 0; @@ -6173,11 +7974,12 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, freq, wait); goto nla_put_failure; } - wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; " - "cookie 0x%llx", (long long unsigned int) cookie); + wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; " + "cookie 0x%llx", no_ack ? " (no ACK)" : "", + (long long unsigned int) cookie); if (cookie_out) - *cookie_out = cookie; + *cookie_out = no_ack ? (u64) -1 : cookie; nla_put_failure: nlmsg_free(msg); @@ -6189,7 +7991,8 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, unsigned int wait_time, const u8 *dst, const u8 *src, const u8 *bssid, - const u8 *data, size_t data_len) + const u8 *data, size_t data_len, + int no_cck) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -6198,7 +8001,7 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, struct ieee80211_hdr *hdr; wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, " - "wait=%d ms)", drv->ifindex, wait_time); + "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck); buf = os_zalloc(24 + data_len); if (buf == NULL) @@ -6211,12 +8014,14 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); - if (drv->nlmode == NL80211_IFTYPE_AP) - ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len); + if (is_ap_interface(drv->nlmode)) + ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len, + 0); else - ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf, + ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf, 24 + data_len, - &drv->send_action_cookie); + &drv->send_action_cookie, + no_cck, 0, 1); os_free(buf); return ret; @@ -6234,8 +8039,7 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) if (!msg) return; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_FRAME_WAIT_CANCEL, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); @@ -6264,8 +8068,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_REMAIN_ON_CHANNEL, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); @@ -6273,17 +8076,20 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, cookie = 0; ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); + msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie " "0x%llx for freq=%u MHz duration=%u", (long long unsigned int) cookie, freq, duration); drv->remain_on_chan_cookie = cookie; + drv->pending_remain_on_chan = 1; return 0; } wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel " "(freq=%d duration=%u): %d (%s)", freq, duration, ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } @@ -6309,18 +8115,19 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv) if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: " "%d (%s)", ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } @@ -6331,60 +8138,43 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report) struct wpa_driver_nl80211_data *drv = bss->drv; if (!report) { - if (drv->nl_handle_preq) { + if (bss->nl_preq && drv->device_ap_sme && + is_ap_interface(drv->nlmode)) { + /* + * Do not disable Probe Request reporting that was + * enabled in nl80211_setup_ap(). + */ + wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of " + "Probe Request reporting nl_preq=%p while " + "in AP mode", bss->nl_preq); + } else if (bss->nl_preq) { + wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request " + "reporting nl_preq=%p", bss->nl_preq); eloop_unregister_read_sock( - nl_socket_get_fd(drv->nl_handle_preq)); - nl_cache_free(drv->nl_cache_preq); - nl80211_handle_destroy(drv->nl_handle_preq); - drv->nl_handle_preq = NULL; + nl_socket_get_fd(bss->nl_preq)); + nl_destroy_handles(&bss->nl_preq); } return 0; } - if (drv->nl_handle_preq) { + if (bss->nl_preq) { wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting " - "already on!"); + "already on! nl_preq=%p", bss->nl_preq); return 0; } - drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb); - if (drv->nl_handle_preq == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate " - "netlink callbacks (preq)"); - goto out_err1; - } - - if (genl_connect(drv->nl_handle_preq)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to " - "generic netlink (preq)"); - goto out_err2; + bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq"); + if (bss->nl_preq == NULL) return -1; - } + wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request " + "reporting nl_preq=%p", bss->nl_preq); -#ifdef CONFIG_LIBNL20 - if (genl_ctrl_alloc_cache(drv->nl_handle_preq, - &drv->nl_cache_preq) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (preq)"); - goto out_err2; - } -#else /* CONFIG_LIBNL20 */ - drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq); - if (drv->nl_cache_preq == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (preq)"); - goto out_err2; - } -#endif /* CONFIG_LIBNL20 */ - - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_PROBE_REQ << 4), - NULL, 0) < 0) { - goto out_err3; - } - -#ifdef ANDROID_BRCM_P2P_PATCH + NULL, 0) < 0) + goto out_err; +#ifdef ANDROID_P2P if (drv->nlmode != NL80211_IFTYPE_AP && drv->nlmode != NL80211_IFTYPE_P2P_GO) { wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only " @@ -6392,49 +8182,51 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report) drv->nlmode); goto done; } - - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ASSOC_REQ << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; } - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_REASSOC_REQ << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; } - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_DISASSOC << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; } - - if (nl80211_register_frame(drv, drv->nl_handle_preq, + + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_DEAUTH << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; + } + + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ACTION << 4), + NULL, 0) < 0) { + goto out_err; } done: -#endif - eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq), - wpa_driver_nl80211_event_receive, drv, - drv->nl_handle_preq); +#endif /* ANDROID_P2P */ + eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq), + wpa_driver_nl80211_event_receive, bss->nl_cb, + bss->nl_preq); return 0; - out_err3: - nl_cache_free(drv->nl_cache_preq); - out_err2: - nl80211_handle_destroy(drv->nl_handle_preq); - drv->nl_handle_preq = NULL; - out_err1: + out_err: + nl_destroy_handles(&bss->nl_preq); return -1; } @@ -6450,8 +8242,7 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_TX_BITRATE_MASK, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); @@ -6466,8 +8257,10 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, band = nla_nest_start(msg, NL80211_BAND_2GHZ); if (!band) goto nla_put_failure; - NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, - "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + if (disabled) { + NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + } nla_nest_end(msg, band); nla_nest_end(msg, bands); @@ -6487,23 +8280,14 @@ nla_put_failure: } -static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - drv->disable_11b_rates = disabled; - return nl80211_disable_11b_rates(drv, drv->ifindex, disabled); -} - - static int wpa_driver_nl80211_deinit_ap(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nlmode != NL80211_IFTYPE_AP) + if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(drv); - return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA); + return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION); } @@ -6511,7 +8295,7 @@ static void wpa_driver_nl80211_resume(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on " "resume event"); } @@ -6526,10 +8310,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, int ret; u8 *data, *pos; size_t data_len; - u8 own_addr[ETH_ALEN]; - - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0) - return -1; + const u8 *own_addr = bss->addr; if (action != 1) { wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action " @@ -6561,7 +8342,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0, drv->bssid, own_addr, drv->bssid, - data, data_len); + data, data_len, 0); os_free(data); return ret; @@ -6581,8 +8362,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_CQM, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); @@ -6599,8 +8379,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) msg = NULL; nla_put_failure: - if (cqm) - nlmsg_free(cqm); + nlmsg_free(cqm); nlmsg_free(msg); return -1; } @@ -6621,34 +8400,58 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) } -static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, - int encrypt) +static int wpa_driver_nl80211_shared_freq(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); -} + struct wpa_driver_nl80211_data *driver; + int freq = 0; + /* + * If the same PHY is in connected state with some other interface, + * then retrieve the assoc freq. + */ + wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s", + drv->phyname); -static int nl80211_set_intra_bss(void *priv, int enabled) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; + dl_list_for_each(driver, &drv->global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (drv == driver || + os_strcmp(drv->phyname, driver->phyname) != 0 || +#ifdef ANDROID_P2P + (!driver->associated && !is_ap_interface(driver->nlmode))) +#else + !driver->associated) +#endif + continue; - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; + wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s " + MACSTR, + driver->phyname, driver->first_bss.ifname, + MAC2STR(driver->first_bss.addr)); +#ifdef ANDROID_P2P + if(is_ap_interface(driver->nlmode)) + freq = driver->first_bss.freq; + else +#endif + freq = nl80211_get_assoc_freq(driver); + wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d", + drv->phyname, freq); + } - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); + if (!freq) + wpa_printf(MSG_DEBUG, "nl80211: No shared interface for " + "PHY (%s) in associated state", drv->phyname); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled); + return freq; +} - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; + +static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, + int encrypt) +{ + struct i802_bss *bss = priv; + return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0); } @@ -6668,6 +8471,15 @@ static int nl80211_set_param(void *priv, const char *param) drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } +#ifdef ANDROID_P2P + if(os_strstr(param, "use_multi_chan_concurrent=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel " + "concurrency"); + drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT; + } +#endif #endif /* CONFIG_P2P */ return 0; @@ -6677,11 +8489,42 @@ static int nl80211_set_param(void *priv, const char *param) static void * nl80211_global_init(void) { struct nl80211_global *global; + struct netlink_config *cfg; + global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; + global->ioctl_sock = -1; dl_list_init(&global->interfaces); + global->if_add_ifindex = -1; + + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto err; + + cfg->ctx = global; + cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; + global->netlink = netlink_init(cfg); + if (global->netlink == NULL) { + os_free(cfg); + goto err; + } + + if (wpa_driver_nl80211_init_nl_global(global) < 0) + goto err; + + global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (global->ioctl_sock < 0) { + perror("socket(PF_INET,SOCK_DGRAM)"); + goto err; + } + return global; + +err: + nl80211_global_deinit(global); + return NULL; } @@ -6695,6 +8538,23 @@ static void nl80211_global_deinit(void *priv) "nl80211_global_deinit", dl_list_len(&global->interfaces)); } + + if (global->netlink) + netlink_deinit(global->netlink); + + nl_destroy_handles(&global->nl); + + if (global->nl_event) { + eloop_unregister_read_sock( + nl_socket_get_fd(global->nl_event)); + nl_destroy_handles(&global->nl_event); + } + + nl_cb_put(global->nl_cb); + + if (global->ioctl_sock >= 0) + close(global->ioctl_sock); + os_free(global); } @@ -6716,8 +8576,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0, - cmd, 0); + nl80211_cmd(bss->drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); if (pmkid) @@ -6727,6 +8586,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, return send_and_recv_msgs(bss->drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -6756,6 +8616,366 @@ static int nl80211_flush_pmkid(void *priv) } +static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck, + const u8 *replay_ctr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nlattr *replay_nested; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); + if (!replay_nested) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek); + NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck); + NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN, + replay_ctr); + + nla_nest_end(msg, replay_nested); + + send_and_recv_msgs(drv, msg, NULL, NULL); + return; + nla_put_failure: + nlmsg_free(msg); +} + + +static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr, + const u8 *addr, int qos) +{ + /* send data frame to poll STA and check whether + * this frame is ACKed */ + struct { + struct ieee80211_hdr hdr; + u16 qos_ctl; + } STRUCT_PACKED nulldata; + size_t size; + + /* Send data frame to poll STA and check whether this frame is ACKed */ + + os_memset(&nulldata, 0, sizeof(nulldata)); + + if (qos) { + nulldata.hdr.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_QOS_NULL); + size = sizeof(nulldata); + } else { + nulldata.hdr.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_NULLFUNC); + size = sizeof(struct ieee80211_hdr); + } + + nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); + os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); + os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + + if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0) + wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to " + "send poll frame"); +} + +static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr, + int qos) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + if (!drv->poll_command_supported) { + nl80211_send_null_frame(bss, own_addr, addr, qos); + return; + } + + msg = nlmsg_alloc(); + if (!msg) + return; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + send_and_recv_msgs(drv, msg, NULL, NULL); + return; + nla_put_failure: + nlmsg_free(msg); +} + + +static int nl80211_set_power_save(struct i802_bss *bss, int enabled) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, + enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED); + return send_and_recv_msgs(bss->drv, msg, NULL, NULL); +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps, + int ctwindow) +{ + struct i802_bss *bss = priv; + + wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d " + "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow); + + if (opp_ps != -1 || ctwindow != -1) + return -1; /* Not yet supported */ + + if (legacy_ps == -1) + return 0; + if (legacy_ps != 0 && legacy_ps != 1) + return -1; /* Not yet supported */ + + return nl80211_set_power_save(bss, legacy_ps); +} + + +#ifdef CONFIG_TDLS + +static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, + u8 dialog_token, u16 status_code, + const u8 *buf, size_t len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + if (!dst) + return -EINVAL; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); + NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); + NLA_PUT(msg, NL80211_ATTR_IE, len, buf); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + enum nl80211_tdls_operation nl80211_oper; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + switch (oper) { + case TDLS_DISCOVERY_REQ: + nl80211_oper = NL80211_TDLS_DISCOVERY_REQ; + break; + case TDLS_SETUP: + nl80211_oper = NL80211_TDLS_SETUP; + break; + case TDLS_TEARDOWN: + nl80211_oper = NL80211_TDLS_TEARDOWN; + break; + case TDLS_ENABLE_LINK: + nl80211_oper = NL80211_TDLS_ENABLE_LINK; + break; + case TDLS_DISABLE_LINK: + nl80211_oper = NL80211_TDLS_DISABLE_LINK; + break; + case TDLS_ENABLE: + return 0; + case TDLS_DISABLE: + return 0; + default: + return -EINVAL; + } + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +#endif /* CONFIG TDLS */ + + +#ifdef ANDROID + +typedef struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +static int drv_errors = 0; + +static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) +{ + drv_errors++; + if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv_errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } +} + + +static int android_priv_cmd(struct i802_bss *bss, const char *cmd) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + char buf[MAX_DRV_CMD_SIZE]; + int ret; + + os_memset(&ifr, 0, sizeof(ifr)); + os_memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + os_memset(buf, 0, sizeof(buf)); + os_strlcpy(buf, cmd, sizeof(buf)); + + priv_cmd.buf = buf; + priv_cmd.used_len = sizeof(buf); + priv_cmd.total_len = sizeof(buf); + ifr.ifr_data = &priv_cmd; + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s: failed to issue private commands", + __func__); + wpa_driver_send_hang_msg(drv); + return ret; + } + + drv_errors = 0; + return 0; +} + + +static int android_pno_start(struct i802_bss *bss, + struct wpa_driver_scan_params *params) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + int ret = 0, i = 0, bp; + char buf[WEXT_PNO_MAX_COMMAND_SIZE]; + + bp = WEXT_PNOSETUP_HEADER_SIZE; + os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); + buf[bp++] = WEXT_PNO_TLV_PREFIX; + buf[bp++] = WEXT_PNO_TLV_VERSION; + buf[bp++] = WEXT_PNO_TLV_SUBVERSION; + buf[bp++] = WEXT_PNO_TLV_RESERVED; + + while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { + /* Check that there is enough space needed for 1 more SSID, the + * other sections and null termination */ + if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) + break; + wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + buf[bp++] = WEXT_PNO_SSID_SECTION; + buf[bp++] = params->ssids[i].ssid_len; + os_memcpy(&buf[bp], params->ssids[i].ssid, + params->ssids[i].ssid_len); + bp += params->ssids[i].ssid_len; + i++; + } + + buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", + WEXT_PNO_SCAN_INTERVAL); + bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; + + buf[bp++] = WEXT_PNO_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_REPEAT); + bp += WEXT_PNO_REPEAT_LENGTH; + + buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_MAX_REPEAT); + bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; + + memset(&ifr, 0, sizeof(ifr)); + memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + priv_cmd.buf = buf; + priv_cmd.used_len = bp; + priv_cmd.total_len = bp; + ifr.ifr_data = &priv_cmd; + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", + ret); + wpa_driver_send_hang_msg(drv); + return ret; + } + + drv_errors = 0; + + return android_priv_cmd(bss, "PNOFORCE 1"); +} + + +static int android_pno_stop(struct i802_bss *bss) +{ + return android_priv_cmd(bss, "PNOFORCE 0"); +} + +#endif /* ANDROID */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -6763,6 +8983,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_ssid = wpa_driver_nl80211_get_ssid, .set_key = wpa_driver_nl80211_set_key, .scan2 = wpa_driver_nl80211_scan, + .sched_scan = wpa_driver_nl80211_sched_scan, + .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan, .get_scan_results2 = wpa_driver_nl80211_get_scan_results, .deauthenticate = wpa_driver_nl80211_deauthenticate, .disassociate = wpa_driver_nl80211_disassociate, @@ -6776,7 +8998,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_operstate = wpa_driver_nl80211_set_operstate, .set_supp_port = wpa_driver_nl80211_set_supp_port, .set_country = wpa_driver_nl80211_set_country, - .set_beacon = wpa_driver_nl80211_set_beacon, + .set_ap = wpa_driver_nl80211_set_ap, .if_add = wpa_driver_nl80211_if_add, .if_remove = wpa_driver_nl80211_if_remove, .send_mlme = wpa_driver_nl80211_send_mlme, @@ -6798,13 +9020,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .sta_clear_stats = i802_sta_clear_stats, .set_rts = i802_set_rts, .set_frag = i802_set_frag, - .set_cts_protect = i802_set_cts_protect, - .set_preamble = i802_set_preamble, - .set_short_slot_time = i802_set_short_slot_time, .set_tx_queue_params = i802_set_tx_queue_params, .set_sta_vlan = i802_set_sta_vlan, - .set_ht_params = i802_set_ht_params, - .set_rate_sets = i802_set_rate_sets, .sta_deauth = i802_sta_deauth, .sta_disassoc = i802_sta_disassoc, #endif /* HOSTAPD || CONFIG_AP */ @@ -6815,22 +9032,30 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .cancel_remain_on_channel = wpa_driver_nl80211_cancel_remain_on_channel, .probe_req_report = wpa_driver_nl80211_probe_req_report, - .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates, .deinit_ap = wpa_driver_nl80211_deinit_ap, .resume = wpa_driver_nl80211_resume, .send_ft_action = nl80211_send_ft_action, .signal_monitor = nl80211_signal_monitor, .signal_poll = nl80211_signal_poll, .send_frame = nl80211_send_frame, - .set_intra_bss = nl80211_set_intra_bss, + .shared_freq = wpa_driver_nl80211_shared_freq, .set_param = nl80211_set_param, .get_radio_name = nl80211_get_radio_name, .add_pmkid = nl80211_add_pmkid, .remove_pmkid = nl80211_remove_pmkid, .flush_pmkid = nl80211_flush_pmkid, -#ifdef ANDROID_BRCM_P2P_PATCH - .get_noa = wpa_driver_get_p2p_noa, + .set_rekey_info = nl80211_set_rekey_info, + .poll_client = nl80211_poll_client, +#ifndef ANDROID_P2P + .set_p2p_powersave = nl80211_set_p2p_powersave, +#endif +#ifdef CONFIG_TDLS + .send_tdls_mgmt = nl80211_send_tdls_mgmt, + .tdls_oper = nl80211_tdls_oper, +#endif /* CONFIG_TDLS */ +#ifdef ANDROID_P2P .set_noa = wpa_driver_set_p2p_noa, + .get_noa = wpa_driver_get_p2p_noa, .set_p2p_powersave = wpa_driver_set_p2p_ps, .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie, #endif diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m deleted file mode 100644 index 69ca4b5..0000000 --- a/src/drivers/driver_osx.m +++ /dev/null @@ -1,459 +0,0 @@ -/* - * 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 "common/ieee802_11_defs.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, struct wpa_driver_scan_params *params) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - 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 void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res, - WirelessNetworkInfo *info) -{ - struct wpa_scan_res *result, **tmp; - size_t extra_len; - u8 *pos; - - extra_len = 2 + info->ssid_len; - - result = os_zalloc(sizeof(*result) + extra_len); - if (result == NULL) - return; - os_memcpy(result->bssid, info->bssid, ETH_ALEN); - result->freq = 2407 + info->channel * 5; - //result->beacon_int =; - result->caps = info->capability; - //result->qual = info->signal; - result->noise = info->noise; - - pos = (u8 *)(result + 1); - - *pos++ = WLAN_EID_SSID; - *pos++ = info->ssid_len; - os_memcpy(pos, info->ssid, info->ssid_len); - pos += info->ssid_len; - - result->ie_len = pos - (u8 *)(result + 1); - - tmp = os_realloc(res->res, - (res->num + 1) * sizeof(struct wpa_scan_res *)); - if (tmp == NULL) { - os_free(result); - return; - } - tmp[res->num++] = result; - res->res = tmp; -} - - -static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv) -{ - struct wpa_driver_osx_data *drv = priv; - struct wpa_scan_results *res; - size_t i, num; - - if (drv->scan_results == NULL) - return 0; - - num = CFArrayGetCount(drv->scan_results); - - res = os_zalloc(sizeof(*res)); - if (res == NULL) - return NULL; - - for (i = 0; i < num; i++) - wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *) - CFDataGetBytePtr(CFArrayGetValueAtIndex( - drv->scan_results, i))); - - return res; -} - - -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(const char *ifname, void *priv, - enum 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, - .scan2 = wpa_driver_osx_scan, - .get_scan_results2 = 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/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c deleted file mode 100644 index a1e27be..0000000 --- a/src/drivers/driver_ralink.c +++ /dev/null @@ -1,1498 +0,0 @@ -/* - * 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 "common/ieee802_11_defs.h" -#include "priv_netlink.h" -#include "netlink.h" -#include "linux_ioctl.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; - struct netlink_data *netlink; - 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; - BOOLEAN bAddWepKey; -}; - -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; - u8 *req_ies = NULL, *resp_ies = NULL; - - 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; - - req_ies = os_malloc(bytes); - if (req_ies == NULL) - return; - os_memcpy(req_ies, spos, bytes); - data.assoc_info.req_ies = req_ies; - data.assoc_info.req_ies_len = 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; - - resp_ies = os_malloc(bytes); - if (resp_ies == NULL) - goto done; - os_memcpy(resp_ies, spos, bytes); - data.assoc_info.resp_ies = resp_ies; - data.assoc_info.resp_ies_len = bytes; - } - - wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - - done: - /* free allocated memory */ - os_free(resp_ies); - os_free(req_ies); - } -} - -static void ralink_interface_up(struct wpa_driver_ralink_data *drv) -{ - union wpa_event_data event; - int enable_wpa_supplicant = 0; - drv->g_driver_down = 0; - os_memset(&event, 0, sizeof(event)); - os_snprintf(event.interface_status.ifname, - sizeof(event.interface_status.ifname), "%s", drv->ifname); - - event.interface_status.ievent = EVENT_INTERFACE_ADDED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); - - 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_INFO, "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"); - } -} - -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_supplicant_event(ctx, EVENT_ASSOC, NULL); - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive ASSOCIATED_EVENT !!!"); - } 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_INTERFACE_UP) { - ralink_interface_up(drv); - } 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(void *ctx, struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct wpa_driver_ralink_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg)); - - attrlen = len; - wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen); - attr = (struct rtattr *) buf; - 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 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 void * wpa_driver_ralink_init(void *ctx, const char *ifname) -{ - int s; - struct wpa_driver_ralink_data *drv; - struct ifreq ifr; - UCHAR enable_wpa_supplicant = 0; - struct netlink_config *cfg; - - 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; - - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) { - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - cfg->ctx = drv; - cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - drv->no_of_pmkid = 4; /* Number of PMKID saved supported */ - - linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); - 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); - /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */ - } - - eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx); - netlink_deinit(drv->netlink); - 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, - struct wpa_driver_scan_params *params) -{ - 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 0 - 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); */ -#endif - - if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE, - (char *) params->extra_ies, params->extra_ies_len) < - 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "RT_OID_WPS_PROBE_REQ_IE"); - } - - 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 struct wpa_scan_results * -wpa_driver_ralink_get_scan_results(void *priv) -{ - struct wpa_driver_ralink_data *drv = priv; - UCHAR *buf = NULL; - size_t buf_len; - NDIS_802_11_BSSID_LIST_EX *wsr; - NDIS_WLAN_BSSID_EX *wbi; - struct iwreq iwr; - size_t ap_num; - u8 *pos; - struct wpa_scan_results *res; - - if (drv->g_driver_down == 1) - return NULL; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->we_version_compiled >= 17) - buf_len = 8192; - else - buf_len = 4096; - - for (;;) { - buf = os_zalloc(buf_len); - iwr.u.data.length = buf_len; - if (buf == NULL) - return NULL; - - 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 (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0) - break; - - if (errno == E2BIG && buf_len < 65535) { - os_free(buf); - buf = NULL; - buf_len *= 2; - if (buf_len > 65535) - buf_len = 65535; /* 16-bit length field */ - wpa_printf(MSG_DEBUG, "Scan results did not fit - " - "trying larger buffer (%lu bytes)", - (unsigned long) buf_len); - } else { - perror("ioctl[RT_PRIV_IOCTL]"); - os_free(buf); - return NULL; - } - } - - res = os_zalloc(sizeof(*res)); - if (res == NULL) { - os_free(buf); - return NULL; - } - - res->res = os_zalloc(wsr->NumberOfItems * - sizeof(struct wpa_scan_res *)); - if (res->res == NULL) { - os_free(res); - os_free(buf); - return NULL; - } - - for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems; - ++ap_num) { - struct wpa_scan_res *r = NULL; - size_t extra_len = 0, var_ie_len = 0; - u8 *pos2; - - /* SSID data element */ - extra_len += 2 + wbi->Ssid.SsidLength; - var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs); - r = os_zalloc(sizeof(*r) + extra_len + var_ie_len); - if (r == NULL) - break; - res->res[res->num++] = r; - - wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid); - /* get ie's */ - wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs", - (u8 *) &wbi->IEs[0], wbi->IELength); - - os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN); - - extra_len += (2 + wbi->Ssid.SsidLength); - r->ie_len = extra_len + var_ie_len; - pos2 = (u8 *) (r + 1); - - /* - * Generate a fake SSID IE since the driver did not report - * a full IE list. - */ - *pos2++ = WLAN_EID_SSID; - *pos2++ = wbi->Ssid.SsidLength; - os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength); - pos2 += wbi->Ssid.SsidLength; - - r->freq = (wbi->Configuration.DSConfig / 1000); - - pos = (u8 *) wbi + sizeof(*wbi) - 1; - - pos += sizeof(NDIS_802_11_FIXED_IEs) - 2; - os_memcpy(&(r->caps), pos, 2); - pos += 2; - - if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs)) - os_memcpy(pos2, pos, var_ie_len); - - wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length); - } - - os_free(buf); - return res; -} - -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 ralink_set_encr_type(struct wpa_driver_ralink_data *drv, - NDIS_802_11_WEP_STATUS encr_type) -{ - NDIS_802_11_WEP_STATUS wep_status = encr_type; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (ralink_set_oid(drv, OID_802_11_WEP_STATUS, - (char *) &wep_status, sizeof(wep_status)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_WEP_STATUS (%d)", - (int) wep_status); - 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(const char *ifname, void *priv, - enum 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__); - - drv->bAddWepKey = FALSE; - - if (addr == NULL || is_broadcast_ether_addr(addr)) { - /* 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) { - drv->bAddWepKey = TRUE; - 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_set_gen_ie(void *priv, const u8 *ie, - size_t ie_len) -{ - struct wpa_driver_ralink_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; - - wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ", - (u8 *) ie, ie_len); - - if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { - perror("ioctl[SIOCSIWGENIE]"); - ret = -1; - } - - return ret; -} - -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; - BOOLEAN ieee8021x_required_key = TRUE; - - 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->key_mgmt_suite == KEY_MGMT_WPS) { - UCHAR enable_wps = 0x80; - /* trigger driver support wpa_supplicant */ - if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, - (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) { - wpa_printf(MSG_INFO, "RALINK: Failed to set " - "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", - (int) enable_wps); - } - - wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie, - params->wpa_ie_len); - - ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen); - - ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled); - } else { -#ifdef CONFIG_WPS - UCHAR enable_wpa_supplicant; - - if (drv->ap_scan == 1) - enable_wpa_supplicant = 0x01; - else - enable_wpa_supplicant = 0x02; - - /* 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_driver_ralink_set_gen_ie(priv, (u8 *) "", 0); -#endif /* CONFIG_WPS */ - - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { - if (params->auth_alg & WPA_AUTH_ALG_SHARED) { - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - 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; - if (drv->bAddWepKey) - ieee8021x_required_key = FALSE; - } else - ieee8021xMode = 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", - ieee8021x_required_key ? "TRUE" : "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); - } - - ralink_set_encr_type(drv, 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, - .scan2 = wpa_driver_ralink_scan, - .get_scan_results2 = 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/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h deleted file mode 100644 index d13df28..0000000 --- a/src/drivers/driver_ralink.h +++ /dev/null @@ -1,383 +0,0 @@ -/* - * 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 RT_OID_WPS_PROBE_REQ_IE 0x0625 - -#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_INTERFACE_UP 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/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c index c014b96..61b75b1 100644 --- a/src/drivers/driver_roboswitch.c +++ b/src/drivers/driver_roboswitch.c @@ -364,7 +364,7 @@ static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname) /* 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> */ + /* find the '.' separating <interface> and <vlan> */ while (sep > drv->ifname && *sep != '.') sep--; if (sep <= drv->ifname) { wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in " diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 6bfa46d..f8e314b 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -89,7 +89,6 @@ struct wpa_driver_test_data { 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; @@ -117,6 +116,7 @@ struct wpa_driver_test_data { u8 pending_action_dst[ETH_ALEN]; u8 pending_action_bssid[ETH_ALEN]; unsigned int pending_action_freq; + unsigned int pending_action_no_cck; unsigned int pending_listen_freq; unsigned int pending_listen_duration; int pending_p2p_scan; @@ -309,7 +309,7 @@ static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src, static int wpa_driver_test_send_mlme(void *priv, const u8 *data, - size_t data_len) + size_t data_len, int noack) { struct test_driver_bss *dbss = priv; struct wpa_driver_test_data *drv = dbss->drv; @@ -561,7 +561,7 @@ static void test_driver_scan(struct wpa_driver_test_data *drv, wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); #ifdef CONFIG_P2P if (drv->p2p) - p2p_probe_req_rx(drv->p2p, sa, ie, ielen); + p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); #endif /* CONFIG_P2P */ } @@ -1102,13 +1102,6 @@ static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type, } -static int test_driver_valid_bss_mask(void *priv, const u8 *addr, - const u8 *mask) -{ - return 0; -} - - static int test_driver_set_ssid(void *priv, const u8 *buf, int len) { struct test_driver_bss *bss = priv; @@ -1232,6 +1225,7 @@ static void * test_driver_init(struct hostapd_data *hapd, return NULL; drv->ap = 1; bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + drv->global = params->global_priv; bss->bss_ctx = hapd; os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN); @@ -1966,6 +1960,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) { os_memset(&event, 0, sizeof(event)); event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; event.rx_probe_req.ie = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = data_len - (mgmt->u.probe_req.variable - data); @@ -1974,6 +1970,7 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, #ifdef CONFIG_P2P if (drv->p2p) p2p_probe_req_rx(drv->p2p, mgmt->sa, + mgmt->da, mgmt->bssid, event.rx_probe_req.ie, event.rx_probe_req.ie_len); #endif /* CONFIG_P2P */ @@ -2028,7 +2025,7 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, ielen = 0; drv->probe_from = from; drv->probe_from_len = fromlen; - p2p_probe_req_rx(drv->p2p, sa, ie, ielen); + p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); drv->probe_from = NULL; } #endif /* CONFIG_P2P */ @@ -2390,13 +2387,6 @@ static int wpa_driver_test_set_param(void *priv, const char *param) 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 */ - if (os_strstr(param, "p2p_mgmt=1")) { wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P " "management"); @@ -2510,8 +2500,6 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) 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; if (drv->p2p) capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT; capa->flags |= WPA_DRIVER_FLAGS_AP; @@ -2541,50 +2529,6 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, } -static int wpa_driver_test_set_channel(void *priv, - enum hostapd_hw_mode phymode, - int chan, int freq) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d", - __func__, phymode, chan, freq); - drv->current_freq = freq; - 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; -} - - static void * wpa_driver_test_global_init(void) { struct wpa_driver_test_global *global; @@ -2727,7 +2671,8 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *src, const u8 *bssid, - const u8 *data, size_t data_len) + const u8 *data, size_t data_len, + int no_cck) { struct test_driver_bss *dbss = priv; struct wpa_driver_test_data *drv = dbss->drv; @@ -2760,7 +2705,7 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); - ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len); + ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0); os_free(buf); return ret; } @@ -2770,7 +2715,6 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_test_data *drv = eloop_ctx; - int res; if (drv->pending_action_tx == NULL) return; @@ -2783,12 +2727,13 @@ static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) } wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to " MACSTR, MAC2STR(drv->pending_action_dst)); - res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, - drv->pending_action_dst, - drv->pending_action_src, - drv->pending_action_bssid, - wpabuf_head(drv->pending_action_tx), - wpabuf_len(drv->pending_action_tx)); + wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, + drv->pending_action_dst, + drv->pending_action_src, + drv->pending_action_bssid, + wpabuf_head(drv->pending_action_tx), + wpabuf_len(drv->pending_action_tx), + drv->pending_action_no_cck); } #endif /* CONFIG_P2P */ @@ -2980,6 +2925,7 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, int ret; struct wpabuf *wps_ie, *ies; int social_channels[] = { 2412, 2437, 2462, 0, 0 }; + size_t ielen; wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)", __func__, type, freq); @@ -3001,7 +2947,8 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, if (wps_ie == NULL) return -1; - ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100); + ielen = p2p_scan_ie_buf_len(drv->p2p); + ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); if (ies == NULL) { wpabuf_free(wps_ie); return -1; @@ -3069,6 +3016,7 @@ static int test_send_action(void *ctx, unsigned int freq, const u8 *dst, os_memcpy(drv->pending_action_dst, dst, ETH_ALEN); os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN); drv->pending_action_freq = freq; + drv->pending_action_no_cck = 1; if (drv->off_channel_freq == freq) { /* Already on requested channel; send immediately */ @@ -3248,7 +3196,8 @@ static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic, static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, const u8 *dev_addr, const u8 *pri_dev_type, const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab) + u8 dev_capab, u8 group_capab, + const u8 *group_id, size_t group_id_len) { wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", __func__, MAC2STR(peer), config_methods); @@ -3343,7 +3292,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .get_hw_feature_data = wpa_driver_test_get_hw_feature_data, .if_add = test_driver_if_add, .if_remove = test_driver_if_remove, - .valid_bss_mask = test_driver_valid_bss_mask, .hapd_set_ssid = test_driver_set_ssid, .set_privacy = test_driver_set_privacy, .set_sta_vlan = test_driver_set_sta_vlan, @@ -3362,11 +3310,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .get_mac_addr = wpa_driver_test_get_mac_addr, .send_eapol = wpa_driver_test_send_eapol, .mlme_setprotection = wpa_driver_test_mlme_setprotection, - .set_channel = wpa_driver_test_set_channel, - .set_ssid = wpa_driver_test_set_ssid, - .set_bssid = wpa_driver_test_set_bssid, - .mlme_add_sta = wpa_driver_test_mlme_add_sta, - .mlme_remove_sta = wpa_driver_test_mlme_remove_sta, .get_scan_results2 = wpa_driver_test_get_scan_results2, .global_init = wpa_driver_test_global_init, .global_deinit = wpa_driver_test_global_deinit, diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 001716e..381cb3e 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -25,7 +25,7 @@ #include <fcntl.h> #include <net/if_arp.h> -#include "wireless_copy.h" +#include "linux_wext.h" #include "common.h" #include "eloop.h" #include "common/ieee802_11_defs.h" @@ -37,6 +37,9 @@ #include "driver.h" #include "driver_wext.h" +#ifdef ANDROID +#include "android_drv.h" +#endif /* ANDROID */ static int wpa_driver_wext_flush_pmkid(void *priv); static int wpa_driver_wext_get_range(void *priv); @@ -842,12 +845,13 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) } drv->mlme_sock = -1; + #ifdef ANDROID drv->errors = 0; drv->driver_is_started = TRUE; drv->skip_disconnect = 0; drv->bgscan_enabled = 0; -#endif +#endif /* ANDROID */ if (wpa_driver_wext_finish_drv_init(drv) < 0) goto err3; @@ -1416,7 +1420,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, tmp[res->num++] = r; res->res = tmp; } - + /** * wpa_driver_wext_get_scan_results - Fetch the latest scan results @@ -1426,7 +1430,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, 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; + size_t len; int first; u8 *res_buf; struct iw_event iwe_buf, *iwe = &iwe_buf; @@ -1438,7 +1442,6 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) if (res_buf == NULL) return NULL; - ap_num = 0; first = 1; res = os_zalloc(sizeof(*res)); @@ -1868,8 +1871,10 @@ 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 }; +#ifndef ANDROID u8 ssid[32]; int i; +#endif /* ANDROID */ /* * Only force-disconnect when the card is in infrastructure mode, @@ -1884,40 +1889,39 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) } if (iwr.u.mode == IW_MODE_INFRA) { + /* Clear the BSSID selection */ + if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) { + wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID " + "selection on disconnect"); + } + +#ifndef ANDROID if (drv->cfg80211) { /* * cfg80211 supports SIOCSIWMLME commands, so there is * no need for the random SSID hack, but clear the - * BSSID and SSID. + * SSID. */ - if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || -#ifdef ANDROID - 0) { -#else - wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { -#endif + if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " - "to disconnect"); + "SSID on disconnect"); } return; } + /* - * 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). + * 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). */ for (i = 0; i < 32; i++) ssid[i] = rand() & 0xFF; - if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || -#ifdef ANDROID - 0) { -#else - wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { -#endif + if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " - "BSSID/SSID to disconnect"); + "SSID to disconnect"); } +#endif /* ANDROID */ } } @@ -2350,6 +2354,129 @@ static const char * wext_get_radio_name(void *priv) } +#ifdef ANDROID + +static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd) +{ + struct iwreq iwr; + char buf[MAX_DRV_CMD_SIZE]; + int ret; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + + os_memset(buf, 0, sizeof(buf)); + os_strlcpy(buf, cmd, sizeof(buf)); + + iwr.u.data.pointer = buf; + iwr.u.data.length = sizeof(buf); + + ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, + cmd); + drv->errors++; + if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv->errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE + "HANGED"); + } + return ret; + } + + drv->errors = 0; + return 0; +} + + +static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params, + u32 interval) +{ + struct wpa_driver_wext_data *drv = priv; + struct iwreq iwr; + int ret = 0, i = 0, bp; + char buf[WEXT_PNO_MAX_COMMAND_SIZE]; + + bp = WEXT_PNOSETUP_HEADER_SIZE; + os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); + buf[bp++] = WEXT_PNO_TLV_PREFIX; + buf[bp++] = WEXT_PNO_TLV_VERSION; + buf[bp++] = WEXT_PNO_TLV_SUBVERSION; + buf[bp++] = WEXT_PNO_TLV_RESERVED; + + while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { + /* + * Check that there is enough space needed for 1 more SSID, the + * other sections and null termination. + */ + if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) + break; + + wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + buf[bp++] = WEXT_PNO_SSID_SECTION; + buf[bp++] = params->ssids[i].ssid_len; + os_memcpy(&buf[bp], params->ssids[i].ssid, + params->ssids[i].ssid_len); + bp += params->ssids[i].ssid_len; + i++; + } + + buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; + /* TODO: consider using interval parameter (interval in msec) instead + * of hardcoded value here */ + os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", + WEXT_PNO_SCAN_INTERVAL); + bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; + + buf[bp++] = WEXT_PNO_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_REPEAT); + bp += WEXT_PNO_REPEAT_LENGTH; + + buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_MAX_REPEAT); + bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = buf; + iwr.u.data.length = bp; + + ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); + if (ret < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", + ret); + drv->errors++; + if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv->errors = 0; + wpa_msg(drv->ctx, MSG_INFO, + WPA_EVENT_DRIVER_STATE "HANGED"); + } + return ret; + } + + drv->errors = 0; + drv->bgscan_enabled = 1; + + return android_wext_cmd(drv, "PNOFORCE 1"); +} + + +static int wext_stop_sched_scan(void *priv) +{ + struct wpa_driver_wext_data *drv = priv; + drv->bgscan_enabled = 0; + return android_wext_cmd(drv, "PNOFORCE 0"); +} + +#endif /* ANDROID */ + + const struct wpa_driver_ops wpa_driver_wext_ops = { .name = "wext", .desc = "Linux wireless extensions (generic)", @@ -2371,7 +2498,7 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .set_operstate = wpa_driver_wext_set_operstate, .get_radio_name = wext_get_radio_name, #ifdef ANDROID - .signal_poll = wpa_driver_signal_poll, - .driver_cmd = wpa_driver_wext_driver_cmd, -#endif + .sched_scan = wext_sched_scan, + .stop_sched_scan = wext_stop_sched_scan, +#endif /* ANDROID */ }; diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index 51e4d98..03df8e4 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -50,12 +50,13 @@ struct wpa_driver_wext_data { int cfg80211; /* whether driver is using cfg80211 */ u8 max_level; + #ifdef ANDROID int errors; int driver_is_started; int skip_disconnect; int bgscan_enabled; -#endif +#endif /* ANDROID */ }; int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); @@ -90,9 +91,4 @@ int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, int wpa_driver_wext_cipher2wext(int cipher); int wpa_driver_wext_keymgmt2wext(int keymgmt); -#ifdef ANDROID -#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE " -#define WEXT_CSCAN_AMOUNT 9 -#endif - #endif /* DRIVER_WEXT_H */ diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index b710778..667ea22 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -27,9 +27,6 @@ extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ #ifdef CONFIG_DRIVER_MADWIFI extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */ #endif /* CONFIG_DRIVER_MADWIFI */ -#ifdef CONFIG_DRIVER_BROADCOM -extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */ -#endif /* CONFIG_DRIVER_BROADCOM */ #ifdef CONFIG_DRIVER_BSD extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ #endif /* CONFIG_DRIVER_BSD */ @@ -42,15 +39,6 @@ extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ #ifdef CONFIG_DRIVER_TEST extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */ #endif /* CONFIG_DRIVER_TEST */ -#ifdef CONFIG_DRIVER_RALINK -extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */ -#endif /* CONFIG_DRIVER_RALINK */ -#ifdef CONFIG_DRIVER_OSX -extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */ -#endif /* CONFIG_DRIVER_OSX */ -#ifdef CONFIG_DRIVER_IPHONE -extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */ -#endif /* CONFIG_DRIVER_IPHONE */ #ifdef CONFIG_DRIVER_ROBOSWITCH /* driver_roboswitch.c */ extern struct wpa_driver_ops wpa_driver_roboswitch_ops; @@ -77,9 +65,6 @@ struct wpa_driver_ops *wpa_drivers[] = #ifdef CONFIG_DRIVER_MADWIFI &wpa_driver_madwifi_ops, #endif /* CONFIG_DRIVER_MADWIFI */ -#ifdef CONFIG_DRIVER_BROADCOM - &wpa_driver_broadcom_ops, -#endif /* CONFIG_DRIVER_BROADCOM */ #ifdef CONFIG_DRIVER_BSD &wpa_driver_bsd_ops, #endif /* CONFIG_DRIVER_BSD */ @@ -92,15 +77,6 @@ struct wpa_driver_ops *wpa_drivers[] = #ifdef CONFIG_DRIVER_TEST &wpa_driver_test_ops, #endif /* CONFIG_DRIVER_TEST */ -#ifdef CONFIG_DRIVER_RALINK - &wpa_driver_ralink_ops, -#endif /* CONFIG_DRIVER_RALINK */ -#ifdef CONFIG_DRIVER_OSX - &wpa_driver_osx_ops, -#endif /* CONFIG_DRIVER_OSX */ -#ifdef CONFIG_DRIVER_IPHONE - &wpa_driver_iphone_ops, -#endif /* CONFIG_DRIVER_IPHONE */ #ifdef CONFIG_DRIVER_ROBOSWITCH &wpa_driver_roboswitch_ops, #endif /* CONFIG_DRIVER_ROBOSWITCH */ diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index ebf39c8..0cc81f9 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -12,29 +12,11 @@ DRV_AP_LIBS = ##### COMMON DRIVERS -ifdef CONFIG_DRIVER_HOSTAP -DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP -DRV_OBJS += ../src/drivers/driver_hostap.o -CONFIG_WIRELESS_EXTENSION=y -NEED_AP_MLME=y -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_WIRED DRV_CFLAGS += -DCONFIG_DRIVER_WIRED DRV_OBJS += ../src/drivers/driver_wired.o endif -ifdef CONFIG_DRIVER_MADWIFI -DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI -DRV_OBJS += ../src/drivers/driver_madwifi.o -CONFIG_WIRELESS_EXTENSION=y -CONFIG_L2_PACKET=linux -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += ../src/drivers/driver_nl80211.o @@ -44,15 +26,22 @@ NEED_AP_MLME=y NEED_NETLINK=y NEED_LINUX_IOCTL=y NEED_RFKILL=y -ifdef CONFIG_LIBNL_TINY -DRV_LIBS += -lnl-tiny + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 else -DRV_LIBS += -lnl -endif + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif -ifdef CONFIG_LIBNL20 -DRV_LIBS += -lnl-genl -DRV_CFLAGS += -DCONFIG_LIBNL20 + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif endif endif @@ -79,6 +68,24 @@ endif ##### PURE AP DRIVERS +ifdef CONFIG_DRIVER_HOSTAP +DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP +DRV_AP_OBJS += ../src/drivers/driver_hostap.o +CONFIG_WIRELESS_EXTENSION=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_MADWIFI +DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI +DRV_AP_OBJS += ../src/drivers/driver_madwifi.o +CONFIG_WIRELESS_EXTENSION=y +CONFIG_L2_PACKET=linux +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + ifdef CONFIG_DRIVER_ATHEROS DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS DRV_AP_OBJS += ../src/drivers/driver_atheros.o @@ -97,18 +104,6 @@ NEED_LINUX_IOCTL=y NEED_RFKILL=y endif -ifdef CONFIG_DRIVER_RALINK -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK -DRV_WPA_OBJS += ../src/drivers/driver_ralink.o -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - -ifdef CONFIG_DRIVER_BROADCOM -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM -DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o -endif - ifdef CONFIG_DRIVER_NDIS DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS DRV_WPA_OBJS += ../src/drivers/driver_ndis.o @@ -124,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO endif endif -ifdef CONFIG_DRIVER_OSX -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX -DRV_WPA_OBJS += ../src/drivers/driver_osx.o -DRV_WPA_LDFLAGS += -framework CoreFoundation -DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 -endif - -ifdef CONFIG_DRIVER_IPHONE -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE -DRV_WPA_OBJS += ../src/drivers/driver_iphone.o -DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o -DRV_WPA_LDFLAGS += -framework CoreFoundation -endif - ifdef CONFIG_DRIVER_ROBOSWITCH DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk index c690e1c..1d7129c 100644 --- a/src/drivers/drivers.mk +++ b/src/drivers/drivers.mk @@ -12,29 +12,11 @@ DRV_AP_LIBS = ##### COMMON DRIVERS -ifdef CONFIG_DRIVER_HOSTAP -DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP -DRV_OBJS += src/drivers/driver_hostap.c -CONFIG_WIRELESS_EXTENSION=y -NEED_AP_MLME=y -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_WIRED DRV_CFLAGS += -DCONFIG_DRIVER_WIRED DRV_OBJS += src/drivers/driver_wired.c endif -ifdef CONFIG_DRIVER_MADWIFI -DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI -DRV_OBJS += src/drivers/driver_madwifi.c -CONFIG_WIRELESS_EXTENSION=y -CONFIG_L2_PACKET=linux -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += src/drivers/driver_nl80211.c @@ -44,15 +26,22 @@ NEED_AP_MLME=y NEED_NETLINK=y NEED_LINUX_IOCTL=y NEED_RFKILL=y -ifdef CONFIG_LIBNL_TINY -DRV_LIBS += -lnl-tiny + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 else -DRV_LIBS += -lnl -endif + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif -ifdef CONFIG_LIBNL20 -DRV_LIBS += -lnl-genl -DRV_CFLAGS += -DCONFIG_LIBNL20 + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif endif endif @@ -79,6 +68,24 @@ endif ##### PURE AP DRIVERS +ifdef CONFIG_DRIVER_HOSTAP +DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP +DRV_AP_OBJS += src/drivers/driver_hostap.c +CONFIG_WIRELESS_EXTENSION=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_MADWIFI +DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI +DRV_AP_OBJS += src/drivers/driver_madwifi.c +CONFIG_WIRELESS_EXTENSION=y +CONFIG_L2_PACKET=linux +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + ifdef CONFIG_DRIVER_ATHEROS DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS DRV_AP_OBJS += src/drivers/driver_atheros.c @@ -97,18 +104,6 @@ NEED_LINUX_IOCTL=y NEED_RFKILL=y endif -ifdef CONFIG_DRIVER_RALINK -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK -DRV_WPA_OBJS += src/drivers/driver_ralink.c -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - -ifdef CONFIG_DRIVER_BROADCOM -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM -DRV_WPA_OBJS += src/drivers/driver_broadcom.c -endif - ifdef CONFIG_DRIVER_NDIS DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS DRV_WPA_OBJS += src/drivers/driver_ndis.c @@ -124,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO endif endif -ifdef CONFIG_DRIVER_OSX -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX -DRV_WPA_OBJS += src/drivers/driver_osx.c -DRV_WPA_LDFLAGS += -framework CoreFoundation -DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 -endif - -ifdef CONFIG_DRIVER_IPHONE -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE -DRV_WPA_OBJS += src/drivers/driver_iphone.c -DRV_WPA_OBJS += src/drivers/MobileApple80211.c -DRV_WPA_LDFLAGS += -framework CoreFoundation -endif - ifdef CONFIG_DRIVER_ROBOSWITCH DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH DRV_WPA_OBJS += src/drivers/driver_roboswitch.c diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c index 0d6cf54..d7501cf 100644 --- a/src/drivers/linux_ioctl.c +++ b/src/drivers/linux_ioctl.c @@ -24,6 +24,7 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up) { struct ifreq ifr; + int ret; if (sock < 0) return -1; @@ -32,9 +33,10 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up) os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", ifname, strerror(errno)); - return -1; + return ret; } if (dev_up) { @@ -48,15 +50,38 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up) } if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s", ifname, strerror(errno)); - return -1; + return ret; } return 0; } +int linux_iface_up(int sock, const char *ifname) +{ + struct ifreq ifr; + int ret; + + if (sock < 0) + return -1; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + + if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; + wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", + ifname, strerror(errno)); + return ret; + } + + return !!(ifr.ifr_flags & IFF_UP); +} + + int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr) { struct ifreq ifr; diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h index a555738..e0bf673 100644 --- a/src/drivers/linux_ioctl.h +++ b/src/drivers/linux_ioctl.h @@ -16,6 +16,7 @@ #define LINUX_IOCTL_H int linux_set_iface_flags(int sock, const char *ifname, int dev_up); +int linux_iface_up(int sock, const char *ifname); int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr); int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr); int linux_br_add(int sock, const char *brname); diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h new file mode 100644 index 0000000..b6eea68 --- /dev/null +++ b/src/drivers/linux_wext.h @@ -0,0 +1,51 @@ +/* + * Driver interaction with generic Linux Wireless Extensions + * Copyright (c) 2003-2011, 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 LINUX_WEXT_H +#define LINUX_WEXT_H + +#ifndef ANDROID + +/* + * Avoid including other kernel header to avoid conflicts with C library + * headers. + */ +#define _LINUX_TYPES_H +#define _LINUX_SOCKET_H +#define _LINUX_IF_H + +#include <sys/types.h> +#include <net/if.h> +typedef __uint32_t __u32; +typedef __int32_t __s32; +typedef __uint16_t __u16; +typedef __int16_t __s16; +typedef __uint8_t __u8; +#ifndef __user +#define __user +#endif /* __user */ + +#endif /* ANDROID */ + +#include <linux/wireless.h> + +#ifndef IW_ENCODE_ALG_PMK +#define IW_ENCODE_ALG_PMK 4 +#endif + +#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE +#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 +#endif + +#endif /* LINUX_WEXT_H */ diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c index ad15b1d..6778907 100644 --- a/src/drivers/netlink.c +++ b/src/drivers/netlink.c @@ -34,7 +34,7 @@ static void netlink_receive_link(struct netlink_data *netlink, if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg)) return; cb(netlink->cfg->ctx, NLMSG_DATA(h), - NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), + (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg))); } diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 7483a89..f9261c2 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -6,7 +6,7 @@ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2008 Michael Wu <flamingice@sourmilk.net> * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com> - * Copyright 2008 Michael Buesch <mb@bu3sch.de> + * Copyright 2008 Michael Buesch <m@bues.ch> * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com> * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> * Copyright 2008 Colin McCabe <colin@cozybit.com> @@ -77,6 +77,39 @@ */ /** + * DOC: Virtual interface / concurrency capabilities + * + * Some devices are able to operate with virtual MACs, they can have + * more than one virtual interface. The capability handling for this + * is a bit complex though, as there may be a number of restrictions + * on the types of concurrency that are supported. + * + * To start with, each device supports the interface types listed in + * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the + * types there no concurrency is implied. + * + * Once concurrency is desired, more attributes must be observed: + * To start with, since some interface types are purely managed in + * software, like the AP-VLAN type in mac80211 for example, there's + * an additional list of these, they can be added at any time and + * are only restricted by some semantic restrictions (e.g. AP-VLAN + * cannot be added without a corresponding AP interface). This list + * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute. + * + * Further, the list of supported combinations is exported. This is + * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically, + * it exports a list of "groups", and at any point in time the + * interfaces that are currently active must fall into any one of + * the advertised groups. Within each group, there are restrictions + * on the number of interfaces of different types that are supported + * and also the number of different channels, along with potentially + * some other restrictions. See &enum nl80211_if_combination_attrs. + * + * All together, these attributes define the concurrency of virtual + * interfaces that a given device supports. + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -128,6 +161,13 @@ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. + * Following attributes are provided for drivers that generate full Beacon + * and Probe Response frames internally: %NL80211_ATTR_SSID, + * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, + * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, + * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP, + * %NL80211_ATTR_IE_ASSOC_RESP. * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, * parameters are like for %NL80211_CMD_SET_BEACON. * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it @@ -148,6 +188,10 @@ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by + * %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP. + * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by + * %NL80211_ATTR_MAC. * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the * the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC @@ -172,10 +216,10 @@ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will * store this as a valid request and then query userspace for it. * - * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the + * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the * interface identified by %NL80211_ATTR_IFINDEX * - * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the + * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the * interface identified by %NL80211_ATTR_IFINDEX * * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The @@ -194,11 +238,36 @@ * * @NL80211_CMD_GET_SCAN: get scan results * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * probe requests at CCK rate or not. * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to * NL80211_CMD_GET_SCAN and on the "scan" multicast group) * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * + * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain + * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. + * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) + * are passed, they are used in the probe requests. For + * broadcast, a broadcast SSID must be passed (ie. an empty + * string). If no SSID is passed, no probe requests are sent and + * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES, + * if passed, define which channels should be scanned; if not + * passed, all channels allowed for the current regulatory domain + * are used. Extra IEs can also be passed from the userspace by + * using the %NL80211_ATTR_IE attribute. + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT + * if scheduled scan is not running. + * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan + * results available. + * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has + * stopped. The driver may issue this event at any time during a + * scheduled scan. One reason for stopping the scan is if the hardware + * does not support starting an association or a normal scan while running + * a scheduled scan. This event is also sent when the + * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface + * is brought down while a scheduled scan was running. + * * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation * or noise level * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to @@ -365,6 +434,8 @@ * specified using %NL80211_ATTR_DURATION. When called, this operation * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the * TX status event pertaining to the TX request. + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * management frames at CCK rate or not in 2GHz band. * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this * command may be used with the corresponding cookie to cancel the wait * time if it is known that it is no longer necessary. @@ -406,11 +477,72 @@ * notification. This event is used to indicate that an unprotected * disassociation frame was dropped when MFP is in use. * + * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a + * beacon or probe response from a compatible mesh peer. This is only + * sent while no station information (sta_info) exists for the new peer + * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On + * reception of this notification, userspace may decide to create a new + * station (@NL80211_CMD_NEW_STATION). To stop this notification from + * reoccurring, the userspace authentication daemon may want to create the + * new station with the AUTHENTICATED flag unset and maybe change it later + * depending on the authentication result. + * + * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings. + * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings. + * Since wireless is more complex than wired ethernet, it supports + * various triggers. These triggers can be configured through this + * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For + * more background information, see + * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * + * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver + * the necessary information for supporting GTK rekey offload. This + * feature is typically used during WoWLAN. The configuration data + * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and + * contains the data in sub-attributes). After rekeying happened, + * this command may also be sent by the driver as an MLME event to + * inform userspace of the new replay counter. + * + * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace + * of PMKSA caching dandidates. + * + * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * + * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP + * (or GO) interface (i.e. hostapd) to ask for unexpected frames to + * implement sending deauth to stations that send unexpected class 3 + * frames. Also used as the event sent by the kernel when such a frame + * is received. + * For the event, the %NL80211_ATTR_MAC attribute carries the TA and + * other attributes like the interface index are present. + * If used as the command it must have an interface index and you can + * only unsubscribe from the event by closing the socket. Subscription + * is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events. + * + * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the + * associated station identified by %NL80211_ATTR_MAC sent a 4addr frame + * and wasn't already in a 4-addr VLAN. The event will be sent similarly + * to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener. + * + * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface + * by sending a null data frame to it and reporting when the frame is + * acknowleged. This is used to allow timing out inactive clients. Uses + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a + * direct reply with an %NL80211_ATTR_COOKIE that is later used to match + * up the event with the request. The event includes the same data and + * has %NL80211_ATTR_ACK set if the frame was ACKed. + * + * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from + * other BSSes when any interfaces are in AP mode. This helps implement + * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME + * messages. Note that per PHY only one application may register. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ enum nl80211_commands { -/* don't change the order or add anything inbetween, this is ABI! */ +/* don't change the order or add anything between, this is ABI! */ NL80211_CMD_UNSPEC, NL80211_CMD_GET_WIPHY, /* can dump */ @@ -448,8 +580,8 @@ enum nl80211_commands { NL80211_CMD_SET_REG, NL80211_CMD_REQ_SET_REG, - NL80211_CMD_GET_MESH_PARAMS, - NL80211_CMD_SET_MESH_PARAMS, + NL80211_CMD_GET_MESH_CONFIG, + NL80211_CMD_SET_MESH_CONFIG, NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */, @@ -518,6 +650,31 @@ enum nl80211_commands { NL80211_CMD_UNPROT_DEAUTHENTICATE, NL80211_CMD_UNPROT_DISASSOCIATE, + NL80211_CMD_NEW_PEER_CANDIDATE, + + NL80211_CMD_GET_WOWLAN, + NL80211_CMD_SET_WOWLAN, + + NL80211_CMD_START_SCHED_SCAN, + NL80211_CMD_STOP_SCHED_SCAN, + NL80211_CMD_SCHED_SCAN_RESULTS, + NL80211_CMD_SCHED_SCAN_STOPPED, + + NL80211_CMD_SET_REKEY_OFFLOAD, + + NL80211_CMD_PMKSA_CANDIDATE, + + NL80211_CMD_TDLS_OPER, + NL80211_CMD_TDLS_MGMT, + + NL80211_CMD_UNEXPECTED_FRAME, + + NL80211_CMD_PROBE_CLIENT, + + NL80211_CMD_REGISTER_BEACONS, + + NL80211_CMD_UNEXPECTED_4ADDR_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -538,6 +695,13 @@ enum nl80211_commands { #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +/* source-level API compatibility */ +#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG +#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG +#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE + /** * enum nl80211_attrs - nl80211 netlink attributes * @@ -608,7 +772,7 @@ enum nl80211_commands { * consisting of a nested array. * * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). - * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. + * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link. * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path * info given for %NL80211_CMD_GET_MPATH, nested attribute described at @@ -653,8 +817,14 @@ enum nl80211_commands { * * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with * a single scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can + * scan with a single scheduled scan request, a wiphy attribute. * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements * that can be added to a scan request + * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information + * elements that can be added to a scheduled scan request + * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be + * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute. * * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive @@ -735,18 +905,20 @@ enum nl80211_commands { * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT * event (u16) * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating - * that protected APs should be used. + * that protected APs should be used. This is also used with NEW_BEACON to + * indicate that the BSS is to use protection. * - * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to - * indicate which unicast key ciphers will be used with the connection + * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON + * to indicate which unicast key ciphers will be used with the connection * (an array of u32). - * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate - * which group key cipher will be used with the connection (a u32). - * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate - * which WPA version(s) the AP we want to associate with is using + * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which group key cipher will be used with the connection (a + * u32). + * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which WPA version(s) the AP we want to associate with is using * (a u32 with flags from &enum nl80211_wpa_versions). - * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate - * which key management algorithm(s) to use (an array of u32). + * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which key management algorithm(s) to use (an array of u32). * * @NL80211_ATTR_REQ_IE: (Re)association request information elements as * sent out by the card, for ROAM and successful CONNECT events. @@ -852,7 +1024,13 @@ enum nl80211_commands { * This can be used to mask out antennas which are not attached or should * not be used for receiving. If an antenna is not selected in this bitmap * the hardware should not be configured to receive on this antenna. - * For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available + * for configuration as TX antennas via the above parameters. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available + * for configuration as RX antennas via the above parameters. * * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS * @@ -868,11 +1046,135 @@ enum nl80211_commands { * attributes, specifying what a key should be set as default as. * See &enum nl80211_key_default_types. * + * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be + * changed once the mesh is active. + * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute + * containing attributes from &enum nl80211_meshconf_params. + * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver + * allows auth frames in a mesh to be passed to userspace for processing via + * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. + * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as + * defined in &enum nl80211_plink_state. Used when userspace is + * driving the peer link management state machine. + * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. + * + * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy + * capabilities, the supported WoWLAN triggers + * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to + * indicate which WoW triggers should be enabled. This is also + * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN + * triggers. + + * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan + * cycles, in msecs. + + * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more + * sets of attributes to match during scheduled scans. Only BSSs + * that match any of the sets will be reported. These are + * pass-thru filter rules. + * For a match to succeed, the BSS must match all attributes of a + * set. Since not every hardware supports matching all types of + * attributes, there is no guarantee that the reported BSSs are + * fully complying with the match sets and userspace needs to be + * able to ignore them by itself. + * Thus, the implementation is somewhat hardware-dependent, but + * this is only an optimization and the userspace application + * needs to handle all the non-filtered results anyway. + * If the match attributes don't make sense when combined with + * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID + * is included in the probe request, but the match attributes + * will never let it go through), -EINVAL may be returned. + * If ommited, no filtering is done. + * + * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported + * interface combinations. In each nested item, it contains attributes + * defined in &enum nl80211_if_combination_attrs. + * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like + * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that + * are managed in software: interfaces of these types aren't subject to + * any restrictions in their number or combinations. + * + * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information + * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. + * + * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan, + * nested array attribute containing an entry for each band, with the entry + * being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but + * without the length restriction (at most %NL80211_MAX_SUPP_RATES). + * + * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon + * and Probe Response (when response to wildcard Probe Request); see + * &enum nl80211_hidden_ssid, represented as a u32 + * + * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame. + * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to + * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the + * driver (or firmware) replies to Probe Request frames. + * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association + * Response frames. This is used with %NL80211_CMD_NEW_BEACON and + * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into + * (Re)Association Response frames when the driver (or firmware) replies to + * (Re)Association Request frames. + * + * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration + * of the station, see &enum nl80211_sta_wme_attr. + * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working + * as AP. + * + * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of + * roaming to another AP in the same ESS if the signal lever is low. + * + * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching + * candidate information, see &enum nl80211_pmksa_candidate_attr. + * + * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not + * for management frames transmission. In order to avoid p2p probe/action + * frames are being transmitted at CCK rate in 2GHz band, the user space + * applications use this attribute. + * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and + * %NL80211_CMD_FRAME commands. + * + * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup + * request, link setup confirm, link teardown, etc.). Values are + * described in the TDLS (802.11z) specification. + * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a + * TDLS conversation between two devices. + * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see + * &enum nl80211_tdls_operation, represented as a u8. + * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate + * as a TDLS peer sta. + * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown + * procedures should be performed by sending TDLS packets via + * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be + * used for asking the driver to perform a TDLS operation. + * + * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices + * that have AP support to indicate that they have the AP SME integrated + * with support for the features listed in this attribute, see + * &enum nl80211_ap_sme_features. + * + * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells + * the driver to not wait for an acknowledgement. Note that due to this, + * it will also not give a status callback nor return a cookie. This is + * mostly useful for probe responses to save airtime. + * + * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from + * &enum nl80211_feature_flags and is advertised in wiphy information. + * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe + * + * requests while operating in AP-mode. + * This attribute holds a bitmap of the supported protocols for + * offloading (see &enum nl80211_probe_resp_offload_support_attr). + * + * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire + * probe-response frame. The DA field in the 802.11 header is zero-ed out, + * to be filled by the FW. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ enum nl80211_attrs { -/* don't change the order or add anything inbetween, this is ABI! */ +/* don't change the order or add anything between, this is ABI! */ NL80211_ATTR_UNSPEC, NL80211_ATTR_WIPHY, @@ -922,7 +1224,7 @@ enum nl80211_attrs { NL80211_ATTR_REG_ALPHA2, NL80211_ATTR_REG_RULES, - NL80211_ATTR_MESH_PARAMS, + NL80211_ATTR_MESH_CONFIG, NL80211_ATTR_BSS_BASIC_RATES, @@ -1050,6 +1352,62 @@ enum nl80211_attrs { NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, + NL80211_ATTR_MESH_SETUP, + + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + + NL80211_ATTR_SUPPORT_MESH_AUTH, + NL80211_ATTR_STA_PLINK_STATE, + + NL80211_ATTR_WOWLAN_TRIGGERS, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, + + NL80211_ATTR_SCHED_SCAN_INTERVAL, + + NL80211_ATTR_INTERFACE_COMBINATIONS, + NL80211_ATTR_SOFTWARE_IFTYPES, + + NL80211_ATTR_REKEY_DATA, + + NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, + NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, + + NL80211_ATTR_SCAN_SUPP_RATES, + + NL80211_ATTR_HIDDEN_SSID, + + NL80211_ATTR_IE_PROBE_RESP, + NL80211_ATTR_IE_ASSOC_RESP, + + NL80211_ATTR_STA_WME, + NL80211_ATTR_SUPPORT_AP_UAPSD, + + NL80211_ATTR_ROAM_SUPPORT, + + NL80211_ATTR_SCHED_SCAN_MATCH, + NL80211_ATTR_MAX_MATCH_SETS, + + NL80211_ATTR_PMKSA_CANDIDATE, + + NL80211_ATTR_TX_NO_CCK_RATE, + + NL80211_ATTR_TDLS_ACTION, + NL80211_ATTR_TDLS_DIALOG_TOKEN, + NL80211_ATTR_TDLS_OPERATION, + NL80211_ATTR_TDLS_SUPPORT, + NL80211_ATTR_TDLS_EXTERNAL_SETUP, + + NL80211_ATTR_DEVICE_AP_SME, + + NL80211_ATTR_DONT_WAIT_FOR_ACK, + + NL80211_ATTR_FEATURE_FLAGS, + + NL80211_ATTR_PROBE_RESP_OFFLOAD, + + NL80211_ATTR_PROBE_RESP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1058,6 +1416,7 @@ enum nl80211_attrs { /* source-level API compatibility */ #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION +#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG /* * Allow user space programs to use #ifdef on new attributes by defining them @@ -1083,6 +1442,7 @@ enum nl80211_attrs { #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES #define NL80211_ATTR_KEY NL80211_ATTR_KEY #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 @@ -1101,7 +1461,9 @@ enum nl80211_attrs { * @NL80211_IFTYPE_ADHOC: independent BSS member * @NL80211_IFTYPE_STATION: managed BSS member * @NL80211_IFTYPE_AP: access point - * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points + * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces + * are a bit special in that they must always be tied to a pre-existing + * AP type interface. * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames * @NL80211_IFTYPE_MESH_POINT: mesh point @@ -1143,6 +1505,8 @@ enum nl80211_iftype { * with short barker preamble * @NL80211_STA_FLAG_WME: station is WME/QoS capable * @NL80211_STA_FLAG_MFP: station uses management frame protection + * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated + * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer * @NL80211_STA_FLAG_MAX: highest station flag number currently defined * @__NL80211_STA_FLAG_AFTER_LAST: internal use */ @@ -1152,6 +1516,8 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_SHORT_PREAMBLE, NL80211_STA_FLAG_WME, NL80211_STA_FLAG_MFP, + NL80211_STA_FLAG_AUTHENTICATED, + NL80211_STA_FLAG_TDLS_PEER, /* keep last */ __NL80211_STA_FLAG_AFTER_LAST, @@ -1197,6 +1563,36 @@ enum nl80211_rate_info { }; /** + * enum nl80211_sta_bss_param - BSS information collected by STA + * + * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM + * when getting information about the bitrate of a station. + * + * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved + * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag) + * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8) + * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16) + * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined + * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use + */ +enum nl80211_sta_bss_param { + __NL80211_STA_BSS_PARAM_INVALID, + NL80211_STA_BSS_PARAM_CTS_PROT, + NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, + NL80211_STA_BSS_PARAM_DTIM_PERIOD, + NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + + /* keep last */ + __NL80211_STA_BSS_PARAM_AFTER_LAST, + NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1 +}; + +/** * enum nl80211_sta_info - station information * * These attribute types are used with %NL80211_ATTR_STA_INFO @@ -1206,17 +1602,27 @@ enum nl80211_rate_info { * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) - * @__NL80211_STA_INFO_AFTER_LAST: internal - * @NL80211_STA_INFO_MAX: highest possible station info attribute * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute - * containing info as possible, see &enum nl80211_sta_info_txrate. + * containing info as possible, see &enum nl80211_rate_info * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this * station) * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) + * @NL80211_STA_INFO_LLID: the station's mesh LLID + * @NL80211_STA_INFO_PLID: the station's mesh PLID + * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station + * (see %enum nl80211_plink_state) + * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested + * attribute, like NL80211_STA_INFO_TX_BITRATE. + * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute + * containing info as possible, see &enum nl80211_sta_bss_param + * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected + * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute */ enum nl80211_sta_info { __NL80211_STA_INFO_INVALID, @@ -1233,6 +1639,10 @@ enum nl80211_sta_info { NL80211_STA_INFO_TX_RETRIES, NL80211_STA_INFO_TX_FAILED, NL80211_STA_INFO_SIGNAL_AVG, + NL80211_STA_INFO_RX_BITRATE, + NL80211_STA_INFO_BSS_PARAM, + NL80211_STA_INFO_CONNECTED_TIME, + NL80211_STA_INFO_STA_FLAGS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -1388,7 +1798,7 @@ enum nl80211_bitrate_attr { * 802.11 country information element with regulatory information it * thinks we should consider. cfg80211 only processes the country * code from the IE, and relies on the regulatory domain information - * structure pased by userspace (CRDA) from our wireless-regdb. + * structure passed by userspace (CRDA) from our wireless-regdb. * If a channel is enabled but the country code indicates it should * be disabled we disable the channel and re-enable it upon disassociation. */ @@ -1462,6 +1872,26 @@ enum nl80211_reg_rule_attr { }; /** + * enum nl80211_sched_scan_match_attr - scheduled scan match attributes + * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, + * only report BSS with matching SSID. + * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter + * attribute number currently defined + * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use + */ +enum nl80211_sched_scan_match_attr { + __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID, + + NL80211_ATTR_SCHED_SCAN_MATCH_SSID, + + /* keep last */ + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, + NL80211_SCHED_SCAN_MATCH_ATTR_MAX = + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_reg_rule_flags - regulatory rule flags * * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed @@ -1559,14 +1989,15 @@ enum nl80211_mntr_flags { /** * enum nl80211_meshconf_params - mesh configuration parameters * - * Mesh configuration parameters + * Mesh configuration parameters. These can be changed while the mesh is + * active. * * @__NL80211_MESHCONF_INVALID: internal use * * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in * millisecond units, used by the Peer Link Open message * - * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in + * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in * millisecond units, used by the peer link management to close a peer link * * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in @@ -1582,9 +2013,6 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh * point. * - * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a - * source mesh point for path selection elements. - * * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically * open peer links when we detect compatible mesh peers. * @@ -1609,7 +2037,17 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) * that it takes for an HWMP information element to propagate across the mesh * - * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not + * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not + * + * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a + * source mesh point for path selection elements. + * + * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between + * root announcements are transmitted. + * + * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has + * access to a broader network beyond the MBSS. This is done via Root + * Announcement frames. * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * @@ -1632,6 +2070,8 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, NL80211_MESHCONF_HWMP_ROOTMODE, NL80211_MESHCONF_ELEMENT_TTL, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + NL80211_MESHCONF_GATE_ANNOUNCEMENTS, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, @@ -1639,6 +2079,54 @@ enum nl80211_meshconf_params { }; /** + * enum nl80211_mesh_setup_params - mesh setup parameters + * + * Mesh setup parameters. These are used to start/join a mesh and cannot be + * changed while the mesh is active. + * + * @__NL80211_MESH_SETUP_INVALID: Internal use + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a + * vendor specific path selection algorithm or disable it to use the default + * HWMP. + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a + * vendor specific path metric or disable it to use the default Airtime + * metric. + * + * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a + * robust security network ie, or a vendor specific information element that + * vendors will use to identify the path selection methods and metrics in use. + * + * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication + * daemon will be authenticating mesh candidates. + * + * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication + * daemon will be securing peer link frames. AMPE is a secured version of Mesh + * Peering Management (MPM) and is implemented with the assistance of a + * userspace daemon. When this flag is set, the kernel will send peer + * management frames to a userspace daemon that will implement AMPE + * functionality (security capabilities selection, key confirmation, and key + * management). When the flag is unset (default), the kernel can autonomously + * complete (unsecured) mesh peering without the need of a userspace daemon. + * + * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number + * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use + */ +enum nl80211_mesh_setup_params { + __NL80211_MESH_SETUP_INVALID, + NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, + NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, + NL80211_MESH_SETUP_IE, + NL80211_MESH_SETUP_USERSPACE_AUTH, + NL80211_MESH_SETUP_USERSPACE_AMPE, + + /* keep last */ + __NL80211_MESH_SETUP_ATTR_AFTER_LAST, + NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_txq_attr - TX queue parameter attributes * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) @@ -1936,4 +2424,341 @@ enum nl80211_tx_power_setting { NL80211_TX_POWER_FIXED, }; +/** + * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute + * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute + * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has + * a zero bit are ignored + * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have + * a bit for each byte in the pattern. The lowest-order bit corresponds + * to the first byte of the pattern, but the bytes of the pattern are + * in a little-endian-like format, i.e. the 9th byte of the pattern + * corresponds to the lowest-order bit in the second byte of the mask. + * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where + * xx indicates "don't care") would be represented by a pattern of + * twelve zero bytes, and a mask of "0xed,0x07". + * Note that the pattern matching is done as though frames were not + * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked + * first (including SNAP header unpacking) and then matched. + * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes + * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number + */ +enum nl80211_wowlan_packet_pattern_attr { + __NL80211_WOWLAN_PKTPAT_INVALID, + NL80211_WOWLAN_PKTPAT_MASK, + NL80211_WOWLAN_PKTPAT_PATTERN, + + NUM_NL80211_WOWLAN_PKTPAT, + MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, +}; + +/** + * struct nl80211_wowlan_pattern_support - pattern support information + * @max_patterns: maximum number of patterns supported + * @min_pattern_len: minimum length of each pattern + * @max_pattern_len: maximum length of each pattern + * + * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when + * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the + * capability information given by the kernel to userspace. + */ +struct nl80211_wowlan_pattern_support { + __u32 max_patterns; + __u32 min_pattern_len; + __u32 max_pattern_len; +} __attribute__((packed)); + +/** + * enum nl80211_wowlan_triggers - WoWLAN trigger definitions + * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes + * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put + * the chip into a special state -- works best with chips that have + * support for low-power operation already (flag) + * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect + * is detected is implementation-specific (flag) + * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed + * by 16 repetitions of MAC addr, anywhere in payload) (flag) + * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns + * which are passed in an array of nested attributes, each nested attribute + * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. + * Each pattern defines a wakeup packet. The matching is done on the MSDU, + * i.e. as though the packet was an 802.3 packet, so the pattern matching + * is done after the packet is converted to the MSDU. + * + * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute + * carrying a &struct nl80211_wowlan_pattern_support. + * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be + * used when setting, used only to indicate that GTK rekeying is supported + * by the device (flag) + * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if + * done by the device) (flag) + * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request + * packet (flag) + * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) + * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released + * (on devices that have rfkill in the device) (flag) + * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers + * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number + */ +enum nl80211_wowlan_triggers { + __NL80211_WOWLAN_TRIG_INVALID, + NL80211_WOWLAN_TRIG_ANY, + NL80211_WOWLAN_TRIG_DISCONNECT, + NL80211_WOWLAN_TRIG_MAGIC_PKT, + NL80211_WOWLAN_TRIG_PKT_PATTERN, + NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED, + NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, + NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, + NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, + NL80211_WOWLAN_TRIG_RFKILL_RELEASE, + + /* keep last */ + NUM_NL80211_WOWLAN_TRIG, + MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 +}; + +/** + * enum nl80211_iface_limit_attrs - limit attributes + * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) + * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that + * can be chosen from this set of interface types (u32) + * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a + * flag attribute for each interface type in this set + * @NUM_NL80211_IFACE_LIMIT: number of attributes + * @MAX_NL80211_IFACE_LIMIT: highest attribute number + */ +enum nl80211_iface_limit_attrs { + NL80211_IFACE_LIMIT_UNSPEC, + NL80211_IFACE_LIMIT_MAX, + NL80211_IFACE_LIMIT_TYPES, + + /* keep last */ + NUM_NL80211_IFACE_LIMIT, + MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1 +}; + +/** + * enum nl80211_if_combination_attrs -- interface combination attributes + * + * @NL80211_IFACE_COMB_UNSPEC: (reserved) + * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits + * for given interface types, see &enum nl80211_iface_limit_attrs. + * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of + * interfaces that can be created in this group. This number doesn't + * apply to interfaces purely managed in software, which are listed + * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE. + * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that + * beacon intervals within this group must be all the same even for + * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt + * the infrastructure network's beacon interval. + * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many + * different channels may be used within this group. + * @NUM_NL80211_IFACE_COMB: number of attributes + * @MAX_NL80211_IFACE_COMB: highest attribute number + * + * Examples: + * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 + * => allows an AP and a STA that must match BIs + * + * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 + * => allows 8 of AP/GO + * + * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 + * => allows two STAs on different channels + * + * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 + * => allows a STA plus three P2P interfaces + * + * The list of these four possiblities could completely be contained + * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate + * that any of these groups must match. + * + * "Combinations" of just a single interface will not be listed here, + * a single interface of any valid interface type is assumed to always + * be possible by itself. This means that implicitly, for each valid + * interface type, the following group always exists: + * numbers = [ #{<type>} <= 1 ], channels = 1, max = 1 + */ +enum nl80211_if_combination_attrs { + NL80211_IFACE_COMB_UNSPEC, + NL80211_IFACE_COMB_LIMITS, + NL80211_IFACE_COMB_MAXNUM, + NL80211_IFACE_COMB_STA_AP_BI_MATCH, + NL80211_IFACE_COMB_NUM_CHANNELS, + + /* keep last */ + NUM_NL80211_IFACE_COMB, + MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 +}; + + +/** + * enum nl80211_plink_state - state of a mesh peer link finite state machine + * + * @NL80211_PLINK_LISTEN: initial state, considered the implicit + * state of non existant mesh peer links + * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to + * this mesh peer + * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received + * from this mesh peer + * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been + * received from this mesh peer + * @NL80211_PLINK_ESTAB: mesh peer link is established + * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled + * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh + * plink are discarded + * @NUM_NL80211_PLINK_STATES: number of peer link states + * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states + */ +enum nl80211_plink_state { + NL80211_PLINK_LISTEN, + NL80211_PLINK_OPN_SNT, + NL80211_PLINK_OPN_RCVD, + NL80211_PLINK_CNF_RCVD, + NL80211_PLINK_ESTAB, + NL80211_PLINK_HOLDING, + NL80211_PLINK_BLOCKED, + + /* keep last */ + NUM_NL80211_PLINK_STATES, + MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 +}; + +#define NL80211_KCK_LEN 16 +#define NL80211_KEK_LEN 16 +#define NL80211_REPLAY_CTR_LEN 8 + +/** + * enum nl80211_rekey_data - attributes for GTK rekey offload + * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes + * @NL80211_REKEY_DATA_KEK: key encryption key (binary) + * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) + * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) + * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) + */ +enum nl80211_rekey_data { + __NL80211_REKEY_DATA_INVALID, + NL80211_REKEY_DATA_KEK, + NL80211_REKEY_DATA_KCK, + NL80211_REKEY_DATA_REPLAY_CTR, + + /* keep last */ + NUM_NL80211_REKEY_DATA, + MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1 +}; + +/** + * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID + * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in + * Beacon frames) + * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element + * in Beacon frames + * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID + * element in Beacon frames but zero out each byte in the SSID + */ +enum nl80211_hidden_ssid { + NL80211_HIDDEN_SSID_NOT_IN_USE, + NL80211_HIDDEN_SSID_ZERO_LEN, + NL80211_HIDDEN_SSID_ZERO_CONTENTS +}; + +/** + * enum nl80211_sta_wme_attr - station WME attributes + * @__NL80211_STA_WME_INVALID: invalid number for nested attribute + * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format + * is the same as the AC bitmap in the QoS info field. + * @NL80211_STA_WME_MAX_SP: max service period. the format is the same + * as the MAX_SP field in the QoS info field (but already shifted down). + * @__NL80211_STA_WME_AFTER_LAST: internal + * @NL80211_STA_WME_MAX: highest station WME attribute + */ +enum nl80211_sta_wme_attr { + __NL80211_STA_WME_INVALID, + NL80211_STA_WME_UAPSD_QUEUES, + NL80211_STA_WME_MAX_SP, + + /* keep last */ + __NL80211_STA_WME_AFTER_LAST, + NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1 +}; + +/** + * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates + * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes + * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher + * priority) + * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets) + * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag) + * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes + * (internal) + * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute + * (internal) + */ +enum nl80211_pmksa_candidate_attr { + __NL80211_PMKSA_CANDIDATE_INVALID, + NL80211_PMKSA_CANDIDATE_INDEX, + NL80211_PMKSA_CANDIDATE_BSSID, + NL80211_PMKSA_CANDIDATE_PREAUTH, + + /* keep last */ + NUM_NL80211_PMKSA_CANDIDATE, + MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 +}; + +/** + * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION + * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request + * @NL80211_TDLS_SETUP: Setup TDLS link + * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established + * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link + * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link + */ +enum nl80211_tdls_operation { + NL80211_TDLS_DISCOVERY_REQ, + NL80211_TDLS_SETUP, + NL80211_TDLS_TEARDOWN, + NL80211_TDLS_ENABLE_LINK, + NL80211_TDLS_DISABLE_LINK, +}; + +/* + * enum nl80211_ap_sme_features - device-integrated AP features + * Reserved for future use, no bits are defined in + * NL80211_ATTR_DEVICE_AP_SME yet. +enum nl80211_ap_sme_features { +}; + */ + +/** + * enum nl80211_feature_flags - device/driver features + * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back + * TX status to the socket error queue when requested with the + * socket option. + */ +enum nl80211_feature_flags { + NL80211_FEATURE_SK_TX_STATUS = 1 << 0, +}; + +/** + * enum nl80211_probe_resp_offload_support_attr - optional supported + * protocols for probe-response offloading by the driver/FW. + * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute. + * Each enum value represents a bit in the bitmap of supported + * protocols. Typically a subset of probe-requests belonging to a + * supported protocol will be excluded from offload and uploaded + * to the host. + * + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u + */ +enum nl80211_probe_resp_offload_support_attr { + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h deleted file mode 100644 index 201719b..0000000 --- a/src/drivers/wireless_copy.h +++ /dev/null @@ -1,1185 +0,0 @@ -/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 22. - * I have just removed kernel related headers and added some typedefs etc. to - * make this easier to include into user space programs. - * Jouni Malinen, 2005-03-12. - */ - - -/* - * This file define a set of standard wireless extensions - * - * Version : 22 16.3.07 - * - * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> - * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. - */ - -#ifndef _LINUX_WIRELESS_H -#define _LINUX_WIRELESS_H - -/************************** DOCUMENTATION **************************/ -/* - * Initial APIs (1996 -> onward) : - * ----------------------------- - * Basically, the wireless extensions are for now a set of standard ioctl - * call + /proc/net/wireless - * - * The entry /proc/net/wireless give statistics and information on the - * driver. - * This is better than having each driver having its entry because - * its centralised and we may remove the driver module safely. - * - * Ioctl are used to configure the driver and issue commands. This is - * better than command line options of insmod because we may want to - * change dynamically (while the driver is running) some parameters. - * - * The ioctl mechanimsm are copied from standard devices ioctl. - * We have the list of command plus a structure descibing the - * data exchanged... - * Note that to add these ioctl, I was obliged to modify : - * # net/core/dev.c (two place + add include) - * # net/ipv4/af_inet.c (one place + add include) - * - * /proc/net/wireless is a copy of /proc/net/dev. - * We have a structure for data passed from the driver to /proc/net/wireless - * Too add this, I've modified : - * # net/core/dev.c (two other places) - * # include/linux/netdevice.h (one place) - * # include/linux/proc_fs.h (one place) - * - * New driver API (2002 -> onward) : - * ------------------------------- - * This file is only concerned with the user space API and common definitions. - * The new driver API is defined and documented in : - * # include/net/iw_handler.h - * - * Note as well that /proc/net/wireless implementation has now moved in : - * # net/core/wireless.c - * - * Wireless Events (2002 -> onward) : - * -------------------------------- - * Events are defined at the end of this file, and implemented in : - * # net/core/wireless.c - * - * Other comments : - * -------------- - * Do not add here things that are redundant with other mechanisms - * (drivers init, ifconfig, /proc/net/dev, ...) and with are not - * wireless specific. - * - * These wireless extensions are not magic : each driver has to provide - * support for them... - * - * IMPORTANT NOTE : As everything in the kernel, this is very much a - * work in progress. Contact me if you have ideas of improvements... - */ - -/***************************** INCLUDES *****************************/ - - /* jkm - replaced linux headers with C library headers, added typedefs */ -#if 0 -#include <linux/types.h> /* for __u* and __s* typedefs */ -#include <linux/socket.h> /* for "struct sockaddr" et al */ -#include <linux/if.h> /* for IFNAMSIZ and co... */ -#else -#include <sys/types.h> -#include <net/if.h> -#ifndef ANDROID -typedef __uint32_t __u32; -typedef __int32_t __s32; -typedef __uint16_t __u16; -typedef __int16_t __s16; -typedef __uint8_t __u8; -#endif /* ANDROID */ -#ifndef __user -#define __user -#endif /* __user */ -#endif - -/***************************** VERSION *****************************/ -/* - * This constant is used to know the availability of the wireless - * extensions and to know which version of wireless extensions it is - * (there is some stuff that will be added in the future...) - * I just plan to increment with each new version. - */ -#define WIRELESS_EXT 22 - -/* - * Changes : - * - * V2 to V3 - * -------- - * Alan Cox start some incompatibles changes. I've integrated a bit more. - * - Encryption renamed to Encode to avoid US regulation problems - * - Frequency changed from float to struct to avoid problems on old 386 - * - * V3 to V4 - * -------- - * - Add sensitivity - * - * V4 to V5 - * -------- - * - Missing encoding definitions in range - * - Access points stuff - * - * V5 to V6 - * -------- - * - 802.11 support (ESSID ioctls) - * - * V6 to V7 - * -------- - * - define IW_ESSID_MAX_SIZE and IW_MAX_AP - * - * V7 to V8 - * -------- - * - Changed my e-mail address - * - More 802.11 support (nickname, rate, rts, frag) - * - List index in frequencies - * - * V8 to V9 - * -------- - * - Support for 'mode of operation' (ad-hoc, managed...) - * - Support for unicast and multicast power saving - * - Change encoding to support larger tokens (>64 bits) - * - Updated iw_params (disable, flags) and use it for NWID - * - Extracted iw_point from iwreq for clarity - * - * V9 to V10 - * --------- - * - Add PM capability to range structure - * - Add PM modifier : MAX/MIN/RELATIVE - * - Add encoding option : IW_ENCODE_NOKEY - * - Add TxPower ioctls (work like TxRate) - * - * V10 to V11 - * ---------- - * - Add WE version in range (help backward/forward compatibility) - * - Add retry ioctls (work like PM) - * - * V11 to V12 - * ---------- - * - Add SIOCSIWSTATS to get /proc/net/wireless programatically - * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space - * - Add new statistics (frag, retry, beacon) - * - Add average quality (for user space calibration) - * - * V12 to V13 - * ---------- - * - Document creation of new driver API. - * - Extract union iwreq_data from struct iwreq (for new driver API). - * - Rename SIOCSIWNAME as SIOCSIWCOMMIT - * - * V13 to V14 - * ---------- - * - Wireless Events support : define struct iw_event - * - Define additional specific event numbers - * - Add "addr" and "param" fields in union iwreq_data - * - AP scanning stuff (SIOCSIWSCAN and friends) - * - * V14 to V15 - * ---------- - * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg - * - Make struct iw_freq signed (both m & e), add explicit padding - * - Add IWEVCUSTOM for driver specific event/scanning token - * - Add IW_MAX_GET_SPY for driver returning a lot of addresses - * - Add IW_TXPOW_RANGE for range of Tx Powers - * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points - * - Add IW_MODE_MONITOR for passive monitor - * - * V15 to V16 - * ---------- - * - Increase the number of bitrates in iw_range to 32 (for 802.11g) - * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) - * - Reshuffle struct iw_range for increases, add filler - * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses - * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support - * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" - * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index - * - * V16 to V17 - * ---------- - * - Add flags to frequency -> auto/fixed - * - Document (struct iw_quality *)->updated, add new flags (INVALID) - * - Wireless Event capability in struct iw_range - * - Add support for relative TxPower (yick !) - * - * V17 to V18 (From Jouni Malinen <j@w1.fi>) - * ---------- - * - Add support for WPA/WPA2 - * - Add extended encoding configuration (SIOCSIWENCODEEXT and - * SIOCGIWENCODEEXT) - * - Add SIOCSIWGENIE/SIOCGIWGENIE - * - Add SIOCSIWMLME - * - Add SIOCSIWPMKSA - * - Add struct iw_range bit field for supported encoding capabilities - * - Add optional scan request parameters for SIOCSIWSCAN - * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA - * related parameters (extensible up to 4096 parameter values) - * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, - * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND - * - * V18 to V19 - * ---------- - * - Remove (struct iw_point *)->pointer from events and streams - * - Remove header includes to help user space - * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 - * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros - * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM - * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros - * - * V19 to V20 - * ---------- - * - RtNetlink requests support (SET/GET) - * - * V20 to V21 - * ---------- - * - Remove (struct net_device *)->get_wireless_stats() - * - Change length in ESSID and NICK to strlen() instead of strlen()+1 - * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers - * - Power/Retry relative values no longer * 100000 - * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI - * - * V21 to V22 - * ---------- - * - Prevent leaking of kernel space in stream on 64 bits. - */ - -/**************************** CONSTANTS ****************************/ - -/* -------------------------- IOCTL LIST -------------------------- */ - -/* Wireless Identification */ -#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ -#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ -/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. - * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... - * Don't put the name of your driver there, it's useless. */ - -/* Basic operations */ -#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ -#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ -#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ -#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ -#define SIOCSIWMODE 0x8B06 /* set operation mode */ -#define SIOCGIWMODE 0x8B07 /* get operation mode */ -#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ -#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ - -/* Informative stuff */ -#define SIOCSIWRANGE 0x8B0A /* Unused */ -#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ -#define SIOCSIWPRIV 0x8B0C /* Unused */ -#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ -#define SIOCSIWSTATS 0x8B0E /* Unused */ -#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ -/* SIOCGIWSTATS is strictly used between user space and the kernel, and - * is never passed to the driver (i.e. the driver will never see it). */ - -/* Spy support (statistics per MAC address - used for Mobile IP support) */ -#define SIOCSIWSPY 0x8B10 /* set spy addresses */ -#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ -#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ -#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ - -/* Access Point manipulation */ -#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ -#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ -#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ -#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ -#define SIOCGIWSCAN 0x8B19 /* get scanning results */ - -/* 802.11 specific support */ -#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ -#define SIOCGIWESSID 0x8B1B /* get ESSID */ -#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ -#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ -/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit - * within the 'iwreq' structure, so we need to use the 'data' member to - * point to a string in user space, like it is done for RANGE... */ - -/* Other parameters useful in 802.11 and some other devices */ -#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ -#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ -#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ -#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ -#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ -#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ -#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ -#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ -#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ -#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ - -/* Encoding stuff (scrambling, hardware security, WEP...) */ -#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ -#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ -/* Power saving stuff (power management, unicast and multicast) */ -#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ -#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ - -/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). - * This ioctl uses struct iw_point and data buffer that includes IE id and len - * fields. More than one IE may be included in the request. Setting the generic - * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers - * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers - * are required to report the used IE as a wireless event, e.g., when - * associating with an AP. */ -#define SIOCSIWGENIE 0x8B30 /* set generic IE */ -#define SIOCGIWGENIE 0x8B31 /* get generic IE */ - -/* WPA : IEEE 802.11 MLME requests */ -#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses - * struct iw_mlme */ -/* WPA : Authentication mode parameters */ -#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ -#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ - -/* WPA : Extended version of encoding configuration */ -#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ -#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ - -/* WPA2 : PMKSA cache management */ -#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ - -/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ - -/* These 32 ioctl are wireless device private, for 16 commands. - * Each driver is free to use them for whatever purpose it chooses, - * however the driver *must* export the description of those ioctls - * with SIOCGIWPRIV and *must* use arguments as defined below. - * If you don't follow those rules, DaveM is going to hate you (reason : - * it make mixed 32/64bit operation impossible). - */ -#define SIOCIWFIRSTPRIV 0x8BE0 -#define SIOCIWLASTPRIV 0x8BFF -/* Previously, we were using SIOCDEVPRIVATE, but we now have our - * separate range because of collisions with other tools such as - * 'mii-tool'. - * We now have 32 commands, so a bit more space ;-). - * Also, all 'even' commands are only usable by root and don't return the - * content of ifr/iwr to user (but you are not obliged to use the set/get - * convention, just use every other two command). More details in iwpriv.c. - * And I repeat : you are not forced to use them with iwpriv, but you - * must be compliant with it. - */ - -/* ------------------------- IOCTL STUFF ------------------------- */ - -/* The first and the last (range) */ -#define SIOCIWFIRST 0x8B00 -#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ -#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) -#define IW_HANDLER(id, func) \ - [IW_IOCTL_IDX(id)] = func - -/* Odd : get (world access), even : set (root access) */ -#define IW_IS_SET(cmd) (!((cmd) & 0x1)) -#define IW_IS_GET(cmd) ((cmd) & 0x1) - -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* Those are *NOT* ioctls, do not issue request on them !!! */ -/* Most events use the same identifier as ioctl requests */ - -#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ -#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ -#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ -#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ -#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ -#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) - * (scan results); This includes id and - * length fields. One IWEVGENIE may - * contain more than one IE. Scan - * results may contain one or more - * IWEVGENIE events. */ -#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure - * (struct iw_michaelmicfailure) - */ -#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. - * The data includes id and length - * fields and may contain more than one - * IE. This event is required in - * Managed mode if the driver - * generates its own WPA/RSN IE. This - * should be sent just before - * IWEVREGISTERED event for the - * association. */ -#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association - * Response. The data includes id and - * length fields and may contain more - * than one IE. This may be sent - * between IWEVASSOCREQIE and - * IWEVREGISTERED events for the - * association. */ -#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN - * pre-authentication - * (struct iw_pmkid_cand) */ - -#define IWEVFIRST 0x8C00 -#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) - -/* ------------------------- PRIVATE INFO ------------------------- */ -/* - * The following is used with SIOCGIWPRIV. It allow a driver to define - * the interface (name, type of data) for its private ioctl. - * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV - */ - -#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ -#define IW_PRIV_TYPE_NONE 0x0000 -#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ -#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ -#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ -#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ -#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ - -#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ - -#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ - -/* - * Note : if the number of args is fixed and the size < 16 octets, - * instead of passing a pointer we will put args in the iwreq struct... - */ - -/* ----------------------- OTHER CONSTANTS ----------------------- */ - -/* Maximum frequencies in the range struct */ -#define IW_MAX_FREQUENCIES 32 -/* Note : if you have something like 80 frequencies, - * don't increase this constant and don't fill the frequency list. - * The user will be able to set by channel anyway... */ - -/* Maximum bit rates in the range struct */ -#define IW_MAX_BITRATES 32 - -/* Maximum tx powers in the range struct */ -#define IW_MAX_TXPOWER 8 -/* Note : if you more than 8 TXPowers, just set the max and min or - * a few of them in the struct iw_range. */ - -/* Maximum of address that you may set with SPY */ -#define IW_MAX_SPY 8 - -/* Maximum of address that you may get in the - list of access points in range */ -#define IW_MAX_AP 64 - -/* Maximum size of the ESSID and NICKN strings */ -#define IW_ESSID_MAX_SIZE 32 - -/* Modes of operation */ -#define IW_MODE_AUTO 0 /* Let the driver decides */ -#define IW_MODE_ADHOC 1 /* Single cell network */ -#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ -#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ -#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ -#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ -#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ -#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ - -/* Statistics flags (bitmask in updated) */ -#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ -#define IW_QUAL_LEVEL_UPDATED 0x02 -#define IW_QUAL_NOISE_UPDATED 0x04 -#define IW_QUAL_ALL_UPDATED 0x07 -#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ -#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ -#define IW_QUAL_LEVEL_INVALID 0x20 -#define IW_QUAL_NOISE_INVALID 0x40 -#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ -#define IW_QUAL_ALL_INVALID 0x70 - -/* Frequency flags */ -#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ -#define IW_FREQ_FIXED 0x01 /* Force a specific value */ - -/* Maximum number of size of encoding token available - * they are listed in the range structure */ -#define IW_MAX_ENCODING_SIZES 8 - -/* Maximum size of the encoding token in bytes */ -#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ - -/* Flags for encoding (along with the token) */ -#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ -#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ -#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ -#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ -#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ -#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ -#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ -#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ -#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ - -/* Power management flags available (along with the value, if any) */ -#define IW_POWER_ON 0x0000 /* No details... */ -#define IW_POWER_TYPE 0xF000 /* Type of parameter */ -#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ -#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ -#define IW_POWER_MODE 0x0F00 /* Power Management mode */ -#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ -#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ -#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ -#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ -#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ -#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ -#define IW_POWER_MIN 0x0001 /* Value is a minimum */ -#define IW_POWER_MAX 0x0002 /* Value is a maximum */ -#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ - -/* Transmit Power flags available */ -#define IW_TXPOW_TYPE 0x00FF /* Type of value */ -#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ -#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ -#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ -#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ - -/* Retry limits and lifetime flags available */ -#define IW_RETRY_ON 0x0000 /* No details... */ -#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ -#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ -#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ -#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ -#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ -#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ -#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ -#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ -#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ - -/* Scanning request flags */ -#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ -#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ -#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ -#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ -#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ -#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ -#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ -#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ -#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ -/* struct iw_scan_req scan_type */ -#define IW_SCAN_TYPE_ACTIVE 0 -#define IW_SCAN_TYPE_PASSIVE 1 -/* Maximum size of returned data */ -#define IW_SCAN_MAX_DATA 4096 /* In bytes */ - -/* Scan capability flags - in (struct iw_range *)->scan_capa */ -#define IW_SCAN_CAPA_NONE 0x00 -#define IW_SCAN_CAPA_ESSID 0x01 -#define IW_SCAN_CAPA_BSSID 0x02 -#define IW_SCAN_CAPA_CHANNEL 0x04 -#define IW_SCAN_CAPA_MODE 0x08 -#define IW_SCAN_CAPA_RATE 0x10 -#define IW_SCAN_CAPA_TYPE 0x20 -#define IW_SCAN_CAPA_TIME 0x40 - -/* Max number of char in custom event - use multiple of them if needed */ -#define IW_CUSTOM_MAX 256 /* In bytes */ - -/* Generic information element */ -#define IW_GENERIC_IE_MAX 1024 - -/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ -#define IW_MLME_DEAUTH 0 -#define IW_MLME_DISASSOC 1 -#define IW_MLME_AUTH 2 -#define IW_MLME_ASSOC 3 - -/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ -#define IW_AUTH_INDEX 0x0FFF -#define IW_AUTH_FLAGS 0xF000 -/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) - * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the - * parameter that is being set/get to; value will be read/written to - * struct iw_param value field) */ -#define IW_AUTH_WPA_VERSION 0 -#define IW_AUTH_CIPHER_PAIRWISE 1 -#define IW_AUTH_CIPHER_GROUP 2 -#define IW_AUTH_KEY_MGMT 3 -#define IW_AUTH_TKIP_COUNTERMEASURES 4 -#define IW_AUTH_DROP_UNENCRYPTED 5 -#define IW_AUTH_80211_AUTH_ALG 6 -#define IW_AUTH_WPA_ENABLED 7 -#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 -#define IW_AUTH_ROAMING_CONTROL 9 -#define IW_AUTH_PRIVACY_INVOKED 10 -#define IW_AUTH_CIPHER_GROUP_MGMT 11 -#define IW_AUTH_MFP 12 - -/* IW_AUTH_WPA_VERSION values (bit field) */ -#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 -#define IW_AUTH_WPA_VERSION_WPA 0x00000002 -#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 - -/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT - * values (bit field) */ -#define IW_AUTH_CIPHER_NONE 0x00000001 -#define IW_AUTH_CIPHER_WEP40 0x00000002 -#define IW_AUTH_CIPHER_TKIP 0x00000004 -#define IW_AUTH_CIPHER_CCMP 0x00000008 -#define IW_AUTH_CIPHER_WEP104 0x00000010 -#define IW_AUTH_CIPHER_AES_CMAC 0x00000020 - -/* IW_AUTH_KEY_MGMT values (bit field) */ -#define IW_AUTH_KEY_MGMT_802_1X 1 -#define IW_AUTH_KEY_MGMT_PSK 2 - -/* IW_AUTH_80211_AUTH_ALG values (bit field) */ -#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 -#define IW_AUTH_ALG_SHARED_KEY 0x00000002 -#define IW_AUTH_ALG_LEAP 0x00000004 - -/* IW_AUTH_ROAMING_CONTROL values */ -#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ -#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming - * control */ - -/* IW_AUTH_MFP (management frame protection) values */ -#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ -#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ -#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ - -/* SIOCSIWENCODEEXT definitions */ -#define IW_ENCODE_SEQ_MAX_SIZE 8 -/* struct iw_encode_ext ->alg */ -#define IW_ENCODE_ALG_NONE 0 -#define IW_ENCODE_ALG_WEP 1 -#define IW_ENCODE_ALG_TKIP 2 -#define IW_ENCODE_ALG_CCMP 3 -#define IW_ENCODE_ALG_PMK 4 -#define IW_ENCODE_ALG_AES_CMAC 5 -/* struct iw_encode_ext ->ext_flags */ -#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 -#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 -#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 -#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 - -/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ -#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ -#define IW_MICFAILURE_GROUP 0x00000004 -#define IW_MICFAILURE_PAIRWISE 0x00000008 -#define IW_MICFAILURE_STAKEY 0x00000010 -#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) - */ - -/* Bit field values for enc_capa in struct iw_range */ -#define IW_ENC_CAPA_WPA 0x00000001 -#define IW_ENC_CAPA_WPA2 0x00000002 -#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 -#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 -#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 - -/* Event capability macros - in (struct iw_range *)->event_capa - * Because we have more than 32 possible events, we use an array of - * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ -#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ - (cmd - SIOCIWFIRSTPRIV + 0x60) : \ - (cmd - SIOCIWFIRST)) -#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) -#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) -/* Event capability constants - event autogenerated by the kernel - * This list is valid for most 802.11 devices, customise as needed... */ -#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ - IW_EVENT_CAPA_MASK(0x8B06) | \ - IW_EVENT_CAPA_MASK(0x8B1A)) -#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) -/* "Easy" macro to set events in iw_range (less efficient) */ -#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) -#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } - - -/****************************** TYPES ******************************/ - -/* --------------------------- SUBTYPES --------------------------- */ -/* - * Generic format for most parameters that fit in an int - */ -struct iw_param -{ - __s32 value; /* The value of the parameter itself */ - __u8 fixed; /* Hardware should not use auto select */ - __u8 disabled; /* Disable the feature */ - __u16 flags; /* Various specifc flags (if any) */ -}; - -/* - * For all data larger than 16 octets, we need to use a - * pointer to memory allocated in user space. - */ -struct iw_point -{ - void __user *pointer; /* Pointer to the data (in user space) */ - __u16 length; /* number of fields or size in bytes */ - __u16 flags; /* Optional params */ -}; - -#ifdef __KERNEL__ -#ifdef CONFIG_COMPAT - -#include <linux/compat.h> - -struct compat_iw_point { - compat_caddr_t pointer; - __u16 length; - __u16 flags; -}; -#endif -#endif - -/* - * A frequency - * For numbers lower than 10^9, we encode the number in 'm' and - * set 'e' to 0 - * For number greater than 10^9, we divide it by the lowest power - * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... - * The power of 10 is in 'e', the result of the division is in 'm'. - */ -struct iw_freq -{ - __s32 m; /* Mantissa */ - __s16 e; /* Exponent */ - __u8 i; /* List index (when in range struct) */ - __u8 flags; /* Flags (fixed/auto) */ -}; - -/* - * Quality of the link - */ -struct iw_quality -{ - __u8 qual; /* link quality (%retries, SNR, - %missed beacons or better...) */ - __u8 level; /* signal level (dBm) */ - __u8 noise; /* noise level (dBm) */ - __u8 updated; /* Flags to know if updated */ -}; - -/* - * Packet discarded in the wireless adapter due to - * "wireless" specific problems... - * Note : the list of counter and statistics in net_device_stats - * is already pretty exhaustive, and you should use that first. - * This is only additional stats... - */ -struct iw_discarded -{ - __u32 nwid; /* Rx : Wrong nwid/essid */ - __u32 code; /* Rx : Unable to code/decode (WEP) */ - __u32 fragment; /* Rx : Can't perform MAC reassembly */ - __u32 retries; /* Tx : Max MAC retries num reached */ - __u32 misc; /* Others cases */ -}; - -/* - * Packet/Time period missed in the wireless adapter due to - * "wireless" specific problems... - */ -struct iw_missed -{ - __u32 beacon; /* Missed beacons/superframe */ -}; - -/* - * Quality range (for spy threshold) - */ -struct iw_thrspy -{ - struct sockaddr addr; /* Source address (hw/mac) */ - struct iw_quality qual; /* Quality of the link */ - struct iw_quality low; /* Low threshold */ - struct iw_quality high; /* High threshold */ -}; - -/* - * Optional data for scan request - * - * Note: these optional parameters are controlling parameters for the - * scanning behavior, these do not apply to getting scan results - * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and - * provide a merged results with all BSSes even if the previous scan - * request limited scanning to a subset, e.g., by specifying an SSID. - * Especially, scan results are required to include an entry for the - * current BSS if the driver is in Managed mode and associated with an AP. - */ -struct iw_scan_req -{ - __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ - __u8 essid_len; - __u8 num_channels; /* num entries in channel_list; - * 0 = scan all allowed channels */ - __u8 flags; /* reserved as padding; use zero, this may - * be used in the future for adding flags - * to request different scan behavior */ - struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or - * individual address of a specific BSS */ - - /* - * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using - * the current ESSID. This allows scan requests for specific ESSID - * without having to change the current ESSID and potentially breaking - * the current association. - */ - __u8 essid[IW_ESSID_MAX_SIZE]; - - /* - * Optional parameters for changing the default scanning behavior. - * These are based on the MLME-SCAN.request from IEEE Std 802.11. - * TU is 1.024 ms. If these are set to 0, driver is expected to use - * reasonable default values. min_channel_time defines the time that - * will be used to wait for the first reply on each channel. If no - * replies are received, next channel will be scanned after this. If - * replies are received, total time waited on the channel is defined by - * max_channel_time. - */ - __u32 min_channel_time; /* in TU */ - __u32 max_channel_time; /* in TU */ - - struct iw_freq channel_list[IW_MAX_FREQUENCIES]; -}; - -/* ------------------------- WPA SUPPORT ------------------------- */ - -/* - * Extended data structure for get/set encoding (this is used with - * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* - * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and - * only the data contents changes (key data -> this structure, including - * key data). - * - * If the new key is the first group key, it will be set as the default - * TX key. Otherwise, default TX key index is only changed if - * IW_ENCODE_EXT_SET_TX_KEY flag is set. - * - * Key will be changed with SIOCSIWENCODEEXT in all cases except for - * special "change TX key index" operation which is indicated by setting - * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. - * - * tx_seq/rx_seq are only used when respective - * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal - * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start - * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally - * used only by an Authenticator (AP or an IBSS station) to get the - * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and - * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for - * debugging/testing. - */ -struct iw_encode_ext -{ - __u32 ext_flags; /* IW_ENCODE_EXT_* */ - __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast - * (group) keys or unicast address for - * individual keys */ - __u16 alg; /* IW_ENCODE_ALG_* */ - __u16 key_len; - __u8 key[0]; -}; - -/* SIOCSIWMLME data */ -struct iw_mlme -{ - __u16 cmd; /* IW_MLME_* */ - __u16 reason_code; - struct sockaddr addr; -}; - -/* SIOCSIWPMKSA data */ -#define IW_PMKSA_ADD 1 -#define IW_PMKSA_REMOVE 2 -#define IW_PMKSA_FLUSH 3 - -#define IW_PMKID_LEN 16 - -struct iw_pmksa -{ - __u32 cmd; /* IW_PMKSA_* */ - struct sockaddr bssid; - __u8 pmkid[IW_PMKID_LEN]; -}; - -/* IWEVMICHAELMICFAILURE data */ -struct iw_michaelmicfailure -{ - __u32 flags; - struct sockaddr src_addr; - __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ -}; - -/* IWEVPMKIDCAND data */ -#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ -struct iw_pmkid_cand -{ - __u32 flags; /* IW_PMKID_CAND_* */ - __u32 index; /* the smaller the index, the higher the - * priority */ - struct sockaddr bssid; -}; - -/* ------------------------ WIRELESS STATS ------------------------ */ -/* - * Wireless statistics (used for /proc/net/wireless) - */ -struct iw_statistics -{ - __u16 status; /* Status - * - device dependent for now */ - - struct iw_quality qual; /* Quality of the link - * (instant/mean/max) */ - struct iw_discarded discard; /* Packet discarded counts */ - struct iw_missed miss; /* Packet missed counts */ -}; - -/* ------------------------ IOCTL REQUEST ------------------------ */ -/* - * This structure defines the payload of an ioctl, and is used - * below. - * - * Note that this structure should fit on the memory footprint - * of iwreq (which is the same as ifreq), which mean a max size of - * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... - * You should check this when increasing the structures defined - * above in this file... - */ -union iwreq_data -{ - /* Config - generic */ - char name[IFNAMSIZ]; - /* Name : used to verify the presence of wireless extensions. - * Name of the protocol/provider... */ - - struct iw_point essid; /* Extended network name */ - struct iw_param nwid; /* network id (or domain - the cell) */ - struct iw_freq freq; /* frequency or channel : - * 0-1000 = channel - * > 1000 = frequency in Hz */ - - struct iw_param sens; /* signal level threshold */ - struct iw_param bitrate; /* default bit rate */ - struct iw_param txpower; /* default transmit power */ - struct iw_param rts; /* RTS threshold threshold */ - struct iw_param frag; /* Fragmentation threshold */ - __u32 mode; /* Operation mode */ - struct iw_param retry; /* Retry limits & lifetime */ - - struct iw_point encoding; /* Encoding stuff : tokens */ - struct iw_param power; /* PM duration/timeout */ - struct iw_quality qual; /* Quality part of statistics */ - - struct sockaddr ap_addr; /* Access point address */ - struct sockaddr addr; /* Destination address (hw/mac) */ - - struct iw_param param; /* Other small parameters */ - struct iw_point data; /* Other large parameters */ -}; - -/* - * The structure to exchange data for ioctl. - * This structure is the same as 'struct ifreq', but (re)defined for - * convenience... - * Do I need to remind you about structure size (32 octets) ? - */ -struct iwreq -{ - union - { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ - } ifr_ifrn; - - /* Data part (defined just above) */ - union iwreq_data u; -}; - -/* -------------------------- IOCTL DATA -------------------------- */ -/* - * For those ioctl which want to exchange mode data that what could - * fit in the above structure... - */ - -/* - * Range of parameters - */ - -struct iw_range -{ - /* Informative stuff (to choose between different interface) */ - __u32 throughput; /* To give an idea... */ - /* In theory this value should be the maximum benchmarked - * TCP/IP throughput, because with most of these devices the - * bit rate is meaningless (overhead an co) to estimate how - * fast the connection will go and pick the fastest one. - * I suggest people to play with Netperf or any benchmark... - */ - - /* NWID (or domain id) */ - __u32 min_nwid; /* Minimal NWID we are able to set */ - __u32 max_nwid; /* Maximal NWID we are able to set */ - - /* Old Frequency (backward compat - moved lower ) */ - __u16 old_num_channels; - __u8 old_num_frequency; - - /* Scan capabilities */ - __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */ - - /* Wireless event capability bitmasks */ - __u32 event_capa[6]; - - /* signal level threshold range */ - __s32 sensitivity; - - /* Quality of link & SNR stuff */ - /* Quality range (link, level, noise) - * If the quality is absolute, it will be in the range [0 ; max_qual], - * if the quality is dBm, it will be in the range [max_qual ; 0]. - * Don't forget that we use 8 bit arithmetics... */ - struct iw_quality max_qual; /* Quality of the link */ - /* This should contain the average/typical values of the quality - * indicator. This should be the threshold between a "good" and - * a "bad" link (example : monitor going from green to orange). - * Currently, user space apps like quality monitors don't have any - * way to calibrate the measurement. With this, they can split - * the range between 0 and max_qual in different quality level - * (using a geometric subdivision centered on the average). - * I expect that people doing the user space apps will feedback - * us on which value we need to put in each driver... */ - struct iw_quality avg_qual; /* Quality of the link */ - - /* Rates */ - __u8 num_bitrates; /* Number of entries in the list */ - __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ - - /* RTS threshold */ - __s32 min_rts; /* Minimal RTS threshold */ - __s32 max_rts; /* Maximal RTS threshold */ - - /* Frag threshold */ - __s32 min_frag; /* Minimal frag threshold */ - __s32 max_frag; /* Maximal frag threshold */ - - /* Power Management duration & timeout */ - __s32 min_pmp; /* Minimal PM period */ - __s32 max_pmp; /* Maximal PM period */ - __s32 min_pmt; /* Minimal PM timeout */ - __s32 max_pmt; /* Maximal PM timeout */ - __u16 pmp_flags; /* How to decode max/min PM period */ - __u16 pmt_flags; /* How to decode max/min PM timeout */ - __u16 pm_capa; /* What PM options are supported */ - - /* Encoder stuff */ - __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ - __u8 num_encoding_sizes; /* Number of entry in the list */ - __u8 max_encoding_tokens; /* Max number of tokens */ - /* For drivers that need a "login/passwd" form */ - __u8 encoding_login_index; /* token index for login token */ - - /* Transmit power */ - __u16 txpower_capa; /* What options are supported */ - __u8 num_txpower; /* Number of entries in the list */ - __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ - - /* Wireless Extension version info */ - __u8 we_version_compiled; /* Must be WIRELESS_EXT */ - __u8 we_version_source; /* Last update of source */ - - /* Retry limits and lifetime */ - __u16 retry_capa; /* What retry options are supported */ - __u16 retry_flags; /* How to decode max/min retry limit */ - __u16 r_time_flags; /* How to decode max/min retry life */ - __s32 min_retry; /* Minimal number of retries */ - __s32 max_retry; /* Maximal number of retries */ - __s32 min_r_time; /* Minimal retry lifetime */ - __s32 max_r_time; /* Maximal retry lifetime */ - - /* Frequency */ - __u16 num_channels; /* Number of channels [0; num - 1] */ - __u8 num_frequency; /* Number of entry in the list */ - struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ - /* Note : this frequency list doesn't need to fit channel numbers, - * because each entry contain its channel index */ - - __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ -}; - -/* - * Private ioctl interface information - */ - -struct iw_priv_args -{ - __u32 cmd; /* Number of the ioctl to issue */ - __u16 set_args; /* Type and number of args */ - __u16 get_args; /* Type and number of args */ - char name[IFNAMSIZ]; /* Name of the extension */ -}; - -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* - * Wireless events are carried through the rtnetlink socket to user - * space. They are encapsulated in the IFLA_WIRELESS field of - * a RTM_NEWLINK message. - */ - -/* - * A Wireless Event. Contains basically the same data as the ioctl... - */ -struct iw_event -{ - __u16 len; /* Real length of this stuff */ - __u16 cmd; /* Wireless IOCTL */ - union iwreq_data u; /* IOCTL fixed payload */ -}; - -/* Size of the Event prefix (including padding and alignement junk) */ -#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) -/* Size of the various events */ -#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) -#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) -#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) -#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) -#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) -#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) - -/* iw_point events are special. First, the payload (extra data) come at - * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, - * we omit the pointer, so start at an offset. */ -#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ - (char *) NULL) -#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ - IW_EV_POINT_OFF) - -#ifdef __KERNEL__ -#ifdef CONFIG_COMPAT -struct __compat_iw_event { - __u16 len; /* Real length of this stuff */ - __u16 cmd; /* Wireless IOCTL */ - compat_caddr_t pointer; -}; -#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) -#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) - -/* Size of the various events for compat */ -#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ) -#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32)) -#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq)) -#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param)) -#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr)) -#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality)) -#define IW_EV_COMPAT_POINT_LEN \ - (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ - IW_EV_COMPAT_POINT_OFF) -#endif -#endif - -/* Size of the Event prefix when packed in stream */ -#define IW_EV_LCP_PK_LEN (4) -/* Size of the various events when packed in stream */ -#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ) -#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32)) -#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq)) -#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) -#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) -#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) -#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4) - -#endif /* _LINUX_WIRELESS_H */ |