aboutsummaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2010-10-29 08:01:21 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2010-10-29 08:01:21 +0000
commit02b5aa59ffe0c7ce093caa72e935418a1b0ae370 (patch)
tree0b2308ac0b6239b9bd8d56cb4a658ca35f20a06b /src/drivers
parent95ea342968b919b418b028d9360eedf685a55220 (diff)
Notes
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/.gitignore2
-rw-r--r--src/drivers/Makefile2
-rw-r--r--src/drivers/driver.h1712
-rw-r--r--src/drivers/driver_atheros.c1298
-rw-r--r--src/drivers/driver_atmel.c31
-rw-r--r--src/drivers/driver_broadcom.c119
-rw-r--r--src/drivers/driver_bsd.c1456
-rw-r--r--src/drivers/driver_hostap.c1168
-rw-r--r--src/drivers/driver_hostap.h71
-rw-r--r--src/drivers/driver_iphone.m2
-rw-r--r--src/drivers/driver_ipw.c35
-rw-r--r--src/drivers/driver_madwifi.c1305
-rw-r--r--src/drivers/driver_ndis.c181
-rw-r--r--src/drivers/driver_ndis.h1
-rw-r--r--src/drivers/driver_ndiswrapper.c42
-rw-r--r--src/drivers/driver_nl80211.c5976
-rw-r--r--src/drivers/driver_none.c99
-rw-r--r--src/drivers/driver_osx.m87
-rw-r--r--src/drivers/driver_prism54.c381
-rw-r--r--src/drivers/driver_privsep.c118
-rw-r--r--src/drivers/driver_ps3.c186
-rw-r--r--src/drivers/driver_ralink.c654
-rw-r--r--src/drivers/driver_ralink.h3
-rw-r--r--src/drivers/driver_roboswitch.c20
-rw-r--r--src/drivers/driver_test.c2091
-rw-r--r--src/drivers/driver_wext.c552
-rw-r--r--src/drivers/driver_wext.h10
-rw-r--r--src/drivers/driver_wired.c420
-rw-r--r--src/drivers/drivers.c28
-rw-r--r--src/drivers/drivers.mak181
-rw-r--r--src/drivers/linux_ioctl.c198
-rw-r--r--src/drivers/linux_ioctl.h27
-rw-r--r--src/drivers/netlink.c204
-rw-r--r--src/drivers/netlink.h33
-rw-r--r--src/drivers/nl80211_copy.h1644
-rw-r--r--src/drivers/priv_netlink.h9
-rw-r--r--src/drivers/radiotap.c287
-rw-r--r--src/drivers/radiotap.h242
-rw-r--r--src/drivers/radiotap_iter.h41
-rw-r--r--src/drivers/scan_helpers.c182
-rw-r--r--src/drivers/wireless_copy.h1099
41 files changed, 17215 insertions, 4982 deletions
diff --git a/src/drivers/.gitignore b/src/drivers/.gitignore
new file mode 100644
index 0000000000000..1d9e0e661afee
--- /dev/null
+++ b/src/drivers/.gitignore
@@ -0,0 +1,2 @@
+build.wpa_supplicant
+build.hostapd
diff --git a/src/drivers/Makefile b/src/drivers/Makefile
index cffba620da04f..07600e52c2fde 100644
--- a/src/drivers/Makefile
+++ b/src/drivers/Makefile
@@ -2,8 +2,8 @@ all:
@echo Nothing to be made.
clean:
- for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+ rm -f build.wpa_supplicant build.hostapd
install:
@echo Nothing to be made.
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index c2975d2c1215f..fa49da454e83a 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant - driver interface definition
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Driver interface definition
+ * Copyright (c) 2003-2010, 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
@@ -10,79 +10,117 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * This file defines a driver interface used by both %wpa_supplicant and
+ * hostapd. The first part of the file defines data structures used in various
+ * driver operations. This is followed by the struct wpa_driver_ops that each
+ * driver wrapper will beed to define with callback functions for requesting
+ * driver operations. After this, there are definitions for driver event
+ * reporting with wpa_supplicant_event() and some convenience helper functions
+ * that can be used to report events.
*/
#ifndef DRIVER_H
#define DRIVER_H
-#define WPA_SUPPLICANT_DRIVER_VERSION 3
+#define WPA_SUPPLICANT_DRIVER_VERSION 4
+
+#include "common/defs.h"
+
+#define HOSTAPD_CHAN_DISABLED 0x00000001
+#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
+#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_RADAR 0x00000008
+
+/**
+ * struct hostapd_channel_data - Channel information
+ */
+struct hostapd_channel_data {
+ /**
+ * chan - Channel number (IEEE 802.11)
+ */
+ short chan;
+
+ /**
+ * freq - Frequency in MHz
+ */
+ short freq;
+
+ /**
+ * flag - Channel flags (HOSTAPD_CHAN_*)
+ */
+ int flag;
+
+ /**
+ * max_tx_power - maximum transmit power in dBm
+ */
+ u8 max_tx_power;
+};
+
+/**
+ * struct hostapd_hw_modes - Supported hardware mode information
+ */
+struct hostapd_hw_modes {
+ /**
+ * mode - Hardware mode
+ */
+ enum hostapd_hw_mode mode;
-#include "defs.h"
+ /**
+ * num_channels - Number of entries in the channels array
+ */
+ int num_channels;
+
+ /**
+ * channels - Array of supported channels
+ */
+ struct hostapd_channel_data *channels;
+
+ /**
+ * num_rates - Number of entries in the rates array
+ */
+ int num_rates;
+
+ /**
+ * rates - Array of supported rates in 100 kbps units
+ */
+ int *rates;
+
+ /**
+ * ht_capab - HT (IEEE 802.11n) capabilities
+ */
+ u16 ht_capab;
+
+ /**
+ * mcs_set - MCS (IEEE 802.11n) rate parameters
+ */
+ u8 mcs_set[16];
+
+ /**
+ * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
+ */
+ u8 a_mpdu_params;
+};
-#define AUTH_ALG_OPEN_SYSTEM 0x01
-#define AUTH_ALG_SHARED_KEY 0x02
-#define AUTH_ALG_LEAP 0x04
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
+#define IEEE80211_MODE_AP 2
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
-#define SSID_MAX_WPA_IE_LEN 40
-/**
- * struct wpa_scan_result - Scan results (old structure)
- * @bssid: BSSID
- * @ssid: SSID
- * @ssid_len: length of the ssid
- * @wpa_ie: WPA IE
- * @wpa_ie_len: length of the wpa_ie
- * @rsn_ie: RSN IE
- * @rsn_ie_len: length of the RSN IE
- * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
- * @caps: capability information field in host byte order
- * @qual: signal quality
- * @noise: noise level
- * @level: signal level
- * @maxrate: maximum supported rate
- * @mdie_present: Whether MDIE was included in Beacon/ProbeRsp frame
- * @mdie: Mobility domain identifier IE (IEEE 802.11r MDIE) (starting from
- * IE type field)
- * @tsf: Timestamp
- *
- * This structure is used as a generic format for scan results from the
- * driver. Each driver interface implementation is responsible for converting
- * the driver or OS specific scan results into this format.
- *
- * This structure is the old data structure used for scan results. It is
- * obsoleted by the new struct wpa_scan_res structure and the old version is
- * only included for backwards compatibility with existing driver wrapper
- * implementations. New implementations are encouraged to implement for struct
- * wpa_scan_res. The old structure will be removed at some point.
- */
-struct wpa_scan_result {
- u8 bssid[ETH_ALEN];
- u8 ssid[32];
- size_t ssid_len;
- u8 wpa_ie[SSID_MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[SSID_MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- int freq;
- u16 caps;
- int qual;
- int noise;
- int level;
- int maxrate;
- int mdie_present;
- u8 mdie[5];
- u64 tsf;
-};
-
+#define WPA_SCAN_QUAL_INVALID BIT(0)
+#define WPA_SCAN_NOISE_INVALID BIT(1)
+#define WPA_SCAN_LEVEL_INVALID BIT(2)
+#define WPA_SCAN_LEVEL_DBM BIT(3)
+#define WPA_SCAN_AUTHENTICATED BIT(4)
+#define WPA_SCAN_ASSOCIATED BIT(5)
/**
* struct wpa_scan_res - Scan result for an BSS/IBSS
+ * @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
* @bssid: BSSID
* @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
* @beacon_int: beacon interval in TUs (host byte order)
@@ -91,7 +129,10 @@ struct wpa_scan_result {
* @noise: noise level
* @level: signal level
* @tsf: Timestamp
+ * @age: Age of the information in milliseconds (i.e., how many milliseconds
+ * ago the last Beacon or Probe Response frame was received)
* @ie_len: length of the following IE field in octets
+ * @beacon_ie_len: length of the following Beacon IE field in octets
*
* This structure is used as a generic format for scan results from the
* driver. Each driver interface implementation is responsible for converting
@@ -103,6 +144,7 @@ struct wpa_scan_result {
* report all IEs to make it easier to support future additions.
*/
struct wpa_scan_res {
+ unsigned int flags;
u8 bssid[ETH_ALEN];
int freq;
u16 beacon_int;
@@ -111,8 +153,16 @@ struct wpa_scan_res {
int noise;
int level;
u64 tsf;
+ unsigned int age;
size_t ie_len;
- /* followed by ie_len octets of IEs */
+ size_t beacon_ie_len;
+ /*
+ * Followed by ie_len octets of IEs from Probe Response frame (or if
+ * the driver does not indicate source of IEs, these may also be from
+ * Beacon frame). After the first set of IEs, another set of IEs may
+ * follow (with beacon_ie_len octets of data) if the driver provides
+ * both IE sets.
+ */
};
/**
@@ -142,6 +192,95 @@ struct wpa_interface_info {
const char *drv_name;
};
+#define WPAS_MAX_SCAN_SSIDS 4
+
+/**
+ * struct wpa_driver_scan_params - Scan parameters
+ * Data for struct wpa_driver_ops::scan2().
+ */
+struct wpa_driver_scan_params {
+ /**
+ * ssids - SSIDs to scan for
+ */
+ struct wpa_driver_scan_ssid {
+ /**
+ * ssid - specific SSID to scan for (ProbeReq)
+ * %NULL or zero-length SSID is used to indicate active scan
+ * with wildcard SSID.
+ */
+ const u8 *ssid;
+ /**
+ * ssid_len: Length of the SSID in octets
+ */
+ size_t ssid_len;
+ } ssids[WPAS_MAX_SCAN_SSIDS];
+
+ /**
+ * num_ssids - Number of entries in ssids array
+ * Zero indicates a request for a passive scan.
+ */
+ size_t num_ssids;
+
+ /**
+ * extra_ies - Extra IE(s) to add into Probe Request or %NULL
+ */
+ const u8 *extra_ies;
+
+ /**
+ * extra_ies_len - Length of extra_ies in octets
+ */
+ size_t extra_ies_len;
+
+ /**
+ * freqs - Array of frequencies to scan or %NULL for all frequencies
+ *
+ * The frequency is set in MHz. The array is zero-terminated.
+ */
+ int *freqs;
+
+ /**
+ * filter_ssids - Filter for reporting SSIDs
+ *
+ * This optional parameter can be used to request the driver wrapper to
+ * filter scan results to include only the specified SSIDs. %NULL
+ * indicates that no filtering is to be done. This can be used to
+ * reduce memory needs for scan results in environments that have large
+ * number of APs with different SSIDs.
+ *
+ * The driver wrapper is allowed to take this allocated buffer into its
+ * own use by setting the pointer to %NULL. In that case, the driver
+ * wrapper is responsible for freeing the buffer with os_free() once it
+ * is not needed anymore.
+ */
+ struct wpa_driver_scan_filter {
+ u8 ssid[32];
+ size_t ssid_len;
+ } *filter_ssids;
+
+ /**
+ * num_filter_ssids - Number of entries in filter_ssids array
+ */
+ size_t num_filter_ssids;
+};
+
+/**
+ * struct wpa_driver_auth_params - Authentication parameters
+ * Data for struct wpa_driver_ops::authenticate().
+ */
+struct wpa_driver_auth_params {
+ int freq;
+ const u8 *bssid;
+ const u8 *ssid;
+ size_t ssid_len;
+ int auth_alg;
+ const u8 *ie;
+ size_t ie_len;
+ const u8 *wep_key[4];
+ size_t wep_key_len[4];
+ int wep_tx_keyidx;
+ int local_state_change;
+};
+
/**
* struct wpa_driver_associate_params - Association parameters
* Data for struct wpa_driver_ops::associate().
@@ -157,6 +296,10 @@ struct wpa_driver_associate_params {
* ssid - The selected SSID
*/
const u8 *ssid;
+
+ /**
+ * ssid_len - Length of the SSID (1..32)
+ */
size_t ssid_len;
/**
@@ -185,20 +328,36 @@ struct wpa_driver_associate_params {
* When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE.
*/
const u8 *wpa_ie;
+
/**
* wpa_ie_len - length of the wpa_ie
*/
size_t wpa_ie_len;
- /* The selected pairwise/group cipher and key management
- * suites. These are usually ignored if @wpa_ie is used. */
- wpa_cipher pairwise_suite;
- wpa_cipher group_suite;
- wpa_key_mgmt key_mgmt_suite;
+ /**
+ * pairwise_suite - Selected pairwise cipher suite
+ *
+ * This is usually ignored if @wpa_ie is used.
+ */
+ enum wpa_cipher pairwise_suite;
+
+ /**
+ * group_suite - Selected group cipher suite
+ *
+ * This is usually ignored if @wpa_ie is used.
+ */
+ enum wpa_cipher group_suite;
+
+ /**
+ * key_mgmt_suite - Selected key management suite
+ *
+ * This is usually ignored if @wpa_ie is used.
+ */
+ enum wpa_key_mgmt key_mgmt_suite;
/**
* auth_alg - Allowed authentication algorithms
- * Bit field of AUTH_ALG_*
+ * Bit field of WPA_AUTH_ALG_*
*/
int auth_alg;
@@ -225,11 +384,7 @@ struct wpa_driver_associate_params {
/**
* mgmt_frame_protection - IEEE 802.11w management frame protection
*/
- enum {
- NO_MGMT_FRAME_PROTECTION,
- MGMT_FRAME_PROTECTION_OPTIONAL,
- MGMT_FRAME_PROTECTION_REQUIRED
- } mgmt_frame_protection;
+ enum mfp_options mgmt_frame_protection;
/**
* ft_ies - IEEE 802.11r / FT information elements
@@ -288,6 +443,23 @@ struct wpa_driver_associate_params {
* be prepared to handle %NULL value as an error.
*/
const u8 *psk;
+
+ /**
+ * drop_unencrypted - Enable/disable unencrypted frame filtering
+ *
+ * Configure the driver to drop all non-EAPOL frames (both receive and
+ * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
+ * still be allowed for key negotiation.
+ */
+ int drop_unencrypted;
+
+ /**
+ * prev_bssid - Previously used BSSID in this ESS
+ *
+ * When not %NULL, this is a request to use reassociation instead of
+ * association.
+ */
+ const u8 *prev_bssid;
};
/**
@@ -316,59 +488,119 @@ struct wpa_driver_capa {
/* Driver generated WPA/RSN IE */
#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
/* 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
+#define WPA_DRIVER_FLAGS_WIRED 0x00000010
+/* Driver provides separate commands for authentication and association (SME in
+ * wpa_supplicant). */
+#define WPA_DRIVER_FLAGS_SME 0x00000020
+/* Driver supports AP mode */
+#define WPA_DRIVER_FLAGS_AP 0x00000040
+/* Driver needs static WEP key setup after association has been completed */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080
unsigned int flags;
+
+ int max_scan_ssids;
+
+ /**
+ * max_remain_on_chan - Maximum remain-on-channel duration in msec
+ */
+ unsigned int max_remain_on_chan;
};
-#define WPA_CHAN_W_SCAN 0x00000001
-#define WPA_CHAN_W_ACTIVE_SCAN 0x00000002
-#define WPA_CHAN_W_IBSS 0x00000004
+struct hostapd_data;
-struct wpa_channel_data {
- short chan; /* channel number (IEEE 802.11) */
- short freq; /* frequency in MHz */
- int flag; /* flag for user space use (WPA_CHAN_*) */
+struct hostap_sta_driver_data {
+ unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+ unsigned long current_tx_rate;
+ unsigned long inactive_msec;
+ unsigned long flags;
+ unsigned long num_ps_buf_frames;
+ unsigned long tx_retry_failed;
+ unsigned long tx_retry_count;
+ int last_rssi;
+ int last_ack_rssi;
};
-#define WPA_RATE_ERP 0x00000001
-#define WPA_RATE_BASIC 0x00000002
-#define WPA_RATE_PREAMBLE2 0x00000004
-#define WPA_RATE_SUPPORTED 0x00000010
-#define WPA_RATE_OFDM 0x00000020
-#define WPA_RATE_CCK 0x00000040
-#define WPA_RATE_MANDATORY 0x00000100
+struct hostapd_sta_add_params {
+ const u8 *addr;
+ u16 aid;
+ u16 capability;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ u16 listen_interval;
+ const struct ieee80211_ht_capabilities *ht_capabilities;
+};
-struct wpa_rate_data {
- int rate; /* rate in 100 kbps */
- int flags; /* WPA_RATE_ flags */
+struct hostapd_freq_params {
+ int mode;
+ int freq;
+ int channel;
+ int ht_enabled;
+ int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+ * secondary channel below primary, 1 = HT40
+ * enabled, secondary channel above primary */
};
-typedef enum {
- WPA_MODE_IEEE80211B,
- WPA_MODE_IEEE80211G,
- WPA_MODE_IEEE80211A,
- NUM_WPA_MODES
-} wpa_hw_mode;
+enum wpa_driver_if_type {
+ /**
+ * WPA_IF_STATION - Station mode interface
+ */
+ WPA_IF_STATION,
-struct wpa_hw_modes {
- wpa_hw_mode mode;
- int num_channels;
- struct wpa_channel_data *channels;
- int num_rates;
- struct wpa_rate_data *rates;
+ /**
+ * WPA_IF_AP_VLAN - AP mode VLAN interface
+ *
+ * This interface shares its address and Beacon frame with the main
+ * BSS.
+ */
+ WPA_IF_AP_VLAN,
+
+ /**
+ * WPA_IF_AP_BSS - AP mode BSS interface
+ *
+ * This interface has its own address and Beacon frame.
+ */
+ WPA_IF_AP_BSS,
+};
+
+struct wpa_init_params {
+ const u8 *bssid;
+ const char *ifname;
+ const u8 *ssid;
+ size_t ssid_len;
+ const char *test_socket;
+ int use_pae_group_addr;
+ char **bridge;
+ size_t num_bridge;
+
+ u8 *own_addr; /* buffer for writing own MAC address */
};
-struct ieee80211_rx_status {
- int channel;
- int ssi;
+struct wpa_bss_params {
+ /** Interface name (for multi-SSID/VLAN support) */
+ const char *ifname;
+ /** Whether IEEE 802.1X or WPA/WPA2 is enabled */
+ int enabled;
+
+ int wpa;
+ int ieee802_1x;
+ int wpa_group;
+ int wpa_pairwise;
+ int wpa_key_mgmt;
+ int rsn_preauth;
};
+#define WPA_STA_AUTHORIZED BIT(0)
+#define WPA_STA_WMM BIT(1)
+#define WPA_STA_SHORT_PREAMBLE BIT(2)
+#define WPA_STA_MFP BIT(3)
/**
* struct wpa_driver_ops - Driver interface API definition
@@ -414,31 +646,8 @@ struct wpa_driver_ops {
int (*get_ssid)(void *priv, u8 *ssid);
/**
- * set_wpa - Enable/disable WPA support (OBSOLETE)
- * @priv: private driver interface data
- * @enabled: 1 = enable, 0 = disable
- *
- * Returns: 0 on success, -1 on failure
- *
- * Note: This function is included for backwards compatibility. This is
- * called only just after init and just before deinit, so these
- * functions can be used to implement same functionality and the driver
- * interface need not define this function.
- *
- * Configure the kernel driver to enable/disable WPA support. This may
- * be empty function, if WPA support is always enabled. Common
- * configuration items are WPA IE (clearing it when WPA support is
- * disabled), Privacy flag configuration for capability field (note:
- * this the value need to set in associate handler to allow plaintext
- * mode to be used) when trying to associate with, roaming mode (can
- * allow wpa_supplicant to control roaming if ap_scan=1 is used;
- * however, drivers can also implement roaming if desired, especially
- * ap_scan=2 mode is used for this).
- */
- int (*set_wpa)(void *priv, int enabled);
-
- /**
* set_key - Configure encryption key
+ * @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
* %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
@@ -480,8 +689,9 @@ struct wpa_driver_ops {
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
- int (*set_key)(void *priv, wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx, const u8 *seq, size_t seq_len,
+ int (*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);
/**
@@ -543,55 +753,6 @@ struct wpa_driver_ops {
int (*set_countermeasures)(void *priv, int enabled);
/**
- * set_drop_unencrypted - Enable/disable unencrypted frame filtering
- * @priv: private driver interface data
- * @enabled: 1 = unencrypted Tx/Rx frames will be dropped, 0 = disabled
- *
- * Returns: 0 on success, -1 on failure
- *
- * Configure the driver to drop all non-EAPOL frames (both receive and
- * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
- * still be allowed for key negotiation.
- */
- int (*set_drop_unencrypted)(void *priv, int enabled);
-
- /**
- * scan - Request the driver to initiate scan
- * @priv: private driver interface data
- * @ssid: specific SSID to scan for (ProbeReq) or %NULL to scan for
- * all SSIDs (either active scan with broadcast SSID or passive
- * scan
- * @ssid_len: length of the SSID
- *
- * Returns: 0 on success, -1 on failure
- *
- * Once the scan results are ready, the driver should report scan
- * results event for wpa_supplicant which will eventually request the
- * results with wpa_driver_get_scan_results().
- */
- int (*scan)(void *priv, const u8 *ssid, size_t ssid_len);
-
- /**
- * get_scan_results - Fetch the latest scan results (old version)
- * @priv: private driver interface data
- * @results: pointer to buffer for scan results
- * @max_size: maximum number of entries (buffer size)
- *
- * Returns: Number of scan result entries used on success, -1 on
- * failure
- *
- * If scan results include more than max_size BSSes, max_size will be
- * returned and the remaining entries will not be included in the
- * buffer.
- *
- * This function is depracated. New driver wrapper implementations
- * should implement support for get_scan_results2().
- */
- int (*get_scan_results)(void *priv,
- struct wpa_scan_result *results,
- size_t max_size);
-
- /**
* deauthenticate - Request driver to deauthenticate
* @priv: private driver interface data
* @addr: peer address (BSSID of the AP)
@@ -624,27 +785,6 @@ struct wpa_driver_ops {
struct wpa_driver_associate_params *params);
/**
- * set_auth_alg - Set IEEE 802.11 authentication algorithm
- * @priv: private driver interface data
- * @auth_alg: bit field of AUTH_ALG_*
- *
- * If the driver supports more than one authentication algorithm at the
- * same time, it should configure all supported algorithms. If not, one
- * algorithm needs to be selected arbitrarily. Open System
- * authentication should be ok for most cases and it is recommended to
- * be used if other options are not supported. Static WEP configuration
- * may also use Shared Key authentication and LEAP requires its own
- * algorithm number. For LEAP, user can make sure that only one
- * algorithm is used at a time by configuring LEAP as the only
- * supported EAP method. This information is also available in
- * associate() params, so set_auth_alg may not be needed in case of
- * most drivers.
- *
- * Returns: 0 on success, -1 on failure
- */
- int (*set_auth_alg)(void *priv, int auth_alg);
-
- /**
* add_pmkid - Add PMKSA cache entry to the driver
* @priv: private driver interface data
* @bssid: BSSID for the PMKSA cache entry
@@ -764,9 +904,9 @@ struct wpa_driver_ops {
* with driver specific functionality. If this function pointer is set,
* l2_packet module is not used at all and the driver interface code is
* responsible for receiving and sending all EAPOL packets. The
- * received EAPOL packets are sent to core code by calling
- * wpa_supplicant_rx_eapol(). The driver interface is required to
- * implement get_mac_addr() handler if send_eapol() is used.
+ * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
+ * event. The driver interface is required to implement get_mac_addr()
+ * handler if send_eapol() is used.
*/
int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
const u8 *data, size_t data_len);
@@ -813,16 +953,16 @@ struct wpa_driver_ops {
* failure. Caller is responsible for freeing this.
*
* This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant.
+ * (management frame processing) to %wpa_supplicant or hostapd.
*/
- struct wpa_hw_modes * (*get_hw_feature_data)(void *priv,
- u16 *num_modes,
- u16 *flags);
+ 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: WPA_MODE_IEEE80211B, ..
+ * @phymode: HOSTAPD_MODE_IEEE80211B, ..
* @chan: IEEE 802.11 channel number
* @freq: Frequency of the channel in MHz
* Returns: 0 on success, -1 on failure
@@ -830,7 +970,7 @@ struct wpa_driver_ops {
* This function is only needed for drivers that export MLME
* (management frame processing) to wpa_supplicant.
*/
- int (*set_channel)(void *priv, wpa_hw_mode phymode, int chan,
+ int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan,
int freq);
/**
@@ -941,29 +1081,6 @@ struct wpa_driver_ops {
struct wpa_scan_results * (*get_scan_results2)(void *priv);
/**
- * set_probe_req_ie - Set information element(s) for Probe Request
- * @priv: private driver interface data
- * @ies: Information elements to append or %NULL to remove extra IEs
- * @ies_len: Length of the IE buffer in octets
- * Returns: 0 on success, -1 on failure
- */
- int (*set_probe_req_ie)(void *priv, const u8 *ies, size_t ies_len);
-
- /**
- * set_mode - Request driver to set the operating mode
- * @priv: private driver interface data
- * @mode: Operation mode (infra/ibss) IEEE80211_MODE_*
- *
- * This handler will be called before any key configuration and call to
- * associate() handler in order to allow the operation mode to be
- * configured as early as possible. This information is also available
- * in associate() params and as such, some driver wrappers may not need
- * to implement set_mode() handler.
- * Returns: 0 on success, -1 on failure
- */
- int (*set_mode)(void *priv, int mode);
-
- /**
* set_country - Set country
* @priv: Private driver interface data
* @alpha2: country to which to switch to
@@ -1017,19 +1134,644 @@ struct wpa_driver_ops {
* failure
*/
struct wpa_interface_info * (*get_interfaces)(void *global_priv);
+
+ /**
+ * scan2 - Request the driver to initiate scan
+ * @priv: private driver interface data
+ * @params: Scan parameters
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Once the scan results are ready, the driver should report scan
+ * results event for wpa_supplicant which will eventually request the
+ * results with wpa_driver_get_scan_results2().
+ */
+ int (*scan2)(void *priv, struct wpa_driver_scan_params *params);
+
+ /**
+ * authenticate - Request driver to authenticate
+ * @priv: private driver interface data
+ * @params: authentication parameters
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is an optional function that can be used with drivers that
+ * support separate authentication and association steps, i.e., when
+ * wpa_supplicant can act as the SME. If not implemented, associate()
+ * function is expected to take care of IEEE 802.11 authentication,
+ * too.
+ */
+ int (*authenticate)(void *priv,
+ struct wpa_driver_auth_params *params);
+
+ /**
+ * set_beacon - Set Beacon frame template
+ * @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
+ *
+ * This function is used to configure Beacon template 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.
+ */
+ 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);
+
+ /**
+ * hapd_init - Initialize driver interface (hostapd only)
+ * @hapd: Pointer to hostapd context
+ * @params: Configuration for the driver wrapper
+ * 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.
+ */
+ void * (*hapd_init)(struct hostapd_data *hapd,
+ struct wpa_init_params *params);
+
+ /**
+ * hapd_deinit - Deinitialize driver interface (hostapd only)
+ * @priv: Private driver interface data from hapd_init()
+ */
+ void (*hapd_deinit)(void *priv);
+
+ /**
+ * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only)
+ * @priv: Private driver interface data
+ * @params: BSS parameters
+ * Returns: 0 on success, -1 on failure
+ *
+ * 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
+ * for Beacon frames.
+ */
+ int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
+
+ /**
+ * set_privacy - Enable/disable privacy (AP only)
+ * @priv: Private driver interface data
+ * @enabled: 1 = privacy enabled, 0 = disabled
+ * Returns: 0 on success, -1 on failure
+ *
+ * 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().
+ */
+ int (*set_privacy)(void *priv, int enabled);
+
+ /**
+ * get_seqnum - Fetch the current TSC/packet number (AP only)
+ * @ifname: The interface name (main or virtual)
+ * @priv: Private driver interface data
+ * @addr: MAC address of the station or %NULL for group keys
+ * @idx: Key index
+ * @seq: Buffer for returning the latest used TSC/packet number
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to fetch the last used TSC/packet number for
+ * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so
+ * there is no strict requirement on implementing support for unicast
+ * keys (i.e., addr != %NULL).
+ */
+ int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq);
+
+ /**
+ * flush - Flush all association stations (AP only)
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function requests the driver to disassociate all associated
+ * stations. This function does not need to be implemented if the
+ * driver does not process association frames internally.
+ */
+ int (*flush)(void *priv);
+
+ /**
+ * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP)
+ * @priv: Private driver interface data
+ * @elem: Information elements
+ * @elem_len: Length of the elem buffer in octets
+ * Returns: 0 on success, -1 on failure
+ *
+ * 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().
+ */
+ int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
+
+ /**
+ * read_sta_data - Fetch station data (AP only)
+ * @priv: Private driver interface data
+ * @data: Buffer for returning station information
+ * @addr: MAC address of the station
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr);
+
+ /**
+ * hapd_send_eapol - Send an EAPOL packet (AP only)
+ * @priv: private driver interface data
+ * @addr: Destination MAC address
+ * @data: EAPOL packet starting with IEEE 802.1X header
+ * @data_len: Length of the EAPOL packet in octets
+ * @encrypt: Whether the frame should be encrypted
+ * @own_addr: Source MAC address
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt,
+ const u8 *own_addr);
+
+ /**
+ * sta_deauth - Deauthenticate a station (AP only)
+ * @priv: Private driver interface data
+ * @own_addr: Source address and BSSID for the Deauthentication frame
+ * @addr: MAC address of the station to deauthenticate
+ * @reason: Reason code for the Deauthentiation frame
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function requests a specific station to be deauthenticated and
+ * a Deauthentication frame to be sent to it.
+ */
+ int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason);
+
+ /**
+ * sta_disassoc - Disassociate a station (AP only)
+ * @priv: Private driver interface data
+ * @own_addr: Source address and BSSID for the Disassociation frame
+ * @addr: MAC address of the station to disassociate
+ * @reason: Reason code for the Disassociation frame
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function requests a specific station to be disassociated and
+ * a Disassociation frame to be sent to it.
+ */
+ int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason);
+
+ /**
+ * sta_remove - Remove a station entry (AP only)
+ * @priv: Private driver interface data
+ * @addr: MAC address of the station to be removed
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*sta_remove)(void *priv, const u8 *addr);
+
+ /**
+ * hapd_get_ssid - Get the current SSID (AP only)
+ * @priv: Private driver interface data
+ * @buf: Buffer for returning the SSID
+ * @len: Maximum length of the buffer
+ * 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.
+ */
+ int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
+
+ /**
+ * hapd_set_ssid - Set SSID (AP only)
+ * @priv: Private driver interface data
+ * @buf: SSID
+ * @len: Length of the SSID in octets
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
+
+ /**
+ * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP)
+ * @priv: Private driver interface data
+ * @enabled: 1 = countermeasures enabled, 0 = disabled
+ * Returns: 0 on success, -1 on failure
+ *
+ * This need not be implemented if the driver does not take care of
+ * association processing.
+ */
+ int (*hapd_set_countermeasures)(void *priv, int enabled);
+
+ /**
+ * sta_add - Add a station entry
+ * @priv: Private driver interface data
+ * @params: Station parameters
+ * Returns: 0 on success, -1 on failure
+ *
+ * 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.
+ */
+ int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
+
+ /**
+ * get_inact_sec - Get station inactivity duration (AP only)
+ * @priv: Private driver interface data
+ * @addr: Station address
+ * Returns: Number of seconds station has been inactive, -1 on failure
+ */
+ int (*get_inact_sec)(void *priv, const u8 *addr);
+
+ /**
+ * sta_clear_stats - Clear station statistics (AP only)
+ * @priv: Private driver interface data
+ * @addr: Station address
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+ /**
+ * set_freq - Set channel/frequency (AP only)
+ * @priv: Private driver interface data
+ * @freq: Channel parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_freq)(void *priv, struct hostapd_freq_params *freq);
+
+ /**
+ * set_rts - Set RTS threshold
+ * @priv: Private driver interface data
+ * @rts: RTS threshold in octets
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_rts)(void *priv, int rts);
+
+ /**
+ * set_frag - Set fragmentation threshold
+ * @priv: Private driver interface data
+ * @frag: Fragmentation threshold in octets
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_frag)(void *priv, int frag);
+
+ /**
+ * sta_set_flags - Set station flags (AP only)
+ * @priv: Private driver interface data
+ * @addr: Station address
+ * @total_flags: Bitmap of all WPA_STA_* flags currently set
+ * @flags_or: Bitmap of WPA_STA_* flags to add
+ * @flags_and: Bitmap of WPA_STA_* flags to us as a mask
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*sta_set_flags)(void *priv, const u8 *addr,
+ 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
+ * @aifs: AIFS
+ * @cw_min: cwMin
+ * @cw_max: cwMax
+ * @burst_time: Maximum length for bursting in 0.1 msec units
+ */
+ int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
+ 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
+ * @ifname: Interface name for the new virtual interface
+ * @addr: Local address to use for the interface or %NULL to use the
+ * parent interface address
+ * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
+ * @drv_priv: Pointer for overwriting the driver context or %NULL if
+ * not allowed (applies only to %WPA_IF_AP_BSS type)
+ * @force_ifname: Buffer for returning an interface name that the
+ * driver ended up using if it differs from the requested ifname
+ * @if_addr: Buffer for returning the allocated interface address
+ * (this may differ from the requested addr if the driver cannot
+ * change interface address)
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*if_add)(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, const u8 *addr, void *bss_ctx,
+ void **drv_priv, char *force_ifname, u8 *if_addr);
+
+ /**
+ * if_remove - Remove a virtual interface
+ * @priv: Private driver interface data
+ * @type: Interface type
+ * @ifname: Interface name of the virtual interface to be removed
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*if_remove)(void *priv, enum wpa_driver_if_type type,
+ const char *ifname);
+
+ /**
+ * set_sta_vlan - Bind a station into a specific interface (AP only)
+ * @priv: Private driver interface data
+ * @ifname: Interface (main or virtual BSS or VLAN)
+ * @addr: MAC address of the associated station
+ * @vlan_id: VLAN ID
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to bind a station to a specific virtual
+ * interface. It is only used if when virtual interfaces are supported,
+ * e.g., to assign stations to different VLAN interfaces based on
+ * information from a RADIUS server. This allows separate broadcast
+ * domains to be used with a single BSS.
+ */
+ int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
+ int vlan_id);
+
+ /**
+ * commit - Optional commit changes handler (AP only)
+ * @priv: driver private data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This optional handler function can be registered if the driver
+ * interface implementation needs to commit changes (e.g., by setting
+ * network interface up) at the end of initial configuration. If set,
+ * this handler will be called after initial setup has been completed.
+ */
+ int (*commit)(void *priv);
+
+ /**
+ * send_ether - Send an ethernet packet (AP only)
+ * @priv: private driver interface data
+ * @dst: Destination MAC address
+ * @src: Source MAC address
+ * @proto: Ethertype
+ * @data: EAPOL packet starting with IEEE 802.1X header
+ * @data_len: Length of the EAPOL packet in octets
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
+ const u8 *data, size_t data_len);
+
+ /**
+ * set_radius_acl_auth - Notification of RADIUS ACL change
+ * @priv: Private driver interface data
+ * @mac: MAC address of the station
+ * @accepted: Whether the station was accepted
+ * @session_timeout: Session timeout for the station
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
+ u32 session_timeout);
+
+ /**
+ * set_radius_acl_expire - Notification of RADIUS ACL expiration
+ * @priv: Private driver interface data
+ * @mac: MAC address of the station
+ * Returns: 0 on success, -1 on failure
+ */
+ 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)
+ * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove
+ * extra IE(s)
+ * Returns: 0 on success, -1 on failure
+ *
+ * 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()
+ * and does not process Probe Request frames.
+ */
+ int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp);
+
+ /**
+ * set_supp_port - Set IEEE 802.1X Supplicant Port status
+ * @priv: Private driver interface data
+ * @authorized: Whether the port is authorized
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_supp_port)(void *priv, int authorized);
+
+ /**
+ * set_wds_sta - Bind a station into a 4-address WDS (AP only)
+ * @priv: Private driver interface data
+ * @addr: MAC address of the associated station
+ * @aid: Association ID
+ * @val: 1 = bind to 4-address WDS; 0 = unbind
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val);
+
+ /**
+ * send_action - Transmit an Action frame
+ * @priv: Private driver interface data
+ * @freq: Frequency (in MHz) of the channel
+ * @dst: Destination MAC address (Address 1)
+ * @src: Source MAC address (Address 2)
+ * @bssid: BSSID (Address 3)
+ * @data: Frame body
+ * @data_len: data length in octets
+ * Returns: 0 on success, -1 on failure
+ *
+ * This command can be used to request the driver to transmit an action
+ * frame to the specified destination. If a remain-on-channel duration
+ * is in progress, the frame is transmitted on that channel. Otherwise,
+ * the frame is transmitted on the current operational channel if in
+ * associated state in station mode or if operating as an AP. If none
+ * of these conditions is in effect, send_action() cannot be used.
+ */
+ int (*send_action)(void *priv, unsigned int freq,
+ const u8 *dst, const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len);
+
+ /**
+ * remain_on_channel - Remain awake on a channel
+ * @priv: Private driver interface data
+ * @freq: Frequency (in MHz) of the channel
+ * @duration: Duration in milliseconds
+ * Returns: 0 on success, -1 on failure
+ *
+ * This command is used to request the driver to remain awake on the
+ * specified channel for the specified duration and report received
+ * Action frames with EVENT_RX_ACTION events. Optionally, received
+ * Probe Request frames may also be requested to be reported by calling
+ * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
+ *
+ * The driver may not be at the requested channel when this function
+ * returns, i.e., the return code is only indicating whether the
+ * request was accepted. The caller will need to wait until the
+ * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has
+ * completed the channel change. This may take some time due to other
+ * need for the radio and the caller should be prepared to timing out
+ * its wait since there are no guarantees on when this request can be
+ * executed.
+ */
+ int (*remain_on_channel)(void *priv, unsigned int freq,
+ unsigned int duration);
+
+ /**
+ * cancel_remain_on_channel - Cancel remain-on-channel operation
+ * @priv: Private driver interface data
+ *
+ * This command can be used to cancel a remain-on-channel operation
+ * before its originally requested duration has passed. This could be
+ * used, e.g., when remain_on_channel() is used to request extra time
+ * to receive a response to an Action frame and the response is
+ * received when there is still unneeded time remaining on the
+ * remain-on-channel operation.
+ */
+ int (*cancel_remain_on_channel)(void *priv);
+
+ /**
+ * probe_req_report - Request Probe Request frames to be indicated
+ * @priv: Private driver interface data
+ * @report: Whether to report received Probe Request frames
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ *
+ * This command can be used to request the driver to indicate when
+ * Probe Request frames are received with EVENT_RX_PROBE_REQ events.
+ * Since this operation may require extra resources, e.g., due to less
+ * optimal hardware/firmware RX filtering, many drivers may disable
+ * Probe Request reporting at least in station mode. This command is
+ * used to notify the driver when the Probe Request frames need to be
+ * reported, e.g., during remain-on-channel operations.
+ */
+ 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)
+ *
+ * This optional function can be used to disable AP mode related
+ * configuration and change the driver mode to station mode to allow
+ * normal station operations like scanning to be completed.
+ */
+ int (*deinit_ap)(void *priv);
+
+ /**
+ * suspend - Notification on system suspend/hibernate event
+ * @priv: Private driver interface data
+ */
+ void (*suspend)(void *priv);
+
+ /**
+ * resume - Notification on system resume/thaw event
+ * @priv: Private driver interface data
+ */
+ void (*resume)(void *priv);
+
+ /**
+ * signal_monitor - Set signal monitoring parameters
+ * @priv: Private driver interface data
+ * @threshold: Threshold value for signal change events; 0 = disabled
+ * @hysteresis: Minimum change in signal strength before indicating a
+ * new event
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ *
+ * This function can be used to configure monitoring of signal strength
+ * with the current AP. Whenever signal strength drops below the
+ * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event
+ * should be generated assuming the signal strength has changed at
+ * least %hysteresis from the previously indicated signal change event.
+ */
+ int (*signal_monitor)(void *priv, int threshold, int hysteresis);
+
+ /**
+ * send_frame - Send IEEE 802.11 frame (testing use only)
+ * @priv: Private driver interface data
+ * @data: IEEE 802.11 frame with IEEE 802.11 header
+ * @data_len: Size of the frame
+ * @encrypt: Whether to encrypt the frame (if keys are set)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used for debugging purposes and is not
+ * required to be implemented for normal operations.
+ */
+ int (*send_frame)(void *priv, const u8 *data, size_t data_len,
+ int encrypt);
};
-/* Function to check whether a driver is for wired connections */
-static inline int IS_WIRED(const struct wpa_driver_ops *drv)
-{
- return os_strcmp(drv->name, "wired") == 0 ||
- os_strcmp(drv->name, "roboswitch") == 0;
-}
/**
* enum wpa_event_type - Event type for wpa_supplicant_event() calls
*/
-typedef enum wpa_event_type {
+enum wpa_event_type {
/**
* EVENT_ASSOC - Association completed
*
@@ -1049,7 +1791,10 @@ typedef enum wpa_event_type {
*
* This event should be called when association is lost either due to
* receiving deauthenticate or disassociate frame from the AP or when
- * sending either of these frames to the current AP.
+ * sending either of these frames to the current AP. If the driver
+ * supports separate deauthentication event, EVENT_DISASSOC should only
+ * be used for disassociation and EVENT_DEAUTH for deauthentication.
+ * In AP mode, union wpa_event_data::disassoc_info is required.
*/
EVENT_DISASSOC,
@@ -1075,7 +1820,8 @@ typedef enum wpa_event_type {
* EVENT_SCAN_RESULTS call. If such event is not available from the
* driver, the driver wrapper code is expected to use a registered
* timeout to generate EVENT_SCAN_RESULTS call after the time that the
- * scan is expected to be completed.
+ * scan is expected to be completed. Optional information about
+ * completed scan can be provided with union wpa_event_data::scan_info.
*/
EVENT_SCAN_RESULTS,
@@ -1147,8 +1893,161 @@ typedef enum wpa_event_type {
* FT authentication sequence from the AP. The FT IEs are included in
* the extra information in union wpa_event_data::ft_ies.
*/
- EVENT_FT_RESPONSE
-} wpa_event_type;
+ EVENT_FT_RESPONSE,
+
+ /**
+ * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS
+ *
+ * The driver can use this event to inform wpa_supplicant about a STA
+ * in an IBSS with which protected frames could be exchanged. This
+ * event starts RSN authentication with the other STA to authenticate
+ * the STA and set up encryption keys with it.
+ */
+ EVENT_IBSS_RSN_START,
+
+ /**
+ * EVENT_AUTH - Authentication result
+ *
+ * This event should be called when authentication attempt has been
+ * completed. This is only used if the driver supports separate
+ * authentication step (struct wpa_driver_ops::authenticate).
+ * Information about authentication result is included in
+ * union wpa_event_data::auth.
+ */
+ EVENT_AUTH,
+
+ /**
+ * EVENT_DEAUTH - Authentication lost
+ *
+ * This event should be called when authentication is lost either due
+ * to receiving deauthenticate frame from the AP or when sending that
+ * frame to the current AP.
+ * In AP mode, union wpa_event_data::deauth_info is required.
+ */
+ EVENT_DEAUTH,
+
+ /**
+ * EVENT_ASSOC_REJECT - Association rejected
+ *
+ * This event should be called when (re)association attempt has been
+ * rejected by the AP. Information about authentication result is
+ * included in union wpa_event_data::assoc_reject.
+ */
+ EVENT_ASSOC_REJECT,
+
+ /**
+ * EVENT_AUTH_TIMED_OUT - Authentication timed out
+ */
+ EVENT_AUTH_TIMED_OUT,
+
+ /**
+ * EVENT_ASSOC_TIMED_OUT - Association timed out
+ */
+ EVENT_ASSOC_TIMED_OUT,
+
+ /**
+ * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
+ */
+ EVENT_FT_RRB_RX,
+
+ /**
+ * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
+ */
+ EVENT_WPS_BUTTON_PUSHED,
+
+ /**
+ * EVENT_TX_STATUS - Report TX status
+ */
+ EVENT_TX_STATUS,
+
+ /**
+ * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA
+ */
+ EVENT_RX_FROM_UNKNOWN,
+
+ /**
+ * EVENT_RX_MGMT - Report RX of a management frame
+ */
+ EVENT_RX_MGMT,
+
+ /**
+ * EVENT_RX_ACTION - Action frame received
+ *
+ * This event is used to indicate when an Action frame has been
+ * received. Information about the received frame is included in
+ * union wpa_event_data::rx_action.
+ */
+ EVENT_RX_ACTION,
+
+ /**
+ * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started
+ *
+ * This event is used to indicate when the driver has started the
+ * requested remain-on-channel duration. Information about the
+ * operation is included in union wpa_event_data::remain_on_channel.
+ */
+ EVENT_REMAIN_ON_CHANNEL,
+
+ /**
+ * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out
+ *
+ * This event is used to indicate when the driver has completed
+ * remain-on-channel duration, i.e., may noot be available on the
+ * requested channel anymore. Information about the
+ * operation is included in union wpa_event_data::remain_on_channel.
+ */
+ EVENT_CANCEL_REMAIN_ON_CHANNEL,
+
+ /**
+ * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
+ *
+ * This event is used only by driver_test.c and userspace MLME.
+ */
+ EVENT_MLME_RX,
+
+ /**
+ * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
+ *
+ * This event is used to indicate when a Probe Request frame has been
+ * received. Information about the received frame is included in
+ * union wpa_event_data::rx_probe_req. The driver is required to report
+ * these events only after successfully completed probe_req_report()
+ * commands to request the events (i.e., report parameter is non-zero)
+ * in station mode. In AP mode, Probe Request frames should always be
+ * reported.
+ */
+ EVENT_RX_PROBE_REQ,
+
+ /**
+ * EVENT_NEW_STA - New wired device noticed
+ *
+ * This event is used to indicate that a new device has been detected
+ * in a network that does not use association-like functionality (i.e.,
+ * mainly wired Ethernet). This can be used to start EAPOL
+ * authenticator when receiving a frame from a device. The address of
+ * the device is included in union wpa_event_data::new_sta.
+ */
+ EVENT_NEW_STA,
+
+ /**
+ * EVENT_EAPOL_RX - Report received EAPOL frame
+ *
+ * When in AP mode with hostapd, this event is required to be used to
+ * deliver the receive EAPOL frames from the driver. With
+ * %wpa_supplicant, this event is used only if the send_eapol() handler
+ * is used to override the use of l2_packet for EAPOL frame TX.
+ */
+ EVENT_EAPOL_RX,
+
+ /**
+ * EVENT_SIGNAL_CHANGE - Indicate change in signal strength
+ *
+ * This event is used to indicate changes in the signal strength
+ * observed in frames received from the current AP if signal strength
+ * monitoring has been enabled with signal_monitor().
+ */
+ EVENT_SIGNAL_CHANGE
+};
/**
@@ -1175,7 +2074,7 @@ union wpa_event_data {
* This should start with the first IE (fixed fields before IEs
* are not included).
*/
- u8 *req_ies;
+ const u8 *req_ies;
/**
* req_ies_len - Length of req_ies in bytes
@@ -1193,7 +2092,7 @@ union wpa_event_data {
* This should start with the first IE (fixed fields before IEs
* are not included).
*/
- u8 *resp_ies;
+ const u8 *resp_ies;
/**
* resp_ies_len - Length of resp_ies in bytes
@@ -1216,18 +2115,61 @@ union wpa_event_data {
* This should start with the first IE (fixed fields before IEs
* are not included).
*/
- u8 *beacon_ies;
+ const u8 *beacon_ies;
/**
* beacon_ies_len - Length of beacon_ies */
size_t beacon_ies_len;
+
+ /**
+ * freq - Frequency of the operational channel in MHz
+ */
+ unsigned int freq;
+
+ /**
+ * addr - Station address (for AP mode)
+ */
+ const u8 *addr;
} assoc_info;
/**
+ * struct disassoc_info - Data for EVENT_DISASSOC events
+ */
+ struct disassoc_info {
+ /**
+ * addr - Station address (for AP mode)
+ */
+ const u8 *addr;
+
+ /**
+ * reason_code - Reason Code (host byte order) used in
+ * Deauthentication frame
+ */
+ u16 reason_code;
+ } disassoc_info;
+
+ /**
+ * struct deauth_info - Data for EVENT_DEAUTH events
+ */
+ struct deauth_info {
+ /**
+ * addr - Station address (for AP mode)
+ */
+ const u8 *addr;
+
+ /**
+ * reason_code - Reason Code (host byte order) used in
+ * Deauthentication frame
+ */
+ u16 reason_code;
+ } deauth_info;
+
+ /**
* struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE
*/
struct michael_mic_failure {
int unicast;
+ const u8 *src;
} michael_mic_failure;
/**
@@ -1273,7 +2215,228 @@ union wpa_event_data {
size_t ies_len;
int ft_action;
u8 target_ap[ETH_ALEN];
+ /** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */
+ const u8 *ric_ies;
+ /** Length of ric_ies buffer in octets */
+ size_t ric_ies_len;
} ft_ies;
+
+ /**
+ * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START
+ */
+ struct ibss_rsn_start {
+ u8 peer[ETH_ALEN];
+ } ibss_rsn_start;
+
+ /**
+ * struct auth_info - Data for EVENT_AUTH events
+ */
+ struct auth_info {
+ u8 peer[ETH_ALEN];
+ u16 auth_type;
+ u16 status_code;
+ const u8 *ies;
+ size_t ies_len;
+ } auth;
+
+ /**
+ * struct assoc_reject - Data for EVENT_ASSOC_REJECT events
+ */
+ struct assoc_reject {
+ /**
+ * resp_ies - (Re)Association Response IEs
+ *
+ * Optional association data from the driver. This data is not
+ * required WPA, but may be useful for some protocols and as
+ * such, should be reported if this is available to the driver
+ * interface.
+ *
+ * This should start with the first IE (fixed fields before IEs
+ * are not included).
+ */
+ u8 *resp_ies;
+
+ /**
+ * resp_ies_len - Length of resp_ies in bytes
+ */
+ size_t resp_ies_len;
+
+ /**
+ * status_code - Status Code from (Re)association Response
+ */
+ u16 status_code;
+ } assoc_reject;
+
+ struct timeout_event {
+ u8 addr[ETH_ALEN];
+ } timeout_event;
+
+ /**
+ * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
+ */
+ struct ft_rrb_rx {
+ const u8 *src;
+ const u8 *data;
+ size_t data_len;
+ } ft_rrb_rx;
+
+ /**
+ * struct tx_status - Data for EVENT_TX_STATUS events
+ */
+ struct tx_status {
+ u16 type;
+ u16 stype;
+ const u8 *dst;
+ const u8 *data;
+ size_t data_len;
+ int ack;
+ } tx_status;
+
+ /**
+ * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
+ */
+ struct rx_from_unknown {
+ const u8 *frame;
+ size_t len;
+ } rx_from_unknown;
+
+ /**
+ * struct rx_mgmt - Data for EVENT_RX_MGMT events
+ */
+ struct rx_mgmt {
+ const u8 *frame;
+ size_t frame_len;
+ u32 datarate;
+ u32 ssi_signal;
+ } rx_mgmt;
+
+ /**
+ * struct rx_action - Data for EVENT_RX_ACTION events
+ */
+ struct rx_action {
+ /**
+ * da - Destination address of the received Action frame
+ */
+ const u8 *da;
+
+ /**
+ * sa - Source address of the received Action frame
+ */
+ const u8 *sa;
+
+ /**
+ * bssid - Address 3 of the received Action frame
+ */
+ const u8 *bssid;
+
+ /**
+ * category - Action frame category
+ */
+ u8 category;
+
+ /**
+ * data - Action frame body after category field
+ */
+ const u8 *data;
+
+ /**
+ * len - Length of data in octets
+ */
+ size_t len;
+
+ /**
+ * freq - Frequency (in MHz) on which the frame was received
+ */
+ int freq;
+ } rx_action;
+
+ /**
+ * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events
+ *
+ * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events.
+ */
+ struct remain_on_channel {
+ /**
+ * freq - Channel frequency in MHz
+ */
+ unsigned int freq;
+
+ /**
+ * duration - Duration to remain on the channel in milliseconds
+ */
+ unsigned int duration;
+ } remain_on_channel;
+
+ /**
+ * struct scan_info - Optional data for EVENT_SCAN_RESULTS events
+ * @aborted: Whether the scan was aborted
+ * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
+ * @num_freqs: Number of entries in freqs array
+ * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
+ * SSID)
+ * @num_ssids: Number of entries in ssids array
+ */
+ struct scan_info {
+ int aborted;
+ const int *freqs;
+ size_t num_freqs;
+ struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
+ size_t num_ssids;
+ } scan_info;
+
+ /**
+ * struct mlme_rx - Data for EVENT_MLME_RX events
+ */
+ struct mlme_rx {
+ const u8 *buf;
+ size_t len;
+ int freq;
+ int channel;
+ int ssi;
+ } mlme_rx;
+
+ /**
+ * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
+ */
+ struct rx_probe_req {
+ /**
+ * sa - Source address of the received Probe Request frame
+ */
+ const u8 *sa;
+
+ /**
+ * ie - IEs from the Probe Request body
+ */
+ const u8 *ie;
+
+ /**
+ * ie_len - Length of ie buffer in octets
+ */
+ size_t ie_len;
+ } rx_probe_req;
+
+ /**
+ * struct new_sta - Data for EVENT_NEW_STA events
+ */
+ struct new_sta {
+ const u8 *addr;
+ } new_sta;
+
+ /**
+ * struct eapol_rx - Data for EVENT_EAPOL_RX events
+ */
+ struct eapol_rx {
+ const u8 *src;
+ const u8 *data;
+ size_t data_len;
+ } eapol_rx;
+
+ /**
+ * struct signal_change - Data for EVENT_SIGNAL_CHANGE events
+ */
+ struct signal_change {
+ int above_threshold;
+ } signal_change;
};
/**
@@ -1286,40 +2449,43 @@ union wpa_event_data {
* Driver wrapper code should call this function whenever an event is received
* from the driver.
*/
-void wpa_supplicant_event(void *ctx, wpa_event_type event,
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data);
-/**
- * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
- * @ctx: Context pointer (wpa_s); this is the ctx variable registered
- * with struct wpa_driver_ops::init()
- * @src_addr: Source address of the EAPOL frame
- * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
- * @len: Length of the EAPOL data
- *
- * This function is called for each received EAPOL frame. Most driver
- * interfaces rely on more generic OS mechanism for receiving frames through
- * l2_packet, but if such a mechanism is not available, the driver wrapper may
- * take care of received EAPOL frames and deliver them to the core supplicant
- * code by calling this function.
+
+/*
+ * The following inline functions are provided for convenience to simplify
+ * event indication for some of the common events.
*/
-void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
- const u8 *buf, size_t len);
-void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len,
- struct ieee80211_rx_status *rx_status);
-void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features,
- size_t num_hw_features);
+static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie,
+ size_t ielen)
+{
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_info.req_ies = ie;
+ event.assoc_info.req_ies_len = ielen;
+ event.assoc_info.addr = addr;
+ wpa_supplicant_event(ctx, EVENT_ASSOC, &event);
+}
-const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
-#define WPA_IE_VENDOR_TYPE 0x0050f201
-#define WPS_IE_VENDOR_TYPE 0x0050f204
-const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
- u32 vendor_type);
-struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
- u32 vendor_type);
-int wpa_scan_get_max_rate(const struct wpa_scan_res *res);
-void wpa_scan_results_free(struct wpa_scan_results *res);
-void wpa_scan_sort_results(struct wpa_scan_results *res);
+static inline void drv_event_disassoc(void *ctx, const u8 *addr)
+{
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.disassoc_info.addr = addr;
+ wpa_supplicant_event(ctx, EVENT_DISASSOC, &event);
+}
+
+static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
+ size_t data_len)
+{
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.eapol_rx.src = src;
+ event.eapol_rx.data = data;
+ event.eapol_rx.data_len = data_len;
+ wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
+}
#endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
new file mode 100644
index 0000000000000..5c25f00b16431
--- /dev/null
+++ b/src/drivers/driver_atheros.c
@@ -0,0 +1,1298 @@
+/*
+ * hostapd / Driver interaction with Atheros driver
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * 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 <net/if.h>
+#include <sys/ioctl.h>
+
+#include "common.h"
+#ifndef _BYTE_ORDER
+#ifdef WORDS_BIGENDIAN
+#define _BYTE_ORDER _BIG_ENDIAN
+#else
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#endif
+#endif /* _BYTE_ORDER */
+
+/*
+ * Note, the ATH_WPS_IE setting must match with the driver build.. If the
+ * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail.
+ */
+#define ATH_WPS_IE
+
+#include "os/linux/include/ieee80211_external.h"
+
+
+#ifdef CONFIG_WPS
+#include <netpacket/packet.h>
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW 0x0019
+#endif
+#endif /* CONFIG_WPS */
+
+#include "wireless_copy.h"
+
+#include "driver.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "l2_packet/l2_packet.h"
+#include "common/ieee802_11_defs.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+
+
+struct madwifi_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ int ifindex;
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ struct l2_packet_data *sock_recv; /* raw packet recv socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ struct netlink_data *netlink;
+ int we_version;
+ u8 acct_mac[ETH_ALEN];
+ struct hostap_sta_driver_data acct_data;
+
+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+};
+
+static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code);
+static int madwifi_set_privacy(void *priv, int enabled);
+
+static const char * athr_get_ioctl_name(int op)
+{
+ switch (op) {
+ case IEEE80211_IOCTL_SETPARAM:
+ return "SETPARAM";
+ case IEEE80211_IOCTL_GETPARAM:
+ return "GETPARAM";
+ case IEEE80211_IOCTL_SETKEY:
+ return "SETKEY";
+ case IEEE80211_IOCTL_SETWMMPARAMS:
+ return "SETWMMPARAMS";
+ case IEEE80211_IOCTL_DELKEY:
+ return "DELKEY";
+ case IEEE80211_IOCTL_GETWMMPARAMS:
+ return "GETWMMPARAMS";
+ case IEEE80211_IOCTL_SETMLME:
+ return "SETMLME";
+ case IEEE80211_IOCTL_GETCHANINFO:
+ return "GETCHANINFO";
+ case IEEE80211_IOCTL_SETOPTIE:
+ return "SETOPTIE";
+ case IEEE80211_IOCTL_GETOPTIE:
+ return "GETOPTIE";
+ case IEEE80211_IOCTL_ADDMAC:
+ return "ADDMAC";
+ case IEEE80211_IOCTL_DELMAC:
+ return "DELMAC";
+ case IEEE80211_IOCTL_GETCHANLIST:
+ return "GETCHANLIST";
+ case IEEE80211_IOCTL_SETCHANLIST:
+ return "SETCHANLIST";
+ case IEEE80211_IOCTL_KICKMAC:
+ return "KICKMAC";
+ case IEEE80211_IOCTL_CHANSWITCH:
+ return "CHANSWITCH";
+ case IEEE80211_IOCTL_GETMODE:
+ return "GETMODE";
+ case IEEE80211_IOCTL_SETMODE:
+ return "SETMODE";
+ case IEEE80211_IOCTL_GET_APPIEBUF:
+ return "GET_APPIEBUF";
+ case IEEE80211_IOCTL_SET_APPIEBUF:
+ return "SET_APPIEBUF";
+ case IEEE80211_IOCTL_SET_ACPARAMS:
+ return "SET_ACPARAMS";
+ case IEEE80211_IOCTL_FILTERFRAME:
+ return "FILTERFRAME";
+ case IEEE80211_IOCTL_SET_RTPARAMS:
+ return "SET_RTPARAMS";
+ case IEEE80211_IOCTL_SENDADDBA:
+ return "SENDADDBA";
+ case IEEE80211_IOCTL_GETADDBASTATUS:
+ return "GETADDBASTATUS";
+ case IEEE80211_IOCTL_SENDDELBA:
+ return "SENDDELBA";
+ case IEEE80211_IOCTL_SET_MEDENYENTRY:
+ return "SET_MEDENYENTRY";
+ case IEEE80211_IOCTL_SET_ADDBARESP:
+ return "SET_ADDBARESP";
+ case IEEE80211_IOCTL_GET_MACADDR:
+ return "GET_MACADDR";
+ case IEEE80211_IOCTL_SET_HBRPARAMS:
+ return "SET_HBRPARAMS";
+ case IEEE80211_IOCTL_SET_RXTIMEOUT:
+ return "SET_RXTIMEOUT";
+ case IEEE80211_IOCTL_STA_STATS:
+ return "STA_STATS";
+ case IEEE80211_IOCTL_GETWPAIE:
+ return "GETWPAIE";
+ default:
+ return "??";
+ }
+}
+
+
+static const char * athr_get_param_name(int op)
+{
+ switch (op) {
+ case IEEE80211_IOC_MCASTCIPHER:
+ return "MCASTCIPHER";
+ case IEEE80211_PARAM_MCASTKEYLEN:
+ return "MCASTKEYLEN";
+ case IEEE80211_PARAM_UCASTCIPHERS:
+ return "UCASTCIPHERS";
+ case IEEE80211_PARAM_KEYMGTALGS:
+ return "KEYMGTALGS";
+ case IEEE80211_PARAM_RSNCAPS:
+ return "RSNCAPS";
+ case IEEE80211_PARAM_WPA:
+ return "WPA";
+ case IEEE80211_PARAM_AUTHMODE:
+ return "AUTHMODE";
+ case IEEE80211_PARAM_PRIVACY:
+ return "PRIVACY";
+ case IEEE80211_PARAM_COUNTERMEASURES:
+ return "COUNTERMEASURES";
+ default:
+ return "??";
+ }
+}
+
+
+static int
+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+{
+ struct iwreq iwr;
+ int do_inline = len < IFNAMSIZ;
+
+ /* Certain ioctls must use the non-inlined method */
+ if (op == IEEE80211_IOCTL_SET_APPIEBUF ||
+ op == IEEE80211_IOCTL_FILTERFRAME)
+ do_inline = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ if (do_inline) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ 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->ioctl_sock, op, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x "
+ "(%s) len=%d failed: %d (%s)",
+ __func__, drv->iface, op,
+ athr_get_ioctl_name(op),
+ len, errno, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct madwifi_driver_data *drv, int op, int arg)
+{
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.mode = op;
+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
+ "(%s) arg %d)", __func__, drv->iface, op,
+ athr_get_param_name(op), arg);
+ return -1;
+ }
+ return 0;
+}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+madwifi_configure_wpa(struct madwifi_driver_data *drv,
+ struct wpa_bss_params *params)
+{
+ int v;
+
+ switch (params->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+ params->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u\n", v);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (params->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (params->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (params->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, params->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
+ params->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ params->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (params->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, params->rsn_preauth);
+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
+ if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
+ printf("Unable to set WPA to %u\n", params->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
+
+ if (!params->enabled) {
+ /* XXX restore state */
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ IEEE80211_AUTH_AUTO) < 0)
+ return -1;
+ /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
+ return madwifi_set_privacy(drv, 0);
+ }
+ if (!params->wpa && !params->ieee802_1x) {
+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_privacy(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
+ __func__, authorized ? "" : "un", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WPA_STA_AUTHORIZED)
+ return madwifi_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WPA_STA_AUTHORIZED))
+ return madwifi_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+ " key_idx %d)", __func__, ether_sprintf(addr),
+ key_idx);
+ }
+
+ return ret;
+}
+
+static int
+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 madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+ int ret;
+
+ if (alg == WPA_ALG_NONE)
+ return madwifi_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ switch (alg) {
+ case WPA_ALG_WEP:
+ cipher = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ cipher = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
+ default:
+ printf("%s: unknown/unsupported algorithm %d\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %lu too big\n", __func__,
+ (unsigned long) key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+ " key_idx %d alg %d key_len %lu set_tx %d)",
+ __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+ alg, (unsigned long) key_len, set_tx);
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+ "(addr " MACSTR " key_idx %d)",
+ __func__, MAC2STR(wk.ik_macaddr), idx);
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+#ifndef WPA_KEY_RSC_LEN
+#define WPA_KEY_RSC_LEN 8
+#endif
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+madwifi_flush(void *priv)
+{
+ u8 allsta[IEEE80211_ADDR_LEN];
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return madwifi_sta_deauth(priv, NULL, allsta,
+ IEEE80211_REASON_AUTH_LEAVE);
+}
+
+
+static int
+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_sta_stats stats;
+
+ memset(data, 0, sizeof(*data));
+
+ /*
+ * Fetch statistics for station from the system.
+ */
+ memset(&stats, 0, sizeof(stats));
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS,
+ &stats, sizeof(stats))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+
+ printf("Failed to get station stats information element.\n");
+ return -1;
+ }
+
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ return 0;
+}
+
+
+static int
+madwifi_sta_clear_stats(void *priv, const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
+
+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
+ MACSTR " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ union wpa_event_data event;
+
+ /* Send Probe Request information to WPS processing */
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+ event.rx_probe_req.ie_len =
+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+}
+#endif /* CONFIG_WPS */
+
+static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
+{
+ int ret = 0;
+#ifdef CONFIG_WPS
+ struct ieee80211req_set_filter filt;
+
+ wpa_printf(MSG_DEBUG, "%s Enter", __func__);
+ filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+ sizeof(struct ieee80211req_set_filter));
+ if (ret)
+ return ret;
+
+ drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
+ madwifi_raw_receive, drv, 1);
+ if (drv->sock_raw == NULL)
+ return -1;
+#endif /* CONFIG_WPS */
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+static int
+madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+{
+ struct madwifi_driver_data *drv = priv;
+ u8 buf[256];
+ struct ieee80211req_getset_appiebuf *beac_ie;
+
+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+ (unsigned long) len);
+
+ beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ beac_ie->app_frmtype = frametype;
+ beac_ie->app_buflen = len;
+ memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+ return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) + len);
+}
+
+static int
+madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp)
+{
+ if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
+ beacon ? wpabuf_len(beacon) : 0,
+ IEEE80211_APPIE_FRAME_BEACON))
+ return -1;
+ return madwifi_set_wps_ie(priv,
+ proberesp ? wpabuf_head(proberesp) : NULL,
+ proberesp ? wpabuf_len(proberesp): 0,
+ IEEE80211_APPIE_FRAME_PROBE_RESP);
+}
+#else /* CONFIG_WPS */
+#define madwifi_set_ap_wps_ie NULL
+#endif /* CONFIG_WPS */
+
+static void
+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211req_wpaie ie;
+ int ielen = 0;
+ u8 *iebuf = NULL;
+
+ /*
+ * Fetch negotiated WPA/RSN parameters from the system.
+ */
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
+ /*
+ * See ATH_WPS_IE comment in the beginning of the file for a
+ * possible cause for the failure..
+ */
+ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s",
+ __func__, strerror(errno));
+ goto no_ie;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+ ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+ ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+ iebuf = ie.wpa_ie;
+ /* madwifi seems to return some random data if WPA/RSN IE is not set.
+ * Assume the IE was not included if the IE type is unknown. */
+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+ iebuf[1] = 0;
+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+ /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+ * set. This is needed for WPA2. */
+ iebuf = ie.rsn_ie;
+ if (iebuf[0] != WLAN_EID_RSN)
+ iebuf[1] = 0;
+ }
+
+ ielen = iebuf[1];
+ if (ielen == 0)
+ iebuf = NULL;
+ else
+ ielen += 2;
+
+no_ie:
+ drv_event_assoc(hapd, addr, iebuf, ielen);
+
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ /* Cached accounting data is not valid anymore. */
+ memset(drv->acct_mac, 0, ETH_ALEN);
+ memset(&drv->acct_data, 0, sizeof(drv->acct_data));
+ }
+}
+
+static void
+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+ char *custom, char *end)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ union wpa_event_data data;
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = 1;
+ data.michael_mic_failure.src = addr;
+ wpa_supplicant_event(drv->hapd,
+ EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+ char *key, *value;
+ u32 val;
+ key = custom;
+ while ((key = strchr(key, '\n')) != NULL) {
+ key++;
+ value = strchr(key, '=');
+ if (value == NULL)
+ continue;
+ *value++ = '\0';
+ val = strtoul(value, NULL, 10);
+ if (strcmp(key, "mac") == 0)
+ hwaddr_aton(value, drv->acct_mac);
+ else if (strcmp(key, "rx_packets") == 0)
+ drv->acct_data.rx_packets = val;
+ else if (strcmp(key, "tx_packets") == 0)
+ drv->acct_data.tx_packets = val;
+ else if (strcmp(key, "rx_bytes") == 0)
+ drv->acct_data.rx_bytes = val;
+ else if (strcmp(key, "tx_bytes") == 0)
+ drv->acct_data.tx_bytes = val;
+ key = value;
+ }
+#ifdef CONFIG_WPS
+ } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) {
+ /* Some atheros kernels send push button as a wireless event */
+ /* PROBLEM! this event is received for ALL BSSs ...
+ * so all are enabled for WPS... ugh.
+ */
+ wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
+ } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
+ /*
+ * Atheros driver uses a hack to pass Probe Request frames as a
+ * binary data in the custom wireless event. The old way (using
+ * packet sniffing) didn't work when bridging.
+ * Format: "Manage.prob_req <frame len>" | zero padding | frame
+ */
+#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
+ int len = atoi(custom + 16);
+ if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
+ "length %d", len);
+ return;
+ }
+ madwifi_raw_receive(drv, NULL,
+ (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS */
+ }
+}
+
+static void
+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_MSGDUMP, "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 > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ 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;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVEXPIRED:
+ drv_event_disassoc(drv->hapd,
+ (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVREGISTERED:
+ madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVASSOCREQIE:
+ /* Driver hack.. Use IWEVASSOCREQIE to bypass
+ * IWEVCUSTOM size limitations. Need to handle this
+ * just like IWEVCUSTOM.
+ */
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return; /* XXX */
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ madwifi_wireless_event_wireless_custom(
+ drv, buf, buf + iwe->u.data.length);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void
+madwifi_wireless_event_rtm_newlink(void *ctx,
+ struct ifinfomsg *ifi, u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+
+ if (ifi->ifi_index != drv->ifindex)
+ return;
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ madwifi_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static int
+madwifi_get_we_version(struct madwifi_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int
+madwifi_wireless_event_init(struct madwifi_driver_data *drv)
+{
+ struct netlink_config *cfg;
+
+ madwifi_get_we_version(drv);
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ return -1;
+ cfg->ctx = drv;
+ cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Ethernet header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %lu!\n", (unsigned long) len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = host_to_be16(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+{
+ struct madwifi_driver_data *drv;
+ struct ifreq ifr;
+ struct iwreq iwr;
+ char brname[IFNAMSIZ];
+
+ drv = os_zalloc(sizeof(struct madwifi_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for madwifi driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ goto bad;
+ }
+ drv->ifindex = ifr.ifr_ifindex;
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
+ goto bad;
+ if (params->bridge[0]) {
+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+ params->bridge[0]);
+ drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
+ ETH_P_EAPOL, handle_read, drv,
+ 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else if (linux_br_get(brname, drv->iface) == 0) {
+ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
+ "EAPOL receive", brname);
+ drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else
+ drv->sock_recv = drv->sock_xmit;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.mode = IW_MODE_MASTER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMODE]");
+ printf("Could not set interface to master mode!\n");
+ goto bad;
+ }
+
+ /* mark down during setup */
+ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+ madwifi_set_privacy(drv, 0); /* default to no privacy */
+
+ madwifi_receive_probe_req(drv);
+
+ if (madwifi_wireless_event_init(drv))
+ goto bad;
+
+ return drv;
+bad:
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+madwifi_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ netlink_deinit(drv->netlink);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->sock_raw)
+ l2_packet_deinit(drv->sock_raw);
+ free(drv);
+}
+
+static int
+madwifi_set_ssid(void *priv, const u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_get_ssid(void *priv, u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ return ret;
+}
+
+static int
+madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+madwifi_commit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+ return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
+}
+
+const struct wpa_driver_ops wpa_driver_atheros_ops = {
+ .name = "atheros",
+ .hapd_init = madwifi_init,
+ .hapd_deinit = madwifi_deinit,
+ .set_ieee8021x = madwifi_set_ieee8021x,
+ .set_privacy = madwifi_set_privacy,
+ .set_key = madwifi_set_key,
+ .get_seqnum = madwifi_get_seqnum,
+ .flush = madwifi_flush,
+ .set_generic_elem = madwifi_set_opt_ie,
+ .sta_set_flags = madwifi_sta_set_flags,
+ .read_sta_data = madwifi_read_sta_driver_data,
+ .hapd_send_eapol = madwifi_send_eapol,
+ .sta_disassoc = madwifi_sta_disassoc,
+ .sta_deauth = madwifi_sta_deauth,
+ .hapd_set_ssid = madwifi_set_ssid,
+ .hapd_get_ssid = madwifi_get_ssid,
+ .set_countermeasures = madwifi_set_countermeasures,
+ .sta_clear_stats = madwifi_sta_clear_stats,
+ .commit = madwifi_commit,
+ .set_ap_wps_ie = madwifi_set_ap_wps_ie,
+};
diff --git a/src/drivers/driver_atmel.c b/src/drivers/driver_atmel.c
index 0a7a66ddb5f2e..cbec6c38d78d4 100644
--- a/src/drivers/driver_atmel.c
+++ b/src/drivers/driver_atmel.c
@@ -188,9 +188,10 @@ static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
}
-static int wpa_driver_atmel_set_key(void *priv, wpa_alg alg,
- const u8 *addr, int key_idx,
- int set_tx, const u8 *seq, size_t seq_len,
+static int wpa_driver_atmel_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_atmel_data *drv = priv;
@@ -273,16 +274,6 @@ static int wpa_driver_atmel_set_countermeasures(void *priv,
}
-static int wpa_driver_atmel_set_drop_unencrypted(void *priv,
- int enabled)
-{
- /* FIX */
- printf("wpa_driver_atmel_set_drop_unencrypted - not yet "
- "implemented\n");
- return 0;
-}
-
-
static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
int reason_code)
{
@@ -347,7 +338,7 @@ static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
#if 0
/* Atmel driver uses specific values for each cipher suite */
-static int convertSuiteToDriver(wpa_cipher suite)
+static int convertSuiteToDriver(enum wpa_cipher suite)
{
u8 suite_type;
@@ -430,10 +421,11 @@ static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
}
-static int wpa_driver_atmel_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_atmel_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
struct wpa_driver_atmel_data *drv = priv;
- return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+ return wpa_driver_wext_scan(drv->wext, params);
}
@@ -473,6 +465,8 @@ static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
return NULL;
}
+ wpa_driver_atmel_set_wpa(drv, 1);
+
return drv;
}
@@ -480,6 +474,7 @@ static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
static void wpa_driver_atmel_deinit(void *priv)
{
struct wpa_driver_atmel_data *drv = priv;
+ wpa_driver_atmel_set_wpa(drv, 0);
wpa_driver_wext_deinit(drv->wext);
close(drv->sock);
os_free(drv);
@@ -491,13 +486,11 @@ const struct wpa_driver_ops wpa_driver_atmel_ops = {
.desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
.get_bssid = wpa_driver_atmel_get_bssid,
.get_ssid = wpa_driver_atmel_get_ssid,
- .set_wpa = wpa_driver_atmel_set_wpa,
.set_key = wpa_driver_atmel_set_key,
.init = wpa_driver_atmel_init,
.deinit = wpa_driver_atmel_deinit,
.set_countermeasures = wpa_driver_atmel_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_atmel_set_drop_unencrypted,
- .scan = wpa_driver_atmel_scan,
+ .scan2 = wpa_driver_atmel_scan,
.get_scan_results2 = wpa_driver_atmel_get_scan_results,
.deauthenticate = wpa_driver_atmel_deauthenticate,
.disassociate = wpa_driver_atmel_disassociate,
diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c
index 3600dae110468..cb88543c2c36a 100644
--- a/src/drivers/driver_broadcom.c
+++ b/src/drivers/driver_broadcom.c
@@ -162,7 +162,8 @@ static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
return 0;
}
-static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
+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)
@@ -232,7 +233,8 @@ static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
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;
@@ -256,21 +258,16 @@ static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
left);
if (left > 0) {
- data.assoc_info.resp_ies = os_malloc(left);
- if (data.assoc_info.resp_ies == NULL)
+ resp_ies = os_malloc(left);
+ if (resp_ies == NULL)
return;
- os_memcpy(data.assoc_info.resp_ies,
- buf + WL_WPA_HEADER_LEN, left);
+ 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_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
- "into resp_ies",
- data.assoc_info.resp_ies, left);
}
- /* data.assoc_info.req_ies = NULL; */
- /* data.assoc_info.req_ies_len = 0; */
- wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
+ os_free(resp_ies);
break;
case WLC_DISASSOC_MSG:
wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
@@ -291,7 +288,6 @@ static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
wwh->type);
break;
}
- os_free(data.assoc_info.resp_ies);
}
static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
@@ -348,6 +344,7 @@ static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
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;
}
@@ -355,6 +352,7 @@ static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
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);
@@ -379,12 +377,12 @@ 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);
+ int _restrict = (enabled ? 1 : 0);
if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
- &restrict, sizeof(restrict)) < 0 ||
+ &_restrict, sizeof(_restrict)) < 0 ||
broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
- &restrict, sizeof(restrict)) < 0)
+ &_restrict, sizeof(_restrict)) < 0)
return -1;
return 0;
@@ -397,11 +395,13 @@ static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
}
-static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
- size_t ssid_len)
+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;
@@ -431,20 +431,19 @@ struct bss_ie_hdr {
/* u16 version; */
} __attribute__ ((packed));
-static int
-wpa_driver_broadcom_get_scan_results(void *priv,
- struct wpa_scan_result *results,
- size_t max_size)
+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 -1;
+ return NULL;
wsr = (wl_scan_results_t *) buf;
@@ -454,40 +453,34 @@ wpa_driver_broadcom_get_scan_results(void *priv,
if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
os_free(buf);
- return -1;
+ return NULL;
}
- os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+ 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) {
- int left;
- struct bss_ie_hdr *ie;
-
- os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
- os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
- results[ap_num].ssid_len = wbi->SSID_len;
- results[ap_num].freq = frequency_list[wbi->channel - 1];
- /* get ie's */
- wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
- (u8 *) wbi + sizeof(*wbi), wbi->ie_length);
- ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
- for (left = wbi->ie_length; left > 0;
- left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
- ((u8 *) ie + 2 + ie->len)) {
- wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
- ie->elem_id, ie->len);
- if (ie->len >= 3)
- wpa_printf(MSG_MSGDUMP,
- "BROADCOM: oui:%02x%02x%02x",
- ie->oui[0], ie->oui[1], ie->oui[2]);
- if (ie->elem_id != 0xdd ||
- ie->len < 6 ||
- os_memcmp(ie->oui, WPA_OUI, 3) != 0)
- continue;
- os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
- results[ap_num].wpa_ie_len = ie->len + 2;
+ 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);
}
@@ -497,8 +490,8 @@ wpa_driver_broadcom_get_scan_results(void *priv,
wsr->buflen, (unsigned long) ap_num);
os_free(buf);
- return ap_num;
-}
+ return res;
+ }
static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
int reason_code)
@@ -516,7 +509,7 @@ static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
int reason_code)
{
struct wpa_driver_broadcom_data *drv = priv;
- return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0);
+ return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
}
static int
@@ -530,7 +523,11 @@ wpa_driver_broadcom_associate(void *priv,
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);
@@ -582,7 +579,7 @@ wpa_driver_broadcom_associate(void *priv,
broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
return -1;
- return 0;
+ return ret;
}
const struct wpa_driver_ops wpa_driver_broadcom_ops = {
@@ -590,14 +587,12 @@ const struct wpa_driver_ops wpa_driver_broadcom_ops = {
.desc = "Broadcom wl.o driver",
.get_bssid = wpa_driver_broadcom_get_bssid,
.get_ssid = wpa_driver_broadcom_get_ssid,
- .set_wpa = wpa_driver_broadcom_set_wpa,
.set_key = wpa_driver_broadcom_set_key,
.init = wpa_driver_broadcom_init,
.deinit = wpa_driver_broadcom_deinit,
.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
- .scan = wpa_driver_broadcom_scan,
- .get_scan_results = wpa_driver_broadcom_get_scan_results,
+ .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_bsd.c b/src/drivers/driver_bsd.c
index 218d913869fd9..99de6c7ff48e4 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1,6 +1,7 @@
/*
* WPA Supplicant - driver interaction with BSD net80211 layer
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, 2Wire, Inc
*
* 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
@@ -18,297 +19,329 @@
#include "common.h"
#include "driver.h"
#include "eloop.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
#include <net/if.h>
+#include <net/if_media.h>
#ifdef __NetBSD__
#include <net/if_ether.h>
-#define COMPAT_FREEBSD_NET80211
#else
#include <net/ethernet.h>
#endif
+#include <net/route.h>
+#ifdef __DragonFly__
+#include <netproto/802_11/ieee80211_ioctl.h>
+#include <netproto/802_11/ieee80211_dragonfly.h>
+#else /* __DragonFly__ */
+#ifdef __GLIBC__
+#include <netinet/ether.h>
+#endif /* __GLIBC__ */
#include <net80211/ieee80211.h>
-#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_crypto.h>
+#endif /* __DragonFly__ || __GLIBC__ */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <net80211/ieee80211_freebsd.h>
+#endif
+#if __NetBSD__
+#include <net80211/ieee80211_netbsd.h>
+#endif
+
+#include "l2_packet/l2_packet.h"
+
+struct bsd_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
-struct wpa_driver_bsd_data {
int sock; /* open socket for 802.11 ioctls */
+ struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
int route; /* routing socket for events */
char ifname[IFNAMSIZ+1]; /* interface name */
unsigned int ifindex; /* interface index */
void *ctx;
- int prev_roaming; /* roaming state to restore on deinit */
- int prev_privacy; /* privacy state to restore on deinit */
- int prev_wpa; /* wpa state to restore on deinit */
+ struct wpa_driver_capa capa; /* driver capability */
+ int is_ap; /* Access point mode */
+ int prev_roaming; /* roaming state to restore on deinit */
+ int prev_privacy; /* privacy state to restore on deinit */
+ int prev_wpa; /* wpa state to restore on deinit */
};
+/* Generic functions for hostapd and wpa_supplicant */
+
static int
-set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
+bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
{
+ struct bsd_driver_data *drv = priv;
struct ieee80211req ireq;
os_memset(&ireq, 0, sizeof(ireq));
- os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
ireq.i_type = op;
- ireq.i_len = arg_len;
+ ireq.i_val = val;
ireq.i_data = (void *) arg;
+ ireq.i_len = arg_len;
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
- fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
- op, arg_len, strerror(errno));
+ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
+ "arg_len=%u]: %s", op, val, arg_len,
+ strerror(errno));
return -1;
}
return 0;
}
static int
-get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
+bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
+ int arg_len)
{
- struct ieee80211req ireq;
+ struct bsd_driver_data *drv = priv;
- os_memset(&ireq, 0, sizeof(ireq));
- os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
- ireq.i_type = op;
- ireq.i_len = arg_len;
- ireq.i_data = arg;
+ os_memset(ireq, 0, sizeof(*ireq));
+ os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name));
+ ireq->i_type = op;
+ ireq->i_len = arg_len;
+ ireq->i_data = arg;
- if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
- fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
- op, arg_len, strerror(errno));
+ if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
+ "arg_len=%u]: %s", op, arg_len, strerror(errno));
return -1;
}
- return ireq.i_len;
+ return 0;
}
static int
-set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
+get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
{
struct ieee80211req ireq;
- os_memset(&ireq, 0, sizeof(ireq));
- os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
- ireq.i_type = op;
- ireq.i_val = arg;
-
- if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
- fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
- op, arg, strerror(errno));
+ if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0)
return -1;
- }
- return 0;
+ return ireq.i_len;
}
static int
-get80211param(struct wpa_driver_bsd_data *drv, int op)
+set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
{
- struct ieee80211req ireq;
-
- os_memset(&ireq, 0, sizeof(ireq));
- os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
- ireq.i_type = op;
+ return bsd_set80211(drv, op, 0, arg, arg_len);
+}
- if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
- fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
- op, strerror(errno));
- return -1;
- }
- return ireq.i_val;
+static int
+set80211param(struct bsd_driver_data *drv, int op, int arg)
+{
+ return bsd_set80211(drv, op, arg, NULL, 0);
}
static int
-getifflags(struct wpa_driver_bsd_data *drv, int *flags)
+bsd_get_ssid(void *priv, u8 *ssid, int len)
{
+ struct bsd_driver_data *drv = priv;
+#ifdef SIOCG80211NWID
+ struct ieee80211_nwid nwid;
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
- perror("SIOCGIFFLAGS");
- return errno;
- }
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
+ ifr.ifr_data = (void *)&nwid;
+ if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+ nwid.i_len > IEEE80211_NWID_LEN)
+ return -1;
+ os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
+ return nwid.i_len;
+#else
+ return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN);
+#endif
}
static int
-setifflags(struct wpa_driver_bsd_data *drv, int flags)
+bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
{
+ struct bsd_driver_data *drv = priv;
+#ifdef SIOCS80211NWID
+ struct ieee80211_nwid nwid;
struct ifreq ifr;
+ os_memcpy(nwid.i_nwid, ssid, ssid_len);
+ nwid.i_len = ssid_len;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
- perror("SIOCSIFFLAGS");
- return errno;
- }
- return 0;
+ ifr.ifr_data = (void *)&nwid;
+ return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+#else
+ return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
+#endif
}
static int
-wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
+bsd_get_if_media(void *priv)
{
- struct wpa_driver_bsd_data *drv = priv;
+ struct bsd_driver_data *drv = priv;
+ struct ifmediareq ifmr;
- return get80211var(drv, IEEE80211_IOC_BSSID,
- bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
-}
+ os_memset(&ifmr, 0, sizeof(ifmr));
+ os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
-#if 0
-static int
-wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
-{
- struct wpa_driver_bsd_data *drv = priv;
+ if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
+ wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
+ strerror(errno));
+ return -1;
+ }
- return set80211var(drv, IEEE80211_IOC_BSSID,
- bssid, IEEE80211_ADDR_LEN);
+ return ifmr.ifm_current;
}
-#endif
static int
-wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
+bsd_set_if_media(void *priv, int media)
{
- struct wpa_driver_bsd_data *drv = priv;
+ struct bsd_driver_data *drv = priv;
+ struct ifreq ifr;
- return get80211var(drv, IEEE80211_IOC_SSID,
- ssid, IEEE80211_NWID_LEN);
-}
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_media = media;
-static int
-wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
- size_t ssid_len)
-{
- struct wpa_driver_bsd_data *drv = priv;
+ if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
+ strerror(errno));
+ return -1;
+ }
- return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
+ return 0;
}
static int
-wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
- const u8 *wpa_ie, size_t wpa_ie_len)
+bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode)
{
- return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
+ int media = bsd_get_if_media(priv);
+
+ if (media < 0)
+ return -1;
+ media &= ~mask;
+ media |= mode;
+ if (bsd_set_if_media(priv, media) < 0)
+ return -1;
+ return 0;
}
static int
-wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
+bsd_del_key(void *priv, const u8 *addr, int key_idx)
{
- struct wpa_driver_bsd_data *drv = priv;
- int ret = 0;
-
- wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
- __FUNCTION__, wpa, privacy);
+ struct ieee80211req_del_key wk;
- if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
- ret = -1;
- if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
- ret = -1;
- if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
- ret = -1;
+ os_memset(&wk, 0, sizeof(wk));
+ if (addr == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx);
+ wk.idk_keyix = key_idx;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__,
+ MAC2STR(addr));
+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */
+ }
- return ret;
+ return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
}
static int
-wpa_driver_bsd_set_wpa(void *priv, int enabled)
+bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
{
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ struct ieee80211req_mlme mlme;
- return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = op;
+ mlme.im_reason = reason;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
}
static int
-wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
- const unsigned char *addr)
+bsd_ctrl_iface(void *priv, int enable)
{
- struct ieee80211req_del_key wk;
+ struct bsd_driver_data *drv = priv;
+ struct ifreq ifr;
- os_memset(&wk, 0, sizeof(wk));
- if (addr != NULL &&
- bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
- struct ether_addr ea;
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
- wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
- __func__, ether_ntoa(&ea), key_idx);
- os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
- wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
- } else {
- wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
- wk.idk_keyix = key_idx;
+ if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (enable)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
}
- return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
+
+ return 0;
}
static int
-wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+ const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key, size_t key_len)
{
- struct wpa_driver_bsd_data *drv = priv;
struct ieee80211req_key wk;
- struct ether_addr ea;
- char *alg_name;
- u_int8_t cipher;
- if (alg == WPA_ALG_NONE)
- return wpa_driver_bsd_del_key(drv, key_idx, addr);
+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
+ "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
+ set_tx, seq_len, key_len);
+
+ if (alg == WPA_ALG_NONE) {
+#ifndef HOSTAPD
+ if (addr == NULL ||
+ os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ IEEE80211_ADDR_LEN) == 0)
+ return bsd_del_key(priv, NULL, key_idx);
+ else
+#endif /* HOSTAPD */
+ return bsd_del_key(priv, addr, key_idx);
+ }
+ os_memset(&wk, 0, sizeof(wk));
switch (alg) {
case WPA_ALG_WEP:
- alg_name = "WEP";
- cipher = IEEE80211_CIPHER_WEP;
+ wk.ik_type = IEEE80211_CIPHER_WEP;
break;
case WPA_ALG_TKIP:
- alg_name = "TKIP";
- cipher = IEEE80211_CIPHER_TKIP;
+ wk.ik_type = IEEE80211_CIPHER_TKIP;
break;
case WPA_ALG_CCMP:
- alg_name = "CCMP";
- cipher = IEEE80211_CIPHER_AES_CCM;
+ wk.ik_type = IEEE80211_CIPHER_AES_CCM;
break;
default:
- wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
- __func__, alg);
+ wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg);
return -1;
}
- os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
- wpa_printf(MSG_DEBUG,
- "%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
- __func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
- seq_len, key_len);
-
- if (seq_len > sizeof(u_int64_t)) {
- wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
- __func__, seq_len);
- return -2;
- }
- if (key_len > sizeof(wk.ik_keydata)) {
- wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
- __func__, key_len);
- return -3;
- }
-
- os_memset(&wk, 0, sizeof(wk));
- wk.ik_type = cipher;
wk.ik_flags = IEEE80211_KEY_RECV;
if (set_tx)
wk.ik_flags |= IEEE80211_KEY_XMIT;
- os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
- /*
- * Deduce whether group/global or unicast key by checking
- * the address (yech). Note also that we can only mark global
- * keys default; doing this for a unicast key is an error.
- */
- if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
- wk.ik_flags |= IEEE80211_KEY_GROUP;
+
+ if (addr == NULL) {
+ os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
wk.ik_keyix = key_idx;
} else {
- wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ /*
+ * Deduce whether group/global or unicast key by checking
+ * the address (yech). Note also that we can only mark global
+ * keys default; doing this for a unicast key is an error.
+ */
+ if (os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ IEEE80211_ADDR_LEN) == 0) {
+ wk.ik_flags |= IEEE80211_KEY_GROUP;
+ wk.ik_keyix = key_idx;
+ } else {
+ wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE :
+ key_idx;
+ }
}
if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
@@ -316,73 +349,689 @@ wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
os_memcpy(&wk.ik_keyrsc, seq, seq_len);
os_memcpy(wk.ik_keydata, key, key_len);
- return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
+ return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
}
static int
-wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
+bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
+{
+#ifndef IEEE80211_IOC_APPIE
+ static const char *ciphernames[] =
+ { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
+ int v;
+
+ switch (params->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ printf("Unknown group key cipher %u\n",
+ params->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
+ __func__, ciphernames[v], v);
+ if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u (%s)\n",
+ v, ciphernames[v]);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (params->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (params->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (params->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, params->wpa_key_mgmt);
+ if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
+ params->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ params->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (params->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, params->rsn_preauth);
+ if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+#endif /* IEEE80211_IOC_APPIE */
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
+ if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
+ printf("Unable to set WPA to %u\n", params->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
+
+ if (!params->enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_IOC_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!params->wpa && !params->ieee802_1x) {
+ wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled",
+ __func__);
+ return -1;
+ }
+ if (params->wpa && bsd_configure_wpa(priv, params) != 0) {
+ wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state",
+ __func__);
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
+ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X",
+ __func__);
+ return -1;
+ }
+ return bsd_ctrl_iface(priv, 1);
+}
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ int authorized = -1;
+
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WPA_STA_AUTHORIZED)
+ authorized = 1;
+ if (!(flags_and & WPA_STA_AUTHORIZED))
+ authorized = 0;
+
+ if (authorized < 0)
+ return 0;
+
+ return bsd_send_mlme_param(priv, authorized ?
+ IEEE80211_MLME_AUTHORIZE :
+ IEEE80211_MLME_UNAUTHORIZE, 0, addr);
+}
+
+static void
+bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct ieee80211req_wpaie ie;
+ int ielen = 0;
+ u8 *iebuf = NULL;
+
+ /*
+ * Fetch and validate any negotiated WPA/RSN parameters.
+ */
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+ if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
+ printf("Failed to get WPA/RSN information element.\n");
+ goto no_ie;
+ }
+ iebuf = ie.wpa_ie;
+ ielen = ie.wpa_ie[1];
+ if (ielen == 0)
+ iebuf = NULL;
+ else
+ ielen += 2;
+
+no_ie:
+ drv_event_assoc(ctx, addr, iebuf, ielen);
+}
+
+static int
+bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
{
- struct wpa_driver_bsd_data *drv = priv;
+ struct bsd_driver_data *drv = priv;
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len);
+
+ return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data,
+ data_len);
+}
+
+static int
+bsd_set_freq(void *priv, u16 channel)
+{
+ struct bsd_driver_data *drv = priv;
+#ifdef SIOCS80211CHANNEL
+ struct ieee80211chanreq creq;
+#endif /* SIOCS80211CHANNEL */
+ u32 mode;
+
+ if (channel < 14)
+ mode = IFM_IEEE80211_11G;
+ else if (channel == 14)
+ mode = IFM_IEEE80211_11B;
+ else
+ mode = IFM_IEEE80211_11A;
+ if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to set modulation mode",
+ __func__);
+ return -1;
+ }
+
+#ifdef SIOCS80211CHANNEL
+ os_memset(&creq, 0, sizeof(creq));
+ os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
+ creq.i_channel = channel;
+ return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
+#else /* SIOCS80211CHANNEL */
+ return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
+#endif /* SIOCS80211CHANNEL */
+}
+
+static int
+bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+{
+#ifdef IEEE80211_IOC_APPIE
+ wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__,
+ (unsigned long)ie_len);
+ return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA,
+ ie, ie_len);
+#endif /* IEEE80211_IOC_APPIE */
+ return 0;
+}
+
+
+#ifdef HOSTAPD
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from net80211 header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+
+static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code);
+
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+
+static int
+bsd_set_privacy(void *priv, int enabled)
+{
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
- return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
+
+ return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled);
+}
+
+static int
+bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
+ printf("Failed to get encryption.\n");
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+bsd_flush(void *priv)
+{
+ u8 allsta[IEEE80211_ADDR_LEN];
+
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE);
}
static int
-wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
+bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
{
- struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_sta_stats stats;
+
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats))
+ > 0) {
+ /* XXX? do packets counts include non-data frames? */
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ }
+ return 0;
+}
+static int
+bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
+{
+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
+ addr);
+}
+
+static int
+bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code)
+{
+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
+ addr);
+}
+
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+ struct bsd_driver_data *drv = ctx;
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+ struct ieee80211_michael_event *mic;
+ struct ieee80211_join_event *join;
+ struct ieee80211_leave_event *leave;
+ int n;
+ union wpa_event_data data;
+
+ n = read(sock, buf, sizeof(buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("read(PF_ROUTE)");
+ return;
+ }
+
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Routing message version %d not "
+ "understood\n", rtm->rtm_version);
+ return;
+ }
+ ifan = (struct if_announcemsghdr *) rtm;
+ switch (rtm->rtm_type) {
+ case RTM_IEEE80211:
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ case RTM_IEEE80211_DISASSOC:
+ case RTM_IEEE80211_SCAN:
+ break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ drv_event_disassoc(drv->hapd, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, drv->hapd, join->iev_addr);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = 1;
+ data.michael_mic_failure.src = mic->iev_src;
+ wpa_supplicant_event(drv->hapd,
+ EVENT_MICHAEL_MIC_FAILURE, &data);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct bsd_driver_data *drv = ctx;
+ drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
+}
+
+static int
+hostapd_bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+ return bsd_set_freq(priv, freq->channel);
+}
+
+static void *
+bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+{
+ struct bsd_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct bsd_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for bsd driver data\n");
+ goto bad;
+ }
+
+ drv->hapd = hapd;
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+
+ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
+ handle_read, drv, 0);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
+ goto bad;
+
+ /* mark down during setup */
+ if (bsd_ctrl_iface(drv, 0) < 0)
+ goto bad;
+
+ drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (drv->route < 0) {
+ perror("socket(PF_ROUTE,SOCK_RAW)");
+ goto bad;
+ }
+ eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
+ NULL);
+
+ if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
+ __func__);
+ goto bad;
+ }
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->sock >= 0)
+ close(drv->sock);
+ if (drv != NULL)
+ os_free(drv);
+ return NULL;
+}
+
+
+static void
+bsd_deinit(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+
+ if (drv->route >= 0) {
+ eloop_unregister_read_sock(drv->route);
+ close(drv->route);
+ }
+ bsd_ctrl_iface(drv, 0);
+ if (drv->sock >= 0)
+ close(drv->sock);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ os_free(drv);
+}
+
+#else /* HOSTAPD */
+
+static int
+get80211param(struct bsd_driver_data *drv, int op)
+{
+ struct ieee80211req ireq;
+
+ if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0)
+ return -1;
+ return ireq.i_val;
+}
+
+static int
+wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
+{
+ struct bsd_driver_data *drv = priv;
+#ifdef SIOCG80211BSSID
+ struct ieee80211_bssid bs;
+
+ os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
+ if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+ return -1;
+ os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
+ return 0;
+#else
+ return get80211var(drv, IEEE80211_IOC_BSSID,
+ bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
+#endif
+}
+
+static int
+wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
+{
+ struct bsd_driver_data *drv = priv;
+ return bsd_get_ssid(drv, ssid, 0);
+}
+
+static int
+wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie,
+ size_t wpa_ie_len)
+{
+#ifdef IEEE80211_IOC_APPIE
+ return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len);
+#else /* IEEE80211_IOC_APPIE */
+ return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
+#endif /* IEEE80211_IOC_APPIE */
+}
+
+static int
+wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
+ __FUNCTION__, wpa, privacy);
+
+ if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
+ ret = -1;
+ if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+ ret = -1;
+ if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+wpa_driver_bsd_set_wpa(void *priv, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
+}
+
+static int
+wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
+{
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
- return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
+ return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled);
}
+
static int
-wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
+wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
{
- struct wpa_driver_bsd_data *drv = priv;
- struct ieee80211req_mlme mlme;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
+}
- wpa_printf(MSG_DEBUG, "%s", __func__);
- os_memset(&mlme, 0, sizeof(mlme));
- mlme.im_op = IEEE80211_MLME_DEAUTH;
- mlme.im_reason = reason_code;
- os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+static int
+wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
+ addr);
}
static int
wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
{
- struct wpa_driver_bsd_data *drv = priv;
- struct ieee80211req_mlme mlme;
+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
+ addr);
+}
- wpa_printf(MSG_DEBUG, "%s", __func__);
- os_memset(&mlme, 0, sizeof(mlme));
- mlme.im_op = IEEE80211_MLME_DISASSOC;
- mlme.im_reason = reason_code;
- os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+static int
+wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
+{
+ 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(priv, IEEE80211_IOC_AUTHMODE, authmode);
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct bsd_driver_data *drv = ctx;
+
+ drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
}
static int
wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
{
- struct wpa_driver_bsd_data *drv = priv;
+ struct bsd_driver_data *drv = priv;
struct ieee80211req_mlme mlme;
+ u32 mode;
+ u16 channel;
int privacy;
+ int ret = 0;
wpa_printf(MSG_DEBUG,
"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
, __func__
- , params->ssid_len, params->ssid
- , params->wpa_ie_len
+ , (unsigned int) params->ssid_len, params->ssid
+ , (unsigned int) params->wpa_ie_len
, params->pairwise_suite
, params->group_suite
, params->key_mgmt_suite
);
+ switch (params->mode) {
+ case IEEE80211_MODE_INFRA:
+ mode = 0 /* STA */;
+ break;
+ case IEEE80211_MODE_IBSS:
+ mode = IFM_IEEE80211_IBSS;
+ break;
+ case IEEE80211_MODE_AP:
+ mode = IFM_IEEE80211_HOSTAP;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__);
+ return -1;
+ }
+ if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
+ __func__);
+ return -1;
+ }
+
+ if (params->mode == IEEE80211_MODE_AP) {
+ if (params->freq >= 2412 && params->freq <= 2472)
+ channel = (params->freq - 2407) / 5;
+ else if (params->freq == 2484)
+ channel = 14;
+ else if ((params->freq >= 5180 && params->freq <= 5240) ||
+ (params->freq >= 5745 && params->freq <= 5825))
+ channel = (params->freq - 5000) / 5;
+ else
+ channel = 0;
+ if (bsd_set_freq(drv, channel) < 0)
+ return -1;
+
+ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
+ handle_read, drv, 0);
+ if (drv->sock_xmit == NULL)
+ return -1;
+ drv->is_ap = 1;
+ return 0;
+ }
+
+ if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted)
+ < 0)
+ ret = -1;
+ if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0)
+ ret = -1;
/* XXX error handling is wrong but unclear what to do... */
if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
return -1;
@@ -410,62 +1059,89 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
return -1;
- return 0;
+ return ret;
}
static int
-wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
+wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
{
- struct wpa_driver_bsd_data *drv = priv;
- int authmode;
+ struct bsd_driver_data *drv = priv;
+#ifdef IEEE80211_IOC_SCAN_MAX_SSID
+ struct ieee80211_scan_req sr;
+ int i;
+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
- if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
- (auth_alg & AUTH_ALG_SHARED_KEY))
- authmode = IEEE80211_AUTH_AUTO;
- else if (auth_alg & AUTH_ALG_SHARED_KEY)
- authmode = IEEE80211_AUTH_SHARED;
- else
- authmode = IEEE80211_AUTH_OPEN;
+ if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
+ __func__);
+ return -1;
+ }
- return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
-}
+ if (set80211param(drv, IEEE80211_IOC_ROAMING,
+ IEEE80211_ROAMING_MANUAL) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to set "
+ "wpa_supplicant-based roaming: %s", __func__,
+ strerror(errno));
+ return -1;
+ }
-static int
-wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
- struct wpa_driver_bsd_data *drv = priv;
- int flags;
+ if (wpa_driver_bsd_set_wpa(drv, 1) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__,
+ strerror(errno));
+ return -1;
+ }
/* NB: interface must be marked UP to do a scan */
- if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
+ if (bsd_ctrl_iface(drv, 1) < 0)
return -1;
+#ifdef IEEE80211_IOC_SCAN_MAX_SSID
+ os_memset(&sr, 0, sizeof(sr));
+ sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE |
+ IEEE80211_IOC_SCAN_NOJOIN;
+ sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
+ if (params->num_ssids > 0) {
+ sr.sr_nssid = params->num_ssids;
+#if 0
+ /* Boundary check is done by upper layer */
+ if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID)
+ sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID;
+#endif
+
+ /* NB: check scan cache first */
+ sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK;
+ }
+ for (i = 0; i < sr.sr_nssid; i++) {
+ sr.sr_ssid[i].len = params->ssids[i].ssid_len;
+ os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid,
+ sr.sr_ssid[i].len);
+ }
+
+ /* NB: net80211 delivers a scan complete event so no need to poll */
+ return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr));
+#else /* IEEE80211_IOC_SCAN_MAX_SSID */
/* set desired ssid before scan */
- if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
+ if (bsd_set_ssid(drv, params->ssids[0].ssid,
+ params->ssids[0].ssid_len) < 0)
return -1;
/* NB: net80211 delivers a scan complete event so no need to poll */
return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
}
-#include <net/route.h>
-#if __FreeBSD__
-#include <net80211/ieee80211_freebsd.h>
-#endif
-#if __NetBSD__
-#include <net80211/ieee80211_netbsd.h>
-#endif
-
static void
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
{
- struct wpa_driver_bsd_data *drv = sock_ctx;
+ struct bsd_driver_data *drv = sock_ctx;
char buf[2048];
struct if_announcemsghdr *ifan;
struct if_msghdr *ifm;
struct rt_msghdr *rtm;
union wpa_event_data event;
struct ieee80211_michael_event *mic;
+ struct ieee80211_leave_event *leave;
+ struct ieee80211_join_event *join;
int n;
n = read(sock, buf, sizeof(buf));
@@ -487,8 +1163,8 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
ifan = (struct if_announcemsghdr *) rtm;
if (ifan->ifan_index != drv->ifindex)
break;
- strlcpy(event.interface_status.ifname, drv->ifname,
- sizeof(event.interface_status.ifname));
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
switch (ifan->ifan_what) {
case IFAN_DEPARTURE:
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
@@ -508,14 +1184,31 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
switch (ifan->ifan_what) {
case RTM_IEEE80211_ASSOC:
case RTM_IEEE80211_REASSOC:
+ if (drv->is_ap)
+ break;
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
break;
case RTM_IEEE80211_DISASSOC:
+ if (drv->is_ap)
+ break;
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
break;
case RTM_IEEE80211_SCAN:
+ if (drv->is_ap)
+ break;
wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ drv_event_disassoc(ctx, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, ctx, join->iev_addr);
+ break;
case RTM_IEEE80211_REPLAY:
/* ignore */
break;
@@ -539,8 +1232,8 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
if (ifm->ifm_index != drv->ifindex)
break;
if ((rtm->rtm_flags & RTF_UP) == 0) {
- strlcpy(event.interface_status.ifname, drv->ifname,
- sizeof(event.interface_status.ifname));
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
event.interface_status.ifname);
@@ -550,135 +1243,167 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
}
}
-/* Compare function for sorting scan results. Return >0 if @b is consider
- * better. */
-static int
-wpa_scan_result_compar(const void *a, const void *b)
+static void
+wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
+ struct ieee80211req_scan_result *sr)
{
- const struct wpa_scan_result *wa = a;
- const struct wpa_scan_result *wb = b;
+ struct wpa_scan_res *result, **tmp;
+ size_t extra_len;
+ u8 *pos;
- /* WPA/WPA2 support preferred */
- if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
- !(wa->wpa_ie_len || wa->rsn_ie_len))
- return 1;
- if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
- (wa->wpa_ie_len || wa->rsn_ie_len))
- return -1;
+ extra_len = 2 + sr->isr_ssid_len;
+ extra_len += 2 + sr->isr_nrates;
+ extra_len += 3; /* ERP IE */
+ extra_len += sr->isr_ie_len;
- /* privacy support preferred */
- if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
- (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
- return 1;
- if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
- (wb->caps & IEEE80211_CAPINFO_PRIVACY))
- return -1;
+ result = os_zalloc(sizeof(*result) + extra_len);
+ if (result == NULL)
+ return;
+ os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN);
+ result->freq = sr->isr_freq;
+ result->beacon_int = sr->isr_intval;
+ result->caps = sr->isr_capinfo;
+ result->qual = sr->isr_rssi;
+ result->noise = sr->isr_noise;
+
+ pos = (u8 *)(result + 1);
+
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = sr->isr_ssid_len;
+ os_memcpy(pos, sr + 1, sr->isr_ssid_len);
+ pos += sr->isr_ssid_len;
+
+ /*
+ * Deal all rates as supported rate.
+ * Because net80211 doesn't report extended supported rate or not.
+ */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = sr->isr_nrates;
+ os_memcpy(pos, sr->isr_rates, sr->isr_nrates);
+ pos += sr->isr_nrates;
+
+ *pos++ = WLAN_EID_ERP_INFO;
+ *pos++ = 1;
+ *pos++ = sr->isr_erp;
- /* best/max rate preferred if signal level close enough XXX */
- if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
- return wb->maxrate - wa->maxrate;
+ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
+ pos += sr->isr_ie_len;
- /* use freq for channel preference */
+ result->ie_len = pos - (u8 *)(result + 1);
- /* all things being equal, use signal level */
- return wb->level - wa->level;
+ 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 int
-getmaxrate(uint8_t rates[15], uint8_t nrates)
+struct wpa_scan_results *
+wpa_driver_bsd_get_scan_results2(void *priv)
{
- int i, maxrate = -1;
+ struct ieee80211req_scan_result *sr;
+ struct wpa_scan_results *res;
+ int len, rest;
+ uint8_t buf[24*1024], *pos;
+
+ len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024);
+ if (len < 0)
+ return NULL;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return NULL;
- for (i = 0; i < nrates; i++) {
- int rate = rates[i] & IEEE80211_RATE_VAL;
- if (rate > maxrate)
- rate = maxrate;
+ pos = buf;
+ rest = len;
+ while (rest >= sizeof(struct ieee80211req_scan_result)) {
+ sr = (struct ieee80211req_scan_result *)pos;
+ wpa_driver_bsd_add_scan_entry(res, sr);
+ pos += sr->isr_len;
+ rest -= sr->isr_len;
}
- return maxrate;
-}
-/* unalligned little endian access */
-#define LE_READ_4(p) \
- ((u_int32_t) \
- ((((const u_int8_t *)(p))[0] ) | \
- (((const u_int8_t *)(p))[1] << 8) | \
- (((const u_int8_t *)(p))[2] << 16) | \
- (((const u_int8_t *)(p))[3] << 24)))
+ wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)",
+ len, (unsigned long)res->num);
-static int __inline
-iswpaoui(const u_int8_t *frm)
-{
- return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+ return res;
}
-static int
-wpa_driver_bsd_get_scan_results(void *priv,
- struct wpa_scan_result *results,
- size_t max_size)
+static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
{
-#define min(a,b) ((a)>(b)?(b):(a))
- struct wpa_driver_bsd_data *drv = priv;
- uint8_t buf[24*1024];
- uint8_t *cp, *vp;
- struct ieee80211req_scan_result *sr;
- struct wpa_scan_result *wsr;
- int len, ielen;
-
- os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+#ifdef IEEE80211_IOC_DEVCAPS
+/* kernel definitions copied from net80211/ieee80211_var.h */
+#define IEEE80211_CIPHER_WEP 0
+#define IEEE80211_CIPHER_TKIP 1
+#define IEEE80211_CIPHER_AES_CCM 3
+#define IEEE80211_CRYPTO_WEP (1<<IEEE80211_CIPHER_WEP)
+#define IEEE80211_CRYPTO_TKIP (1<<IEEE80211_CIPHER_TKIP)
+#define IEEE80211_CRYPTO_AES_CCM (1<<IEEE80211_CIPHER_AES_CCM)
+#define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */
+#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */
+#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */
+ struct ieee80211_devcaps_req devcaps;
- len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
- if (len < 0)
+ if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps,
+ sizeof(devcaps)) < 0) {
+ wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s",
+ strerror(errno));
return -1;
- cp = buf;
- wsr = results;
- while (len >= sizeof(struct ieee80211req_scan_result)) {
- sr = (struct ieee80211req_scan_result *) cp;
- os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
- wsr->ssid_len = sr->isr_ssid_len;
- wsr->freq = sr->isr_freq;
- wsr->noise = sr->isr_noise;
- wsr->qual = sr->isr_rssi;
- wsr->level = 0; /* XXX? */
- wsr->caps = sr->isr_capinfo;
- wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
- vp = (u_int8_t *)(sr+1);
- os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
- if (sr->isr_ie_len > 0) {
- vp += sr->isr_ssid_len;
- ielen = sr->isr_ie_len;
- while (ielen > 0) {
- switch (vp[0]) {
- case IEEE80211_ELEMID_VENDOR:
- if (!iswpaoui(vp))
- break;
- wsr->wpa_ie_len =
- min(2+vp[1], SSID_MAX_WPA_IE_LEN);
- os_memcpy(wsr->wpa_ie, vp,
- wsr->wpa_ie_len);
- break;
- case IEEE80211_ELEMID_RSN:
- wsr->rsn_ie_len =
- min(2+vp[1], SSID_MAX_WPA_IE_LEN);
- os_memcpy(wsr->rsn_ie, vp,
- wsr->rsn_ie_len);
- break;
- }
- ielen -= 2+vp[1];
- vp += 2+vp[1];
- }
- }
-
- cp += sr->isr_len, len -= sr->isr_len;
- wsr++;
}
- qsort(results, wsr - results, sizeof(struct wpa_scan_result),
- wpa_scan_result_compar);
- wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
- len, wsr - results);
+ wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x",
+ __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps);
+
+ if (devcaps.dc_drivercaps & IEEE80211_C_WPA1)
+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ if (devcaps.dc_drivercaps & IEEE80211_C_WPA2)
+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- return wsr - results;
-#undef min
+ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+
+ if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+#undef IEEE80211_CIPHER_WEP
+#undef IEEE80211_CIPHER_TKIP
+#undef IEEE80211_CIPHER_AES_CCM
+#undef IEEE80211_CRYPTO_WEP
+#undef IEEE80211_CRYPTO_TKIP
+#undef IEEE80211_CRYPTO_AES_CCM
+#undef IEEE80211_C_HOSTAP
+#undef IEEE80211_C_WPA1
+#undef IEEE80211_C_WPA2
+#else /* IEEE80211_IOC_DEVCAPS */
+ /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP |
+ WPA_DRIVER_CAPA_ENC_CCMP;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+#endif /* IEEE80211_IOC_DEVCAPS */
+#ifdef IEEE80211_IOC_SCAN_MAX_SSID
+ drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID;
+#else /* IEEE80211_IOC_SCAN_MAX_SSID */
+ drv->capa.max_scan_ssids = 1;
+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ return 0;
}
static void *
@@ -686,7 +1411,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
{
#define GETPARAM(drv, param, v) \
(((v) = get80211param(drv, param)) != -1)
- struct wpa_driver_bsd_data *drv;
+ struct bsd_driver_data *drv;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
@@ -715,6 +1440,10 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
drv->ctx = ctx;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ /* Down interface during setup. */
+ if (bsd_ctrl_iface(drv, 0) < 0)
+ goto fail;
+
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
__func__, strerror(errno));
@@ -730,17 +1459,9 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
__func__, strerror(errno));
goto fail;
}
- if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
- "roaming: %s", __func__, strerror(errno));
- goto fail;
- }
- if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
- __func__, strerror(errno));
+ if (wpa_driver_bsd_capa(drv))
goto fail;
- }
return drv;
fail:
@@ -754,41 +1475,68 @@ fail1:
static void
wpa_driver_bsd_deinit(void *priv)
{
- struct wpa_driver_bsd_data *drv = priv;
- int flags;
+ struct bsd_driver_data *drv = priv;
+ wpa_driver_bsd_set_wpa(drv, 0);
eloop_unregister_read_sock(drv->route);
/* NB: mark interface down */
- if (getifflags(drv, &flags) == 0)
- (void) setifflags(drv, flags &~ IFF_UP);
+ bsd_ctrl_iface(drv, 0);
wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
__func__);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
(void) close(drv->route); /* ioctl socket */
(void) close(drv->sock); /* event socket */
os_free(drv);
}
+static int
+wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct bsd_driver_data *drv = priv;
+
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+#endif /* HOSTAPD */
+
const struct wpa_driver_ops wpa_driver_bsd_ops = {
.name = "bsd",
- .desc = "BSD 802.11 support (Atheros, etc.)",
+ .desc = "BSD 802.11 support",
+#ifdef HOSTAPD
+ .hapd_init = bsd_init,
+ .hapd_deinit = bsd_deinit,
+ .set_privacy = bsd_set_privacy,
+ .get_seqnum = bsd_get_seqnum,
+ .flush = bsd_flush,
+ .read_sta_data = bsd_read_sta_driver_data,
+ .sta_disassoc = bsd_sta_disassoc,
+ .sta_deauth = bsd_sta_deauth,
+ .set_freq = hostapd_bsd_set_freq,
+#else /* HOSTAPD */
.init = wpa_driver_bsd_init,
.deinit = wpa_driver_bsd_deinit,
.get_bssid = wpa_driver_bsd_get_bssid,
.get_ssid = wpa_driver_bsd_get_ssid,
- .set_wpa = wpa_driver_bsd_set_wpa,
- .set_key = wpa_driver_bsd_set_key,
.set_countermeasures = wpa_driver_bsd_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted,
- .scan = wpa_driver_bsd_scan,
- .get_scan_results = wpa_driver_bsd_get_scan_results,
+ .scan2 = wpa_driver_bsd_scan,
+ .get_scan_results2 = wpa_driver_bsd_get_scan_results2,
.deauthenticate = wpa_driver_bsd_deauthenticate,
.disassociate = wpa_driver_bsd_disassociate,
.associate = wpa_driver_bsd_associate,
- .set_auth_alg = wpa_driver_bsd_set_auth_alg,
+ .get_capa = wpa_driver_bsd_get_capa,
+#endif /* HOSTAPD */
+ .set_key = bsd_set_key,
+ .set_ieee8021x = bsd_set_ieee8021x,
+ .hapd_set_ssid = bsd_set_ssid,
+ .hapd_get_ssid = bsd_get_ssid,
+ .hapd_send_eapol = bsd_send_eapol,
+ .sta_set_flags = bsd_set_sta_authorized,
+ .set_generic_elem = bsd_set_opt_ie,
};
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 84ef3bdedc549..952f3891abdeb 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant - driver interaction with Linux Host AP driver
+ * Driver interaction with Linux Host AP driver
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,1099 @@
#include "driver_hostap.h"
+#ifdef HOSTAPD
+
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+
+#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "common/ieee802_11_defs.h"
+
+
+/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
+ * frames that might be longer than normal default MTU and they are not
+ * fragmented */
+#define HOSTAPD_MTU 2290
+
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+struct hostap_driver_data {
+ struct hostapd_data *hapd;
+
+ char iface[IFNAMSIZ + 1];
+ int sock; /* raw packet socket for driver access */
+ int ioctl_sock; /* socket for ioctl() use */
+ struct netlink_data *netlink;
+
+ int we_version;
+
+ u8 *generic_ie;
+ size_t generic_ie_len;
+ u8 *wps_ie;
+ size_t wps_ie_len;
+};
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+ int len);
+static int hostap_set_iface_flags(void *priv, int dev_up);
+
+static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
+ u16 stype)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, ethertype;
+ u8 *pos, *sa;
+ size_t left;
+ union wpa_event_data event;
+
+ if (len < sizeof(struct ieee80211_hdr))
+ return;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) {
+ printf("Not ToDS data frame (fc=0x%04x)\n", fc);
+ return;
+ }
+
+ sa = hdr->addr2;
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.frame = buf;
+ event.rx_from_unknown.len = len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+
+ if (left < sizeof(rfc1042_header)) {
+ printf("Too short data frame\n");
+ return;
+ }
+
+ if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) {
+ printf("Data frame with no RFC1042 header\n");
+ return;
+ }
+ pos += sizeof(rfc1042_header);
+ left -= sizeof(rfc1042_header);
+
+ if (left < 2) {
+ printf("No ethertype in data frame\n");
+ return;
+ }
+
+ ethertype = WPA_GET_BE16(pos);
+ pos += 2;
+ left -= 2;
+ switch (ethertype) {
+ case ETH_P_PAE:
+ drv_event_eapol_rx(drv->hapd, sa, pos, left);
+ break;
+
+ default:
+ printf("Unknown ethertype 0x%04x in data frame\n", ethertype);
+ break;
+ }
+}
+
+
+static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf,
+ size_t len, int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = buf;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ok;
+ wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event);
+}
+
+
+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;
+
+ /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
+ * these to user space */
+ if (len < 24) {
+ wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) {
+ wpa_hexdump(MSG_MSGDUMP, "Received management frame",
+ buf, len);
+ }
+
+ ver = fc & WLAN_FC_PVER;
+
+ /* protocol version 3 is reserved for indicating extra data after the
+ * payload, version 2 for indicating ACKed frame (TX callbacks), and
+ * version 1 for indicating failed frame (no ACK, TX callbacks) */
+ if (ver == 3) {
+ u8 *pos = buf + len - 2;
+ extra_len = WPA_GET_LE16(pos);
+ printf("extra data in frame (elen=%d)\n", extra_len);
+ if ((size_t) extra_len + 2 > len) {
+ printf(" extra data overflow\n");
+ 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;
+ } else if (ver != 0) {
+ printf("unknown protocol version %d\n", ver);
+ return;
+ }
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = data_len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA");
+ handle_data(drv, buf, data_len, stype);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "unknown frame type %d", type);
+ break;
+ }
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostap_driver_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ handle_frame(drv, buf, len);
+}
+
+
+static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+ if (hostap_set_iface_flags(drv, 1)) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ return linux_get_ifhwaddr(drv->sock, drv->iface, own_addr);
+}
+
+
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
+ int res;
+
+ /* Request TX callback */
+ hdr->frame_control |= host_to_le16(BIT(1));
+ res = send(drv->sock, msg, len, 0);
+ hdr->frame_control &= ~host_to_le16(BIT(1));
+
+ return res;
+}
+
+
+static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for hostapd_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+ pos = (u8 *) (hdr + 1);
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ *((u16 *) pos) = htons(ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = hostap_send_mlme(drv, (u8 *) hdr, len);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
+ "failed: %d (%s)",
+ (unsigned long) len, errno, strerror(errno));
+ }
+ free(hdr);
+
+ return res;
+}
+
+
+static int hostap_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ if (flags_or & WPA_STA_AUTHORIZED)
+ flags_or = BIT(5); /* WLAN_STA_AUTHORIZED */
+ if (!(flags_and & WPA_STA_AUTHORIZED))
+ flags_and = ~BIT(5);
+ else
+ flags_and = ~0;
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.set_flags_sta.flags_or = flags_or;
+ param.u.set_flags_sta.flags_and = flags_and;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_set_iface_flags(void *priv, int dev_up)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ifreq ifr;
+ char ifname[IFNAMSIZ];
+
+ os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface);
+ if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0)
+ return -1;
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+ int len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+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 hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ 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;
+ if (addr == NULL)
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ memcpy(param->sta_addr, addr, ETH_ALEN);
+ switch (alg) {
+ case WPA_ALG_NONE:
+ os_strlcpy((char *) param->u.crypt.alg, "NONE",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ case WPA_ALG_WEP:
+ os_strlcpy((char *) param->u.crypt.alg, "WEP",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ case WPA_ALG_TKIP:
+ os_strlcpy((char *) param->u.crypt.alg, "TKIP",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ case WPA_ALG_CCMP:
+ os_strlcpy((char *) param->u.crypt.alg, "CCMP",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ default:
+ os_free(buf);
+ return -1;
+ }
+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = key_idx;
+ param->u.crypt.key_len = key_len;
+ memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl(drv, param, blen)) {
+ printf("Failed to set encryption.\n");
+ ret = -1;
+ }
+ free(buf);
+
+ return ret;
+}
+
+
+static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(*param) + 32;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_GET_ENCRYPTION;
+ if (addr == NULL)
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ memcpy(param->sta_addr, addr, ETH_ALEN);
+ param->u.crypt.idx = idx;
+
+ if (hostapd_ioctl(drv, param, blen)) {
+ printf("Failed to get encryption.\n");
+ ret = -1;
+ } else {
+ memcpy(seq, param->u.crypt.seq, 8);
+ }
+ free(buf);
+
+ return ret;
+}
+
+
+static int hostap_ioctl_prism2param(void *priv, int param, int value)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+ int *i;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+ struct hostap_driver_data *drv = priv;
+ int enabled = params->enabled;
+
+ /* enable kernel driver support for IEEE 802.1X */
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) {
+ printf("Could not setup IEEE 802.1X support in kernel driver."
+ "\n");
+ return -1;
+ }
+
+ if (!enabled)
+ return 0;
+
+ /* use host driver implementation of encryption to allow
+ * individual keys and passing plaintext EAPOL frames */
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) ||
+ hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) {
+ printf("Could not setup host-based encryption in kernel "
+ "driver.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_privacy(void *priv, int enabled)
+{
+ struct hostap_drvier_data *drv = priv;
+
+ return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
+ enabled);
+}
+
+
+static int hostap_set_ssid(void *priv, const u8 *buf, int len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_flush(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_FLUSH;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_read_sta_data(void *priv,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ char buf[1024], line[128], *pos;
+ FILE *f;
+ unsigned long val;
+
+ memset(data, 0, sizeof(*data));
+ snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
+ drv->iface, MAC2STR(addr));
+
+ f = fopen(buf, "r");
+ if (!f)
+ return -1;
+ /* Need to read proc file with in one piece, so use large enough
+ * buffer. */
+ setbuffer(f, buf, sizeof(buf));
+
+ while (fgets(line, sizeof(line), f)) {
+ pos = strchr(line, '=');
+ if (!pos)
+ continue;
+ *pos++ = '\0';
+ val = strtoul(pos, NULL, 10);
+ if (strcmp(line, "rx_packets") == 0)
+ data->rx_packets = val;
+ else if (strcmp(line, "tx_packets") == 0)
+ data->tx_packets = val;
+ else if (strcmp(line, "rx_bytes") == 0)
+ data->rx_bytes = val;
+ else if (strcmp(line, "tx_bytes") == 0)
+ data->tx_bytes = val;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+static int hostap_sta_add(void *priv, struct hostapd_sta_add_params *params)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+ int tx_supp_rates = 0;
+ size_t i;
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+
+ for (i = 0; i < params->supp_rates_len; i++) {
+ if ((params->supp_rates[i] & 0x7f) == 2)
+ tx_supp_rates |= WLAN_RATE_1M;
+ if ((params->supp_rates[i] & 0x7f) == 4)
+ tx_supp_rates |= WLAN_RATE_2M;
+ if ((params->supp_rates[i] & 0x7f) == 11)
+ tx_supp_rates |= WLAN_RATE_5M5;
+ if ((params->supp_rates[i] & 0x7f) == 22)
+ tx_supp_rates |= WLAN_RATE_11M;
+ }
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_ADD_STA;
+ memcpy(param.sta_addr, params->addr, ETH_ALEN);
+ param.u.add_sta.aid = params->aid;
+ param.u.add_sta.capability = params->capability;
+ param.u.add_sta.tx_supp_rates = tx_supp_rates;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_sta_remove(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ hostap_sta_set_flags(drv, addr, 0, 0, ~WPA_STA_AUTHORIZED);
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ printf("Could not remove station from kernel driver.\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostap_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ return -1;
+ }
+
+ return param.u.get_info_sta.inactive_sec;
+}
+
+
+static int hostap_sta_clear_stats(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen, elem_len;
+
+ elem_len = drv->generic_ie_len + drv->wps_ie_len;
+ blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_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 = elem_len;
+ if (drv->generic_ie) {
+ os_memcpy(param->u.generic_elem.data, drv->generic_ie,
+ drv->generic_ie_len);
+ }
+ if (drv->wps_ie) {
+ os_memcpy(&param->u.generic_elem.data[drv->generic_ie_len],
+ drv->wps_ie, drv->wps_ie_len);
+ }
+ wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE",
+ param->u.generic_elem.data, elem_len);
+ res = hostapd_ioctl(drv, param, blen);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int hostap_set_generic_elem(void *priv,
+ const u8 *elem, size_t elem_len)
+{
+ struct hostap_driver_data *drv = priv;
+
+ os_free(drv->generic_ie);
+ drv->generic_ie = NULL;
+ drv->generic_ie_len = 0;
+ if (elem) {
+ drv->generic_ie = os_malloc(elem_len);
+ if (drv->generic_ie == NULL)
+ return -1;
+ os_memcpy(drv->generic_ie, elem, elem_len);
+ drv->generic_ie_len = elem_len;
+ }
+
+ return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp)
+{
+ struct hostap_driver_data *drv = priv;
+
+ /*
+ * Host AP driver supports only one set of extra IEs, so we need to
+ * use the Probe Response IEs also for Beacon frames since they include
+ * more information.
+ */
+
+ os_free(drv->wps_ie);
+ drv->wps_ie = NULL;
+ drv->wps_ie_len = 0;
+ if (proberesp) {
+ drv->wps_ie = os_malloc(wpabuf_len(proberesp));
+ if (drv->wps_ie == NULL)
+ return -1;
+ os_memcpy(drv->wps_ie, wpabuf_head(proberesp),
+ wpabuf_len(proberesp));
+ drv->wps_ie_len = wpabuf_len(proberesp);
+ }
+
+ return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static void
+hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ union wpa_event_data data;
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = 1;
+ data.michael_mic_failure.src = addr;
+ wpa_supplicant_event(drv->hapd,
+ EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ }
+}
+
+
+static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ 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 > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ 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;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ 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 = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ hostapd_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void hostapd_wireless_event_rtm_newlink(void *ctx,
+ struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
+{
+ struct hostap_driver_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+
+ /* TODO: use ifi->ifi_index to filter out wireless events from other
+ * interfaces */
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ hostapd_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static int hostap_get_we_version(struct hostap_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int hostap_wireless_event_init(struct hostap_driver_data *drv)
+{
+ struct netlink_config *cfg;
+
+ hostap_get_we_version(drv);
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ return -1;
+ cfg->ctx = drv;
+ cfg->newlink_cb = hostapd_wireless_event_rtm_newlink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void * hostap_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct hostap_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct hostap_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for hostapd driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = drv->sock = -1;
+ memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ free(drv);
+ return NULL;
+ }
+
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
+ printf("Could not enable hostapd mode for interface %s\n",
+ drv->iface);
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ if (hostap_init_sockets(drv, params->own_addr) ||
+ hostap_wireless_event_init(drv)) {
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void hostap_driver_deinit(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+
+ netlink_deinit(drv->netlink);
+ (void) hostap_set_iface_flags(drv, 0);
+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0);
+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0);
+
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ os_free(drv->generic_ie);
+ os_free(drv->wps_ie);
+
+ free(drv);
+}
+
+
+static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, own_addr, ETH_ALEN);
+ 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));
+}
+
+
+static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, own_addr, ETH_ALEN);
+ 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));
+}
+
+
+static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
+ u16 *num_modes,
+ u16 *flags)
+{
+ struct hostapd_hw_modes *mode;
+ int i, clen, rlen;
+ const short chan2freq[14] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+ };
+
+ mode = os_zalloc(sizeof(struct hostapd_hw_modes));
+ if (mode == NULL)
+ return NULL;
+
+ *num_modes = 1;
+ *flags = 0;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+ mode->num_channels = 14;
+ mode->num_rates = 4;
+
+ clen = mode->num_channels * sizeof(struct hostapd_channel_data);
+ rlen = mode->num_rates * sizeof(int);
+
+ mode->channels = os_zalloc(clen);
+ mode->rates = os_zalloc(rlen);
+ if (mode->channels == NULL || mode->rates == NULL) {
+ os_free(mode->channels);
+ os_free(mode->rates);
+ os_free(mode);
+ return NULL;
+ }
+
+ for (i = 0; i < 14; i++) {
+ mode->channels[i].chan = i + 1;
+ mode->channels[i].freq = chan2freq[i];
+ /* TODO: Get allowed channel list from the driver */
+ if (i >= 11)
+ mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
+ }
+
+ mode->rates[0] = 10;
+ mode->rates[1] = 20;
+ mode->rates[2] = 55;
+ mode->rates[3] = 110;
+
+ return mode;
+}
+
+#else /* HOSTAPD */
+
struct wpa_driver_hostap_data {
void *wext; /* private data for driver_wext */
void *ctx;
@@ -32,6 +1125,9 @@ struct wpa_driver_hostap_data {
};
+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)
@@ -45,7 +1141,7 @@ static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
int ret = errno;
- if (show_err)
+ if (show_err)
perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
return ret;
}
@@ -147,9 +1243,10 @@ static void show_set_key_error(struct prism2_hostapd_param *param)
}
-static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg,
- const u8 *addr, int key_idx,
- int set_tx, const u8 *seq, size_t seq_len,
+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;
@@ -232,14 +1329,6 @@ static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
}
-static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled)
-{
- struct wpa_driver_hostap_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
- return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled);
-}
-
-
static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
int type)
{
@@ -315,6 +1404,11 @@ wpa_driver_hostap_associate(void *priv,
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ 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. */
@@ -365,18 +1459,21 @@ wpa_driver_hostap_associate(void *priv,
}
-static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len)
+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, ssid, ssid_len);
+ return wpa_driver_wext_scan(drv->wext, params);
}
if (ssid_len > 32)
@@ -404,11 +1501,11 @@ static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
struct wpa_driver_hostap_data *drv = priv;
int algs = 0;
- if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ if (auth_alg & WPA_AUTH_ALG_OPEN)
algs |= 1;
- if (auth_alg & AUTH_ALG_SHARED_KEY)
+ if (auth_alg & WPA_AUTH_ALG_SHARED)
algs |= 2;
- if (auth_alg & AUTH_ALG_LEAP)
+ if (auth_alg & WPA_AUTH_ALG_LEAP)
algs |= 4;
if (algs == 0)
algs = 1; /* at least one algorithm should be set */
@@ -479,6 +1576,8 @@ static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
}
+ wpa_driver_hostap_set_wpa(drv, 1);
+
return drv;
}
@@ -486,28 +1585,51 @@ static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
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);
}
+#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,
+ .set_privacy = hostap_set_privacy,
+ .get_seqnum = hostap_get_seqnum,
+ .flush = hostap_flush,
+ .set_generic_elem = hostap_set_generic_elem,
+ .read_sta_data = hostap_read_sta_data,
+ .hapd_send_eapol = hostap_send_eapol,
+ .sta_set_flags = hostap_sta_set_flags,
+ .sta_deauth = hostap_sta_deauth,
+ .sta_disassoc = hostap_sta_disassoc,
+ .sta_remove = hostap_sta_remove,
+ .hapd_set_ssid = hostap_set_ssid,
+ .send_mlme = hostap_send_mlme,
+ .sta_add = hostap_sta_add,
+ .get_inact_sec = hostap_get_inact_sec,
+ .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_wpa = wpa_driver_hostap_set_wpa,
- .set_key = wpa_driver_hostap_set_key,
.set_countermeasures = wpa_driver_hostap_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted,
- .scan = wpa_driver_hostap_scan,
+ .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,
- .set_auth_alg = wpa_driver_hostap_set_auth_alg,
.init = wpa_driver_hostap_init,
.deinit = wpa_driver_hostap_deinit,
.set_operstate = wpa_driver_hostap_set_operstate,
+#endif /* HOSTAPD */
};
diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h
index a2508ed924f68..66b2bb39b849c 100644
--- a/src/drivers/driver_hostap.h
+++ b/src/drivers/driver_hostap.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant - driver interaction with Linux Host AP driver
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Driver interaction with Linux Host AP driver
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,10 +15,32 @@
#ifndef HOSTAP_DRIVER_H
#define HOSTAP_DRIVER_H
+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
+
+/* New wireless extensions API - SET/GET convention (even ioctl numbers are
+ * root only)
+ */
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
+
+/* following are not in SIOCGIWPRIV list; check permission in the driver code
+ */
+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
enum {
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
@@ -63,6 +85,47 @@ enum {
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
};
+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
+ HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
+
+
+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
+ AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
+ AP_MAC_CMD_KICKALL = 4 };
+
+
+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
+enum {
+ PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
+ /* Note! Old versions of prism2_srec have a fatal error in CRC-16
+ * calculation, which will corrupt all non-volatile downloads.
+ * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
+ * prevent use of old versions of prism2_srec for non-volatile
+ * download. */
+ PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
+ /* Persistent versions of volatile download commands (keep firmware
+ * data in memory and automatically re-download after hw_reset */
+ PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
+};
+
+struct prism2_download_param {
+ u32 dl_cmd;
+ u32 start_addr;
+ u32 num_areas;
+ struct prism2_download_area {
+ u32 addr; /* wlan card address */
+ u32 len;
+ caddr_t ptr; /* pointer to data in user space */
+ } data[0];
+};
+
+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
+#define PRISM2_MAX_DOWNLOAD_LEN 262144
+
+
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
enum {
PRISM2_HOSTAPD_FLUSH = 1,
@@ -140,8 +203,8 @@ struct prism2_hostapd_param {
} u;
};
-#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
-#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
index 8e64ffdcc08a1..8213fdacc32e8 100644
--- a/src/drivers/driver_iphone.m
+++ b/src/drivers/driver_iphone.m
@@ -20,7 +20,7 @@
#include "common.h"
#include "driver.h"
#include "eloop.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
#include "MobileApple80211.h"
diff --git a/src/drivers/driver_ipw.c b/src/drivers/driver_ipw.c
index 3c19cccf46405..77984f9e5c4cc 100644
--- a/src/drivers/driver_ipw.c
+++ b/src/drivers/driver_ipw.c
@@ -93,6 +93,8 @@ struct ipw_param {
/* end of ipw2100.c and ipw2200.c code */
+static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg);
+
static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
struct ipw_param *param, int len, int show_err)
{
@@ -213,10 +215,11 @@ static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
}
-static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+static int wpa_driver_ipw_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_ipw_data *drv = priv;
struct ipw_param *param;
@@ -318,6 +321,11 @@ wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
int ret = 0;
int unencrypted_eapol;
+ if (wpa_driver_ipw_set_auth_alg(drv, params->auth_alg) < 0)
+ ret = -1;
+ if (wpa_driver_ipw_set_drop_unencrypted(drv, params->drop_unencrypted)
+ < 0)
+ ret = -1;
if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
ret = -1;
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
@@ -347,11 +355,11 @@ static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
struct wpa_driver_ipw_data *drv = priv;
int algs = 0;
- if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ if (auth_alg & WPA_AUTH_ALG_OPEN)
algs |= 1;
- if (auth_alg & AUTH_ALG_SHARED_KEY)
+ if (auth_alg & WPA_AUTH_ALG_SHARED)
algs |= 2;
- if (auth_alg & AUTH_ALG_LEAP)
+ if (auth_alg & WPA_AUTH_ALG_LEAP)
algs |= 4;
if (algs == 0)
algs = 1; /* at least one algorithm should be set */
@@ -375,10 +383,11 @@ static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
}
-static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_ipw_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
struct wpa_driver_ipw_data *drv = priv;
- return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+ return wpa_driver_wext_scan(drv->wext, params);
}
@@ -428,6 +437,8 @@ static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
return NULL;
}
+ wpa_driver_ipw_set_wpa(drv, 1);
+
return drv;
}
@@ -435,6 +446,7 @@ static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
static void wpa_driver_ipw_deinit(void *priv)
{
struct wpa_driver_ipw_data *drv = priv;
+ wpa_driver_ipw_set_wpa(drv, 0);
wpa_driver_wext_deinit(drv->wext);
close(drv->sock);
os_free(drv);
@@ -447,16 +459,13 @@ const struct wpa_driver_ops wpa_driver_ipw_ops = {
"or newer)",
.get_bssid = wpa_driver_ipw_get_bssid,
.get_ssid = wpa_driver_ipw_get_ssid,
- .set_wpa = wpa_driver_ipw_set_wpa,
.set_key = wpa_driver_ipw_set_key,
.set_countermeasures = wpa_driver_ipw_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
- .scan = wpa_driver_ipw_scan,
+ .scan2 = wpa_driver_ipw_scan,
.get_scan_results2 = wpa_driver_ipw_get_scan_results,
.deauthenticate = wpa_driver_ipw_deauthenticate,
.disassociate = wpa_driver_ipw_disassociate,
.associate = wpa_driver_ipw_associate,
- .set_auth_alg = wpa_driver_ipw_set_auth_alg,
.init = wpa_driver_ipw_init,
.deinit = wpa_driver_ipw_deinit,
.set_operstate = wpa_driver_ipw_set_operstate,
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index 7521037234ce5..8687404db9026 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -1,7 +1,8 @@
/*
* WPA Supplicant - driver interaction with MADWIFI 802.11 driver
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +13,10 @@
*
* See README and COPYING for more details.
*
- * Please note that madwifi supports WPA configuration via Linux wireless
- * extensions and if the kernel includes support for this, driver_wext.c should
- * be used instead of this driver wrapper.
+ * While this driver wrapper supports both AP (hostapd) and station
+ * (wpa_supplicant) operations, the station side is deprecated and
+ * driver_wext.c should be used instead. This driver wrapper should only be
+ * used with hostapd for AP mode functionality.
*/
#include "includes.h"
@@ -24,7 +26,7 @@
#include "driver.h"
#include "driver_wext.h"
#include "eloop.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
#include "wireless_copy.h"
/*
@@ -42,12 +44,1236 @@
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+#include <netpacket/packet.h>
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW 0x0019
+#endif
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from madwifi header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+#undef WME_OUI_TYPE
+
#ifdef IEEE80211_IOCTL_SETWMMPARAMS
/* Assume this is built against madwifi-ng */
#define MADWIFI_NG
#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
+
+#ifdef HOSTAPD
+
+#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "l2_packet/l2_packet.h"
+
+
+struct madwifi_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ int ifindex;
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ struct l2_packet_data *sock_recv; /* raw packet recv socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ struct netlink_data *netlink;
+ int we_version;
+ u8 acct_mac[ETH_ALEN];
+ struct hostap_sta_driver_data acct_data;
+
+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+};
+
+static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code);
+
+static int
+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+{
+ struct iwreq iwr;
+ int do_inline = len < IFNAMSIZ;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+ /* FILTERFRAME must be NOT inline, regardless of size. */
+ if (op == IEEE80211_IOCTL_FILTERFRAME)
+ do_inline = 0;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+ if (op == IEEE80211_IOCTL_SET_APPIEBUF)
+ do_inline = 0;
+ if (do_inline) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ 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->ioctl_sock, op, &iwr) < 0) {
+#ifdef MADWIFI_NG
+ int first = IEEE80211_IOCTL_SETPARAM;
+ 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]",
+ "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
+ "ioctl[IEEE80211_IOCTL_FILTERFRAME]",
+ "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;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ "ioctl[SIOCIWFIRSTPRIV+3]",
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ "ioctl[SIOCIWFIRSTPRIV+5]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ "ioctl[SIOCIWFIRSTPRIV+7]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ "ioctl[SIOCIWFIRSTPRIV+11]",
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ "ioctl[SIOCIWFIRSTPRIV+13]",
+ "ioctl[IEEE80211_IOCTL_CHANLIST]",
+ "ioctl[SIOCIWFIRSTPRIV+15]",
+ "ioctl[IEEE80211_IOCTL_GETRSN]",
+ "ioctl[SIOCIWFIRSTPRIV+17]",
+ "ioctl[IEEE80211_IOCTL_GETKEY]",
+ };
+#endif /* MADWIFI_NG */
+ int idx = op - first;
+ if (first <= op &&
+ idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+ opnames[idx])
+ perror(opnames[idx]);
+ else
+ perror("ioctl[unknown???]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct madwifi_driver_data *drv, int op, int arg)
+{
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.mode = op;
+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
+ "arg %d)", __func__, op, arg);
+ return -1;
+ }
+ return 0;
+}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+madwifi_configure_wpa(struct madwifi_driver_data *drv,
+ struct wpa_bss_params *params)
+{
+ int v;
+
+ switch (params->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+ params->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u\n", v);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (params->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (params->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (params->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, params->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
+ params->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ params->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (params->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, params->rsn_preauth);
+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
+ if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
+ printf("Unable to set WPA to %u\n", params->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
+
+ if (!params->enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!params->wpa && !params->ieee802_1x) {
+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_privacy(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
+ __func__, authorized ? "" : "un", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WPA_STA_AUTHORIZED)
+ return madwifi_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WPA_STA_AUTHORIZED))
+ return madwifi_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+ " key_idx %d)", __func__, ether_sprintf(addr),
+ key_idx);
+ }
+
+ return ret;
+}
+
+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 madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+ int ret;
+
+ if (alg == WPA_ALG_NONE)
+ return madwifi_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ if (alg == WPA_ALG_WEP)
+ cipher = IEEE80211_CIPHER_WEP;
+ else if (alg == WPA_ALG_TKIP)
+ cipher = IEEE80211_CIPHER_TKIP;
+ else if (alg == WPA_ALG_CCMP)
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ else {
+ printf("%s: unknown/unsupported algorithm %d\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %lu too big\n", __func__,
+ (unsigned long) key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+ " key_idx %d alg %d key_len %lu set_tx %d)",
+ __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+ alg, (unsigned long) key_len, set_tx);
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+ "(addr " MACSTR " key_idx %d)",
+ __func__, MAC2STR(wk.ik_macaddr), idx);
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+madwifi_flush(void *priv)
+{
+#ifdef MADWIFI_BSD
+ u8 allsta[IEEE80211_ADDR_LEN];
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return madwifi_sta_deauth(priv, NULL, allsta,
+ IEEE80211_REASON_AUTH_LEAVE);
+#else /* MADWIFI_BSD */
+ return 0; /* XXX */
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+
+#ifdef MADWIFI_BSD
+ struct ieee80211req_sta_stats stats;
+
+ memset(data, 0, sizeof(*data));
+
+ /*
+ * Fetch statistics for station from the system.
+ */
+ memset(&stats, 0, sizeof(stats));
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv,
+#ifdef MADWIFI_NG
+ IEEE80211_IOCTL_STA_STATS,
+#else /* MADWIFI_NG */
+ IEEE80211_IOCTL_GETSTASTATS,
+#endif /* MADWIFI_NG */
+ &stats, sizeof(stats))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+
+ printf("Failed to get station stats information element.\n");
+ return -1;
+ }
+
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ return 0;
+
+#else /* MADWIFI_BSD */
+
+ char buf[1024], line[128], *pos;
+ FILE *f;
+ unsigned long val;
+
+ memset(data, 0, sizeof(*data));
+ snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
+ drv->iface, MAC2STR(addr));
+
+ f = fopen(buf, "r");
+ if (!f) {
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
+ return -1;
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+ /* Need to read proc file with in one piece, so use large enough
+ * buffer. */
+ setbuffer(f, buf, sizeof(buf));
+
+ while (fgets(line, sizeof(line), f)) {
+ pos = strchr(line, '=');
+ if (!pos)
+ continue;
+ *pos++ = '\0';
+ val = strtoul(pos, NULL, 10);
+ if (strcmp(line, "rx_packets") == 0)
+ data->rx_packets = val;
+ else if (strcmp(line, "tx_packets") == 0)
+ data->tx_packets = val;
+ else if (strcmp(line, "rx_bytes") == 0)
+ data->rx_bytes = val;
+ else if (strcmp(line, "tx_bytes") == 0)
+ data->tx_bytes = val;
+ }
+
+ fclose(f);
+
+ return 0;
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
+
+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ }
+
+ return ret;
+#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+ return 0; /* FIX */
+#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+}
+
+
+static int
+madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
+ MACSTR " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ union wpa_event_data event;
+
+ /* Send Probe Request information to WPS processing */
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+ event.rx_probe_req.ie_len =
+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+}
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
+{
+ int ret = 0;
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+ struct ieee80211req_set_filter filt;
+
+ wpa_printf(MSG_DEBUG, "%s Enter", __func__);
+ filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+ sizeof(struct ieee80211req_set_filter));
+ if (ret)
+ return ret;
+
+ drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
+ madwifi_raw_receive, drv, 1);
+ if (drv->sock_raw == NULL)
+ return -1;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+static int
+madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+{
+ struct madwifi_driver_data *drv = priv;
+ u8 buf[256];
+ struct ieee80211req_getset_appiebuf *beac_ie;
+
+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+ (unsigned long) len);
+
+ beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ beac_ie->app_frmtype = frametype;
+ beac_ie->app_buflen = len;
+ memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+ return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) + len);
+}
+
+static int
+madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp)
+{
+ if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
+ beacon ? wpabuf_len(beacon) : 0,
+ IEEE80211_APPIE_FRAME_BEACON) < 0)
+ return -1;
+ return madwifi_set_wps_ie(priv,
+ proberesp ? wpabuf_head(proberesp) : NULL,
+ proberesp ? wpabuf_len(proberesp) : 0,
+ IEEE80211_APPIE_FRAME_PROBE_RESP);
+}
+#else /* CONFIG_WPS */
+#define madwifi_set_ap_wps_ie NULL
+#endif /* CONFIG_WPS */
+
+static void
+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211req_wpaie ie;
+ int ielen = 0;
+ u8 *iebuf = NULL;
+
+ /*
+ * Fetch negotiated WPA/RSN parameters from the system.
+ */
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE",
+ __func__);
+ goto no_ie;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+ ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+ iebuf = ie.wpa_ie;
+ /* madwifi seems to return some random data if WPA/RSN IE is not set.
+ * Assume the IE was not included if the IE type is unknown. */
+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+ iebuf[1] = 0;
+#ifdef MADWIFI_NG
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+ ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+ /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+ * set. This is needed for WPA2. */
+ iebuf = ie.rsn_ie;
+ if (iebuf[0] != WLAN_EID_RSN)
+ iebuf[1] = 0;
+ }
+#endif /* MADWIFI_NG */
+
+ ielen = iebuf[1];
+ if (ielen == 0)
+ iebuf = NULL;
+ else
+ ielen += 2;
+
+no_ie:
+ drv_event_assoc(hapd, addr, iebuf, ielen);
+
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ /* Cached accounting data is not valid anymore. */
+ memset(drv->acct_mac, 0, ETH_ALEN);
+ memset(&drv->acct_data, 0, sizeof(drv->acct_data));
+ }
+}
+
+static void
+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ union wpa_event_data data;
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = 1;
+ data.michael_mic_failure.src = addr;
+ wpa_supplicant_event(drv->hapd,
+ EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+ char *key, *value;
+ u32 val;
+ key = custom;
+ while ((key = strchr(key, '\n')) != NULL) {
+ key++;
+ value = strchr(key, '=');
+ if (value == NULL)
+ continue;
+ *value++ = '\0';
+ val = strtoul(value, NULL, 10);
+ if (strcmp(key, "mac") == 0)
+ hwaddr_aton(value, drv->acct_mac);
+ else if (strcmp(key, "rx_packets") == 0)
+ drv->acct_data.rx_packets = val;
+ else if (strcmp(key, "tx_packets") == 0)
+ drv->acct_data.tx_packets = val;
+ else if (strcmp(key, "rx_bytes") == 0)
+ drv->acct_data.rx_bytes = val;
+ else if (strcmp(key, "tx_bytes") == 0)
+ drv->acct_data.tx_bytes = val;
+ key = value;
+ }
+ }
+}
+
+static void
+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_MSGDUMP, "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 > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ 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;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVEXPIRED:
+ drv_event_disassoc(drv->hapd,
+ (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVREGISTERED:
+ madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return; /* XXX */
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ madwifi_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void
+madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+
+ if (ifi->ifi_index != drv->ifindex)
+ return;
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ madwifi_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static int
+madwifi_get_we_version(struct madwifi_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int
+madwifi_wireless_event_init(struct madwifi_driver_data *drv)
+{
+ struct netlink_config *cfg;
+
+ madwifi_get_we_version(drv);
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ return -1;
+ cfg->ctx = drv;
+ cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Ethernet header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %lu!\n", (unsigned long) len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = host_to_be16(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+{
+ struct madwifi_driver_data *drv;
+ struct ifreq ifr;
+ struct iwreq iwr;
+ char brname[IFNAMSIZ];
+
+ drv = os_zalloc(sizeof(struct madwifi_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for madwifi driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ goto bad;
+ }
+ drv->ifindex = ifr.ifr_ifindex;
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
+ goto bad;
+ if (params->bridge[0]) {
+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+ params->bridge[0]);
+ drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
+ ETH_P_EAPOL, handle_read, drv,
+ 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else if (linux_br_get(brname, drv->iface) == 0) {
+ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
+ "EAPOL receive", brname);
+ drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else
+ drv->sock_recv = drv->sock_xmit;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.mode = IW_MODE_MASTER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMODE]");
+ printf("Could not set interface to master mode!\n");
+ goto bad;
+ }
+
+ /* mark down during setup */
+ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+ madwifi_set_privacy(drv, 0); /* default to no privacy */
+
+ madwifi_receive_probe_req(drv);
+
+ if (madwifi_wireless_event_init(drv))
+ goto bad;
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+madwifi_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ netlink_deinit(drv->netlink);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->sock_raw)
+ l2_packet_deinit(drv->sock_raw);
+ free(drv);
+}
+
+static int
+madwifi_set_ssid(void *priv, const u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_get_ssid(void *priv, u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ return ret;
+}
+
+static int
+madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+madwifi_commit(void *priv)
+{
+ struct madwifi_driver_data *drv = 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;
@@ -55,6 +1281,11 @@ struct wpa_driver_madwifi_data {
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)
@@ -205,7 +1436,7 @@ wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
}
static int
-wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
+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)
@@ -227,8 +1458,8 @@ wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
* configuration with IEEE80211_IOCTL_SETKEY, so use
* Linux wireless extensions ioctl for this.
*/
- return wpa_driver_wext_set_key(drv->wext, alg, addr,
- key_idx, set_tx,
+ return wpa_driver_wext_set_key(ifname, drv->wext, alg,
+ addr, key_idx, set_tx,
seq, seq_len,
key, key_len);
}
@@ -303,15 +1534,6 @@ wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
}
-
-static int
-wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
- return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
-}
-
static int
wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
{
@@ -348,6 +1570,12 @@ wpa_driver_madwifi_associate(void *priv,
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
@@ -411,10 +1639,10 @@ wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
struct wpa_driver_madwifi_data *drv = priv;
int authmode;
- if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
- (auth_alg & AUTH_ALG_SHARED_KEY))
+ if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
+ (auth_alg & WPA_AUTH_ALG_SHARED))
authmode = IEEE80211_AUTH_AUTO;
- else if (auth_alg & AUTH_ALG_SHARED_KEY)
+ else if (auth_alg & WPA_AUTH_ALG_SHARED)
authmode = IEEE80211_AUTH_SHARED;
else
authmode = IEEE80211_AUTH_OPEN;
@@ -423,11 +1651,16 @@ wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
}
static int
-wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
+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);
@@ -579,23 +1812,43 @@ static void wpa_driver_madwifi_deinit(void *priv)
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,
+ .set_privacy = madwifi_set_privacy,
+ .get_seqnum = madwifi_get_seqnum,
+ .flush = madwifi_flush,
+ .set_generic_elem = madwifi_set_opt_ie,
+ .sta_set_flags = madwifi_sta_set_flags,
+ .read_sta_data = madwifi_read_sta_driver_data,
+ .hapd_send_eapol = madwifi_send_eapol,
+ .sta_disassoc = madwifi_sta_disassoc,
+ .sta_deauth = madwifi_sta_deauth,
+ .hapd_set_ssid = madwifi_set_ssid,
+ .hapd_get_ssid = madwifi_get_ssid,
+ .hapd_set_countermeasures = madwifi_set_countermeasures,
+ .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,
- .set_key = wpa_driver_madwifi_set_key,
.init = wpa_driver_madwifi_init,
.deinit = wpa_driver_madwifi_deinit,
.set_countermeasures = wpa_driver_madwifi_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
- .scan = wpa_driver_madwifi_scan,
+ .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_auth_alg = wpa_driver_madwifi_set_auth_alg,
.set_operstate = wpa_driver_madwifi_set_operstate,
- .set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,
+#endif /* HOSTAPD */
};
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index a90e277ca04de..462dd81f58af3 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -40,7 +40,7 @@ int close(int fd);
#include "common.h"
#include "driver.h"
#include "eloop.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
#include "driver_ndis.h"
int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
@@ -353,6 +353,47 @@ typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
#endif /* OID_802_11_CAPABILITY */
+#ifndef OID_DOT11_CURRENT_OPERATION_MODE
+/* Native 802.11 OIDs */
+#define OID_DOT11_NDIS_START 0x0D010300
+#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8)
+#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11)
+
+typedef enum _DOT11_BSS_TYPE {
+ dot11_BSS_type_infrastructure = 1,
+ dot11_BSS_type_independent = 2,
+ dot11_BSS_type_any = 3
+} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE;
+
+typedef UCHAR DOT11_MAC_ADDRESS[6];
+typedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS;
+
+typedef enum _DOT11_SCAN_TYPE {
+ dot11_scan_type_active = 1,
+ dot11_scan_type_passive = 2,
+ dot11_scan_type_auto = 3,
+ dot11_scan_type_forced = 0x80000000
+} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE;
+
+typedef struct _DOT11_SCAN_REQUEST_V2 {
+ DOT11_BSS_TYPE dot11BSSType;
+ DOT11_MAC_ADDRESS dot11BSSID;
+ DOT11_SCAN_TYPE dot11ScanType;
+ BOOLEAN bRestrictedScan;
+ ULONG udot11SSIDsOffset;
+ ULONG uNumOfdot11SSIDs;
+ BOOLEAN bUseRequestIE;
+ ULONG uRequestIDsOffset;
+ ULONG uNumOfRequestIDs;
+ ULONG uPhyTypeInfosOffset;
+ ULONG uNumOfPhyTypeInfos;
+ ULONG uIEsOffset;
+ ULONG uIEsLength;
+ UCHAR ucBuffer[1];
+} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2;
+
+#endif /* OID_DOT11_CURRENT_OPERATION_MODE */
+
#ifdef CONFIG_USE_NDISUIO
#ifndef _WIN32_WCE
#ifdef __MINGW32_VERSION
@@ -698,25 +739,42 @@ static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr,
}
-static int wpa_driver_ndis_set_wpa(void *priv, int enabled)
+static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
- return 0;
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
}
-static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+static int wpa_driver_ndis_scan_native80211(
+ struct wpa_driver_ndis_data *drv,
+ struct wpa_driver_scan_params *params)
{
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+ DOT11_SCAN_REQUEST_V2 req;
+ int res;
+
+ os_memset(&req, 0, sizeof(req));
+ req.dot11BSSType = dot11_BSS_type_any;
+ os_memset(req.dot11BSSID, 0xff, ETH_ALEN);
+ req.dot11ScanType = dot11_scan_type_auto;
+ res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req,
+ sizeof(req));
+ eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
+ drv->ctx);
+ return res;
}
-static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_ndis_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
struct wpa_driver_ndis_data *drv = priv;
int res;
+ if (drv->native80211)
+ return wpa_driver_ndis_scan_native80211(drv, params);
+
if (!drv->radio_enabled) {
wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first"
" scan");
@@ -734,6 +792,25 @@ static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len)
}
+static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
+{
+ const u8 *end, *pos;
+
+ pos = (const u8 *) (res + 1);
+ end = pos + res->ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
struct wpa_scan_res *r, NDIS_802_11_SSID *ssid)
{
@@ -912,7 +989,8 @@ static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
}
-static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr,
+static int wpa_driver_ndis_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)
@@ -1020,7 +1098,8 @@ wpa_driver_ndis_associate(void *priv,
continue;
wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP "
"key %d", i);
- wpa_driver_ndis_set_key(drv, WPA_ALG_WEP, bcast, i,
+ wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
+ bcast, i,
i == params->wep_tx_keyidx,
NULL, 0, params->wep_key[i],
params->wep_key_len[i]);
@@ -1028,8 +1107,8 @@ wpa_driver_ndis_associate(void *priv,
}
if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
- if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
- if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ 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;
@@ -2801,16 +2880,31 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
mode = Ndis802_11Infrastructure;
if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
(char *) &mode, sizeof(mode)) < 0) {
+ char buf[8];
+ int res;
wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
"OID_802_11_INFRASTRUCTURE_MODE (%d)",
(int) mode);
/* Try to continue anyway */
- if (!drv->has_capability && drv->capa.enc == 0) {
+ res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf,
+ sizeof(buf));
+ if (res > 0) {
+ wpa_printf(MSG_INFO, "NDIS: The driver seems to use "
+ "Native 802.11 OIDs. These are not yet "
+ "fully supported.");
+ drv->native80211 = 1;
+ } else if (!drv->has_capability || drv->capa.enc == 0) {
+ /*
+ * Note: This will also happen with NDIS 6 drivers with
+ * Vista.
+ */
wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
"any wireless capabilities - assume it is "
"a wired interface");
drv->wired = 1;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED;
+ drv->has_capability = 1;
ndis_add_multicast(drv);
}
}
@@ -3096,19 +3190,14 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
"Windows NDIS driver",
wpa_driver_ndis_get_bssid,
wpa_driver_ndis_get_ssid,
- wpa_driver_ndis_set_wpa,
wpa_driver_ndis_set_key,
wpa_driver_ndis_init,
wpa_driver_ndis_deinit,
NULL /* set_param */,
NULL /* set_countermeasures */,
- NULL /* set_drop_unencrypted */,
- wpa_driver_ndis_scan,
- NULL /* get_scan_results */,
wpa_driver_ndis_deauthenticate,
wpa_driver_ndis_disassociate,
wpa_driver_ndis_associate,
- NULL /* set_auth_alg */,
wpa_driver_ndis_add_pmkid,
wpa_driver_ndis_remove_pmkid,
wpa_driver_ndis_flush_pmkid,
@@ -3129,11 +3218,61 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
NULL /* update_ft_ies */,
NULL /* send_ft_action */,
wpa_driver_ndis_get_scan_results,
- NULL /* set_probe_req_ie */,
- NULL /* set_mode */,
NULL /* set_country */,
NULL /* global_init */,
NULL /* global_deinit */,
NULL /* init2 */,
- wpa_driver_ndis_get_interfaces
+ 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 /* 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 */
};
diff --git a/src/drivers/driver_ndis.h b/src/drivers/driver_ndis.h
index cdce4bac85abd..f263f0e435858 100644
--- a/src/drivers/driver_ndis.h
+++ b/src/drivers/driver_ndis.h
@@ -52,6 +52,7 @@ struct wpa_driver_ndis_data {
struct ndis_pmkid_entry *pmkid;
char *adapter_desc;
int wired;
+ int native80211;
int mode;
int wzc_disabled;
int oid_bssid_set;
diff --git a/src/drivers/driver_ndiswrapper.c b/src/drivers/driver_ndiswrapper.c
index b5c534a74d08b..cd2f61e468a04 100644
--- a/src/drivers/driver_ndiswrapper.c
+++ b/src/drivers/driver_ndiswrapper.c
@@ -33,9 +33,8 @@ struct wpa_driver_ndiswrapper_data {
};
-struct wpa_key
-{
- wpa_alg alg;
+struct wpa_key {
+ enum wpa_alg alg;
const u8 *addr;
int key_index;
int set_tx;
@@ -45,17 +44,16 @@ struct wpa_key
size_t key_len;
};
-struct wpa_assoc_info
-{
+struct wpa_assoc_info {
const u8 *bssid;
const u8 *ssid;
size_t ssid_len;
int freq;
const u8 *wpa_ie;
size_t wpa_ie_len;
- wpa_cipher pairwise_suite;
- wpa_cipher group_suite;
- wpa_key_mgmt key_mgmt_suite;
+ enum wpa_cipher pairwise_suite;
+ enum wpa_cipher group_suite;
+ enum wpa_key_mgmt key_mgmt_suite;
int auth_alg;
int mode;
};
@@ -73,6 +71,8 @@ struct wpa_assoc_info
#define WPA_DEINIT SIOCIWFIRSTPRIV+10
#define WPA_GET_CAPA SIOCIWFIRSTPRIV+11
+static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg);
+
static int get_socket(void)
{
static const int families[] = {
@@ -111,7 +111,8 @@ static int wpa_ndiswrapper_set_wpa(void *priv, int enabled)
return ret;
}
-static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr,
+static int wpa_ndiswrapper_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)
@@ -146,8 +147,8 @@ static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr,
* did not associate. Try to make sure the keys are cleared so
* that plaintext APs can be used in all cases.
*/
- wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ wpa_driver_wext_set_key(ifname, drv->wext, alg, addr, key_idx,
+ set_tx, seq, seq_len, key, key_len);
}
return ret;
@@ -223,6 +224,12 @@ wpa_ndiswrapper_associate(void *priv,
struct wpa_assoc_info wpa_assoc_info;
struct iwreq priv_req;
+ if (wpa_ndiswrapper_set_drop_unencrypted(drv,
+ params->drop_unencrypted) < 0)
+ ret = -1;
+ if (wpa_ndiswrapper_set_auth_alg(drv, params->auth_alg) < 0)
+ ret = -1;
+
os_memset(&priv_req, 0, sizeof(priv_req));
os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info));
@@ -274,10 +281,11 @@ static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid)
}
-static int wpa_ndiswrapper_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_ndiswrapper_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
struct wpa_driver_ndiswrapper_data *drv = priv;
- return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+ return wpa_driver_wext_scan(drv->wext, params);
}
@@ -334,6 +342,8 @@ static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
return NULL;
}
+ wpa_ndiswrapper_set_wpa(drv, 1);
+
return drv;
}
@@ -341,6 +351,7 @@ static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
static void wpa_ndiswrapper_deinit(void *priv)
{
struct wpa_driver_ndiswrapper_data *drv = priv;
+ wpa_ndiswrapper_set_wpa(drv, 0);
wpa_driver_wext_deinit(drv->wext);
close(drv->sock);
os_free(drv);
@@ -350,18 +361,15 @@ static void wpa_ndiswrapper_deinit(void *priv)
const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = {
.name = "ndiswrapper",
.desc = "Linux ndiswrapper (deprecated; use wext)",
- .set_wpa = wpa_ndiswrapper_set_wpa,
.set_key = wpa_ndiswrapper_set_key,
.set_countermeasures = wpa_ndiswrapper_set_countermeasures,
- .set_drop_unencrypted = wpa_ndiswrapper_set_drop_unencrypted,
.deauthenticate = wpa_ndiswrapper_deauthenticate,
.disassociate = wpa_ndiswrapper_disassociate,
.associate = wpa_ndiswrapper_associate,
- .set_auth_alg = wpa_ndiswrapper_set_auth_alg,
.get_bssid = wpa_ndiswrapper_get_bssid,
.get_ssid = wpa_ndiswrapper_get_ssid,
- .scan = wpa_ndiswrapper_scan,
+ .scan2 = wpa_ndiswrapper_scan,
.get_scan_results2 = wpa_ndiswrapper_get_scan_results,
.init = wpa_ndiswrapper_init,
.deinit = wpa_ndiswrapper_deinit,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9ab6d17279a96..364158c7d8e25 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1,6 +1,10 @@
/*
- * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
*
* 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
@@ -14,23 +18,30 @@
#include "includes.h"
#include <sys/ioctl.h>
-#include <net/if_arp.h>
+#include <net/if.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
-#include "nl80211_copy.h"
-#ifdef CONFIG_CLIENT_MLME
#include <netpacket/packet.h>
-#include <linux/if_ether.h>
-#include "radiotap.h"
-#include "radiotap_iter.h"
-#endif /* CONFIG_CLIENT_MLME */
+#include <linux/filter.h>
+#include "nl80211_copy.h"
-#include "wireless_copy.h"
#include "common.h"
-#include "driver.h"
#include "eloop.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#include "driver.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl_handle_alloc_cb nl_socket_alloc_cb
+#define nl_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
@@ -46,51 +57,104 @@
#define IF_OPER_UP 6
#endif
+struct i802_bss {
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *next;
+ int ifindex;
+ char ifname[IFNAMSIZ + 1];
+ unsigned int beacon_set:1;
+};
struct wpa_driver_nl80211_data {
void *ctx;
- int wext_event_sock;
- int ioctl_sock;
- char ifname[IFNAMSIZ + 1];
+ struct netlink_data *netlink;
+ int ioctl_sock; /* socket for ioctl() use */
+ char brname[IFNAMSIZ];
int ifindex;
int if_removed;
- u8 *assoc_req_ies;
- size_t assoc_req_ies_len;
- u8 *assoc_resp_ies;
- size_t assoc_resp_ies_len;
struct wpa_driver_capa capa;
int has_capability;
- int we_version_compiled;
-
- /* for set_auth_alg fallback */
- int use_crypt;
- int auth_alg_fallback;
int operstate;
- char mlmedev[IFNAMSIZ + 1];
-
int scan_complete_events;
struct nl_handle *nl_handle;
+ struct nl_handle *nl_handle_event;
struct nl_cache *nl_cache;
+ struct nl_cache *nl_cache_event;
struct nl_cb *nl_cb;
struct genl_family *nl80211;
-#ifdef CONFIG_CLIENT_MLME
- int monitor_sock; /* socket for monitor */
+ 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;
+ unsigned int assoc_freq;
+
+ int monitor_sock;
int monitor_ifidx;
-#endif /* CONFIG_CLIENT_MLME */
+ int probe_req_report;
+ int disable_11b_rates;
+
+ unsigned int pending_remain_on_chan:1;
+ unsigned int added_bridge:1;
+ unsigned int added_if_into_bridge:1;
+
+ u64 remain_on_chan_cookie;
+ u64 send_action_cookie;
+
+ struct wpa_driver_scan_filter *filter_ssids;
+ size_t num_filter_ssids;
+
+ struct i802_bss first_bss;
+
+#ifdef HOSTAPD
+ int eapol_sock; /* socket for EAPOL frames */
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ int last_freq;
+ int last_freq_ht;
+#endif /* HOSTAPD */
};
static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
void *timeout_ctx);
static int wpa_driver_nl80211_set_mode(void *priv, int mode);
-static int wpa_driver_nl80211_flush_pmkid(void *priv);
-static int wpa_driver_nl80211_get_range(void *priv);
-static void
+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,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change);
+static void nl80211_remove_monitor_interface(
+ struct wpa_driver_nl80211_data *drv);
+
+#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);
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
+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)
+{
+ return 0;
+}
+#endif /* HOSTAPD */
+
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int disabled);
/* nl80211 code */
@@ -116,10 +180,17 @@ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
return NL_SKIP;
}
-static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
- struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+
+static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+ struct nl_handle *nl_handle, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
{
struct nl_cb *cb;
int err = -ENOMEM;
@@ -128,7 +199,7 @@ static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
if (!cb)
goto out;
- err = nl_send_auto_complete(drv->nl_handle, msg);
+ err = nl_send_auto_complete(nl_handle, msg);
if (err < 0)
goto out;
@@ -143,7 +214,7 @@ static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
valid_handler, valid_data);
while (err > 0)
- nl_recvmsgs(drv->nl_handle, cb);
+ nl_recvmsgs(nl_handle, cb);
out:
nl_cb_put(cb);
nlmsg_free(msg);
@@ -151,6 +222,16 @@ static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
}
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
+{
+ return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
+ valid_data);
+}
+
+
struct family_data {
const char *group;
int id;
@@ -213,752 +294,678 @@ nla_put_failure:
}
-static int wpa_driver_nl80211_send_oper_ifla(
- struct wpa_driver_nl80211_data *drv,
- int linkmode, int operstate)
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
{
- struct {
- struct nlmsghdr hdr;
- struct ifinfomsg ifinfo;
- char opts[16];
- } req;
- struct rtattr *rta;
- static int nl_seq;
- ssize_t ret;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!drv->associated)
+ return -1;
+ os_memcpy(bssid, drv->bssid, ETH_ALEN);
+ return 0;
+}
- os_memset(&req, 0, sizeof(req));
- req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- req.hdr.nlmsg_type = RTM_SETLINK;
- req.hdr.nlmsg_flags = NLM_F_REQUEST;
- req.hdr.nlmsg_seq = ++nl_seq;
- req.hdr.nlmsg_pid = 0;
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!drv->associated)
+ return -1;
+ os_memcpy(ssid, drv->ssid, drv->ssid_len);
+ return drv->ssid_len;
+}
- req.ifinfo.ifi_family = AF_UNSPEC;
- req.ifinfo.ifi_type = 0;
- req.ifinfo.ifi_index = drv->ifindex;
- req.ifinfo.ifi_flags = 0;
- req.ifinfo.ifi_change = 0;
- if (linkmode != -1) {
- rta = aliasing_hide_typecast(
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
- struct rtattr);
- rta->rta_type = IFLA_LINKMODE;
- rta->rta_len = RTA_LENGTH(sizeof(char));
- *((char *) RTA_DATA(rta)) = linkmode;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
- }
- if (operstate != -1) {
- rta = (struct rtattr *)
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
- rta->rta_type = IFLA_OPERSTATE;
- rta->rta_len = RTA_LENGTH(sizeof(char));
- *((char *) RTA_DATA(rta)) = operstate;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
- }
+static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
+ char *buf, size_t len, int del)
+{
+ union wpa_event_data event;
- wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
- linkmode, operstate);
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
- ret = send(drv->wext_event_sock, &req, req.hdr.nlmsg_len, 0);
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
- "%s (assume operstate is not supported)",
- strerror(errno));
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
+ if (del)
+ drv->if_removed = 1;
+ else
+ drv->if_removed = 0;
}
- return ret < 0 ? -1 : 0;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
}
-static int wpa_driver_nl80211_set_auth_param(
- struct wpa_driver_nl80211_data *drv, int idx, u32 value)
+static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len)
{
- struct iwreq iwr;
- int ret = 0;
+ int attrlen, rta_len;
+ struct rtattr *attr;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.param.flags = idx & IW_AUTH_INDEX;
- iwr.u.param.value = value;
+ attrlen = len;
+ attr = (struct rtattr *) buf;
- if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
- if (errno != EOPNOTSUPP) {
- wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
- "value 0x%x) failed: %s)",
- idx, value, strerror(errno));
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
+ == 0)
+ return 1;
+ else
+ break;
}
- ret = errno == EOPNOTSUPP ? -2 : -1;
+ attr = RTA_NEXT(attr, attrlen);
}
- return ret;
+ return 0;
}
-static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex, u8 *buf, size_t len)
{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (drv->ifindex == ifindex)
+ return 1;
- if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
- perror("ioctl[SIOCGIWAP]");
- ret = -1;
+ if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+ drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
+ "interface");
+ wpa_driver_nl80211_finish_drv_init(drv);
+ return 1;
}
- os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
- return ret;
+ return 0;
}
-static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid)
+static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
+ struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
- if (bssid)
- os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
- else
- os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+ struct wpa_driver_nl80211_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+ u32 brid = 0;
- if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
- perror("ioctl[SIOCSIWAP]");
- ret = -1;
+ if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
+ !have_ifidx(drv, ifi->ifi_index)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
+ "ifindex %d", ifi->ifi_index);
+ return;
}
- return ret;
-}
-
-
-static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.essid.pointer = (caddr_t) ssid;
- iwr.u.essid.length = 32;
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ -1, IF_OPER_UP);
- if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
- ret = -1;
- } else {
- ret = iwr.u.essid.length;
- if (ret > 32)
- ret = 32;
- /* Some drivers include nul termination in the SSID, so let's
- * remove it here before further processing. WE-21 changes this
- * to explicitly require the length _not_ to include nul
- * termination. */
- if (ret > 0 && ssid[ret - 1] == '\0' &&
- drv->we_version_compiled < 21)
- ret--;
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(
+ drv,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ } else if (attr->rta_type == IFLA_MASTER)
+ brid = nla_get_u32((struct nlattr *) attr);
+ attr = RTA_NEXT(attr, attrlen);
}
- return ret;
+#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 */
}
-static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid,
- size_t ssid_len)
+static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
+ struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
- char buf[33];
+ struct wpa_driver_nl80211_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+ u32 brid = 0;
- if (ssid_len > 32)
- return -1;
+ attrlen = len;
+ attr = (struct rtattr *) buf;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
- iwr.u.essid.flags = (ssid_len != 0);
- os_memset(buf, 0, sizeof(buf));
- os_memcpy(buf, ssid, ssid_len);
- iwr.u.essid.pointer = (caddr_t) buf;
- if (drv->we_version_compiled < 21) {
- /* For historic reasons, set SSID length to include one extra
- * character, C string nul termination, even though SSID is
- * really an octet string that should not be presented as a C
- * string. Some Linux drivers decrement the length by one and
- * can thus end up missing the last octet of the SSID if the
- * length is not incremented here. WE-21 changes this to
- * explicitly require the length _not_ to include nul
- * termination. */
- if (ssid_len)
- ssid_len++;
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(
+ drv,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ } else if (attr->rta_type == IFLA_MASTER)
+ brid = nla_get_u32((struct nlattr *) attr);
+ attr = RTA_NEXT(attr, attrlen);
}
- iwr.u.essid.length = ssid_len;
- if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
- ret = -1;
+#ifdef HOSTAPD
+ if (ifi->ifi_family == AF_BRIDGE && brid) {
+ /* device has been removed from bridge */
+ char namebuf[IFNAMSIZ];
+ if_indextoname(brid, namebuf);
+ wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
+ "%s", brid, namebuf);
+ del_ifidx(drv, brid);
}
-
- return ret;
+#endif /* HOSTAPD */
}
-static int wpa_driver_nl80211_set_freq(void *priv, int freq)
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.freq.m = freq * 100000;
- iwr.u.freq.e = 1;
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
- if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
- ret = -1;
+ os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
+ if (len > 24 + sizeof(mgmt->u.auth)) {
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
}
- return ret;
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
}
-static void
-wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom)
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
{
- union wpa_event_data data;
-
- wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
- custom);
-
- os_memset(&data, 0, sizeof(data));
- /* Host AP driver */
- if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
- data.michael_mic_failure.unicast =
- os_strstr(custom, " unicast ") != NULL;
- /* TODO: parse parameters(?) */
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
- } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
- char *spos;
- int bytes;
-
- spos = custom + 17;
-
- bytes = strspn(spos, "0123456789abcdefABCDEF");
- if (!bytes || (bytes & 1))
- return;
- bytes /= 2;
-
- data.assoc_info.req_ies = os_malloc(bytes);
- if (data.assoc_info.req_ies == NULL)
- return;
-
- data.assoc_info.req_ies_len = bytes;
- hexstr2bin(spos, data.assoc_info.req_ies, bytes);
-
- spos += bytes * 2;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 status;
- data.assoc_info.resp_ies = NULL;
- data.assoc_info.resp_ies_len = 0;
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
- if (os_strncmp(spos, " RespIEs=", 9) == 0) {
- spos += 9;
+ status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ if (status != WLAN_STATUS_SUCCESS) {
+ os_memset(&event, 0, sizeof(event));
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_reject.resp_ies =
+ (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_reject.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+ event.assoc_reject.status_code = status;
- bytes = strspn(spos, "0123456789abcdefABCDEF");
- if (!bytes || (bytes & 1))
- goto done;
- bytes /= 2;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
- data.assoc_info.resp_ies = os_malloc(bytes);
- if (data.assoc_info.resp_ies == NULL)
- goto done;
+ drv->associated = 1;
+ os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
- data.assoc_info.resp_ies_len = bytes;
- hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
- }
+ os_memset(&event, 0, sizeof(event));
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_info.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
- wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+ event.assoc_info.freq = drv->assoc_freq;
- done:
- os_free(data.assoc_info.resp_ies);
- os_free(data.assoc_info.req_ies);
-#ifdef CONFIG_PEERKEY
- } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
- if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
- wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
- "STKSTART.request '%s'", custom + 17);
- return;
- }
- wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
-#endif /* CONFIG_PEERKEY */
- }
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
-static int wpa_driver_nl80211_event_wireless_michaelmicfailure(
- void *ctx, const char *ev, size_t len)
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie)
{
- const struct iw_michaelmicfailure *mic;
- union wpa_event_data data;
+ union wpa_event_data event;
- if (len < sizeof(*mic))
- return -1;
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+ "when using userspace SME", cmd);
+ return;
+ }
- mic = (const struct iw_michaelmicfailure *) ev;
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT &&
+ nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
+ if (resp_ie) {
+ event.assoc_reject.resp_ies = nla_data(resp_ie);
+ event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+ }
+ event.assoc_reject.status_code = nla_get_u16(status);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
- wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
- "flags=0x%x src_addr=" MACSTR, mic->flags,
- MAC2STR(mic->src_addr.sa_data));
+ drv->associated = 1;
+ if (addr)
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
- os_memset(&data, 0, sizeof(data));
- data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+ if (resp_ie) {
+ event.assoc_info.resp_ies = nla_data(resp_ie);
+ event.assoc_info.resp_ies_len = nla_len(resp_ie);
+ }
- return 0;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
-static int wpa_driver_nl80211_event_wireless_pmkidcand(
- struct wpa_driver_nl80211_data *drv, const char *ev, size_t len)
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
{
- const struct iw_pmkid_cand *cand;
- union wpa_event_data data;
- const u8 *addr;
-
- if (len < sizeof(*cand))
- return -1;
+ union wpa_event_data event;
+ enum wpa_event_type ev;
- cand = (const struct iw_pmkid_cand *) ev;
- addr = (const u8 *) cand->bssid.sa_data;
+ if (nla_len(addr) != ETH_ALEN)
+ return;
- wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
- "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
- cand->index, MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+ cmd, MAC2STR((u8 *) nla_data(addr)));
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
- data.pmkid_candidate.index = cand->index;
- data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
- wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ ev = EVENT_AUTH_TIMED_OUT;
+ else if (cmd == NL80211_CMD_ASSOCIATE)
+ ev = EVENT_ASSOC_TIMED_OUT;
+ else
+ return;
- return 0;
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, ev, &event);
}
-static int wpa_driver_nl80211_event_wireless_assocreqie(
- struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+static void mlme_event_action(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *freq, const u8 *frame, size_t len)
{
- if (len < 0)
- return -1;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 fc, stype;
- wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
- len);
- os_free(drv->assoc_req_ies);
- drv->assoc_req_ies = os_malloc(len);
- if (drv->assoc_req_ies == NULL) {
- drv->assoc_req_ies_len = 0;
- return -1;
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
+ return;
}
- os_memcpy(drv->assoc_req_ies, ev, len);
- drv->assoc_req_ies_len = len;
- return 0;
-}
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
-
-static int wpa_driver_nl80211_event_wireless_assocrespie(
- struct wpa_driver_nl80211_data *drv, const char *ev, int len)
-{
- if (len < 0)
- return -1;
-
- wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
- len);
- os_free(drv->assoc_resp_ies);
- drv->assoc_resp_ies = os_malloc(len);
- if (drv->assoc_resp_ies == NULL) {
- drv->assoc_resp_ies_len = 0;
- return -1;
- }
- os_memcpy(drv->assoc_resp_ies, ev, len);
- drv->assoc_resp_ies_len = len;
-
- return 0;
+ os_memset(&event, 0, sizeof(event));
+ event.rx_action.da = mgmt->da;
+ event.rx_action.sa = mgmt->sa;
+ event.rx_action.bssid = mgmt->bssid;
+ event.rx_action.category = mgmt->u.action.category;
+ event.rx_action.data = &mgmt->u.action.category + 1;
+ event.rx_action.len = frame + len - event.rx_action.data;
+ if (freq)
+ event.rx_action.freq = nla_get_u32(freq);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
}
-static void wpa_driver_nl80211_event_assoc_ies(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)
{
- union wpa_event_data data;
+ union wpa_event_data event;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+ u64 cookie_val;
- if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ if (!cookie)
return;
- os_memset(&data, 0, sizeof(data));
- if (drv->assoc_req_ies) {
- data.assoc_info.req_ies = drv->assoc_req_ies;
- drv->assoc_req_ies = NULL;
- data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
- }
- if (drv->assoc_resp_ies) {
- data.assoc_info.resp_ies = drv->assoc_resp_ies;
- drv->assoc_resp_ies = NULL;
- data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
- }
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)");
+ if (cookie_val != drv->send_action_cookie)
+ return;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+ hdr = (const struct ieee80211_hdr *) frame;
+ fc = le_to_host16(hdr->frame_control);
- os_free(data.assoc_info.req_ies);
- os_free(data.assoc_info.resp_ies);
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = frame;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
}
-static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv,
- void *ctx, char *data, int len)
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
{
- struct iw_event iwe_buf, *iwe = &iwe_buf;
- char *pos, *end, *custom, *buf;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ const u8 *bssid = NULL;
+ u16 reason_code = 0;
- pos = data;
- end = data + len;
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len >= 24) {
+ bssid = mgmt->bssid;
- 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)
+ if (drv->associated != 0 &&
+ os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
+ /*
+ * We have presumably received this deauth as a
+ * response to a clear_state_mismatch() outgoing
+ * deauth. Don't let it take us offline!
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
+ "from Unknown BSSID " MACSTR " -- ignoring",
+ MAC2STR(bssid));
return;
-
- custom = pos + IW_EV_POINT_LEN;
- if (drv->we_version_compiled > 18 &&
- (iwe->cmd == IWEVMICHAELMICFAILURE ||
- iwe->cmd == IWEVCUSTOM ||
- iwe->cmd == IWEVASSOCREQIE ||
- iwe->cmd == IWEVASSOCRESPIE ||
- iwe->cmd == IWEVPMKIDCAND)) {
- /* WE-19 removed the pointer from struct iw_point */
- char *dpos = (char *) &iwe_buf.u.data.length;
- int dlen = dpos - (char *) &iwe_buf;
- os_memcpy(dpos, pos + IW_EV_LCP_LEN,
- sizeof(struct iw_event) - dlen);
- } else {
- os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
- custom += IW_EV_POINT_OFF;
}
+ }
- switch (iwe->cmd) {
- case SIOCGIWAP:
- wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
- MACSTR,
- MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
- if (is_zero_ether_addr(
- (const u8 *) iwe->u.ap_addr.sa_data) ||
- os_memcmp(iwe->u.ap_addr.sa_data,
- "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
- 0) {
- os_free(drv->assoc_req_ies);
- drv->assoc_req_ies = NULL;
- os_free(drv->assoc_resp_ies);
- drv->assoc_resp_ies = NULL;
- wpa_supplicant_event(ctx, EVENT_DISASSOC,
- NULL);
-
- } else {
- wpa_driver_nl80211_event_assoc_ies(drv);
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
- }
- break;
- case IWEVMICHAELMICFAILURE:
- wpa_driver_nl80211_event_wireless_michaelmicfailure(
- ctx, custom, iwe->u.data.length);
- break;
- case IWEVCUSTOM:
- if (custom + iwe->u.data.length > end)
- return;
- buf = os_malloc(iwe->u.data.length + 1);
- if (buf == NULL)
- return;
- os_memcpy(buf, custom, iwe->u.data.length);
- buf[iwe->u.data.length] = '\0';
- wpa_driver_nl80211_event_wireless_custom(ctx, buf);
- os_free(buf);
- break;
- case IWEVASSOCREQIE:
- wpa_driver_nl80211_event_wireless_assocreqie(
- drv, custom, iwe->u.data.length);
- break;
- case IWEVASSOCRESPIE:
- wpa_driver_nl80211_event_wireless_assocrespie(
- drv, custom, iwe->u.data.length);
- break;
- case IWEVPMKIDCAND:
- wpa_driver_nl80211_event_wireless_pmkidcand(
- drv, custom, iwe->u.data.length);
- break;
- }
+ drv->associated = 0;
+ os_memset(&event, 0, sizeof(event));
+
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
- pos += iwe->len;
+ if (type == EVENT_DISASSOC) {
+ event.disassoc_info.addr = bssid;
+ event.disassoc_info.reason_code = reason_code;
+ } else {
+ event.deauth_info.addr = bssid;
+ event.deauth_info.reason_code = reason_code;
}
+
+ wpa_supplicant_event(drv->ctx, type, &event);
}
-static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
- void *ctx, char *buf, size_t len,
- int del)
+static void mlme_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie)
{
- union wpa_event_data event;
+ if (timed_out && addr) {
+ mlme_timeout_event(drv, cmd, addr);
+ return;
+ }
- os_memset(&event, 0, sizeof(event));
- if (len > sizeof(event.interface_status.ifname))
- len = sizeof(event.interface_status.ifname) - 1;
- os_memcpy(event.interface_status.ifname, buf, len);
- event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
- EVENT_INTERFACE_ADDED;
+ if (frame == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
+ "data", cmd);
+ return;
+ }
- wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
- del ? "DEL" : "NEW",
- event.interface_status.ifname,
- del ? "removed" : "added");
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
+ nla_data(frame), nla_len(frame));
- if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
- if (del)
- drv->if_removed = 1;
- else
- drv->if_removed = 0;
+ switch (cmd) {
+ case NL80211_CMD_AUTHENTICATE:
+ mlme_event_auth(drv, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ASSOCIATE:
+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_DEAUTHENTICATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_DISASSOCIATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ACTION:
+ mlme_event_action(drv, freq, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ACTION_TX_STATUS:
+ mlme_event_action_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
+ break;
+ default:
+ break;
}
-
- wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
}
-static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
- struct nlmsghdr *h)
+static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
{
- struct ifinfomsg *ifi;
- int attrlen, _nlmsg_len, rta_len;
- struct rtattr *attr;
-
- ifi = NLMSG_DATA(h);
-
- _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - _nlmsg_len;
- if (attrlen < 0)
- return 0;
+ union wpa_event_data data;
- attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
+ os_memset(&data, 0, sizeof(data));
+ if (tb[NL80211_ATTR_MAC]) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
+ nla_data(tb[NL80211_ATTR_MAC]),
+ nla_len(tb[NL80211_ATTR_MAC]));
+ data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
+ }
+ if (tb[NL80211_ATTR_KEY_SEQ]) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
+ nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ nla_len(tb[NL80211_ATTR_KEY_SEQ]));
+ }
+ if (tb[NL80211_ATTR_KEY_TYPE]) {
+ enum nl80211_key_type key_type =
+ nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
+ wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
+ if (key_type == NL80211_KEYTYPE_PAIRWISE)
+ data.michael_mic_failure.unicast = 1;
+ } else
+ data.michael_mic_failure.unicast = 1;
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_IFNAME) {
- if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
- == 0)
- return 1;
- else
- break;
- }
- attr = RTA_NEXT(attr, attrlen);
+ if (tb[NL80211_ATTR_KEY_IDX]) {
+ u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
+ wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
}
- return 0;
+ wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
}
-static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
- int ifindex, struct nlmsghdr *h)
+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
{
- if (drv->ifindex == ifindex)
- return 1;
-
- if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) {
- drv->ifindex = if_nametoindex(drv->ifname);
- wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
- "interface");
- wpa_driver_nl80211_finish_drv_init(drv);
- return 1;
+ if (tb[NL80211_ATTR_MAC] == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
+ "event");
+ return;
}
+ os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ drv->associated = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
+ MAC2STR(drv->bssid));
- return 0;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
}
-static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
+ int cancel_event, struct nlattr *tb[])
{
- struct ifinfomsg *ifi;
- int attrlen, _nlmsg_len, rta_len;
- struct rtattr * attr;
+ unsigned int freq, chan_type, duration;
+ union wpa_event_data data;
+ u64 cookie;
- if (len < sizeof(*ifi))
- return;
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ else
+ freq = 0;
- ifi = NLMSG_DATA(h);
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+ chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ else
+ chan_type = 0;
- if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) {
- wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
- ifi->ifi_index);
- return;
- }
+ if (tb[NL80211_ATTR_DURATION])
+ duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
+ else
+ duration = 0;
- wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
- "(%s%s%s%s)",
- drv->operstate, ifi->ifi_flags,
- (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
- (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
- (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
- /*
- * Some drivers send the association event before the operup event--in
- * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
- * fails. This will hit us when wpa_supplicant does not need to do
- * IEEE 802.1X authentication
- */
- if (drv->operstate == 1 &&
- (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
- !(ifi->ifi_flags & IFF_RUNNING))
- wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
+ if (tb[NL80211_ATTR_COOKIE])
+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ else
+ cookie = 0;
- _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+ wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
+ "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
+ cancel_event, freq, chan_type, duration,
+ (long long unsigned int) cookie,
+ cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
- attrlen = h->nlmsg_len - _nlmsg_len;
- if (attrlen < 0)
- return;
+ if (cookie != drv->remain_on_chan_cookie)
+ return; /* not for us */
- attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+ drv->pending_remain_on_chan = !cancel_event;
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_WIRELESS) {
- wpa_driver_nl80211_event_wireless(
- drv, ctx, ((char *) attr) + rta_len,
- attr->rta_len - rta_len);
- } else if (attr->rta_type == IFLA_IFNAME) {
- wpa_driver_nl80211_event_link(
- drv, ctx,
- ((char *) attr) + rta_len,
- attr->rta_len - rta_len, 0);
- }
- attr = RTA_NEXT(attr, attrlen);
- }
+ os_memset(&data, 0, sizeof(data));
+ data.remain_on_channel.freq = freq;
+ data.remain_on_channel.duration = duration;
+ wpa_supplicant_event(drv->ctx, cancel_event ?
+ EVENT_CANCEL_REMAIN_ON_CHANNEL :
+ EVENT_REMAIN_ON_CHANNEL, &data);
}
-static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+ struct nlattr *tb[])
{
- struct ifinfomsg *ifi;
- int attrlen, _nlmsg_len, rta_len;
- struct rtattr * attr;
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
-
- _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - _nlmsg_len;
- if (attrlen < 0)
- return;
+ union wpa_event_data event;
+ struct nlattr *nl;
+ int rem;
+ struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+ int freqs[MAX_REPORT_FREQS];
+ int num_freqs = 0;
- attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->aborted = aborted;
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_IFNAME) {
- wpa_driver_nl80211_event_link(
- drv, ctx,
- ((char *) attr) + rta_len,
- attr->rta_len - rta_len, 1);
+ if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
+ struct wpa_driver_scan_ssid *s =
+ &info->ssids[info->num_ssids];
+ s->ssid = nla_data(nl);
+ s->ssid_len = nla_len(nl);
+ info->num_ssids++;
+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+ break;
}
- attr = RTA_NEXT(attr, attrlen);
}
+ if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+ {
+ freqs[num_freqs] = nla_get_u32(nl);
+ num_freqs++;
+ if (num_freqs == MAX_REPORT_FREQS - 1)
+ break;
+ }
+ info->freqs = freqs;
+ info->num_freqs = num_freqs;
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
}
-static void wpa_driver_nl80211_event_receive_wext(int sock, void *eloop_ctx,
- void *sock_ctx)
+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- int max_events = 10;
+ static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+ [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+ [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+ };
+ struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+ enum nl80211_cqm_rssi_threshold_event event;
+ union wpa_event_data ed;
-try_again:
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- perror("recvfrom(netlink)");
+ if (tb[NL80211_ATTR_CQM] == NULL ||
+ nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
+ cqm_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
return;
}
- h = (struct nlmsghdr *) buf;
- while (left >= (int) sizeof(*h)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "Malformed netlink message: "
- "len=%d left=%d plen=%d",
- len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- case RTM_DELLINK:
- wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- }
-
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
- }
-
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
- "message", left);
- }
+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+ return;
+ event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
- if (--max_events > 0) {
- /*
- * Try to receive all events in one eloop call in order to
- * limit race condition on cases where AssocInfo event, Assoc
- * event, and EAPOL frames are received more or less at the
- * same time. We want to process the event messages first
- * before starting EAPOL processing.
- */
- goto try_again;
- }
-}
+ os_memset(&ed, 0, sizeof(ed));
+ if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+ "event: RSSI high");
+ ed.signal_change.above_threshold = 1;
+ } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+ "event: RSSI low");
+ ed.signal_change.above_threshold = 0;
+ } else
+ return;
-static int no_seq_check(struct nl_msg *msg, void *arg)
-{
- return NL_OK;
+ wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
}
@@ -967,13 +974,14 @@ static int process_event(struct nl_msg *msg, void *arg)
struct wpa_driver_nl80211_data *drv = arg;
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ union wpa_event_data data;
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) {
+ 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);
@@ -981,6 +989,14 @@ static int process_event(struct nl_msg *msg, void *arg)
}
}
+ if (drv->ap_scan_as_station &&
+ (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+ gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
+ wpa_driver_nl80211_set_mode(&drv->first_bss,
+ IEEE80211_MODE_AP);
+ drv->ap_scan_as_station = 0;
+ }
+
switch (gnlh->cmd) {
case NL80211_CMD_TRIGGER_SCAN:
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
@@ -990,7 +1006,7 @@ static int process_event(struct nl_msg *msg, void *arg)
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ send_scan_event(drv, 0, tb);
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
@@ -1000,11 +1016,62 @@ static int process_event(struct nl_msg *msg, void *arg)
*/
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ send_scan_event(drv, 1, tb);
+ break;
+ case NL80211_CMD_AUTHENTICATE:
+ case NL80211_CMD_ASSOCIATE:
+ case NL80211_CMD_DEAUTHENTICATE:
+ case NL80211_CMD_DISASSOCIATE:
+ case NL80211_CMD_ACTION:
+ case NL80211_CMD_ACTION_TX_STATUS:
+ mlme_event(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_CONNECT:
+ case NL80211_CMD_ROAM:
+ mlme_event_connect(drv, gnlh->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);
+ break;
+ case NL80211_CMD_MICHAEL_MIC_FAILURE:
+ mlme_event_michael_mic_failure(drv, tb);
+ break;
+ case NL80211_CMD_JOIN_IBSS:
+ mlme_event_join_ibss(drv, tb);
+ break;
+ case NL80211_CMD_REMAIN_ON_CHANNEL:
+ mlme_event_remain_on_channel(drv, 0, tb);
+ break;
+ case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
+ mlme_event_remain_on_channel(drv, 1, tb);
+ break;
+ case NL80211_CMD_NOTIFY_CQM:
+ nl80211_cqm_event(drv, tb);
break;
default:
- wpa_printf(MSG_DEBUG, "nl0211: Ignored unknown event (cmd=%d)",
- gnlh->cmd);
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", gnlh->cmd);
break;
}
@@ -1025,70 +1092,11 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
return;
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
- nl_recvmsgs(drv->nl_handle, cb);
+ nl_recvmsgs(drv->nl_handle_event, cb);
nl_cb_put(cb);
}
-static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
- const char *ifname, int *flags)
-{
- struct ifreq ifr;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
- return -1;
- }
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-/**
- * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS)
- * @drv: driver_nl80211 private data
- * @flags: Pointer to returned flags value
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv,
- int *flags)
-{
- return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags);
-}
-
-
-static int wpa_driver_nl80211_set_ifflags_ifname(
- struct wpa_driver_nl80211_data *drv,
- const char *ifname, int flags)
-{
- struct ifreq ifr;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("SIOCSIFFLAGS");
- return -1;
- }
- return 0;
-}
-
-
-/**
- * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS)
- * @drv: driver_nl80211 private data
- * @flags: New value for flags
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
- int flags)
-{
- return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags);
-}
-
-
/**
* wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
* @priv: driver_nl80211 private data
@@ -1100,13 +1108,14 @@ static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
*/
static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
char alpha2[3];
struct nl_msg *msg;
msg = nlmsg_alloc();
if (!msg)
- goto nla_put_failure;
+ return -ENOMEM;
alpha2[0] = alpha2_arg[0];
alpha2[1] = alpha2_arg[1];
@@ -1124,306 +1133,127 @@ nla_put_failure:
}
-static int wpa_driver_nl80211_set_probe_req_ie(void *priv, const u8 *ies,
- size_t ies_len)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- struct nl_msg *msg;
- int ret = -1;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_MGMT_EXTRA_IE, 0);
-
- NLA_PUT_U8(msg, NL80211_ATTR_MGMT_SUBTYPE, 4 /* ProbeReq */);
- if (ies)
- NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
-
- ret = 0;
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- return ret;
-
-nla_put_failure:
- return -ENOBUFS;
-}
-
+#ifndef HOSTAPD
+struct wiphy_info_data {
+ int max_scan_ssids;
+ int ap_supported;
+ int auth_supported;
+ int connect_supported;
+};
-#ifdef CONFIG_CLIENT_MLME
-static int nl80211_set_vif(struct wpa_driver_nl80211_data *drv,
- int drop_unencrypted, int userspace_mlme)
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
{
-#ifdef NL80211_CMD_SET_VIF
- struct nl_msg *msg;
- int ret = -1;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_VIF, 0);
-
- if (drop_unencrypted >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_VIF_DROP_UNENCRYPTED,
- drop_unencrypted);
- if (userspace_mlme >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_VIF_USERSPACE_MLME,
- userspace_mlme);
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_info_data *info = arg;
- ret = 0;
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+ info->max_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- return ret;
+ if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
+ struct nlattr *nl_mode;
+ int i;
+ nla_for_each_nested(nl_mode,
+ tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
+ if (nl_mode->nla_type == NL80211_IFTYPE_AP) {
+ info->ap_supported = 1;
+ break;
+ }
+ }
+ }
-nla_put_failure:
- return -ENOBUFS;
-#else /* NL80211_CMD_SET_VIF */
- return -1;
-#endif /* NL80211_CMD_SET_VIF */
-}
+ if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+ struct nlattr *nl_cmd;
+ int i;
+ 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;
+ }
+ }
-static int wpa_driver_nl80211_set_userspace_mlme(
- struct wpa_driver_nl80211_data *drv, int enabled)
-{
- return nl80211_set_vif(drv, -1, enabled);
+ return NL_SKIP;
}
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
- int ifidx)
+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
+ struct wiphy_info_data *info)
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_INTERFACE, 0);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
- return;
-nla_put_failure:
- wpa_printf(MSG_ERROR, "nl80211: Failed to remove interface.");
-}
-
-
-static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
- const char *ifname, enum nl80211_iftype iftype)
-{
- struct nl_msg *msg, *flags = NULL;
- int ifidx, err;
- int ret = -ENOBUFS;
-
+ os_memset(info, 0, sizeof(*info));
msg = nlmsg_alloc();
if (!msg)
return -1;
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_NEW_INTERFACE, 0);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
- NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
-
- if (iftype == NL80211_IFTYPE_MONITOR) {
- flags = nlmsg_alloc();
- if (!flags)
- goto nla_put_failure;
-
- NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
-
- err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
- nlmsg_free(flags);
-
- if (err)
- goto nla_put_failure;
- }
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret) {
- nla_put_failure:
- wpa_printf(MSG_ERROR, "nl80211: Failed to create interface %d",
- ret);
- return ret;
- }
-
- ifidx = if_nametoindex(ifname);
- if (ifidx <= 0)
- return -1;
-
- return ifidx;
-}
-
-
-static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
- int len;
- unsigned char buf[3000];
- struct ieee80211_radiotap_iterator iter;
- int ret;
- int injected = 0, failed = 0, rxflags = 0;
- struct ieee80211_rx_status rx_status;
-
- len = recv(sock, buf, sizeof(buf), 0);
- if (len < 0) {
- perror("recv");
- return;
- }
-
- if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len)) {
- wpa_printf(MSG_DEBUG, "nl80211: received invalid radiotap "
- "frame");
- return;
- }
-
- os_memset(&rx_status, 0, sizeof(rx_status));
-
- while (1) {
- ret = ieee80211_radiotap_iterator_next(&iter);
- if (ret == -ENOENT)
- break;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: received invalid "
- "radiotap frame (%d)", ret);
- return;
- }
- switch (iter.this_arg_index) {
- case IEEE80211_RADIOTAP_FLAGS:
- if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
- len -= 4;
- break;
- case IEEE80211_RADIOTAP_RX_FLAGS:
- rxflags = 1;
- break;
- case IEEE80211_RADIOTAP_TX_FLAGS:
- injected = 1;
- failed = le_to_host16((*(u16 *) iter.this_arg)) &
- IEEE80211_RADIOTAP_F_TX_FAIL;
- break;
- case IEEE80211_RADIOTAP_DATA_RETRIES:
- break;
- case IEEE80211_RADIOTAP_CHANNEL:
- /* TODO convert from freq/flags to channel number
- * rx_status.channel = XXX;
- */
- break;
- case IEEE80211_RADIOTAP_RATE:
- break;
- case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
- rx_status.ssi = *iter.this_arg;
- break;
- }
- }
+ 0, NL80211_CMD_GET_WIPHY, 0);
- if (rxflags && injected)
- return;
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
- if (!injected) {
- wpa_supplicant_sta_rx(drv->ctx, buf + iter.max_length,
- len - iter.max_length, &rx_status);
- } else if (failed) {
- /* TX failure callback */
- } else {
- /* TX success (ACK) callback */
- }
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
+ return 0;
+ msg = NULL;
+nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
}
-static int wpa_driver_nl80211_create_monitor_interface(
- struct wpa_driver_nl80211_data *drv)
+static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
{
- char buf[IFNAMSIZ];
- struct sockaddr_ll ll;
- int optval, flags;
- socklen_t optlen;
-
- os_snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname);
- buf[IFNAMSIZ - 1] = '\0';
-
- drv->monitor_ifidx =
- nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR);
-
- if (drv->monitor_ifidx < 0)
+ struct wiphy_info_data info;
+ if (wpa_driver_nl80211_get_info(drv, &info))
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 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP |
+ WPA_DRIVER_CAPA_ENC_CCMP;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
- if (wpa_driver_nl80211_get_ifflags_ifname(drv, buf, &flags) != 0 ||
- wpa_driver_nl80211_set_ifflags_ifname(drv, buf, flags | IFF_UP) !=
- 0) {
- wpa_printf(MSG_ERROR, "nl80211: Could not set interface '%s' "
- "UP", buf);
- goto error;
- }
+ drv->capa.max_scan_ssids = info.max_scan_ssids;
+ if (info.ap_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
- os_memset(&ll, 0, sizeof(ll));
- ll.sll_family = AF_PACKET;
- ll.sll_ifindex = drv->monitor_ifidx;
- drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (drv->monitor_sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
- goto error;
- }
-
- if (bind(drv->monitor_sock, (struct sockaddr *) &ll,
- sizeof(ll)) < 0) {
- perror("monitor socket bind");
- goto error;
- }
-
- optlen = sizeof(optval);
- optval = 20;
- if (setsockopt
- (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
- perror("Failed to set socket priority");
- goto error;
+ if (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;
}
- if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
- drv, NULL)) {
- wpa_printf(MSG_ERROR, "nl80211: Could not register monitor "
- "read socket");
- goto error;
- }
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+ drv->capa.max_remain_on_chan = 5000;
return 0;
-
- error:
- nl80211_remove_iface(drv, drv->monitor_ifidx);
- return -1;
}
-
-#endif /* CONFIG_CLIENT_MLME */
+#endif /* HOSTAPD */
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv,
+ void *ctx)
{
- int s, ret;
- struct sockaddr_nl local;
- struct wpa_driver_nl80211_data *drv;
+ int ret;
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ /* Initialize generic netlink and nl80211 */
drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
if (drv->nl_cb == NULL) {
@@ -1439,18 +1269,51 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
goto err2;
}
+ drv->nl_handle_event = nl_handle_alloc_cb(drv->nl_cb);
+ if (drv->nl_handle_event == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks (event)");
+ goto err2b;
+ }
+
if (genl_connect(drv->nl_handle)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
"netlink");
goto err3;
}
+ if (genl_connect(drv->nl_handle_event)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink (event)");
+ goto err3;
+ }
+
+#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;
+ }
+#endif /* CONFIG_LIBNL20 */
drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
if (drv->nl80211 == NULL) {
@@ -1461,89 +1324,212 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
ret = nl_get_multicast_id(drv, "nl80211", "scan");
if (ret >= 0)
- ret = nl_socket_add_membership(drv->nl_handle, ret);
+ ret = nl_socket_add_membership(drv->nl_handle_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;
}
- eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
+
+ ret = nl_get_multicast_id(drv, "nl80211", "mlme");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(drv->nl_handle_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;
+ }
+
+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
wpa_driver_nl80211_event_receive, drv, ctx);
+ return 0;
+
+err4:
+ nl_cache_free(drv->nl_cache_event);
+err3b:
+ nl_cache_free(drv->nl_cache);
+err3:
+ nl_handle_destroy(drv->nl_handle_event);
+err2b:
+ nl_handle_destroy(drv->nl_handle);
+err2:
+ nl_cb_put(drv->nl_cb);
+err1:
+ return -1;
+}
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_nl80211_data *drv;
+ struct netlink_config *cfg;
+ struct i802_bss *bss;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ bss = &drv->first_bss;
+ bss->drv = drv;
+ os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+ drv->monitor_ifidx = -1;
+ drv->monitor_sock = -1;
+ drv->ioctl_sock = -1;
+
+ if (wpa_driver_nl80211_init_nl(drv, ctx)) {
+ os_free(drv);
+ return NULL;
+ }
+
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket(PF_INET,SOCK_DGRAM)");
- goto err5;
+ goto failed;
}
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
- goto err6;
+ 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;
}
+ if (wpa_driver_nl80211_finish_drv_init(drv))
+ goto failed;
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- perror("bind(netlink)");
- close(s);
- goto err6;
- }
-
- eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_wext, drv,
- ctx);
- drv->wext_event_sock = s;
-
- wpa_driver_nl80211_finish_drv_init(drv);
+ return bss;
- return drv;
+failed:
+ netlink_deinit(drv->netlink);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
-err6:
- close(drv->ioctl_sock);
-err5:
genl_family_put(drv->nl80211);
-err4:
nl_cache_free(drv->nl_cache);
-err3:
nl_handle_destroy(drv->nl_handle);
-err2:
nl_cb_put(drv->nl_cb);
-err1:
+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
+
os_free(drv);
return NULL;
}
-static void
+static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
+ const u8 *match, size_t match_len)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_REGISTER_ACTION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
+
+ ret = send_and_recv(drv, drv->nl_handle_event, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register Action command "
+ "failed: ret=%d (%s)", ret, strerror(-ret));
+ wpa_hexdump(MSG_DEBUG, "nl80211: Register Action match",
+ match, match_len);
+ goto nla_put_failure;
+ }
+ ret = 0;
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+{
+ /* FT Action frames */
+ if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+ return -1;
+ else
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+
+ return 0;
+}
+
+
+static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
{
- int flags;
+ struct i802_bss *bss = &drv->first_bss;
- drv->ifindex = if_nametoindex(drv->ifname);
+ drv->ifindex = if_nametoindex(bss->ifname);
+ drv->first_bss.ifindex = drv->ifindex;
- if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
- printf("Could not configure driver to use managed mode\n");
+#ifndef HOSTAPD
+ if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
+ "use managed mode");
}
- if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
- printf("Could not get interface '%s' flags\n", drv->ifname);
- else if (!(flags & IFF_UP)) {
- if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
- printf("Could not set interface '%s' UP\n",
- drv->ifname);
- }
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+ wpa_printf(MSG_ERROR, "Could not set interface '%s' UP",
+ bss->ifname);
+ return -1;
}
- /*
- * Make sure that the driver does not have any obsolete PMKID entries.
- */
- wpa_driver_nl80211_flush_pmkid(drv);
+ if (wpa_driver_nl80211_capa(drv))
+ return -1;
- wpa_driver_nl80211_get_range(drv);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
+#endif /* HOSTAPD */
- wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+ 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.
+ */
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *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_DEL_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
}
@@ -1556,54 +1542,80 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
*/
static void wpa_driver_nl80211_deinit(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
- int flags;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
-#ifdef CONFIG_CLIENT_MLME
- if (drv->monitor_sock >= 0) {
- eloop_unregister_read_sock(drv->monitor_sock);
- close(drv->monitor_sock);
+ if (drv->added_if_into_bridge) {
+ if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname)
+ < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "interface %s from bridge %s: %s",
+ bss->ifname, drv->brname, strerror(errno));
+ }
+ if (drv->added_bridge) {
+ if (linux_br_del(drv->ioctl_sock, drv->brname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "bridge %s: %s",
+ drv->brname, strerror(errno));
}
- if (drv->monitor_ifidx > 0)
- nl80211_remove_iface(drv, drv->monitor_ifidx);
- if (drv->capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- wpa_driver_nl80211_set_userspace_mlme(drv, 0);
-#endif /* CONFIG_CLIENT_MLME */
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ nl80211_remove_monitor_interface(drv);
- /*
- * Clear possibly configured driver parameters in order to make it
- * easier to use the driver after wpa_supplicant has been terminated.
- */
- (void) wpa_driver_nl80211_set_bssid(drv,
- (u8 *) "\x00\x00\x00\x00\x00\x00");
+ if (drv->nlmode == NL80211_IFTYPE_AP)
+ wpa_driver_nl80211_del_beacon(drv);
+
+#ifdef HOSTAPD
+ if (drv->last_freq_ht) {
+ /* Clear HT flags from the driver */
+ struct hostapd_freq_params freq;
+ os_memset(&freq, 0, sizeof(freq));
+ freq.freq = drv->last_freq;
+ i802_set_freq(priv, &freq);
+ }
- wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
+ if (drv->eapol_sock >= 0) {
+ eloop_unregister_read_sock(drv->eapol_sock);
+ close(drv->eapol_sock);
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ os_free(drv->if_indices);
+#endif /* HOSTAPD */
+
+ if (drv->disable_11b_rates)
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
- eloop_unregister_read_sock(drv->wext_event_sock);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+ netlink_deinit(drv->netlink);
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
- (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+ (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
+ wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
- close(drv->wext_event_sock);
- close(drv->ioctl_sock);
- os_free(drv->assoc_req_ies);
- os_free(drv->assoc_resp_ies);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
- eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
+ 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);
nl_handle_destroy(drv->nl_handle);
+ nl_handle_destroy(drv->nl_handle_event);
nl_cb_put(drv->nl_cb);
+ eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout,
+ drv, NULL);
+
+ os_free(drv->filter_ssids);
+
os_free(drv);
}
/**
* wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
- * @eloop_ctx: Unused
+ * @eloop_ctx: Driver private data
* @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
*
* This function can be used as registered timeout when starting a scan to
@@ -1611,6 +1623,12 @@ 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) {
+ wpa_driver_nl80211_set_mode(&drv->first_bss,
+ IEEE80211_MODE_AP);
+ drv->ap_scan_as_station = 0;
+ }
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
}
@@ -1618,47 +1636,94 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
/**
* wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
- * all SSIDs (either active scan with broadcast SSID or passive
- * scan
- * @ssid_len: Length of the SSID
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
* Returns: 0 on success, -1 on failure
*/
-static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_nl80211_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = 0, timeout;
- struct nl_msg *msg, *ssids;
+ struct nl_msg *msg, *ssids, *freqs;
+ size_t i;
msg = nlmsg_alloc();
ssids = nlmsg_alloc();
- if (!msg || !ssids) {
+ 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;
+
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
NL80211_CMD_TRIGGER_SCAN, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- if (ssid && ssid_len) {
- /* Request an active scan for a specific SSID */
- NLA_PUT(ssids, 1, ssid_len, ssid);
- } else {
- /* Request an active scan for wildcard SSID */
- NLA_PUT(ssids, 1, 0, "");
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: 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: 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);
}
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
"(%s)", ret, strerror(-ret));
+#ifdef HOSTAPD
+ if (drv->nlmode == NL80211_IFTYPE_AP) {
+ /*
+ * 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))
+ goto nla_put_failure;
+
+ if (wpa_driver_nl80211_scan(drv, params)) {
+ wpa_driver_nl80211_set_mode(bss,
+ IEEE80211_MODE_AP);
+ goto nla_put_failure;
+ }
+
+ /* Restore AP mode when processing scan results */
+ drv->ap_scan_as_station = 1;
+ ret = 0;
+ } else
+ goto nla_put_failure;
+#else /* HOSTAPD */
goto nla_put_failure;
+#endif /* HOSTAPD */
}
/* Not all drivers generate "scan completed" wireless event, so try to
@@ -1666,9 +1731,9 @@ static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
timeout = 10;
if (drv->scan_complete_events) {
/*
- * The driver seems to deliver SIOCGIWSCAN events to notify
- * when scan is complete, so use longer timeout to avoid race
- * conditions with scanning and following association request.
+ * The driver seems to deliver events to notify when scan is
+ * complete, so use longer timeout to avoid race conditions
+ * with scanning and following association request.
*/
timeout = 30;
}
@@ -1681,10 +1746,62 @@ static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
nla_put_failure:
nlmsg_free(ssids);
nlmsg_free(msg);
+ nlmsg_free(freqs);
return ret;
}
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+ const u8 *end, *pos;
+
+ if (ies == NULL)
+ return NULL;
+
+ pos = ies;
+ end = ies + ies_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *ssid;
+ size_t i;
+
+ if (drv->filter_ssids == NULL)
+ return 0;
+
+ ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid == NULL)
+ return 1;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+ os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+ 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+};
+
static int bss_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1699,12 +1816,17 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
+ [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
};
- struct wpa_scan_results *res = arg;
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
- const u8 *ie;
- size_t ie_len;
+ const u8 *ie, *beacon_ie;
+ size_t ie_len, beacon_ie_len;
+ u8 *pos;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -1720,8 +1842,19 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
ie = NULL;
ie_len = 0;
}
+ if (bss[NL80211_BSS_BEACON_IES]) {
+ beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
+ beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
+ } else {
+ beacon_ie = NULL;
+ beacon_ie_len = 0;
+ }
- r = os_zalloc(sizeof(*r) + ie_len);
+ if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ ie ? ie_len : beacon_ie_len))
+ return NL_SKIP;
+
+ r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
if (r == NULL)
return NL_SKIP;
if (bss[NL80211_BSS_BSSID])
@@ -1733,15 +1866,44 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
if (bss[NL80211_BSS_CAPABILITY])
r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
- if (bss[NL80211_BSS_SIGNAL_UNSPEC])
- r->qual = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
- if (bss[NL80211_BSS_SIGNAL_MBM])
+ r->flags |= WPA_SCAN_NOISE_INVALID;
+ if (bss[NL80211_BSS_SIGNAL_MBM]) {
r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+ r->level /= 100; /* mBm to dBm */
+ 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;
+ } else
+ r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
if (bss[NL80211_BSS_TSF])
r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ if (bss[NL80211_BSS_SEEN_MS_AGO])
+ r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
r->ie_len = ie_len;
- if (ie)
- os_memcpy(r + 1, ie, ie_len);
+ pos = (u8 *) (r + 1);
+ if (ie) {
+ os_memcpy(pos, ie, ie_len);
+ pos += ie_len;
+ }
+ r->beacon_ie_len = beacon_ie_len;
+ if (beacon_ie)
+ os_memcpy(pos, beacon_ie, beacon_ie_len);
+
+ if (bss[NL80211_BSS_STATUS]) {
+ enum nl80211_bss_status status;
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ switch (status) {
+ case NL80211_BSS_STATUS_AUTHENTICATED:
+ r->flags |= WPA_SCAN_AUTHENTICATED;
+ break;
+ case NL80211_BSS_STATUS_ASSOCIATED:
+ r->flags |= WPA_SCAN_ASSOCIATED;
+ break;
+ default:
+ break;
+ }
+ }
tmp = os_realloc(res->res,
(res->num + 1) * sizeof(struct wpa_scan_res *));
@@ -1756,22 +1918,95 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
}
-/**
- * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * Returns: Scan results on success, -1 on failure
- */
+static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr)
+{
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
+ "mismatch (" MACSTR ")", MAC2STR(addr));
+ wpa_driver_nl80211_mlme(drv, addr,
+ NL80211_CMD_DEAUTHENTICATE,
+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+ }
+}
+
+
+static void wpa_driver_nl80211_check_bss_status(
+ struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
+{
+ size_t i;
+
+ for (i = 0; i < res->num; i++) {
+ struct wpa_scan_res *r = res->res[i];
+ if (r->flags & WPA_SCAN_AUTHENTICATED) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+ "indicates BSS status with " MACSTR
+ " as authenticated",
+ MAC2STR(r->bssid));
+ if (drv->nlmode == NL80211_IFTYPE_STATION &&
+ os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
+ os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
+ 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
+ " in local state (auth=" MACSTR
+ " assoc=" MACSTR ")",
+ MAC2STR(drv->auth_bssid),
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ }
+ }
+
+ if (r->flags & WPA_SCAN_ASSOCIATED) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+ "indicate BSS status with " MACSTR
+ " as associated",
+ MAC2STR(r->bssid));
+ if (drv->nlmode == NL80211_IFTYPE_STATION &&
+ !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 &&
+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
+ 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Local state "
+ "(associated with " MACSTR ") does "
+ "not match with BSS state",
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ clear_state_mismatch(drv, drv->bssid);
+ }
+ }
+ }
+}
+
+
+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 *
-wpa_driver_nl80211_get_scan_results(void *priv)
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
{
- struct wpa_driver_nl80211_data *drv = priv;
struct nl_msg *msg;
struct wpa_scan_results *res;
int ret;
+ struct nl80211_bss_info_arg arg;
res = os_zalloc(sizeof(*res));
if (res == NULL)
- return 0;
+ return NULL;
msg = nlmsg_alloc();
if (!msg)
goto nla_put_failure;
@@ -1780,7 +2015,9 @@ wpa_driver_nl80211_get_scan_results(void *priv)
NL80211_CMD_GET_SCAN, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
+ arg.drv = drv;
+ arg.res = res;
+ 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)",
@@ -1796,639 +2033,465 @@ nla_put_failure:
}
-static int wpa_driver_nl80211_get_range(void *priv)
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+static struct wpa_scan_results *
+wpa_driver_nl80211_get_scan_results(void *priv)
{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iw_range *range;
- struct iwreq iwr;
- int minlen;
- size_t buflen;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct wpa_scan_results *res;
- /*
- * Use larger buffer than struct iw_range in order to allow the
- * structure to grow in the future.
- */
- buflen = sizeof(struct iw_range) + 500;
- range = os_zalloc(buflen);
- if (range == NULL)
- return -1;
+ res = nl80211_get_scan_results(drv);
+ if (res)
+ wpa_driver_nl80211_check_bss_status(drv, res);
+ return res;
+}
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) range;
- iwr.u.data.length = buflen;
- minlen = ((char *) &range->enc_capa) - (char *) range +
- sizeof(range->enc_capa);
+static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+ struct wpa_scan_results *res;
+ size_t i;
- if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
- os_free(range);
- return -1;
- } else if (iwr.u.data.length >= minlen &&
- range->we_version_compiled >= 18) {
- wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
- "WE(source)=%d enc_capa=0x%x",
- range->we_version_compiled,
- range->we_version_source,
- range->enc_capa);
- drv->has_capability = 1;
- drv->we_version_compiled = range->we_version_compiled;
- if (range->enc_capa & IW_ENC_CAPA_WPA) {
- drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
- }
- if (range->enc_capa & IW_ENC_CAPA_WPA2) {
- drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- }
- drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
- WPA_DRIVER_CAPA_ENC_WEP104;
- if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
- drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
- if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
- drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
- drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
- WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
- wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x",
- drv->capa.key_mgmt, drv->capa.enc);
- } else {
- wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
- "assuming WPA is not supported");
+ res = nl80211_get_scan_results(drv);
+ if (res == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
+ return;
}
- os_free(range);
- return 0;
-}
-
-
-static int wpa_driver_nl80211_set_wpa(void *priv, int enabled)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+ for (i = 0; i < res->num; i++) {
+ struct wpa_scan_res *r = res->res[i];
+ wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
+ (int) i, (int) res->num, MAC2STR(r->bssid),
+ r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ }
- return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
- enabled);
+ wpa_scan_results_free(res);
}
-static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
- const u8 *addr, int key_idx,
- int set_tx, const u8 *seq,
- size_t seq_len,
+static int wpa_driver_nl80211_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_nl80211_data *drv = priv;
- int err;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ifindex = if_nametoindex(ifname);
struct nl_msg *msg;
+ int ret;
- wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
- "seq_len=%lu key_len=%lu",
- __func__, alg, addr, key_idx, set_tx,
+ wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+ "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);
msg = nlmsg_alloc();
- if (msg == NULL)
- return -1;
+ 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);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_KEY, 0);
} else {
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_NEW_KEY, 0);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_KEY, 0);
NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
switch (alg) {
case WPA_ALG_WEP:
if (key_len == 5)
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- 0x000FAC01);
+ WLAN_CIPHER_SUITE_WEP40);
else
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- 0x000FAC05);
+ WLAN_CIPHER_SUITE_WEP104);
break;
case WPA_ALG_TKIP:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_TKIP);
break;
case WPA_ALG_CCMP:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_CCMP);
break;
-#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_AES_CMAC);
break;
-#endif /* CONFIG_IEEE80211W */
default:
+ wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+ "algorithm %d", __func__, alg);
nlmsg_free(msg);
return -1;
}
}
+ if (seq && seq_len)
+ NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
+
if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
{
wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
}
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
- err = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (err) {
- wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
- return -1;
- }
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
+ ret = 0;
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+ ret, strerror(-ret));
- if (set_tx && alg != WPA_ALG_NONE) {
- msg = nlmsg_alloc();
- if (msg == NULL)
- return -1;
+ /*
+ * If we failed or don't need to set the default TX key (below),
+ * we're done here.
+ */
+ if (ret || !set_tx || alg == WPA_ALG_NONE)
+ return ret;
+#ifdef HOSTAPD
+ if (addr)
+ return ret;
+#else /* HOSTAPD */
+ if (drv->nlmode == NL80211_IFTYPE_AP && addr)
+ return ret;
+#endif /* HOSTAPD */
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_KEY, 0);
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
- err = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (err) {
- wpa_printf(MSG_DEBUG, "nl80211: set default key "
- "failed; err=%d", err);
- return -1;
- }
- }
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_KEY, 0);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ if (alg == WPA_ALG_IGTK)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
+ else
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
- return 0;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == -ENOENT)
+ ret = 0;
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
+ "err=%d %s)", ret, strerror(-ret));
+ return ret;
nla_put_failure:
return -ENOBUFS;
}
-static int wpa_driver_nl80211_set_countermeasures(void *priv,
- int enabled)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_TKIP_COUNTERMEASURES,
- enabled);
-}
-
-
-static int wpa_driver_nl80211_set_drop_unencrypted(void *priv,
- int enabled)
+static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
+ int key_idx, int defkey,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
{
- struct wpa_driver_nl80211_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- drv->use_crypt = enabled;
- return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
- enabled);
-}
+ struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+ if (!key_attr)
+ return -1;
+ if (defkey && alg == WPA_ALG_IGTK)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
+ else if (defkey)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
- const u8 *addr, int cmd, int reason_code)
-{
- struct iwreq iwr;
- struct iw_mlme mlme;
- int ret = 0;
+ NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- os_memset(&mlme, 0, sizeof(mlme));
- mlme.cmd = cmd;
- mlme.reason_code = reason_code;
- mlme.addr.sa_family = ARPHRD_ETHER;
- os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
- iwr.u.data.pointer = (caddr_t) &mlme;
- iwr.u.data.length = sizeof(mlme);
-
- if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
- perror("ioctl[SIOCSIWMLME]");
- ret = -1;
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP40);
+ else
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP104);
+ break;
+ case WPA_ALG_TKIP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
+ break;
+ case WPA_ALG_CCMP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
+ break;
+ case WPA_ALG_IGTK:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_AES_CMAC);
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+ "algorithm %d", __func__, alg);
+ return -1;
}
- return ret;
-}
-
+ if (seq && seq_len)
+ NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
-static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
-}
+ NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
+ nla_nest_end(msg, key_attr);
-static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DISASSOC,
- reason_code);
+ return 0;
+ nla_put_failure:
+ return -1;
}
-static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie,
- size_t ie_len)
+static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
{
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
+ int i, privacy = 0;
+ struct nlattr *nl_keys, *nl_key;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) ie;
- iwr.u.data.length = ie_len;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
- perror("ioctl[SIOCSIWGENIE]");
- ret = -1;
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ privacy = 1;
+ break;
}
-
- return ret;
-}
-
-
-static int wpa_driver_nl80211_cipher2wext(int cipher)
-{
- switch (cipher) {
- case CIPHER_NONE:
- return IW_AUTH_CIPHER_NONE;
- case CIPHER_WEP40:
- return IW_AUTH_CIPHER_WEP40;
- case CIPHER_TKIP:
- return IW_AUTH_CIPHER_TKIP;
- case CIPHER_CCMP:
- return IW_AUTH_CIPHER_CCMP;
- case CIPHER_WEP104:
- return IW_AUTH_CIPHER_WEP104;
- default:
+ if (!privacy)
return 0;
- }
-}
+ NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
-static int wpa_driver_nl80211_keymgmt2wext(int keymgmt)
-{
- switch (keymgmt) {
- case KEY_MGMT_802_1X:
- case KEY_MGMT_802_1X_NO_WPA:
- return IW_AUTH_KEY_MGMT_802_1X;
- case KEY_MGMT_PSK:
- return IW_AUTH_KEY_MGMT_PSK;
- default:
- return 0;
- }
-}
-
+ nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
+ if (!nl_keys)
+ goto nla_put_failure;
-static int
-wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv,
- struct wpa_driver_associate_params *params)
-{
- struct iwreq iwr;
- int ret = 0;
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
- wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
- "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+ nl_key = nla_nest_start(msg, i);
+ if (!nl_key)
+ goto nla_put_failure;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- /* Just changing mode, not actual keys */
- iwr.u.encoding.flags = 0;
- iwr.u.encoding.pointer = (caddr_t) NULL;
- iwr.u.encoding.length = 0;
+ NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+ params->wep_key[i]);
+ if (params->wep_key_len[i] == 5)
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP40);
+ else
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP104);
- /*
- * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
- * different things. Here they are used to indicate Open System vs.
- * Shared Key authentication algorithm. However, some drivers may use
- * them to select between open/restricted WEP encrypted (open = allow
- * both unencrypted and encrypted frames; restricted = only allow
- * encrypted frames).
- */
+ NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
- if (!drv->use_crypt) {
- iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
- } else {
- if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
- iwr.u.encoding.flags |= IW_ENCODE_OPEN;
- if (params->auth_alg & AUTH_ALG_SHARED_KEY)
- iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
- }
+ if (i == params->wep_tx_keyidx)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
- if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE]");
- ret = -1;
+ nla_nest_end(msg, nl_key);
}
+ nla_nest_end(msg, nl_keys);
- return ret;
-}
-
-
-static int wpa_driver_nl80211_associate(
- void *priv, struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- int ret = 0;
- int allow_unencrypted_eapol;
- int value;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- /*
- * If the driver did not support SIOCSIWAUTH, fallback to
- * SIOCSIWENCODE here.
- */
- if (drv->auth_alg_fallback &&
- wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0)
- ret = -1;
-
- if (!params->bssid &&
- wpa_driver_nl80211_set_bssid(drv, NULL) < 0)
- ret = -1;
-
- /* TODO: should consider getting wpa version and cipher/key_mgmt suites
- * from configuration, not from here, where only the selected suite is
- * available */
- if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
- < 0)
- ret = -1;
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
- value = IW_AUTH_WPA_VERSION_DISABLED;
- else if (params->wpa_ie[0] == WLAN_EID_RSN)
- value = IW_AUTH_WPA_VERSION_WPA2;
- else
- value = IW_AUTH_WPA_VERSION_WPA;
- if (wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_WPA_VERSION, value) < 0)
- ret = -1;
- value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite);
- if (wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_CIPHER_PAIRWISE, value) < 0)
- ret = -1;
- value = wpa_driver_nl80211_cipher2wext(params->group_suite);
- if (wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_CIPHER_GROUP, value) < 0)
- ret = -1;
- value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite);
- if (wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_KEY_MGMT, value) < 0)
- ret = -1;
- value = params->key_mgmt_suite != KEY_MGMT_NONE ||
- params->pairwise_suite != CIPHER_NONE ||
- params->group_suite != CIPHER_NONE ||
- params->wpa_ie_len;
- if (wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_PRIVACY_INVOKED, value) < 0)
- ret = -1;
-
- /* Allow unencrypted EAPOL messages even if pairwise keys are set when
- * not using WPA. IEEE 802.1X specifies that these frames are not
- * encrypted, but WPA encrypts them when pairwise keys are in use. */
- if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
- params->key_mgmt_suite == KEY_MGMT_PSK)
- allow_unencrypted_eapol = 0;
- else
- allow_unencrypted_eapol = 1;
-
- if (wpa_driver_nl80211_set_auth_param(drv,
- IW_AUTH_RX_UNENCRYPTED_EAPOL,
- allow_unencrypted_eapol) < 0)
- ret = -1;
- if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0)
- ret = -1;
- if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0)
- ret = -1;
- if (params->bssid &&
- wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- int algs = 0, res;
-
- if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
- algs |= IW_AUTH_ALG_OPEN_SYSTEM;
- if (auth_alg & AUTH_ALG_SHARED_KEY)
- algs |= IW_AUTH_ALG_SHARED_KEY;
- if (auth_alg & AUTH_ALG_LEAP)
- algs |= IW_AUTH_ALG_LEAP;
- if (algs == 0) {
- /* at least one algorithm should be set */
- algs = IW_AUTH_ALG_OPEN_SYSTEM;
- }
+ return 0;
- res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
- algs);
- drv->auth_alg_fallback = res == -2;
- return res;
+nla_put_failure:
+ return -ENOBUFS;
}
-/**
- * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change)
{
- struct wpa_driver_nl80211_data *drv = priv;
- int ret = -1, flags;
+ int ret = -1;
struct nl_msg *msg;
msg = nlmsg_alloc();
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_INTERFACE, 0);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
+
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
- mode ? NL80211_IFTYPE_ADHOC : NL80211_IFTYPE_STATION);
+ NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (local_state_change)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (!ret)
- return 0;
- else
- goto try_again;
-
-nla_put_failure:
- wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)",
- ret, strerror(-ret));
- return -1;
-
-try_again:
- /* mac80211 doesn't allow mode changes while the device is up, so
- * take the device down, try to set the mode again, and bring the
- * device back up.
- */
- if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) {
- (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
-
- /* Try to set the mode again while the interface is down */
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_INTERFACE, 0);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
- mode ? NL80211_IFTYPE_ADHOC :
- NL80211_IFTYPE_STATION);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret) {
- wpa_printf(MSG_ERROR, "Failed to set interface %s "
- "mode(try_again): %d (%s)",
- drv->ifname, ret, strerror(-ret));
- }
-
- /* Ignore return value of get_ifflags to ensure that the device
- * is always up like it was before this function was called.
- */
- (void) wpa_driver_nl80211_get_ifflags(drv, &flags);
- (void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
}
+ ret = 0;
+nla_put_failure:
+ nlmsg_free(msg);
return ret;
}
-static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv,
- u32 cmd, const u8 *bssid, const u8 *pmkid)
+static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int reason_code)
{
- struct iwreq iwr;
- struct iw_pmksa pmksa;
- int ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- os_memset(&pmksa, 0, sizeof(pmksa));
- pmksa.cmd = cmd;
- pmksa.bssid.sa_family = ARPHRD_ETHER;
- if (bssid)
- os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
- if (pmkid)
- os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
- iwr.u.data.pointer = (caddr_t) &pmksa;
- iwr.u.data.length = sizeof(pmksa);
-
- if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
- if (errno != EOPNOTSUPP)
- perror("ioctl[SIOCSIWPMKSA]");
- ret = -1;
- }
-
- return ret;
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ drv->associated = 0;
+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+ reason_code, 0);
}
-static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid,
- const u8 *pmkid)
+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
{
- struct wpa_driver_nl80211_data *drv = priv;
- return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+ return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ drv->associated = 0;
+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
+ reason_code, 0);
}
-static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid,
- const u8 *pmkid)
+static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
+ int reason_code)
{
- struct wpa_driver_nl80211_data *drv = priv;
- return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+ return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ drv->associated = 0;
+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
+ reason_code, 0);
}
-static int wpa_driver_nl80211_flush_pmkid(void *priv)
+static int wpa_driver_nl80211_authenticate(
+ void *priv, struct wpa_driver_auth_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
- return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
-}
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, i;
+ struct nl_msg *msg;
+ enum nl80211_auth_type type;
+ int count = 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);
-static int wpa_driver_nl80211_get_capa(void *priv,
- struct wpa_driver_capa *capa)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- if (!drv->has_capability)
+ if (wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
return -1;
- os_memcpy(capa, &drv->capa, sizeof(*capa));
- return 0;
-}
+retry:
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
-static int wpa_driver_nl80211_set_operstate(void *priv, int state)
-{
- struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
+ drv->ifindex);
- wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
- __func__, drv->operstate, state, state ? "UP" : "DORMANT");
- drv->operstate = state;
- return wpa_driver_nl80211_send_oper_ifla(
- drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
-}
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_AUTHENTICATE, 0);
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+ NULL, i,
+ i == params->wep_tx_keyidx, NULL, 0,
+ params->wep_key[i],
+ params->wep_key_len[i]);
+ if (params->wep_tx_keyidx != i)
+ continue;
+ if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
+ params->wep_key[i], params->wep_key_len[i])) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
-#ifdef CONFIG_CLIENT_MLME
-static int wpa_driver_nl80211_open_mlme(struct wpa_driver_nl80211_data *drv)
-{
- if (wpa_driver_nl80211_set_userspace_mlme(drv, 1) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to enable userspace "
- "MLME");
- return -1;
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
}
- if (wpa_driver_nl80211_create_monitor_interface(drv)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to create monitor "
- "interface");
- return -1;
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ }
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->ssid, params->ssid_len);
+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid);
+ }
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
+ if (params->ie)
+ NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+ if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+ type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+ type = NL80211_AUTHTYPE_SHARED_KEY;
+ else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+ type = NL80211_AUTHTYPE_NETWORK_EAP;
+ else if (params->auth_alg & WPA_AUTH_ALG_FT)
+ type = NL80211_AUTHTYPE_FT;
+ else
+ goto nla_put_failure;
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+ if (params->local_state_change) {
+ wpa_printf(MSG_DEBUG, " * Local state change only");
+ NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
}
- return 0;
-}
-#endif /* CONFIG_CLIENT_MLME */
-
-
-static int wpa_driver_nl80211_set_param(void *priv, const char *param)
-{
-#ifdef CONFIG_CLIENT_MLME
- struct wpa_driver_nl80211_data *drv = priv;
-
- if (param == NULL)
- return 0;
-
- wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
-
- if (os_strstr(param, "use_mlme=1")) {
- wpa_printf(MSG_DEBUG, "nl80211: Using user space MLME");
- drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
- if (wpa_driver_nl80211_open_mlme(drv))
- return -1;
+ 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));
+ count++;
+ if (ret == -EALREADY && count == 1 && params->bssid &&
+ !params->local_state_change) {
+ /*
+ * mac80211 does not currently accept new
+ * authentication if we are already authenticated. As a
+ * workaround, force deauthentication and try again.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
+ "after forced deauthentication");
+ wpa_driver_nl80211_deauthenticate(
+ bss, params->bssid,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ nlmsg_free(msg);
+ goto retry;
+ }
+ goto nla_put_failure;
}
-#endif /* CONFIG_CLIENT_MLME */
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
+ "successfully");
- return 0;
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
}
-#ifdef CONFIG_CLIENT_MLME
-
struct phy_info_arg {
u16 *num_modes;
- struct wpa_hw_modes *modes;
+ struct hostapd_hw_modes *modes;
};
-
static int phy_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
@@ -2438,27 +2501,26 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
- static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1]
- = {
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
};
struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
- [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
- { .type = NLA_FLAG },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
};
struct nlattr *nl_band;
struct nlattr *nl_freq;
struct nlattr *nl_rate;
int rem_band, rem_freq, rem_rate;
- struct wpa_hw_modes *mode;
+ struct hostapd_hw_modes *mode;
int idx, mode_is_set;
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -2467,10 +2529,8 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
return NL_SKIP;
- nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS],
- rem_band) {
- mode = os_realloc(phy_info->modes,
- (*phy_info->num_modes + 1) * sizeof(*mode));
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
if (!mode)
return NL_SKIP;
phy_info->modes = mode;
@@ -2478,108 +2538,123 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
mode_is_set = 0;
mode = &phy_info->modes[*(phy_info->num_modes)];
- os_memset(mode, 0, sizeof(*mode));
+ memset(mode, 0, sizeof(*mode));
*(phy_info->num_modes) += 1;
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
nla_len(nl_band), NULL);
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
- rem_freq) {
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_freq), nla_len(nl_freq),
- freq_policy);
+ if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
+ mode->ht_capab = nla_get_u16(
+ tb_band[NL80211_BAND_ATTR_HT_CAPA]);
+ }
+
+ if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
+ mode->a_mpdu_params |= nla_get_u8(
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
+ 0x03;
+ }
+
+ if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
+ mode->a_mpdu_params |= nla_get_u8(
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
+ 2;
+ }
+
+ if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
+ nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
+ u8 *mcs;
+ mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+ os_memcpy(mode->mcs_set, mcs, 16);
+ }
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
continue;
mode->num_channels++;
}
- mode->channels = os_zalloc(mode->num_channels *
- sizeof(struct wpa_channel_data));
+ mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
if (!mode->channels)
return NL_SKIP;
idx = 0;
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
- rem_freq) {
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_freq), nla_len(nl_freq),
- freq_policy);
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
continue;
- mode->channels[idx].freq = nla_get_u32(
- tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
- mode->channels[idx].flag |= WPA_CHAN_W_SCAN |
- WPA_CHAN_W_ACTIVE_SCAN |
- WPA_CHAN_W_IBSS;
+ mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ mode->channels[idx].flag = 0;
if (!mode_is_set) {
/* crude heuristic */
if (mode->channels[idx].freq < 4000)
- mode->mode = WPA_MODE_IEEE80211B;
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
else
- mode->mode = WPA_MODE_IEEE80211A;
+ mode->mode = HOSTAPD_MODE_IEEE80211A;
mode_is_set = 1;
}
/* crude heuristic */
- if (mode->channels[idx].freq < 4000) {
+ if (mode->channels[idx].freq < 4000)
if (mode->channels[idx].freq == 2484)
mode->channels[idx].chan = 14;
else
- mode->channels[idx].chan =
- (mode->channels[idx].freq -
- 2407) / 5;
- } else
- mode->channels[idx].chan =
- mode->channels[idx].freq / 5 - 1000;
+ mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
+ else
+ mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- mode->channels[idx].flag &= ~WPA_CHAN_W_SCAN;
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_DISABLED;
if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
- mode->channels[idx].flag &=
- ~WPA_CHAN_W_ACTIVE_SCAN;
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_PASSIVE_SCAN;
if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
- mode->channels[idx].flag &= ~WPA_CHAN_W_IBSS;
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_NO_IBSS;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_RADAR;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+ !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ mode->channels[idx].max_tx_power =
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+
idx++;
}
- nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES],
- rem_rate) {
- nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
- nla_data(nl_rate), nla_len(nl_rate),
- rate_policy);
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+ nla_len(nl_rate), rate_policy);
if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
continue;
mode->num_rates++;
}
- mode->rates = os_zalloc(mode->num_rates *
- sizeof(struct wpa_rate_data));
+ mode->rates = os_zalloc(mode->num_rates * sizeof(int));
if (!mode->rates)
return NL_SKIP;
idx = 0;
- nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES],
- rem_rate) {
- nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
- nla_data(nl_rate), nla_len(nl_rate),
- rate_policy);
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+ nla_len(nl_rate), rate_policy);
if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
continue;
- mode->rates[idx].rate = nla_get_u32(
- tb_rate[NL80211_BITRATE_ATTR_RATE]);
+ mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
/* crude heuristic */
- if (mode->mode == WPA_MODE_IEEE80211B &&
- mode->rates[idx].rate > 200)
- mode->mode = WPA_MODE_IEEE80211G;
-
- if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE])
- mode->rates[idx].flags |= WPA_RATE_PREAMBLE2;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
+ mode->rates[idx] > 200)
+ mode->mode = HOSTAPD_MODE_IEEE80211G;
idx++;
}
@@ -2588,11 +2663,85 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
return NL_SKIP;
}
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
+{
+ u16 m;
+ struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+ int i, mode11g_idx = -1;
+
+ /* If only 802.11g mode is included, use it to construct matching
+ * 802.11b mode data. */
+
+ for (m = 0; m < *num_modes; m++) {
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
+ return modes; /* 802.11b already included */
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+ mode11g_idx = m;
+ }
+
+ if (mode11g_idx < 0)
+ return modes; /* 2.4 GHz band not supported at all */
+
+ nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+ if (nmodes == NULL)
+ return modes; /* Could not add 802.11b mode */
+
+ mode = &nmodes[*num_modes];
+ os_memset(mode, 0, sizeof(*mode));
+ (*num_modes)++;
+ modes = nmodes;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+
+ mode11g = &modes[mode11g_idx];
+ mode->num_channels = mode11g->num_channels;
+ mode->channels = os_malloc(mode11g->num_channels *
+ sizeof(struct hostapd_channel_data));
+ if (mode->channels == NULL) {
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+ os_memcpy(mode->channels, mode11g->channels,
+ mode11g->num_channels * sizeof(struct hostapd_channel_data));
+
+ mode->num_rates = 0;
+ mode->rates = os_malloc(4 * sizeof(int));
+ if (mode->rates == NULL) {
+ os_free(mode->channels);
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+
+ for (i = 0; i < mode11g->num_rates; i++) {
+ if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
+ mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
+ continue;
+ mode->rates[mode->num_rates] = mode11g->rates[i];
+ mode->num_rates++;
+ if (mode->num_rates == 4)
+ break;
+ }
+
+ if (mode->num_rates == 0) {
+ os_free(mode->channels);
+ os_free(mode->rates);
+ (*num_modes)--;
+ return modes; /* No 802.11b rates */
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
+ "information");
-static struct wpa_hw_modes *
+ return modes;
+}
+
+
+static struct hostapd_hw_modes *
wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct phy_info_arg result = {
.num_modes = num_modes,
@@ -2612,28 +2761,21 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
- return result.modes;
-nla_put_failure:
+ return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+ nla_put_failure:
return NULL;
}
-static int wpa_driver_nl80211_set_channel(void *priv, wpa_hw_mode phymode,
- int chan, int freq)
-{
- return wpa_driver_nl80211_set_freq(priv, freq);
-}
-
-
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len)
+static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt)
{
- struct wpa_driver_nl80211_data *drv = priv;
__u8 rtap_hdr[] = {
0x00, 0x00, /* radiotap version */
0x0e, 0x00, /* radiotap length */
0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
- 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */
+ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
0x00, /* padding */
0x00, 0x00, /* RX and TX flags to indicate that */
0x00, 0x00, /* this is the injected frame directly */
@@ -2645,7 +2787,7 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
},
{
.iov_base = (void *) data,
- .iov_len = data_len,
+ .iov_len = len,
}
};
struct msghdr msg = {
@@ -2658,22 +2800,138 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
.msg_flags = 0,
};
- if (sendmsg(drv->monitor_sock, &msg, 0) < 0) {
- perror("send[MLME]");
+ if (encrypt)
+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+ return sendmsg(drv->monitor_sock, &msg, 0);
+}
+
+
+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ieee80211_mgmt *mgmt;
+ int encrypt = 1;
+ u16 fc;
+
+ mgmt = (struct ieee80211_mgmt *) data;
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ /*
+ * Only one of the authentication frame types is encrypted.
+ * In order for static WEP encryption to work properly (i.e.,
+ * to not encrypt the frame), we need to tell mac80211 about
+ * the frames that must not be encrypted.
+ */
+ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
+ if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
+ encrypt = 0;
+ }
+
+ return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+}
+
+
+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)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ u8 cmd = NL80211_CMD_NEW_BEACON;
+ int ret;
+ int beacon_set;
+ int ifindex = if_nametoindex(bss->ifname);
+
+ beacon_set = bss->beacon_set;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
+ beacon_set);
+ 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);
+ 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);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
+ ret, strerror(-ret));
+ } else {
+ bss->beacon_set = 1;
+ }
+ return ret;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
+ int freq, int ht_enabled,
+ int sec_channel_offset)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ 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);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ if (ht_enabled) {
+ switch (sec_channel_offset) {
+ case -1:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT40MINUS);
+ break;
+ case 1:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT40PLUS);
+ break;
+ default:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT20);
+ break;
+ }
}
- return 0;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
+ "%d (%s)", freq, ret, strerror(-ret));
+nla_put_failure:
+ return -1;
}
-static int wpa_driver_nl80211_mlme_add_sta(void *priv, const u8 *addr,
- const u8 *supp_rates,
- size_t supp_rates_len)
+static int wpa_driver_nl80211_sta_add(void *priv,
+ struct hostapd_sta_add_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret = -ENOBUFS;
msg = nlmsg_alloc();
if (!msg)
@@ -2682,50 +2940,2392 @@ static int wpa_driver_nl80211_mlme_add_sta(void *priv, const u8 *addr,
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
0, NL80211_CMD_NEW_STATION, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, 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->ht_capabilities) {
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
+ sizeof(*params->ht_capabilities),
+ params->ht_capabilities);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
+ "result: %d (%s)", ret, strerror(-ret));
+ if (ret == -EEXIST)
+ ret = 0;
+ nla_put_failure:
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(bss->ifname));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == -ENOENT)
+ return 0;
+ return ret;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
+ int ifidx)
+{
+ struct nl_msg *msg;
+
+ 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);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return;
+ nla_put_failure:
+ wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
+}
+
+
+static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
+ const char *ifname,
+ enum nl80211_iftype iftype,
+ const u8 *addr, int wds)
+{
+ struct nl_msg *msg, *flags = NULL;
+ int ifidx;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_INTERFACE, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+ if (iftype == NL80211_IFTYPE_MONITOR) {
+ int err;
+
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto nla_put_failure;
+
+ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+
+ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
+
+ nlmsg_free(flags);
+
+ if (err)
+ goto nla_put_failure;
+ } else if (wds) {
+ NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ nla_put_failure:
+ wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
+ ifname, ret, strerror(-ret));
+ return ret;
+ }
+
+ ifidx = if_nametoindex(ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
+ ifname, ifidx);
+
+ 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)) {
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+
+ return ifidx;
+}
+
+
+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds)
+{
+ int ret;
+
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+
+ /* if error occured and interface exists already */
+ if (ret == -ENFILE && if_nametoindex(ifname)) {
+ wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
+
+ /* Try to remove the interface that was already there. */
+ nl80211_remove_iface(drv, if_nametoindex(ifname));
+
+ /* Try to create the interface again */
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
+ wds);
+ }
+
+ if (ret >= 0 && drv->disable_11b_rates)
+ nl80211_disable_11b_rates(drv, ret, 1);
+
+ return ret;
+}
+
+
+static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = buf;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ok;
+ wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len)
+{
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.frame = buf;
+ event.rx_from_unknown.len = len;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void handle_frame(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len, int datarate, int ssi_signal)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case WLAN_FC_TYPE_MGMT:
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.datarate = datarate;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* can only get here with PS-Poll frames */
+ wpa_printf(MSG_DEBUG, "CTRL");
+ from_unknown_sta(drv, buf, len);
+ break;
+ case WLAN_FC_TYPE_DATA:
+ from_unknown_sta(drv, buf, len);
+ break;
+ }
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ int datarate = 0, ssi_signal = 0;
+ int injected = 0, failed = 0, rxflags = 0;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (drv->nlmode == NL80211_IFTYPE_STATION && !drv->probe_req_report) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore monitor interface "
+ "frame since Probe Request reporting is disabled");
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
+ printf("received invalid radiotap frame\n");
+ return;
+ }
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ printf("received invalid radiotap frame (%d)\n", ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO: convert from freq/flags to channel number */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ datarate = *iter.this_arg * 5;
+ break;
+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+ ssi_signal = *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected)
+ handle_frame(drv, buf + iter.max_length,
+ len - iter.max_length, datarate, ssi_signal);
+ else
+ handle_tx_callback(drv->ctx, buf + iter.max_length,
+ len - iter.max_length, !failed);
+}
+
+
+/*
+ * we post-process the filter code later and rewrite
+ * this to the offset to the last instruction
+ */
+#define PASS 0xFF
+#define FAIL 0xFE
+
+static struct sock_filter msock_filter_insns[] = {
+ /*
+ * do a little-endian load of the radiotap length field
+ */
+ /* load lower byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
+ /* put it into X (== index register) */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+ /* load upper byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
+ /* left-shift it by 8 */
+ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
+ /* or with X */
+ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
+ /* put result into X */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+
+ /*
+ * Allow management frames through, this also gives us those
+ * management frames that we sent ourselves with status
+ */
+ /* load the lower byte of the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off frame type and version */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
+ /* accept frame if it's both 0, fall through otherwise */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
+
+ /*
+ * TODO: add a bit to radiotap RX flags that indicates
+ * that the sending station is not associated, then
+ * add a filter here that filters on our DA and that flag
+ * to allow us to deauth frames to that bad station.
+ *
+ * Not a regression -- we didn't do it before either.
+ */
+
+#if 0
+ /*
+ * drop non-data frames
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
+ /* drop non-data frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
+#endif
+ /* load the upper byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
+ /* mask off toDS/fromDS */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
+ /* accept WDS frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
+
+ /*
+ * add header length to index
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
+ /* right shift it by 6 to give 0 or 2 */
+ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
+ /* add data frame header length */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
+ /* add index, was start of 802.11 header */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
+ /* move to index, now start of LL header */
+ BPF_STMT(BPF_MISC | BPF_TAX, 0),
+
+ /*
+ * Accept empty data frames, we use those for
+ * polling activity.
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
+
+ /*
+ * Accept EAPOL frames
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
+
+ /* keep these last two statements or change the code below */
+ /* return 0 == "DROP" */
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ /* return ~0 == "keep all" */
+ BPF_STMT(BPF_RET | BPF_K, ~0),
+};
+
+static struct sock_fprog msock_filter = {
+ .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+ .filter = msock_filter_insns,
+};
+
+
+static int add_monitor_filter(int s)
+{
+ int idx;
+
+ /* rewrite all PASS/FAIL jump offsets */
+ for (idx = 0; idx < msock_filter.len; idx++) {
+ struct sock_filter *insn = &msock_filter_insns[idx];
+
+ if (BPF_CLASS(insn->code) == BPF_JMP) {
+ if (insn->code == (BPF_JMP|BPF_JA)) {
+ if (insn->k == PASS)
+ insn->k = msock_filter.len - idx - 2;
+ else if (insn->k == FAIL)
+ insn->k = msock_filter.len - idx - 3;
+ }
+
+ if (insn->jt == PASS)
+ insn->jt = msock_filter.len - idx - 2;
+ else if (insn->jt == FAIL)
+ insn->jt = msock_filter.len - idx - 3;
+
+ if (insn->jf == PASS)
+ insn->jf = msock_filter.len - idx - 2;
+ else if (insn->jf == FAIL)
+ insn->jf = msock_filter.len - idx - 3;
+ }
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
+ &msock_filter, sizeof(msock_filter))) {
+ perror("SO_ATTACH_FILTER");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void nl80211_remove_monitor_interface(
+ struct wpa_driver_nl80211_data *drv)
+{
+ if (drv->monitor_ifidx >= 0) {
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ drv->monitor_ifidx = -1;
+ }
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ drv->monitor_sock = -1;
+ }
+}
+
+
+static int
+nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
+
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+ 0);
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
+ goto error;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ goto error;
+ }
+
+ if (add_monitor_filter(drv->monitor_sock)) {
+ wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
+ "interface; do filtering in user space");
+ /* This works, but will cost in performance. */
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ perror("monitor socket bind");
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ perror("Failed to set socket priority");
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ printf("Could not register monitor read socket\n");
+ goto error;
+ }
+
+ return 0;
+ error:
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+}
+
+
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+static int wpa_driver_nl80211_hapd_send_eapol(
+ void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+#if 0 /* FIX */
+ int qos = sta->flags & WPA_STA_WMM;
+#else
+ int qos = 0;
+#endif
+
+ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
+ data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for i802_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+#if 0 /* To be enabled if qos determination is added above */
+ if (qos) {
+ hdr->frame_control |=
+ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
+ }
+#endif
+
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+ pos = (u8 *) (hdr + 1);
+
+#if 0 /* To be enabled if qos determination is added above */
+ if (qos) {
+ /* add an empty QoS header if needed */
+ pos[0] = 0;
+ pos[1] = 0;
+ pos += 2;
+ }
+#endif
+
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ WPA_PUT_BE16(pos, ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
+ "failed: %d (%s)",
+ (unsigned long) len, errno, strerror(errno));
+ }
+ os_free(hdr);
+
+ return res;
+}
+
+
+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)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg, *flags = NULL;
+ struct nl80211_sta_flag_update upd;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ flags = nlmsg_alloc();
+ if (!flags) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- /* TODO: Get proper Association ID and listen interval */
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
- supp_rates);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 1);
+ /*
+ * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
+ * can be removed eventually.
+ */
+ if (total_flags & WPA_STA_AUTHORIZED)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+
+ if (total_flags & WPA_STA_WMM)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+
+ if (total_flags & WPA_STA_SHORT_PREAMBLE)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+
+ if (total_flags & WPA_STA_MFP)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+
+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
+ goto nla_put_failure;
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
+ upd.set = sta_flags_nl80211(flags_or);
+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+ nlmsg_free(flags);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ nlmsg_free(flags);
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
+ wpa_driver_nl80211_set_freq(drv, 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) */
+
+ return 0;
+}
+
+
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_LEAVE_IBSS, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- /* ignore EEXIST, this happens if a STA associates while associated */
- if (ret == -EEXIST || ret >= 0)
- ret = 0;
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
nla_put_failure:
+ nlmsg_free(msg);
return ret;
}
-static int wpa_driver_nl80211_mlme_remove_sta(void *priv, const u8 *addr)
+static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
{
- struct wpa_driver_nl80211_data *drv = priv;
struct nl_msg *msg;
int ret = -1;
+ int count = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
+
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
+ wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+ "IBSS mode");
+ return -1;
+ }
+
+retry:
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_JOIN_IBSS, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
+ goto nla_put_failure;
+
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->ssid, params->ssid_len);
+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid);
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+
+ ret = nl80211_set_conn_keys(params, msg);
+ if (ret)
+ goto nla_put_failure;
+
+ if (params->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG,
+ " * Extra IEs for Beacon/Probe Response frames",
+ params->wpa_ie, params->wpa_ie_len);
+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ count++;
+ if (ret == -EALREADY && count == 1) {
+ wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
+ "forced leave");
+ nl80211_leave_ibss(drv);
+ nlmsg_free(msg);
+ goto retry;
+ }
+
+ goto nla_put_failure;
+ }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_connect(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct nl_msg *msg;
+ enum nl80211_auth_type type;
+ int ret = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ 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);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ }
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ }
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->ssid, params->ssid_len);
+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid);
+ if (params->ssid_len > sizeof(drv->ssid))
+ goto nla_put_failure;
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+ }
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
+ if (params->wpa_ie)
+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie);
+
+ if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+ type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+ type = NL80211_AUTHTYPE_SHARED_KEY;
+ else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+ type = NL80211_AUTHTYPE_NETWORK_EAP;
+ else if (params->auth_alg & WPA_AUTH_ALG_FT)
+ type = NL80211_AUTHTYPE_FT;
+ else
+ goto nla_put_failure;
+
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+
+ if (params->wpa_ie && params->wpa_ie_len) {
+ enum nl80211_wpa_versions ver;
+
+ if (params->wpa_ie[0] == WLAN_EID_RSN)
+ ver = NL80211_WPA_VERSION_2;
+ else
+ ver = NL80211_WPA_VERSION_1;
+
+ wpa_printf(MSG_DEBUG, " * WPA Version %d", ver);
+ NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ }
+
+ if (params->pairwise_suite != CIPHER_NONE) {
+ int cipher;
+
+ switch (params->pairwise_suite) {
+ case CIPHER_WEP40:
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ break;
+ case CIPHER_WEP104:
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ case CIPHER_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case CIPHER_TKIP:
+ default:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+ }
+
+ if (params->group_suite != CIPHER_NONE) {
+ int cipher;
+
+ switch (params->group_suite) {
+ case CIPHER_WEP40:
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ break;
+ case CIPHER_WEP104:
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ case CIPHER_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case CIPHER_TKIP:
+ default:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+ }
+
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK) {
+ int mgmt = WLAN_AKM_SUITE_PSK;
+
+ switch (params->key_mgmt_suite) {
+ case KEY_MGMT_802_1X:
+ mgmt = WLAN_AKM_SUITE_8021X;
+ break;
+ case KEY_MGMT_PSK:
+ default:
+ mgmt = WLAN_AKM_SUITE_PSK;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+ }
+
+ ret = nl80211_set_conn_keys(params, msg);
+ if (ret)
+ goto nla_put_failure;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+
+}
+
+
+static int wpa_driver_nl80211_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+
+ if (params->mode == IEEE80211_MODE_AP)
+ return wpa_driver_nl80211_ap(drv, params);
+
+ if (params->mode == IEEE80211_MODE_IBSS)
+ 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)
+ return -1;
+ return wpa_driver_nl80211_connect(drv, params);
+ }
+
+ drv->associated = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ 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);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ }
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ drv->assoc_freq = params->freq;
+ } else
+ drv->assoc_freq = 0;
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->ssid, params->ssid_len);
+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid);
+ if (params->ssid_len > sizeof(drv->ssid))
+ goto nla_put_failure;
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+ }
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
+ if (params->wpa_ie)
+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie);
+
+#ifdef CONFIG_IEEE80211W
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+ NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+#endif /* CONFIG_IEEE80211W */
+
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+
+ if (params->prev_bssid) {
+ wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
+ MAC2STR(params->prev_bssid));
+ NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+ params->prev_bssid);
+ }
+
+ 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));
+ nl80211_dump_scan(drv);
+ goto nla_put_failure;
+ }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Association request send "
+ "successfully");
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int mode)
+{
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_STATION, 0);
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ 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);
+ if (!ret)
+ return 0;
+nla_put_failure:
+ 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)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ int nlmode;
+
+ 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) {
+ drv->nlmode = nlmode;
+ ret = 0;
+ goto done;
+ }
+
+ if (nlmode == drv->nlmode) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
+ "requested mode - ignore error");
+ ret = 0;
+ goto done; /* Already in the requested mode */
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so
+ * take the device down, try to set the mode again, and bring the
+ * device back up.
+ */
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == 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))
+ ret = -1;
+ }
+
+ if (!ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
+ "interface is down");
+ drv->nlmode = nlmode;
+ }
+
+done:
+ if (!ret && nlmode == NL80211_IFTYPE_AP) {
+ /* Setup additional AP mode functionality if needed */
+ if (drv->monitor_ifidx < 0 &&
+ nl80211_create_monitor_interface(drv))
+ return -1;
+ } else if (!ret && nlmode != NL80211_IFTYPE_AP) {
+ /* Remove additional AP mode functionality */
+ nl80211_remove_monitor_interface(drv);
+ bss->beacon_set = 0;
+ }
+
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+ "from %d failed", nlmode, drv->nlmode);
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ 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,
+ state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nl80211_sta_flag_update upd;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(bss->ifname));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (authorized)
+ upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+#ifdef HOSTAPD
+
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ int i;
+ int *old;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
+ ifidx);
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == 0) {
+ drv->if_indices[i] = ifidx;
+ return;
+ }
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ old = drv->if_indices;
+ else
+ old = NULL;
+
+ drv->if_indices = os_realloc(old,
+ sizeof(int) * (drv->num_if_indices + 1));
+ if (!drv->if_indices) {
+ if (!old)
+ drv->if_indices = drv->default_if_indices;
+ else
+ drv->if_indices = old;
+ wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+ "interfaces");
+ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+ return;
+ } else if (!old)
+ os_memcpy(drv->if_indices, drv->default_if_indices,
+ sizeof(drv->default_if_indices));
+ drv->if_indices[drv->num_if_indices] = ifidx;
+ drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == ifidx) {
+ drv->if_indices[i] = 0;
+ break;
+ }
+ }
+}
+
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++)
+ if (drv->if_indices[i] == ifidx)
+ return 1;
+
+ return 0;
+}
+
+
+static inline int min_int(int a, int b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+
+static int get_key_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the key index and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending key notifications.
+ */
+
+ if (tb[NL80211_ATTR_KEY_SEQ])
+ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+ return NL_SKIP;
+}
+
+
+static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ 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_GET_KEY, 0);
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ memset(seq, 0, 6);
+
+ 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:
+ return -ENOBUFS;
+}
+
+#endif /* HOSTAPD */
+
+
+/* Set kernel driver on given frequency (MHz) */
+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,
+ freq->sec_channel_offset);
+}
+
+
+#ifdef HOSTAPD
+
+static int i802_set_rts(void *priv, int rts)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+ u32 val;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ if (rts >= 2347)
+ val = (u32) -1;
+ else
+ val = rts;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_WIPHY, 0);
+ 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);
+ if (!ret)
+ return 0;
+nla_put_failure:
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
+ "%d (%s)", rts, ret, strerror(-ret));
+ return ret;
+}
+
+
+static int i802_set_frag(void *priv, int frag)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+ u32 val;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ if (frag >= 2346)
+ val = (u32) -1;
+ else
+ val = frag;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_WIPHY, 0);
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);
+ if (!ret)
+ return 0;
+nla_put_failure:
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
+ "%d: %d (%s)", frag, ret, strerror(-ret));
+ return ret;
+}
+
+
+static int i802_flush(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ /*
+ * XXX: FIX! this needs to flush all VLANs too
+ */
+ 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 get_sta_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct hostap_sta_driver_data *data = arg;
+ struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
+ static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+ [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the interface and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending station notifications.
+ */
+
+ if (!tb[NL80211_ATTR_STA_INFO]) {
+ wpa_printf(MSG_DEBUG, "sta stats missing!");
+ return NL_SKIP;
+ }
+ if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
+ tb[NL80211_ATTR_STA_INFO],
+ stats_policy)) {
+ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
+ return NL_SKIP;
+ }
+
+ if (stats[NL80211_STA_INFO_INACTIVE_TIME])
+ data->inactive_msec =
+ nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
+ if (stats[NL80211_STA_INFO_RX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
+ if (stats[NL80211_STA_INFO_TX_BYTES])
+ data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
+ if (stats[NL80211_STA_INFO_RX_PACKETS])
+ data->rx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
+ if (stats[NL80211_STA_INFO_TX_PACKETS])
+ data->tx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+
+ return NL_SKIP;
+}
+
+static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ os_memset(data, 0, sizeof(*data));
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_STATION, 0);
+
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:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
+ int cw_min, int cw_max, int burst_time)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *txq, *params;
+
+ 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);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+ txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
+ if (!txq)
+ goto nla_put_failure;
+
+ /* We are only sending parameters for a single TXQ at a time */
+ params = nla_nest_start(msg, 1);
+ if (!params)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, queue);
+ /* Burst time is configured in units of 0.1 msec and TXOP parameter in
+ * 32 usec, so need to convert the value here. */
+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
+
+ nla_nest_end(msg, params);
+
+ nla_nest_end(msg, txq);
+
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return 0;
+ nla_put_failure:
+ return -1;
+}
+
+
+static int i802_set_bss(void *priv, int cts, int preamble, int slot)
+{
+ 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);
+
+ 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);
+}
+
+
+static int i802_set_preamble(void *priv, int value)
+{
+ return i802_set_bss(priv, -1, value, -1);
+}
+
+
+static int i802_set_short_slot_time(void *priv, int value)
+{
+ return i802_set_bss(priv, -1, -1, value);
+}
+
+
+static int i802_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(bss->ifname));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
+ if_nametoindex(ifname));
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
+ MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
+ MAC2STR(addr), ifname, vlan_id, ret,
+ strerror(-ret));
+ }
+ nla_put_failure:
+ return ret;
+}
+
+
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ char name[IFNAMSIZ + 1];
+
+ os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+ " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+ if (val) {
+ if (nl80211_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN,
+ NULL, 1) < 0)
+ return -1;
+ linux_set_iface_flags(drv->ioctl_sock, name, 1);
+ return i802_set_sta_vlan(priv, addr, name, 0);
+ } else {
+ i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+ return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+ name);
+ }
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ struct sockaddr_ll lladdr;
+ unsigned char buf[3000];
+ int len;
+ socklen_t fromlen = sizeof(lladdr);
+
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *)&lladdr, &fromlen);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (have_ifidx(drv, lladdr.sll_ifindex))
+ drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
+static int i802_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_sta_driver_data data;
+ int ret;
+
+ data.inactive_msec = (unsigned long) -1;
+ ret = i802_read_sta_data(priv, &data, addr);
+ if (ret || data.inactive_msec == (unsigned long) -1)
+ return -1;
+ return data.inactive_msec / 1000;
+}
+
+
+static int i802_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if 0
+ /* TODO */
+#endif
+ return 0;
+}
+
+
+static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason)
+{
+ struct i802_bss *bss = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth));
+}
+
+
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason)
+{
+ struct i802_bss *bss = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code = host_to_le16(reason);
+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.disassoc));
+}
+
+
+static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
+ const char *brname, const char *ifname)
+{
+ int ifindex;
+ char in_br[IFNAMSIZ];
+
+ os_strlcpy(drv->brname, brname, IFNAMSIZ);
+ ifindex = if_nametoindex(brname);
+ if (ifindex == 0) {
+ /*
+ * Bridge was configured, but the bridge device does
+ * not exist. Try to add it now.
+ */
+ if (linux_br_add(drv->ioctl_sock, brname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
+ "bridge interface %s: %s",
+ brname, strerror(errno));
+ return -1;
+ }
+ drv->added_bridge = 1;
+ add_ifidx(drv, if_nametoindex(brname));
+ }
+
+ if (linux_br_get(in_br, ifname) == 0) {
+ if (os_strcmp(in_br, brname) == 0)
+ return 0; /* already in the bridge */
+
+ 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) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to "
+ "remove interface %s from bridge "
+ "%s: %s",
+ ifname, brname, strerror(errno));
+ return -1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
+ ifname, brname);
+ if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
+ "into bridge %s: %s",
+ ifname, brname, strerror(errno));
+ return -1;
+ }
+ drv->added_if_into_bridge = 1;
+
+ return 0;
+}
+
+
+static void *i802_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *bss;
+ size_t i;
+ char brname[IFNAMSIZ];
+ int ifindex, br_ifindex;
+ int br_added = 0;
+
+ bss = wpa_driver_nl80211_init(hapd, params->ifname);
+ if (bss == NULL)
+ return NULL;
+
+ drv = bss->drv;
+ if (linux_br_get(brname, params->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
+ params->ifname, brname);
+ br_ifindex = if_nametoindex(brname);
+ } else {
+ brname[0] = '\0';
+ br_ifindex = 0;
+ }
+
+ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+ drv->if_indices = drv->default_if_indices;
+ for (i = 0; i < params->num_bridge; i++) {
+ if (params->bridge[i]) {
+ ifindex = if_nametoindex(params->bridge[i]);
+ if (ifindex)
+ add_ifidx(drv, ifindex);
+ if (ifindex == br_ifindex)
+ br_added = 1;
+ }
+ }
+ if (!br_added && br_ifindex &&
+ (params->num_bridge == 0 || !params->bridge[0]))
+ add_ifidx(drv, br_ifindex);
+
+ /* 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))
+ goto failed;
+
+ if (params->bssid) {
+ if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
+ params->bssid))
+ goto failed;
+ }
+
+ if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
+ "into AP mode", bss->ifname);
+ goto failed;
+ }
+
+ if (params->num_bridge && params->bridge[0] &&
+ i802_check_bridge(drv, params->bridge[0], params->ifname) < 0)
+ goto failed;
+
+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
+ goto failed;
+
+ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
+ if (drv->eapol_sock < 0) {
+ perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+ goto failed;
+ }
+
+ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
+ {
+ printf("Could not register read socket for eapol\n");
+ goto failed;
+ }
+
+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
+ goto failed;
+
+ return bss;
+
+failed:
+ nl80211_remove_monitor_interface(drv);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+
+ genl_family_put(drv->nl80211);
+ nl_cache_free(drv->nl_cache);
+ nl_handle_destroy(drv->nl_handle);
+ nl_cb_put(drv->nl_cb);
+
+ os_free(drv);
+ return NULL;
+}
+
+
+static void i802_deinit(void *priv)
+{
+ wpa_driver_nl80211_deinit(priv);
+}
+
+#endif /* HOSTAPD */
+
+
+static enum nl80211_iftype wpa_driver_nl80211_if_type(
+ enum wpa_driver_if_type type)
+{
+ switch (type) {
+ case WPA_IF_STATION:
+ return NL80211_IFTYPE_STATION;
+ case WPA_IF_AP_VLAN:
+ return NL80211_IFTYPE_AP_VLAN;
+ case WPA_IF_AP_BSS:
+ return NL80211_IFTYPE_AP;
+ }
+ return -1;
+}
+
+static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, const u8 *addr,
+ void *bss_ctx, void **drv_priv,
+ char *force_ifname, u8 *if_addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ifidx;
+#ifdef HOSTAPD
+ struct i802_bss *new_bss = NULL;
+
+ if (type == WPA_IF_AP_BSS) {
+ new_bss = os_zalloc(sizeof(*new_bss));
+ if (new_bss == NULL)
+ return -1;
+ }
+#endif /* HOSTAPD */
+
+ if (addr)
+ os_memcpy(if_addr, addr, ETH_ALEN);
+ ifidx = nl80211_create_iface(drv, ifname,
+ wpa_driver_nl80211_if_type(type), addr,
+ 0);
+ if (ifidx < 0) {
+#ifdef HOSTAPD
+ os_free(new_bss);
+#endif /* HOSTAPD */
+ return -1;
+ }
+
+ if (!addr &&
+ linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0)
+ return -1;
+
+#ifdef HOSTAPD
+ if (type == WPA_IF_AP_BSS) {
+ if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
+ nl80211_remove_iface(drv, ifidx);
+ os_free(new_bss);
+ return -1;
+ }
+ os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+ 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;
+ }
+#endif /* HOSTAPD */
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_if_remove(void *priv,
+ enum wpa_driver_if_type type,
+ const char *ifname)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ifindex = if_nametoindex(ifname);
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
+ __func__, type, ifname, ifindex);
+ if (ifindex <= 0)
+ return -1;
+ nl80211_remove_iface(drv, ifindex);
+
+#ifdef HOSTAPD
+ if (type != WPA_IF_AP_BSS)
+ return 0;
+
+ if (bss != &drv->first_bss) {
+ struct i802_bss *tbss = &drv->first_bss;
+
+ while (tbss) {
+ if (tbss->next != bss)
+ continue;
+
+ tbss->next = bss->next;
+ os_free(bss);
+ break;
+ }
+ }
+#endif /* HOSTAPD */
+
+ return 0;
+}
+
+
+static int cookie_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u64 *cookie = arg;
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_COOKIE])
+ *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+ u8 *buf;
+ struct ieee80211_hdr *hdr;
+ u64 cookie;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d)",
+ drv->ifindex);
+
+ buf = os_zalloc(24 + data_len);
+ if (buf == NULL)
+ return ret;
+ os_memcpy(buf + 24, data, data_len);
+ hdr = (struct ieee80211_hdr *) buf;
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+ os_memcpy(hdr->addr1, dst, ETH_ALEN);
+ 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);
+ os_free(buf);
+ return ret;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ os_free(buf);
+ return -1;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_ACTION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ NLA_PUT(msg, NL80211_ATTR_FRAME, 24 + data_len, buf);
+ os_free(buf);
+ buf = NULL;
+
+ cookie = 0;
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Action command failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX command accepted; "
+ "cookie 0x%llx", (long long unsigned int) cookie);
+ drv->send_action_cookie = cookie;
ret = 0;
+nla_put_failure:
+ os_free(buf);
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
+ unsigned int duration)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ u64 cookie;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_REMAIN_ON_CHANNEL, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
+
+ cookie = 0;
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ 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;
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
+ "(freq=%d): %d (%s)", freq, ret, strerror(-ret));
+nla_put_failure:
+ return -1;
+}
+
+
+static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ if (!drv->pending_remain_on_chan) {
+ wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
+ "to cancel");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
+ "0x%llx",
+ (long long unsigned int) drv->remain_on_chan_cookie);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
+
+ 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);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
+ "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+ return -1;
+}
+
+
+static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ if (drv->monitor_ifidx < 0)
+ return; /* monitor interface already removed */
+
+ if (drv->nlmode != NL80211_IFTYPE_STATION)
+ return; /* not in station mode anymore */
+
+ if (drv->probe_req_report)
+ return; /* reporting enabled */
+
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface due to no "
+ "Probe Request reporting needed anymore");
+ nl80211_remove_monitor_interface(drv);
+}
+
+
+static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (drv->nlmode != NL80211_IFTYPE_STATION) {
+ wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
+ "allowed in station mode (iftype=%d)",
+ drv->nlmode);
+ return -1;
+ }
+ drv->probe_req_report = report;
+
+ if (report) {
+ eloop_cancel_timeout(
+ wpa_driver_nl80211_probe_req_report_timeout,
+ drv, NULL);
+ if (drv->monitor_ifidx < 0 &&
+ nl80211_create_monitor_interface(drv))
+ return -1;
+ } else {
+ /*
+ * It takes a while to remove the monitor interface, so try to
+ * avoid doing this if it is needed again shortly. Instead,
+ * schedule the interface to be removed later if no need for it
+ * is seen.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Scheduling monitor interface "
+ "to be removed after 10 seconds of no use");
+ eloop_register_timeout(
+ 10, 0, wpa_driver_nl80211_probe_req_report_timeout,
+ drv, NULL);
+ }
+
+ return 0;
+}
+
+
+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int disabled)
+{
+ struct nl_msg *msg;
+ struct nlattr *bands, *band;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_TX_BITRATE_MASK, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+
+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+ if (!bands)
+ goto nla_put_failure;
+
+ /*
+ * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
+ * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
+ * rates. All 5 GHz rates are left enabled.
+ */
+ 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");
+ nla_nest_end(msg, band);
+
+ nla_nest_end(msg, bands);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ }
+
return ret;
nla_put_failure:
- return -ENOBUFS;
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+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)
+ return -1;
+ wpa_driver_nl80211_del_beacon(drv);
+ return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+}
+
+
+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)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
+ "resume event");
+ }
}
-#endif /* CONFIG_CLIENT_MLME */
+
+static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
+ const u8 *ies, size_t ies_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ 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;
+
+ if (action != 1) {
+ wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
+ "action %d", action);
+ return -1;
+ }
+
+ /*
+ * Action frame payload:
+ * Category[1] = 6 (Fast BSS Transition)
+ * Action[1] = 1 (Fast BSS Transition Request)
+ * STA Address
+ * Target AP Address
+ * FT IEs
+ */
+
+ data_len = 2 + 2 * ETH_ALEN + ies_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ *pos++ = 0x06; /* FT Action category */
+ *pos++ = action;
+ os_memcpy(pos, own_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, target_ap, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, ies, ies_len);
+
+ ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
+ own_addr, drv->bssid,
+ data, data_len);
+ os_free(data);
+
+ return ret;
+}
+
+
+static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg, *cqm = NULL;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
+ "hysteresis=%d", threshold, hysteresis);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_CQM, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+ cqm = nlmsg_alloc();
+ if (cqm == NULL)
+ return -1;
+
+ NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+ NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+ nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
+
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return 0;
+ msg = NULL;
+
+nla_put_failure:
+ if (cqm)
+ nlmsg_free(cqm);
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
+ int encrypt)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+}
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
@@ -2733,34 +5333,58 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.desc = "Linux nl80211/cfg80211",
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
- .set_wpa = wpa_driver_nl80211_set_wpa,
.set_key = wpa_driver_nl80211_set_key,
- .set_countermeasures = wpa_driver_nl80211_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted,
- .scan = wpa_driver_nl80211_scan,
+ .scan2 = wpa_driver_nl80211_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
.deauthenticate = wpa_driver_nl80211_deauthenticate,
.disassociate = wpa_driver_nl80211_disassociate,
- .set_mode = wpa_driver_nl80211_set_mode,
+ .authenticate = wpa_driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
- .set_auth_alg = wpa_driver_nl80211_set_auth_alg,
.init = wpa_driver_nl80211_init,
.deinit = wpa_driver_nl80211_deinit,
- .set_param = wpa_driver_nl80211_set_param,
- .add_pmkid = wpa_driver_nl80211_add_pmkid,
- .remove_pmkid = wpa_driver_nl80211_remove_pmkid,
- .flush_pmkid = wpa_driver_nl80211_flush_pmkid,
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
+ .set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
- .set_probe_req_ie = wpa_driver_nl80211_set_probe_req_ie,
-#ifdef CONFIG_CLIENT_MLME
- .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
- .set_channel = wpa_driver_nl80211_set_channel,
- .set_ssid = wpa_driver_nl80211_set_ssid,
- .set_bssid = wpa_driver_nl80211_set_bssid,
+ .set_beacon = wpa_driver_nl80211_set_beacon,
+ .if_add = wpa_driver_nl80211_if_add,
+ .if_remove = wpa_driver_nl80211_if_remove,
.send_mlme = wpa_driver_nl80211_send_mlme,
- .mlme_add_sta = wpa_driver_nl80211_mlme_add_sta,
- .mlme_remove_sta = wpa_driver_nl80211_mlme_remove_sta,
-#endif /* CONFIG_CLIENT_MLME */
+ .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+ .sta_add = wpa_driver_nl80211_sta_add,
+ .sta_remove = wpa_driver_nl80211_sta_remove,
+ .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
+ .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
+#ifdef HOSTAPD
+ .hapd_init = i802_init,
+ .hapd_deinit = i802_deinit,
+ .get_seqnum = i802_get_seqnum,
+ .flush = i802_flush,
+ .read_sta_data = i802_read_sta_data,
+ .sta_deauth = i802_sta_deauth,
+ .sta_disassoc = i802_sta_disassoc,
+ .get_inact_sec = i802_get_inact_sec,
+ .sta_clear_stats = i802_sta_clear_stats,
+ .set_rts = i802_set_rts,
+ .set_frag = i802_set_frag,
+ .set_rate_sets = i802_set_rate_sets,
+ .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_wds_sta = i802_set_wds_sta,
+#endif /* HOSTAPD */
+ .set_freq = i802_set_freq,
+ .send_action = wpa_driver_nl80211_send_action,
+ .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
+ .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,
+ .send_frame = nl80211_send_frame,
};
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
new file mode 100644
index 0000000000000..aaeacd66435dd
--- /dev/null
+++ b/src/drivers/driver_none.c
@@ -0,0 +1,99 @@
+/*
+ * Driver interface for RADIUS server or WPS ER only (no driver)
+ * Copyright (c) 2008, Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "driver.h"
+
+
+struct none_driver_data {
+ struct hostapd_data *hapd;
+ void *ctx;
+};
+
+
+static void * none_driver_hapd_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct none_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct none_driver_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+ "driver data");
+ return NULL;
+ }
+ drv->hapd = hapd;
+
+ return drv;
+}
+
+
+static void none_driver_hapd_deinit(void *priv)
+{
+ struct none_driver_data *drv = priv;
+
+ os_free(drv);
+}
+
+
+static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
+ u16 proto, const u8 *data, size_t data_len)
+{
+ return 0;
+}
+
+
+static void * none_driver_init(void *ctx, const char *ifname)
+{
+ struct none_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct none_driver_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+ "driver data");
+ return NULL;
+ }
+ drv->ctx = ctx;
+
+ return drv;
+}
+
+
+static void none_driver_deinit(void *priv)
+{
+ struct none_driver_data *drv = priv;
+
+ os_free(drv);
+}
+
+
+static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto,
+ const u8 *data, size_t data_len)
+{
+ return -1;
+}
+
+
+const struct wpa_driver_ops wpa_driver_none_ops = {
+ .name = "none",
+ .desc = "no driver (RADIUS server/WPS ER)",
+ .hapd_init = none_driver_hapd_init,
+ .hapd_deinit = none_driver_hapd_deinit,
+ .send_ether = none_driver_send_ether,
+ .init = none_driver_init,
+ .deinit = none_driver_deinit,
+ .send_eapol = none_driver_send_eapol,
+};
diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m
index 93d7df01adfe0..69ca4b576c3c0 100644
--- a/src/drivers/driver_osx.m
+++ b/src/drivers/driver_osx.m
@@ -20,6 +20,7 @@
#include "common.h"
#include "driver.h"
#include "eloop.h"
+#include "common/ieee802_11_defs.h"
#include "Apple80211.h"
@@ -111,10 +112,12 @@ static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
+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);
@@ -156,43 +159,66 @@ static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
}
-static int wpa_driver_osx_get_scan_results(void *priv,
- struct wpa_scan_result *results,
- size_t max_size)
+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);
- if (num > max_size)
- num = max_size;
- os_memset(results, 0, num * sizeof(struct wpa_scan_result));
- for (i = 0; i < num; i++) {
- struct wpa_scan_result *res = &results[i];
- WirelessNetworkInfo *info;
- info = (WirelessNetworkInfo *)
- CFDataGetBytePtr(CFArrayGetValueAtIndex(
- drv->scan_results, i));
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return NULL;
- os_memcpy(res->bssid, info->bssid, ETH_ALEN);
- if (info->ssid_len > 32) {
- wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
- "scan results", (int) info->ssid_len);
- continue;
- }
- os_memcpy(res->ssid, info->ssid, info->ssid_len);
- res->ssid_len = info->ssid_len;
- res->caps = info->capability;
- res->freq = 2407 + info->channel * 5;
- res->level = info->signal;
- res->noise = info->noise;
- }
+ for (i = 0; i < num; i++)
+ wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
+ CFDataGetBytePtr(CFArrayGetValueAtIndex(
+ drv->scan_results, i)));
- return num;
+ return res;
}
@@ -277,7 +303,8 @@ static int wpa_driver_osx_associate(void *priv,
}
-static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
+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)
@@ -424,8 +451,8 @@ const struct wpa_driver_ops wpa_driver_osx_ops = {
.get_bssid = wpa_driver_osx_get_bssid,
.init = wpa_driver_osx_init,
.deinit = wpa_driver_osx_deinit,
- .scan = wpa_driver_osx_scan,
- .get_scan_results = wpa_driver_osx_get_scan_results,
+ .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_prism54.c b/src/drivers/driver_prism54.c
deleted file mode 100644
index e64e762eddb54..0000000000000
--- a/src/drivers/driver_prism54.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Linux Prism54.org driver
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-#include "driver_hostap.h"
-
-struct wpa_driver_prism54_data {
- void *wext; /* private data for driver_wext */
- void *ctx;
- char ifname[IFNAMSIZ + 1];
- int sock;
-};
-
-#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
-#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
-#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
-
-static void show_set_key_error(struct prism2_hostapd_param *);
-
-static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
- struct prism2_hostapd_param *param,
- int len, int show_err)
-{
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) param;
- iwr.u.data.length = len;
-
- if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
- int ret = errno;
- if (show_err)
- perror("ioctl[PRISM54_HOSTAPD]");
- return ret;
- }
-
- return 0;
-}
-
-
-static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
- const u8 *wpa_ie,
- size_t wpa_ie_len)
-{
- struct prism2_hostapd_param *param;
- int res;
- size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
- if (blen < sizeof(*param))
- blen = sizeof(*param);
-
- param = os_zalloc(blen);
- if (param == NULL)
- return -1;
-
- param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
- param->u.generic_elem.len = wpa_ie_len;
- os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
- res = hostapd_ioctl_prism54(drv, param, blen, 1);
-
- os_free(param);
-
- return res;
-}
-
-
-/* This is called at wpa_supplicant daemon init time */
-static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
-{
- struct wpa_driver_prism54_data *drv = priv;
- struct prism2_hostapd_param *param;
- int res;
- size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
- if (blen < sizeof(*param))
- blen = sizeof(*param);
-
- param = os_zalloc(blen);
- if (param == NULL)
- return -1;
-
- param->cmd = PRISM54_SET_WPA;
- param->u.generic_elem.len = 0;
- res = hostapd_ioctl_prism54(drv, param, blen, 1);
-
- os_free(param);
-
- return res;
-}
-
-
-static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- struct wpa_driver_prism54_data *drv = priv;
- struct prism2_hostapd_param *param;
- u8 *buf;
- size_t blen;
- int ret = 0;
- char *alg_name;
-
- switch (alg) {
- case WPA_ALG_NONE:
- alg_name = "none";
- return -1;
- break;
- case WPA_ALG_WEP:
- alg_name = "WEP";
- return -1;
- break;
- case WPA_ALG_TKIP:
- alg_name = "TKIP";
- break;
- case WPA_ALG_CCMP:
- alg_name = "CCMP";
- return -1;
- break;
- default:
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
- "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
- (unsigned long) seq_len, (unsigned long) key_len);
-
- if (seq_len > 8)
- return -2;
-
- blen = sizeof(*param) + key_len;
- buf = os_zalloc(blen);
- if (buf == NULL)
- return -1;
-
- param = (struct prism2_hostapd_param *) buf;
- param->cmd = PRISM2_SET_ENCRYPTION;
- /* TODO: In theory, STA in client mode can use five keys; four default
- * keys for receiving (with keyidx 0..3) and one individual key for
- * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
- * keyidx 0 is reserved for this unicast use and default keys can only
- * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
- * This should be fine for more or less all cases, but for completeness
- * sake, the driver could be enhanced to support the missing key. */
-#if 0
- if (addr == NULL)
- os_memset(param->sta_addr, 0xff, ETH_ALEN);
- else
- os_memcpy(param->sta_addr, addr, ETH_ALEN);
-#else
- os_memset(param->sta_addr, 0xff, ETH_ALEN);
-#endif
- os_strlcpy((char *) param->u.crypt.alg, alg_name,
- HOSTAP_CRYPT_ALG_NAME_LEN);
- param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
- param->u.crypt.idx = key_idx;
- os_memcpy(param->u.crypt.seq, seq, seq_len);
- param->u.crypt.key_len = key_len;
- os_memcpy((u8 *) (param + 1), key, key_len);
-
- if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
- wpa_printf(MSG_WARNING, "Failed to set encryption.");
- show_set_key_error(param);
- ret = -1;
- }
- os_free(buf);
-
- return ret;
-}
-
-
-static int wpa_driver_prism54_set_countermeasures(void *priv,
- int enabled)
-{
- /* FIX */
- printf("wpa_driver_prism54_set_countermeasures - not yet "
- "implemented\n");
- return 0;
-}
-
-
-static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
- int enabled)
-{
- struct wpa_driver_prism54_data *drv = priv;
- struct prism2_hostapd_param *param;
- int res;
- size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
- if (blen < sizeof(*param))
- blen = sizeof(*param);
-
- param = os_zalloc(blen);
- if (param == NULL)
- return -1;
-
- param->cmd = PRISM54_DROP_UNENCRYPTED;
- param->u.generic_elem.len = 0;
- res = hostapd_ioctl_prism54(drv, param, blen, 1);
-
- os_free(param);
-
- return res;
-}
-
-
-static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- /* FIX */
- printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
- return 0;
-}
-
-
-static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- /* FIX */
- printf("wpa_driver_prism54_disassociate - not yet implemented\n");
- return 0;
-}
-
-
-static int
-wpa_driver_prism54_associate(void *priv,
- struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_prism54_data *drv = priv;
- int ret = 0;
-
- if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
- params->wpa_ie_len) < 0)
- ret = -1;
- if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
- ret = -1;
- if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
- params->ssid_len) < 0)
- ret = -1;
- if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
- ret = -1;
-
- return ret;
-}
-
-static void show_set_key_error(struct prism2_hostapd_param *param)
-{
- switch (param->u.crypt.err) {
- case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
- wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
- param->u.crypt.alg);
- wpa_printf(MSG_INFO, "You may need to load kernel module to "
- "register that algorithm.");
- wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
- "WEP.");
- break;
- case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
- wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
- MAC2STR(param->sta_addr));
- break;
- case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
- wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
- break;
- case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
- wpa_printf(MSG_INFO, "Key setting failed.");
- break;
- case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
- wpa_printf(MSG_INFO, "TX key index setting failed.");
- break;
- case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
- wpa_printf(MSG_INFO, "Card configuration failed.");
- break;
- }
-}
-
-
-static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_prism54_data *drv = priv;
- return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_prism54_data *drv = priv;
- return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
- struct wpa_driver_prism54_data *drv = priv;
- return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_prism54_get_scan_results(void *priv)
-{
- struct wpa_driver_prism54_data *drv = priv;
- return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_prism54_set_operstate(void *priv, int state)
-{
- struct wpa_driver_prism54_data *drv = priv;
- return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
-{
- struct wpa_driver_prism54_data *drv;
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->wext = wpa_driver_wext_init(ctx, ifname);
- if (drv->wext == NULL) {
- os_free(drv);
- return NULL;
- }
-
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->sock < 0) {
- wpa_driver_wext_deinit(drv->wext);
- os_free(drv);
- return NULL;
- }
-
- return drv;
-}
-
-
-static void wpa_driver_prism54_deinit(void *priv)
-{
- struct wpa_driver_prism54_data *drv = priv;
- wpa_driver_wext_deinit(drv->wext);
- close(drv->sock);
- os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_prism54_ops = {
- .name = "prism54",
- .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
- .get_bssid = wpa_driver_prism54_get_bssid,
- .get_ssid = wpa_driver_prism54_get_ssid,
- .set_wpa = wpa_driver_prism54_set_wpa,
- .set_key = wpa_driver_prism54_set_key,
- .set_countermeasures = wpa_driver_prism54_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
- .scan = wpa_driver_prism54_scan,
- .get_scan_results2 = wpa_driver_prism54_get_scan_results,
- .deauthenticate = wpa_driver_prism54_deauthenticate,
- .disassociate = wpa_driver_prism54_disassociate,
- .associate = wpa_driver_prism54_associate,
- .init = wpa_driver_prism54_init,
- .deinit = wpa_driver_prism54_deinit,
- .set_operstate = wpa_driver_prism54_set_operstate,
-};
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index fdf299dc84e44..28485215e2b28 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -18,7 +18,7 @@
#include "common.h"
#include "driver.h"
#include "eloop.h"
-#include "privsep_commands.h"
+#include "common/privsep_commands.h"
struct wpa_driver_privsep_data {
@@ -102,18 +102,12 @@ static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
}
-static int wpa_driver_privsep_set_wpa(void *priv, int enabled)
-{
- struct wpa_driver_privsep_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
- return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled,
- sizeof(enabled), NULL, NULL);
-}
-
-
-static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_privsep_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
+ const u8 *ssid = params->ssids[0].ssid;
+ size_t ssid_len = params->ssids[0].ssid_len;
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
NULL, NULL);
@@ -196,10 +190,11 @@ wpa_driver_privsep_get_scan_results2(void *priv)
}
-static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+static int wpa_driver_privsep_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_privsep_data *drv = priv;
struct privsep_cmd_set_key cmd;
@@ -326,7 +321,8 @@ static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
}
-static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event,
+static void wpa_driver_privsep_event_assoc(void *ctx,
+ enum wpa_event_type event,
u8 *buf, size_t len)
{
union wpa_event_data data;
@@ -438,24 +434,7 @@ static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
{
if (len < ETH_ALEN)
return;
-
- wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
-}
-
-
-static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
-{
-#ifdef CONFIG_CLIENT_MLME
- struct ieee80211_rx_status *rx_status;
-
- if (len < sizeof(*rx_status))
- return;
- rx_status = (struct ieee80211_rx_status *) buf;
- buf += sizeof(*rx_status);
- len -= sizeof(*rx_status);
-
- wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
-#endif /* CONFIG_CLIENT_MLME */
+ drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
}
@@ -535,10 +514,6 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
event_len);
break;
- case PRIVSEP_EVENT_STA_RX:
- wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
- event_len);
- break;
}
os_free(buf);
@@ -747,15 +722,6 @@ static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
}
-static int wpa_driver_privsep_set_mode(void *priv, int mode)
-{
- struct wpa_driver_privsep_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
- return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
- NULL, NULL);
-}
-
-
static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
{
struct wpa_driver_privsep_data *drv = priv;
@@ -768,52 +734,24 @@ static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
struct wpa_driver_ops wpa_driver_privsep_ops = {
"privsep",
"wpa_supplicant privilege separated driver",
- wpa_driver_privsep_get_bssid,
- wpa_driver_privsep_get_ssid,
- wpa_driver_privsep_set_wpa,
- wpa_driver_privsep_set_key,
- wpa_driver_privsep_init,
- wpa_driver_privsep_deinit,
- wpa_driver_privsep_set_param,
- NULL /* set_countermeasures */,
- NULL /* set_drop_unencrypted */,
- wpa_driver_privsep_scan,
- NULL /* get_scan_results */,
- wpa_driver_privsep_deauthenticate,
- wpa_driver_privsep_disassociate,
- wpa_driver_privsep_associate,
- NULL /* set_auth_alg */,
- NULL /* add_pmkid */,
- NULL /* remove_pmkid */,
- NULL /* flush_pmkid */,
- wpa_driver_privsep_get_capa,
- NULL /* poll */,
- NULL /* get_ifname */,
- wpa_driver_privsep_get_mac_addr,
- NULL /* send_eapol */,
- NULL /* set_operstate */,
- NULL /* mlme_setprotection */,
- NULL /* get_hw_feature_data */,
- NULL /* set_channel */,
- NULL /* set_ssid */,
- NULL /* set_bssid */,
- NULL /* send_mlme */,
- NULL /* mlme_add_sta */,
- NULL /* mlme_remove_sta */,
- NULL /* update_ft_ies */,
- NULL /* send_ft_action */,
- wpa_driver_privsep_get_scan_results2,
- NULL /* set_probe_req_ie */,
- wpa_driver_privsep_set_mode,
- wpa_driver_privsep_set_country,
- NULL /* global_init */,
- NULL /* global_deinit */,
- NULL /* init2 */,
- NULL /* get_interfaces */
+ .get_bssid = wpa_driver_privsep_get_bssid,
+ .get_ssid = wpa_driver_privsep_get_ssid,
+ .set_key = wpa_driver_privsep_set_key,
+ .init = wpa_driver_privsep_init,
+ .deinit = wpa_driver_privsep_deinit,
+ .set_param = wpa_driver_privsep_set_param,
+ .scan2 = wpa_driver_privsep_scan,
+ .deauthenticate = wpa_driver_privsep_deauthenticate,
+ .disassociate = wpa_driver_privsep_disassociate,
+ .associate = wpa_driver_privsep_associate,
+ .get_capa = wpa_driver_privsep_get_capa,
+ .get_mac_addr = wpa_driver_privsep_get_mac_addr,
+ .get_scan_results2 = wpa_driver_privsep_get_scan_results2,
+ .set_country = wpa_driver_privsep_set_country,
};
-struct wpa_driver_ops *wpa_supplicant_drivers[] =
+struct wpa_driver_ops *wpa_drivers[] =
{
&wpa_driver_privsep_ops,
NULL
diff --git a/src/drivers/driver_ps3.c b/src/drivers/driver_ps3.c
deleted file mode 100644
index fde3425e281f3..0000000000000
--- a/src/drivers/driver_ps3.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * WPA Supplicant - PS3 Linux wireless extension driver interface
- * Copyright 2007, 2008 Sony Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-#include "wireless_copy.h"
-#include "common.h"
-#include "wpa_common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "driver_wext.h"
-#include "ieee802_11_defs.h"
-
-static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
- struct wpa_driver_associate_params *params)
-{
- int ret, i;
- struct iwreq iwr;
- char *buf, *str;
-
- if (!params->psk && !params->passphrase) {
- wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
- return -EINVAL;
- }
-
- os_memset(&iwr, 0, sizeof(iwr));
- if (params->psk) {
- /* includes null */
- iwr.u.data.length = PMK_LEN * 2 + 1;
- buf = os_malloc(iwr.u.data.length);
- if (!buf)
- return -ENOMEM;
- str = buf;
- for (i = 0; i < PMK_LEN; i++) {
- str += snprintf(str, iwr.u.data.length - (str - buf),
- "%02x", params->psk[i]);
- }
- } else if (params->passphrase) {
- /* including quotations and null */
- iwr.u.data.length = strlen(params->passphrase) + 3;
- buf = os_malloc(iwr.u.data.length);
- if (!buf)
- return -ENOMEM;
- buf[0] = '"';
- os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
- buf[iwr.u.data.length - 2] = '"';
- buf[iwr.u.data.length - 1] = '\0';
- } else
- return -EINVAL;
- iwr.u.data.pointer = (caddr_t) buf;
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
- os_free(buf);
-
- return ret;
-}
-
-static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
- struct wpa_driver_associate_params *params)
-{
- int ret, i;
- struct iwreq iwr;
-
- for (i = 0; i < 4; i++) {
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.encoding.flags = i + 1;
- if (params->wep_key_len[i]) {
- iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
- iwr.u.encoding.length = params->wep_key_len[i];
- } else
- iwr.u.encoding.flags = IW_ENCODE_NOKEY |
- IW_ENCODE_DISABLED;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE]");
- ret = -1;
- }
- }
- return ret;
-}
-
-static int wpa_driver_ps3_associate(void *priv,
- struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_wext_data *drv = priv;
- int ret, value;
-
- wpa_printf(MSG_DEBUG, "%s: <-", __func__);
-
- /* clear BSSID */
- if (!params->bssid &&
- wpa_driver_wext_set_bssid(drv, NULL) < 0)
- ret = -1;
-
- if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
- ret = -1;
-
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
- value = IW_AUTH_WPA_VERSION_DISABLED;
- else if (params->wpa_ie[0] == WLAN_EID_RSN)
- value = IW_AUTH_WPA_VERSION_WPA2;
- else
- value = IW_AUTH_WPA_VERSION_WPA;
- if (wpa_driver_wext_set_auth_param(drv,
- IW_AUTH_WPA_VERSION, value) < 0)
- ret = -1;
- value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
- if (wpa_driver_wext_set_auth_param(drv,
- IW_AUTH_CIPHER_PAIRWISE, value) < 0)
- ret = -1;
- value = wpa_driver_wext_cipher2wext(params->group_suite);
- if (wpa_driver_wext_set_auth_param(drv,
- IW_AUTH_CIPHER_GROUP, value) < 0)
- ret = -1;
- value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
- if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
- ret = -1;
-
- /* set selected BSSID */
- if (params->bssid &&
- wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
- ret = -1;
-
- switch (params->group_suite) {
- case CIPHER_NONE:
- ret = 0;
- break;
- case CIPHER_WEP40:
- case CIPHER_WEP104:
- ret = wpa_driver_ps3_set_wep_keys(drv, params);
- break;
- case CIPHER_TKIP:
- case CIPHER_CCMP:
- ret = wpa_driver_ps3_set_wpa_key(drv, params);
- break;
- }
-
- /* start to associate */
- ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
-
- wpa_printf(MSG_DEBUG, "%s: ->", __func__);
-
- return ret;
-}
-
-static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- int ret;
- wpa_printf(MSG_DEBUG, "%s:<-", __func__);
-
- ret = wpa_driver_wext_get_capa(priv, capa);
- if (ret) {
- wpa_printf(MSG_INFO, "%s: base wext returns error %d",
- __func__, ret);
- return ret;
- }
- /* PS3 hypervisor does association and 4way handshake by itself */
- capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
- wpa_printf(MSG_DEBUG, "%s:->", __func__);
- return 0;
-}
-
-const struct wpa_driver_ops wpa_driver_ps3_ops = {
- .name = "ps3",
- .desc = "PLAYSTATION3 Linux wireless extension driver",
- .get_bssid = wpa_driver_wext_get_bssid,
- .get_ssid = wpa_driver_wext_get_ssid,
- .scan = wpa_driver_wext_scan,
- .get_scan_results2 = wpa_driver_wext_get_scan_results,
- .associate = wpa_driver_ps3_associate, /* PS3 */
- .init = wpa_driver_wext_init,
- .deinit = wpa_driver_wext_deinit,
- .get_capa = wpa_driver_ps3_get_capa, /* PS3 */
-};
diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c
index e9313cb33ef09..09d1ef5405090 100644
--- a/src/drivers/driver_ralink.c
+++ b/src/drivers/driver_ralink.c
@@ -22,8 +22,10 @@
#include "driver.h"
#include "l2_packet/l2_packet.h"
#include "eloop.h"
-#include "ieee802_11_defs.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);
@@ -33,7 +35,7 @@ static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
struct wpa_driver_ralink_data {
void *ctx;
int ioctl_sock;
- int event_sock;
+ struct netlink_data *netlink;
char ifname[IFNAMSIZ + 1];
u8 *assoc_req_ies;
size_t assoc_req_ies_len;
@@ -45,6 +47,7 @@ struct wpa_driver_ralink_data {
int ap_scan;
int scanning_done;
u8 g_driver_down;
+ BOOLEAN bAddWepKey;
};
static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
@@ -450,6 +453,7 @@ 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__);
@@ -478,12 +482,12 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
*/
bytes = drv->assoc_req_ies_len;
- data.assoc_info.req_ies = os_malloc(bytes);
- if (data.assoc_info.req_ies == NULL)
+ 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;
- os_memcpy(data.assoc_info.req_ies, spos, bytes);
/* skip the '\0' byte */
spos += bytes + 1;
@@ -499,21 +503,48 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
if (!bytes)
goto done;
-
- data.assoc_info.resp_ies = os_malloc(bytes);
- if (data.assoc_info.resp_ies == NULL)
+ 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;
- os_memcpy(data.assoc_info.resp_ies, spos, bytes);
}
wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
- /* free allocated memory */
done:
- os_free(data.assoc_info.resp_ies);
- os_free(data.assoc_info.req_ies);
+ /* 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");
}
}
@@ -580,33 +611,9 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
}
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 !!!");
- /* determine whether the dynamic-WEP is used or
- * not */
-#if 0
- if (wpa_s && wpa_s->current_ssid &&
- wpa_s->current_ssid->key_mgmt ==
- WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
- if ((wpa_s->current_ssid->eapol_flags &
- (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
- //wpa_printf(MSG_DEBUG, "The current ssid - (%s), eapol_flag = %d.\n",
- // wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len),wpa_s->current_ssid->eapol_flags);
- ieee8021x_required_key = TRUE;
- }
-
- if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
- {
- wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
- (int) ieee8021x_required_key);
- }
-
- wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d).\n", ieee8021x_required_key ? "TRUE" : "FALSE",
- wpa_s->current_ssid->eapol_flags);
- }
-#endif
-
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
} else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
wpa_printf(MSG_DEBUG, "Custom wireless event: "
"receive ReqIEs !!!");
@@ -689,51 +696,8 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
} else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
drv->g_driver_down = 1;
eloop_terminate();
- } else if (iwe->u.data.flags == RT_REPORT_AP_INFO) {
- if (drv->ap_scan != 1) {
- typedef struct PACKED {
- UCHAR bssid[MAC_ADDR_LEN];
- UCHAR ssid[MAX_LEN_OF_SSID];
- INT ssid_len;
- UCHAR wpa_ie[40];
- INT wpa_ie_len;
- UCHAR rsn_ie[40];
- INT rsn_ie_len;
- INT freq;
- USHORT caps;
- } *PAPINFO;
-
- wpa_printf(MSG_DEBUG, "Custom wireless"
- " event: receive "
- "RT_REPORT_AP_INFO !!!");
- //printf("iwe->u.data.length = %d\n", iwe->u.data.length);
- //wpa_hexdump(MSG_DEBUG, "AP_Info: ", buf, iwe->u.data.length);
-#if 0
- wpa_s->num_scan_results = 1;
- if (wpa_s->scan_results)
- os_free(wpa_s->scan_results);
- wpa_s->scan_results = os_malloc(sizeof(struct wpa_scan_result) + 1);
- if (wpa_s->scan_results) {
- PAPINFO pApInfo = (PAPINFO)buf;
- os_memcpy(wpa_s->scan_results[0].bssid, pApInfo->bssid, ETH_ALEN);
- os_memcpy(wpa_s->scan_results[0].ssid, pApInfo->ssid, pApInfo->ssid_len);
- wpa_s->scan_results[0].ssid_len = pApInfo->ssid_len;
- if (pApInfo->wpa_ie_len > 0) {
- os_memcpy(wpa_s->scan_results[0].wpa_ie, pApInfo->wpa_ie, pApInfo->wpa_ie_len);
- wpa_s->scan_results[0].wpa_ie_len = pApInfo->wpa_ie_len;
- } else if (pApInfo->rsn_ie_len > 0) {
- os_memcpy(wpa_s->scan_results[0].rsn_ie, pApInfo->rsn_ie, pApInfo->rsn_ie_len);
- wpa_s->scan_results[0].rsn_ie_len = pApInfo->rsn_ie_len;
- }
- wpa_s->scan_results[0].caps = pApInfo->caps;
- wpa_s->scan_results[0].freq = pApInfo->freq;
- } else {
- wpa_printf("wpa_s->scan_"
- "results fail to "
- "os_malloc!!\n");
- }
-#endif
- }
+ } else if (iwe->u.data.flags == RT_INTERFACE_UP) {
+ ralink_interface_up(drv);
} else {
wpa_driver_ralink_event_wireless_custom(
drv, ctx, buf);
@@ -747,29 +711,20 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
}
static void
-wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv,
- void *ctx, struct nlmsghdr *h, int len)
+wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr * attr;
+ struct wpa_driver_ralink_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- if (len < (int) sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
+ attrlen = len;
wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ 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);
@@ -787,60 +742,6 @@ wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv,
}
}
-static void wpa_driver_ralink_event_receive(int sock, void *ctx,
- void *sock_ctx)
-{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
-
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- perror("recvfrom(netlink)");
- return;
- }
-
- h = (struct nlmsghdr *) buf;
- wpa_hexdump(MSG_DEBUG, "h: ", (u8 *)h, h->nlmsg_len);
-
- while (left >= (int) sizeof(*h)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "Malformed netlink message: "
- "len=%d left=%d plen=%d", len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- wpa_driver_ralink_event_rtm_newlink(ctx, sock_ctx, h,
- plen);
- break;
- }
-
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
- }
-
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
- "message", left);
- }
-
-}
-
static int
ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
{
@@ -862,45 +763,13 @@ ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
return 0;
}
-static int
-ralink_set_iface_flags(void *priv, int dev_up)
-{
- struct wpa_driver_ralink_data *drv = priv;
- struct ifreq ifr;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (drv->ioctl_sock < 0)
- return -1;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->ifname);
-
- if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
- perror("ioctl[SIOCGIFFLAGS]");
- return -1;
- }
-
- if (dev_up)
- ifr.ifr_flags |= IFF_UP;
- else
- ifr.ifr_flags &= ~IFF_UP;
-
- if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
- perror("ioctl[SIOCSIFFLAGS]");
- return -1;
- }
-
- return 0;
-}
-
static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
{
int s;
struct wpa_driver_ralink_data *drv;
struct ifreq ifr;
- struct sockaddr_nl local;
UCHAR enable_wpa_supplicant = 0;
+ struct netlink_config *cfg;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
@@ -928,31 +797,25 @@ static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
drv->ioctl_sock = s;
drv->g_driver_down = 0;
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL) {
close(drv->ioctl_sock);
os_free(drv);
return NULL;
}
-
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
-
- if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- perror("bind(netlink)");
- close(s);
+ 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;
}
- eloop_register_read_sock(s, wpa_driver_ralink_event_receive, drv, ctx);
- drv->event_sock = s;
drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
- ralink_set_iface_flags(drv, 1); /* mark up during setup */
+ linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
ralink_get_we_version_compiled(drv);
wpa_driver_ralink_flush_pmkid(drv);
@@ -1003,12 +866,11 @@ static void wpa_driver_ralink_deinit(void *priv)
wpa_driver_ralink_flush_pmkid(drv);
sleep(1);
- ralink_set_iface_flags(drv, 0);
+ /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
}
eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
- eloop_unregister_read_sock(drv->event_sock);
- close(drv->event_sock);
+ netlink_deinit(drv->netlink);
close(drv->ioctl_sock);
os_free(drv);
}
@@ -1026,7 +888,8 @@ static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_ralink_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
struct wpa_driver_ralink_data *drv = priv;
struct iwreq iwr;
@@ -1037,6 +900,7 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
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);
@@ -1044,6 +908,14 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
}
/* 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);
@@ -1064,96 +936,124 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
return ret;
}
-static int
-wpa_driver_ralink_get_scan_results(void *priv,
- struct wpa_scan_result *results,
- size_t max_size)
+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;
- int rv = 0;
size_t ap_num;
- u8 *pos, *end;
+ u8 *pos;
+ struct wpa_scan_results *res;
if (drv->g_driver_down == 1)
- return -1;
+ return NULL;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- if (drv->we_version_compiled >= 17) {
- buf = os_zalloc(8192);
- iwr.u.data.length = 8192;
- } else {
- buf = os_zalloc(4096);
- iwr.u.data.length = 4096;
- }
- if (buf == NULL)
- return -1;
+ if (drv->we_version_compiled >= 17)
+ buf_len = 8192;
+ else
+ buf_len = 4096;
- wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
+ for (;;) {
+ buf = os_zalloc(buf_len);
+ iwr.u.data.length = buf_len;
+ if (buf == NULL)
+ return NULL;
- 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;
+ 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 ((rv = ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr)) < 0) {
- wpa_printf(MSG_DEBUG, "ioctl fail: rv = %d", rv);
+ 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 -1;
+ return NULL;
}
- os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+ 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) {
- os_memcpy(results[ap_num].bssid, &wbi->MacAddress, ETH_ALEN);
- os_memcpy(results[ap_num].ssid, wbi->Ssid.Ssid,
- wbi->Ssid.SsidLength);
- results[ap_num].ssid_len = wbi->Ssid.SsidLength;
- results[ap_num].freq = (wbi->Configuration.DSConfig / 1000);
+ 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 + sizeof(*wbi) - 1, wbi->IELength);
+ (u8 *) &wbi->IEs[0], wbi->IELength);
- pos = (u8 *) wbi + sizeof(*wbi) - 1;
- end = (u8 *) wbi + sizeof(*wbi) + wbi->IELength;
+ os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
- if (wbi->IELength < sizeof(NDIS_802_11_FIXED_IEs))
- break;
+ extra_len += (2 + wbi->Ssid.SsidLength);
+ r->ie_len = extra_len + var_ie_len;
+ pos2 = (u8 *) (r + 1);
- pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
- os_memcpy(&results[ap_num].caps, pos, 2);
- pos += 2;
+ /*
+ * 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;
- while (pos + 1 < end && pos + 2 + pos[1] <= end) {
- u8 ielen = 2 + pos[1];
+ r->freq = (wbi->Configuration.DSConfig / 1000);
- if (ielen > SSID_MAX_WPA_IE_LEN) {
- pos += ielen;
- continue;
- }
+ pos = (u8 *) wbi + sizeof(*wbi) - 1;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
- pos[1] >= 4 &&
- os_memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
- os_memcpy(results[ap_num].wpa_ie, pos, ielen);
- results[ap_num].wpa_ie_len = ielen;
- } else if (pos[0] == WLAN_EID_RSN) {
- os_memcpy(results[ap_num].rsn_ie, pos, ielen);
- results[ap_num].rsn_ie_len = ielen;
- }
- pos += ielen;
- }
+ 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 ap_num;
+ return res;
}
static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
@@ -1173,6 +1073,24 @@ static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
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)
@@ -1241,7 +1159,8 @@ static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
return res;
}
-static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
+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)
@@ -1257,6 +1176,8 @@ static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->bAddWepKey = FALSE;
+
if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
ETH_ALEN) == 0) {
/* Group Key */
@@ -1274,6 +1195,7 @@ static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
}
if (alg == WPA_ALG_WEP) {
+ drv->bAddWepKey = TRUE;
return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
set_tx, key, key_len);
}
@@ -1363,6 +1285,29 @@ static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
}
}
+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)
@@ -1373,6 +1318,7 @@ wpa_driver_ralink_associate(void *priv,
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;
@@ -1391,83 +1337,131 @@ wpa_driver_ralink_associate(void *priv,
/* Try to continue anyway */
}
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
- if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
- if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
- auth_mode = Ndis802_11AuthModeAutoSwitch;
- else
- auth_mode = Ndis802_11AuthModeShared;
- } else
- auth_mode = Ndis802_11AuthModeOpen;
- } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
- if (params->key_mgmt_suite == KEY_MGMT_PSK)
- auth_mode = Ndis802_11AuthModeWPA2PSK;
- else
- auth_mode = Ndis802_11AuthModeWPA2;
+ 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 {
- 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;
+#ifdef CONFIG_WPS
+ UCHAR enable_wpa_supplicant;
+
+ if (drv->ap_scan == 1)
+ enable_wpa_supplicant = 0x01;
else
- auth_mode = Ndis802_11AuthModeWPA;
- }
+ 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)
+ switch (params->pairwise_suite) {
+ case CIPHER_CCMP:
encr = Ndis802_11Encryption3Enabled;
- else if (params->group_suite == CIPHER_TKIP)
+ break;
+ case CIPHER_TKIP:
encr = Ndis802_11Encryption2Enabled;
- else
+ 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;
- default:
- encr = Ndis802_11EncryptionDisabled;
- break;
- }
-
- ralink_set_auth_mode(drv, auth_mode);
+ break;
+ }
- /* notify driver that IEEE8021x mode is enabled */
- if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA)
- ieee8021xMode = TRUE;
- else
- ieee8021xMode = FALSE;
+ ralink_set_auth_mode(drv, auth_mode);
- 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);
- }
+ /* 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_WEP_STATUS,
- (char *) &encr, sizeof(encr)) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_WEP_STATUS(%d)",
- (int) encr);
- }
+ 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 ((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) {
+ 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_DROP_UNENCRYPTED(%d)",
- (int) encr);
+ "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);
+ }
}
}
@@ -1494,8 +1488,8 @@ const struct wpa_driver_ops wpa_driver_ralink_ops = {
.init = wpa_driver_ralink_init,
.deinit = wpa_driver_ralink_deinit,
.set_countermeasures = wpa_driver_ralink_set_countermeasures,
- .scan = wpa_driver_ralink_scan,
- .get_scan_results = wpa_driver_ralink_get_scan_results,
+ .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,
diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h
index ddf44de232a3b..d13df28de4564 100644
--- a/src/drivers/driver_ralink.h
+++ b/src/drivers/driver_ralink.h
@@ -54,6 +54,7 @@
#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))
@@ -65,7 +66,7 @@
#define RT_ASSOCINFO_EVENT_FLAG 0x0105
#define RT_PMKIDCAND_FLAG 0x0106
#define RT_INTERFACE_DOWN 0x0107
-#define RT_REPORT_AP_INFO 0x0108
+#define RT_INTERFACE_UP 0x0108
//
// IEEE 802.11 Structures and definitions
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index bc11a48484326..6877eda3ed22c 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -23,10 +23,6 @@
#include "driver.h"
#include "l2_packet/l2_packet.h"
-#ifndef ETH_P_EAPOL
-#define ETH_P_EAPOL 0x888e
-#endif
-
#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */
/* MII access registers */
@@ -183,10 +179,8 @@ static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
struct wpa_driver_roboswitch_data *drv = priv;
if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
- os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) {
- wpa_supplicant_rx_eapol(drv->ctx, src_addr, buf + 14,
- len - 14);
- }
+ os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0)
+ drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14);
}
@@ -205,6 +199,15 @@ static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
}
+static int wpa_driver_roboswitch_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_WIRED;
+ return 0;
+}
+
+
static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
{
struct wpa_driver_roboswitch_data *drv = priv;
@@ -469,6 +472,7 @@ const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
.desc = "wpa_supplicant roboswitch driver",
.get_ssid = wpa_driver_roboswitch_get_ssid,
.get_bssid = wpa_driver_roboswitch_get_bssid,
+ .get_capa = wpa_driver_roboswitch_get_capa,
.init = wpa_driver_roboswitch_init,
.deinit = wpa_driver_roboswitch_deinit,
.set_param = wpa_driver_roboswitch_set_param,
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 2a41cf260a5a9..fb2467350f1ee 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant - testing driver interface
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Testing driver interface for a simulated network driver
+ * Copyright (c) 2004-2010, 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
@@ -12,13 +12,13 @@
* See README and COPYING for more details.
*/
-/* Make dure we get winsock2.h for Windows build to get sockaddr_storage */
+/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */
#include "build_config.h"
#ifdef CONFIG_NATIVE_WINDOWS
#include <winsock2.h>
#endif /* CONFIG_NATIVE_WINDOWS */
-#include "includes.h"
+#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <sys/un.h>
@@ -27,21 +27,50 @@
#define DRIVER_TEST_UNIX
#endif /* CONFIG_NATIVE_WINDOWS */
-#include "common.h"
-#include "driver.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
+#include "utils/trace.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/sha1.h"
#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "sha1.h"
-#include "ieee802_11_defs.h"
+#include "driver.h"
+struct test_client_socket {
+ struct test_client_socket *next;
+ u8 addr[ETH_ALEN];
+ struct sockaddr_un un;
+ socklen_t unlen;
+ struct test_driver_bss *bss;
+};
+
+struct test_driver_bss {
+ struct wpa_driver_test_data *drv;
+ struct dl_list list;
+ void *bss_ctx;
+ char ifname[IFNAMSIZ];
+ u8 bssid[ETH_ALEN];
+ u8 *ie;
+ size_t ielen;
+ u8 *wps_beacon_ie;
+ size_t wps_beacon_ie_len;
+ u8 *wps_probe_resp_ie;
+ size_t wps_probe_resp_ie_len;
+ u8 ssid[32];
+ size_t ssid_len;
+ int privacy;
+};
+
struct wpa_driver_test_global {
- int dummy;
+ int bss_add_used;
+ u8 req_addr[ETH_ALEN];
};
struct wpa_driver_test_data {
struct wpa_driver_test_global *global;
void *ctx;
+ WPA_TRACE_REF(ctx);
u8 own_addr[ETH_ALEN];
int test_socket;
#ifdef DRIVER_TEST_UNIX
@@ -52,9 +81,6 @@ struct wpa_driver_test_data {
int hostapd_addr_udp_set;
char *own_socket_path;
char *test_dir;
- u8 bssid[ETH_ALEN];
- u8 ssid[32];
- size_t ssid_len;
#define MAX_SCAN_RESULTS 30
struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
size_t num_scanres;
@@ -65,9 +91,1164 @@ struct wpa_driver_test_data {
int associated;
u8 *probe_req_ie;
size_t probe_req_ie_len;
+ u8 probe_req_ssid[32];
+ size_t probe_req_ssid_len;
+ int ibss;
+ int ap;
+
+ struct test_client_socket *cli;
+ struct dl_list bss;
+ int udp_port;
+
+ int alloc_iface_idx;
+
+ int probe_req_report;
+ unsigned int remain_on_channel_freq;
+ unsigned int remain_on_channel_duration;
+
+ int current_freq;
};
+static void wpa_driver_test_deinit(void *priv);
+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
+ const char *dir, int ap);
+static void wpa_driver_test_close_test_socket(
+ struct wpa_driver_test_data *drv);
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
+static void test_driver_free_bss(struct test_driver_bss *bss)
+{
+ os_free(bss->ie);
+ os_free(bss->wps_beacon_ie);
+ os_free(bss->wps_probe_resp_ie);
+ os_free(bss);
+}
+
+
+static void test_driver_free_bsses(struct wpa_driver_test_data *drv)
+{
+ struct test_driver_bss *bss, *tmp;
+
+ dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss,
+ list) {
+ dl_list_del(&bss->list);
+ test_driver_free_bss(bss);
+ }
+}
+
+
+static struct test_client_socket *
+test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct test_client_socket *cli = drv->cli;
+
+ while (cli) {
+ if (cli->unlen == fromlen &&
+ strncmp(cli->un.sun_path, from->sun_path,
+ fromlen - sizeof(cli->un.sun_family)) == 0)
+ return cli;
+ cli = cli->next;
+ }
+
+ return NULL;
+}
+
+
+static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt,
+ const u8 *own_addr)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct test_client_socket *cli;
+ struct msghdr msg;
+ struct iovec io[3];
+ struct l2_ethhdr eth;
+
+ if (drv->test_socket < 0)
+ return -1;
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+
+ if (!cli) {
+ wpa_printf(MSG_DEBUG, "%s: no destination client entry",
+ __func__);
+ return -1;
+ }
+
+ memcpy(eth.h_dest, addr, ETH_ALEN);
+ memcpy(eth.h_source, own_addr, ETH_ALEN);
+ eth.h_proto = host_to_be16(ETH_P_EAPOL);
+
+ io[0].iov_base = "EAPOL ";
+ io[0].iov_len = 6;
+ io[1].iov_base = &eth;
+ io[1].iov_len = sizeof(eth);
+ io[2].iov_base = (u8 *) data;
+ io[2].iov_len = data_len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 3;
+ msg.msg_name = &cli->un;
+ msg.msg_namelen = cli->unlen;
+ return sendmsg(drv->test_socket, &msg, 0);
+}
+
+
+static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
+ u16 proto, const u8 *data, size_t data_len)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct msghdr msg;
+ struct iovec io[3];
+ struct l2_ethhdr eth;
+ char desttxt[30];
+ struct sockaddr_un addr;
+ struct dirent *dent;
+ DIR *dir;
+ int ret = 0, broadcast = 0, count = 0;
+
+ if (drv->test_socket < 0 || drv->test_dir == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d "
+ "test_dir=%p)",
+ __func__, drv->test_socket, drv->test_dir);
+ return -1;
+ }
+
+ broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+ snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst));
+
+ memcpy(eth.h_dest, dst, ETH_ALEN);
+ memcpy(eth.h_source, src, ETH_ALEN);
+ eth.h_proto = host_to_be16(proto);
+
+ io[0].iov_base = "ETHER ";
+ io[0].iov_len = 6;
+ io[1].iov_base = &eth;
+ io[1].iov_len = sizeof(eth);
+ io[2].iov_base = (u8 *) data;
+ io[2].iov_len = data_len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 3;
+
+ dir = opendir(drv->test_dir);
+ if (dir == NULL) {
+ perror("test_driver: opendir");
+ return -1;
+ }
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket. Also accept
+ * DT_UNKNOWN (0) in case the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+ drv->test_dir, dent->d_name);
+
+ if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
+ continue;
+ if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s",
+ __func__, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ ret = sendmsg(drv->test_socket, &msg, 0);
+ if (ret < 0)
+ perror("driver_test: sendmsg");
+ count++;
+ }
+ closedir(dir);
+
+ if (!broadcast && count == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found",
+ __func__, MAC2STR(dst));
+ return -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
+ size_t data_len)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct msghdr msg;
+ struct iovec io[2];
+ const u8 *dest;
+ struct sockaddr_un addr;
+ struct dirent *dent;
+ DIR *dir;
+ int broadcast;
+ int ret = 0;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ char cmd[50];
+ int freq;
+#ifdef HOSTAPD
+ char desttxt[30];
+#endif /* HOSTAPD */
+ union wpa_event_data event;
+
+ wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
+ if (drv->test_socket < 0 || data_len < 10) {
+ wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu"
+ " test_dir=%p)",
+ __func__, drv->test_socket,
+ (unsigned long) data_len,
+ drv->test_dir);
+ return -1;
+ }
+
+ dest = data + 4;
+ broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+
+#ifdef HOSTAPD
+ snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
+#endif /* HOSTAPD */
+
+ if (drv->remain_on_channel_freq)
+ freq = drv->remain_on_channel_freq;
+ else
+ freq = drv->current_freq;
+ wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz",
+ dbss->ifname, freq);
+ os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq);
+ io[0].iov_base = cmd;
+ io[0].iov_len = os_strlen(cmd);
+ io[1].iov_base = (void *) data;
+ io[1].iov_len = data_len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+
+#ifdef HOSTAPD
+ if (drv->test_dir == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__);
+ return -1;
+ }
+
+ dir = opendir(drv->test_dir);
+ if (dir == NULL) {
+ perror("test_driver: opendir");
+ return -1;
+ }
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket. Also accept
+ * DT_UNKNOWN (0) in case the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (os_strcmp(dent->d_name, ".") == 0 ||
+ os_strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+ drv->test_dir, dent->d_name);
+
+ if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0)
+ continue;
+ if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
+ __func__, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ ret = sendmsg(drv->test_socket, &msg, 0);
+ if (ret < 0)
+ perror("driver_test: sendmsg(test_socket)");
+ }
+ closedir(dir);
+#else /* HOSTAPD */
+
+ if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
+ drv->test_dir == NULL) {
+ if (drv->hostapd_addr_udp_set) {
+ msg.msg_name = &drv->hostapd_addr_udp;
+ msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ msg.msg_name = &drv->hostapd_addr;
+ msg.msg_namelen = sizeof(drv->hostapd_addr);
+#endif /* DRIVER_TEST_UNIX */
+ }
+ } else if (broadcast) {
+ dir = opendir(drv->test_dir);
+ if (dir == NULL)
+ return -1;
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (os_strcmp(dent->d_name, ".") == 0 ||
+ os_strcmp(dent->d_name, "..") == 0)
+ continue;
+ wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
+ __func__, dent->d_name);
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/%s", drv->test_dir, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+
+ ret = sendmsg(drv->test_socket, &msg, 0);
+ if (ret < 0)
+ perror("driver_test: sendmsg(test_socket)");
+ }
+ closedir(dir);
+ return ret;
+ } else {
+ struct stat st;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
+ if (stat(addr.sun_path, &st) < 0) {
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/STA-" MACSTR,
+ drv->test_dir, MAC2STR(dest));
+ }
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ }
+
+ if (sendmsg(drv->test_socket, &msg, 0) < 0) {
+ perror("sendmsg(test_socket)");
+ return -1;
+ }
+#endif /* HOSTAPD */
+
+ hdr = (struct ieee80211_hdr *) data;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = data;
+ event.tx_status.data_len = data_len;
+ event.tx_status.ack = ret >= 0;
+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+
+ return ret;
+}
+
+
+static void test_driver_scan(struct wpa_driver_test_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ char *data)
+{
+ char buf[512], *pos, *end;
+ int ret;
+ struct test_driver_bss *bss;
+ u8 sa[ETH_ALEN];
+ u8 ie[512];
+ size_t ielen;
+ union wpa_event_data event;
+
+ /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
+
+ wpa_printf(MSG_DEBUG, "test_driver: SCAN");
+
+ if (*data) {
+ if (*data != ' ' ||
+ hwaddr_aton(data + 1, sa)) {
+ wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN "
+ "command format");
+ return;
+ }
+
+ data += 18;
+ while (*data == ' ')
+ data++;
+ ielen = os_strlen(data) / 2;
+ if (ielen > sizeof(ie))
+ ielen = sizeof(ie);
+ if (hexstr2bin(data, ie, ielen) < 0)
+ ielen = 0;
+
+ wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR,
+ MAC2STR(sa));
+ wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_probe_req.sa = sa;
+ event.rx_probe_req.ie = ie;
+ event.rx_probe_req.ie_len = ielen;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
+ }
+
+ dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
+ pos = buf;
+ end = buf + sizeof(buf);
+
+ /* reply: SCANRESP BSSID SSID IEs */
+ ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+ MAC2STR(bss->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos,
+ bss->ssid, bss->ssid_len);
+ ret = snprintf(pos, end - pos, " ");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
+ pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie,
+ bss->wps_probe_resp_ie_len);
+
+ if (bss->privacy) {
+ ret = snprintf(pos, end - pos, " PRIVACY");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ }
+
+ sendto(drv->test_socket, buf, pos - buf, 0,
+ (struct sockaddr *) from, fromlen);
+ }
+}
+
+
+static void test_driver_assoc(struct wpa_driver_test_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ char *data)
+{
+ struct test_client_socket *cli;
+ u8 ie[256], ssid[32];
+ size_t ielen, ssid_len = 0;
+ char *pos, *pos2, cmd[50];
+ struct test_driver_bss *bss, *tmp;
+
+ /* data: STA-addr SSID(hex) IEs(hex) */
+
+ cli = os_zalloc(sizeof(*cli));
+ if (cli == NULL)
+ return;
+
+ if (hwaddr_aton(data, cli->addr)) {
+ printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
+ data);
+ os_free(cli);
+ return;
+ }
+ pos = data + 17;
+ while (*pos == ' ')
+ pos++;
+ pos2 = strchr(pos, ' ');
+ ielen = 0;
+ if (pos2) {
+ ssid_len = (pos2 - pos) / 2;
+ if (hexstr2bin(pos, ssid, ssid_len) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
+ os_free(cli);
+ return;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
+ ssid, ssid_len);
+
+ pos = pos2 + 1;
+ ielen = strlen(pos) / 2;
+ if (ielen > sizeof(ie))
+ ielen = sizeof(ie);
+ if (hexstr2bin(pos, ie, ielen) < 0)
+ ielen = 0;
+ }
+
+ bss = NULL;
+ dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) {
+ if (tmp->ssid_len == ssid_len &&
+ os_memcmp(tmp->ssid, ssid, ssid_len) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
+ "configured BSSes", __func__);
+ os_free(cli);
+ return;
+ }
+
+ cli->bss = bss;
+ memcpy(&cli->un, from, sizeof(cli->un));
+ cli->unlen = fromlen;
+ cli->next = drv->cli;
+ drv->cli = cli;
+ wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
+ (const u8 *) cli->un.sun_path,
+ cli->unlen - sizeof(cli->un.sun_family));
+
+ snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
+ MAC2STR(bss->bssid));
+ sendto(drv->test_socket, cmd, strlen(cmd), 0,
+ (struct sockaddr *) from, fromlen);
+
+ drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen);
+}
+
+
+static void test_driver_disassoc(struct wpa_driver_test_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen)
+{
+ struct test_client_socket *cli;
+
+ cli = test_driver_get_cli(drv, from, fromlen);
+ if (!cli)
+ return;
+
+ drv_event_disassoc(drv->ctx, cli->addr);
+}
+
+
+static void test_driver_eapol(struct wpa_driver_test_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ u8 *data, size_t datalen)
+{
+#ifdef HOSTAPD
+ struct test_client_socket *cli;
+#endif /* HOSTAPD */
+ const u8 *src = NULL;
+
+ if (datalen > 14) {
+ /* Skip Ethernet header */
+ src = data + ETH_ALEN;
+ wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
+ MACSTR " proto=%04x",
+ MAC2STR(data), MAC2STR(src),
+ WPA_GET_BE16(data + 2 * ETH_ALEN));
+ data += 14;
+ datalen -= 14;
+ }
+
+#ifdef HOSTAPD
+ cli = test_driver_get_cli(drv, from, fromlen);
+ if (cli) {
+ drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data,
+ datalen);
+ } else {
+ wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
+ "client");
+ }
+#else /* HOSTAPD */
+ if (src)
+ drv_event_eapol_rx(drv->ctx, src, data, datalen);
+#endif /* HOSTAPD */
+}
+
+
+static void test_driver_ether(struct wpa_driver_test_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ u8 *data, size_t datalen)
+{
+ struct l2_ethhdr *eth;
+
+ if (datalen < sizeof(*eth))
+ return;
+
+ eth = (struct l2_ethhdr *) data;
+ wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
+ MACSTR " proto=%04x",
+ MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
+ be_to_host16(eth->h_proto));
+
+#ifdef CONFIG_IEEE80211R
+ if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
+ union wpa_event_data ev;
+ os_memset(&ev, 0, sizeof(ev));
+ ev.ft_rrb_rx.src = eth->h_source;
+ ev.ft_rrb_rx.data = data + sizeof(*eth);
+ ev.ft_rrb_rx.data_len = datalen - sizeof(*eth);
+ }
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+static void test_driver_mlme(struct wpa_driver_test_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ u8 *data, size_t datalen)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+ int freq = 0, own_freq;
+ struct test_driver_bss *bss;
+
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+ if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) {
+ size_t pos;
+ for (pos = 5; pos < datalen; pos++) {
+ if (data[pos] == ' ')
+ break;
+ }
+ if (pos < datalen) {
+ freq = atoi((const char *) &data[5]);
+ wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
+ "freq %d MHz", bss->ifname, freq);
+ pos++;
+ data += pos;
+ datalen -= pos;
+ }
+ }
+
+ if (drv->remain_on_channel_freq)
+ own_freq = drv->remain_on_channel_freq;
+ else
+ own_freq = drv->current_freq;
+
+ if (freq && own_freq && freq != own_freq) {
+ wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
+ "another frequency %d MHz (own %d MHz)",
+ bss->ifname, freq, own_freq);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) data;
+
+ if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
+ struct test_client_socket *cli;
+ cli = os_zalloc(sizeof(*cli));
+ if (cli == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
+ MAC2STR(hdr->addr2));
+ memcpy(cli->addr, hdr->addr2, ETH_ALEN);
+ memcpy(&cli->un, from, sizeof(cli->un));
+ cli->unlen = fromlen;
+ cli->next = drv->cli;
+ drv->cli = cli;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
+ data, datalen);
+ fc = le_to_host16(hdr->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
+ wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
+ __func__);
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = data;
+ event.rx_mgmt.frame_len = datalen;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_test_data *drv = eloop_ctx;
+ char buf[2000];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(test_socket)");
+ return;
+ }
+ buf[res] = '\0';
+
+ wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
+
+ if (strncmp(buf, "SCAN", 4) == 0) {
+ test_driver_scan(drv, &from, fromlen, buf + 4);
+ } else if (strncmp(buf, "ASSOC ", 6) == 0) {
+ test_driver_assoc(drv, &from, fromlen, buf + 6);
+ } else if (strcmp(buf, "DISASSOC") == 0) {
+ test_driver_disassoc(drv, &from, fromlen);
+ } else if (strncmp(buf, "EAPOL ", 6) == 0) {
+ test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
+ res - 6);
+ } else if (strncmp(buf, "ETHER ", 6) == 0) {
+ test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6,
+ res - 6);
+ } else if (strncmp(buf, "MLME ", 5) == 0) {
+ test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
+ } else {
+ wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
+ (u8 *) buf, res);
+ }
+}
+
+
+static int test_driver_set_generic_elem(void *priv,
+ const u8 *elem, size_t elem_len)
+{
+ struct test_driver_bss *bss = priv;
+
+ os_free(bss->ie);
+
+ if (elem == NULL) {
+ bss->ie = NULL;
+ bss->ielen = 0;
+ return 0;
+ }
+
+ bss->ie = os_malloc(elem_len);
+ if (bss->ie == NULL) {
+ bss->ielen = 0;
+ return -1;
+ }
+
+ memcpy(bss->ie, elem, elem_len);
+ bss->ielen = elem_len;
+ return 0;
+}
+
+
+static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp)
+{
+ struct test_driver_bss *bss = priv;
+
+ if (beacon == NULL)
+ wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE");
+ else
+ wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE",
+ beacon);
+
+ os_free(bss->wps_beacon_ie);
+
+ if (beacon == NULL) {
+ bss->wps_beacon_ie = NULL;
+ bss->wps_beacon_ie_len = 0;
+ } else {
+ bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon));
+ if (bss->wps_beacon_ie == NULL) {
+ bss->wps_beacon_ie_len = 0;
+ return -1;
+ }
+
+ os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon),
+ wpabuf_len(beacon));
+ bss->wps_beacon_ie_len = wpabuf_len(beacon);
+ }
+
+ if (proberesp == NULL)
+ wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS "
+ "IE");
+ else
+ wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS "
+ "IE", proberesp);
+
+ os_free(bss->wps_probe_resp_ie);
+
+ if (proberesp == NULL) {
+ bss->wps_probe_resp_ie = NULL;
+ bss->wps_probe_resp_ie_len = 0;
+ } else {
+ bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp));
+ if (bss->wps_probe_resp_ie == NULL) {
+ bss->wps_probe_resp_ie_len = 0;
+ return -1;
+ }
+
+ os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp),
+ wpabuf_len(proberesp));
+ bss->wps_probe_resp_ie_len = wpabuf_len(proberesp);
+ }
+
+ return 0;
+}
+
+
+static int test_driver_sta_deauth(void *priv, const u8 *own_addr,
+ const u8 *addr, int reason)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct test_client_socket *cli;
+
+ if (drv->test_socket < 0)
+ return -1;
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+
+ if (!cli)
+ return -1;
+
+ return sendto(drv->test_socket, "DEAUTH", 6, 0,
+ (struct sockaddr *) &cli->un, cli->unlen);
+}
+
+
+static int test_driver_sta_disassoc(void *priv, const u8 *own_addr,
+ const u8 *addr, int reason)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct test_client_socket *cli;
+
+ if (drv->test_socket < 0)
+ return -1;
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+
+ if (!cli)
+ return -1;
+
+ return sendto(drv->test_socket, "DISASSOC", 8, 0,
+ (struct sockaddr *) &cli->un, cli->unlen);
+}
+
+
+static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid,
+ void *bss_ctx, void **drv_priv)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct test_driver_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
+ __func__, ifname, MAC2STR(bssid));
+
+ bss = os_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return -1;
+
+ bss->bss_ctx = bss_ctx;
+ bss->drv = drv;
+ os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
+ os_memcpy(bss->bssid, bssid, ETH_ALEN);
+
+ dl_list_add(&drv->bss, &bss->list);
+ if (drv->global) {
+ drv->global->bss_add_used = 1;
+ os_memcpy(drv->global->req_addr, bssid, ETH_ALEN);
+ }
+
+ if (drv_priv)
+ *drv_priv = bss;
+
+ return 0;
+}
+
+
+static int test_driver_bss_remove(void *priv, const char *ifname)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct test_driver_bss *bss;
+ struct test_client_socket *cli, *prev_c;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
+
+ dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
+ if (strcmp(bss->ifname, ifname) != 0)
+ continue;
+
+ for (prev_c = NULL, cli = drv->cli; cli;
+ prev_c = cli, cli = cli->next) {
+ if (cli->bss != bss)
+ continue;
+ if (prev_c)
+ prev_c->next = cli->next;
+ else
+ drv->cli = cli->next;
+ os_free(cli);
+ break;
+ }
+
+ dl_list_del(&bss->list);
+ test_driver_free_bss(bss);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, const u8 *addr,
+ void *bss_ctx, void **drv_priv,
+ char *force_ifname, u8 *if_addr)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+
+ wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)",
+ __func__, type, ifname, bss_ctx);
+ if (addr)
+ os_memcpy(if_addr, addr, ETH_ALEN);
+ else {
+ drv->alloc_iface_idx++;
+ if_addr[0] = 0x02; /* locally administered */
+ sha1_prf(drv->own_addr, ETH_ALEN,
+ "hostapd test addr generation",
+ (const u8 *) &drv->alloc_iface_idx,
+ sizeof(drv->alloc_iface_idx),
+ if_addr + 1, ETH_ALEN - 1);
+ }
+ if (type == WPA_IF_AP_BSS)
+ return test_driver_bss_add(priv, ifname, if_addr, bss_ctx,
+ drv_priv);
+ return 0;
+}
+
+
+static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
+ const char *ifname)
+{
+ wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
+ if (type == WPA_IF_AP_BSS)
+ return test_driver_bss_remove(priv, ifname);
+ return 0;
+}
+
+
+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;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname);
+ wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
+
+ if (len < 0 || (size_t) len > sizeof(bss->ssid))
+ return -1;
+
+ os_memcpy(bss->ssid, buf, len);
+ bss->ssid_len = len;
+
+ return 0;
+}
+
+
+static int test_driver_set_privacy(void *priv, int enabled)
+{
+ struct test_driver_bss *dbss = priv;
+
+ wpa_printf(MSG_DEBUG, "%s(enabled=%d)", __func__, enabled);
+ dbss->privacy = enabled;
+
+ return 0;
+}
+
+
+static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
+ __func__, MAC2STR(addr), ifname, vlan_id);
+ return 0;
+}
+
+
+static int test_driver_sta_add(void *priv,
+ struct hostapd_sta_add_params *params)
+{
+ struct test_driver_bss *bss = priv;
+ struct wpa_driver_test_data *drv = bss->drv;
+ struct test_client_socket *cli;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
+ "capability=0x%x listen_interval=%d)",
+ __func__, bss->ifname, MAC2STR(params->addr), params->aid,
+ params->capability, params->listen_interval);
+ wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
+ params->supp_rates, params->supp_rates_len);
+
+ cli = drv->cli;
+ while (cli) {
+ if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+ if (!cli) {
+ wpa_printf(MSG_DEBUG, "%s: no matching client entry",
+ __func__);
+ return -1;
+ }
+
+ cli->bss = bss;
+
+ return 0;
+}
+
+
+static struct wpa_driver_test_data * test_alloc_data(void *ctx,
+ const char *ifname)
+{
+ struct wpa_driver_test_data *drv;
+ struct test_driver_bss *bss;
+
+ drv = os_zalloc(sizeof(struct wpa_driver_test_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate memory for test "
+ "driver data");
+ return NULL;
+ }
+
+ bss = os_zalloc(sizeof(struct test_driver_bss));
+ if (bss == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ wpa_trace_add_ref(drv, ctx, ctx);
+ dl_list_init(&drv->bss);
+ dl_list_add(&drv->bss, &bss->list);
+ os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
+ bss->bss_ctx = ctx;
+ bss->drv = drv;
+
+ /* Generate a MAC address to help testing with multiple STAs */
+ drv->own_addr[0] = 0x02; /* locally administered */
+ sha1_prf((const u8 *) ifname, os_strlen(ifname),
+ "test mac addr generation",
+ NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
+
+ return drv;
+}
+
+
+static void * test_driver_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct wpa_driver_test_data *drv;
+ struct sockaddr_un addr_un;
+ struct sockaddr_in addr_in;
+ struct sockaddr *addr;
+ socklen_t alen;
+ struct test_driver_bss *bss;
+
+ drv = test_alloc_data(hapd, params->ifname);
+ if (drv == NULL)
+ return NULL;
+ drv->ap = 1;
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+ bss->bss_ctx = hapd;
+ os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
+ os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN);
+
+ if (params->test_socket) {
+ if (os_strlen(params->test_socket) >=
+ sizeof(addr_un.sun_path)) {
+ printf("Too long test_socket path\n");
+ wpa_driver_test_deinit(bss);
+ return NULL;
+ }
+ if (strncmp(params->test_socket, "DIR:", 4) == 0) {
+ size_t len = strlen(params->test_socket) + 30;
+ drv->test_dir = os_strdup(params->test_socket + 4);
+ drv->own_socket_path = os_malloc(len);
+ if (drv->own_socket_path) {
+ snprintf(drv->own_socket_path, len,
+ "%s/AP-" MACSTR,
+ params->test_socket + 4,
+ MAC2STR(params->own_addr));
+ }
+ } else if (strncmp(params->test_socket, "UDP:", 4) == 0) {
+ drv->udp_port = atoi(params->test_socket + 4);
+ } else {
+ drv->own_socket_path = os_strdup(params->test_socket);
+ }
+ if (drv->own_socket_path == NULL && drv->udp_port == 0) {
+ wpa_driver_test_deinit(bss);
+ return NULL;
+ }
+
+ drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX,
+ SOCK_DGRAM, 0);
+ if (drv->test_socket < 0) {
+ perror("socket");
+ wpa_driver_test_deinit(bss);
+ return NULL;
+ }
+
+ if (drv->udp_port) {
+ os_memset(&addr_in, 0, sizeof(addr_in));
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = htons(drv->udp_port);
+ addr = (struct sockaddr *) &addr_in;
+ alen = sizeof(addr_in);
+ } else {
+ os_memset(&addr_un, 0, sizeof(addr_un));
+ addr_un.sun_family = AF_UNIX;
+ os_strlcpy(addr_un.sun_path, drv->own_socket_path,
+ sizeof(addr_un.sun_path));
+ addr = (struct sockaddr *) &addr_un;
+ alen = sizeof(addr_un);
+ }
+ if (bind(drv->test_socket, addr, alen) < 0) {
+ perror("bind(PF_UNIX)");
+ close(drv->test_socket);
+ if (drv->own_socket_path)
+ unlink(drv->own_socket_path);
+ wpa_driver_test_deinit(bss);
+ return NULL;
+ }
+ eloop_register_read_sock(drv->test_socket,
+ test_driver_receive_unix, drv, NULL);
+ } else
+ drv->test_socket = -1;
+
+ return bss;
+}
+
+
static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_test_data *drv = eloop_ctx;
@@ -88,13 +1269,6 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
}
-static int wpa_driver_test_set_wpa(void *priv, int enabled)
-{
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
- return 0;
-}
-
-
static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
@@ -129,11 +1303,31 @@ static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
drv->probe_req_ie_len);
}
+ if (drv->probe_req_ssid_len) {
+ /* Add SSID IE */
+ ret = os_snprintf(pos, end - pos, "%02x%02x",
+ WLAN_EID_SSID,
+ (unsigned int) drv->probe_req_ssid_len);
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid,
+ drv->probe_req_ssid_len);
+ }
end[-1] = '\0';
while ((dent = readdir(dir))) {
- if (os_strncmp(dent->d_name, "AP-", 3) != 0)
+ if (os_strncmp(dent->d_name, "AP-", 3) != 0 &&
+ os_strncmp(dent->d_name, "STA-", 4) != 0)
continue;
+ if (drv->own_socket_path) {
+ size_t olen, dlen;
+ olen = os_strlen(drv->own_socket_path);
+ dlen = os_strlen(dent->d_name);
+ if (olen >= dlen &&
+ os_strcmp(dent->d_name,
+ drv->own_socket_path + olen - dlen) == 0)
+ continue;
+ }
wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
os_memset(&addr, 0, sizeof(addr));
@@ -151,11 +1345,42 @@ static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
#endif /* DRIVER_TEST_UNIX */
-static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_test_scan(void *priv,
+ struct wpa_driver_scan_params *params)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ size_t i;
+
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+ os_free(drv->probe_req_ie);
+ if (params->extra_ies) {
+ drv->probe_req_ie = os_malloc(params->extra_ies_len);
+ if (drv->probe_req_ie == NULL) {
+ drv->probe_req_ie_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->probe_req_ie, params->extra_ies,
+ params->extra_ies_len);
+ drv->probe_req_ie_len = params->extra_ies_len;
+ } else {
+ drv->probe_req_ie = NULL;
+ drv->probe_req_ie_len = 0;
+ }
+
+ for (i = 0; i < params->num_ssids; i++)
+ wpa_hexdump(MSG_DEBUG, "Scan SSID",
+ params->ssids[i].ssid, params->ssids[i].ssid_len);
+ drv->probe_req_ssid_len = 0;
+ if (params->num_ssids) {
+ os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid,
+ params->ssids[0].ssid_len);
+ drv->probe_req_ssid_len = params->ssids[0].ssid_len;
+ }
+ wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)",
+ params->extra_ies, params->extra_ies_len);
+
drv->num_scanres = 0;
#ifdef DRIVER_TEST_UNIX
@@ -186,7 +1411,8 @@ static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
struct wpa_scan_results *res;
size_t i;
@@ -216,22 +1442,37 @@ static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
}
-static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr,
+static int wpa_driver_test_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)
{
- wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
- __func__, priv, alg, key_idx, set_tx);
- if (addr) {
+ wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d "
+ "set_tx=%d",
+ __func__, ifname, priv, alg, key_idx, set_tx);
+ if (addr)
wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
- }
- if (seq) {
+ if (seq)
wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len);
+ if (key)
+ wpa_hexdump_key(MSG_DEBUG, " key", key, key_len);
+ return 0;
+}
+
+
+static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap)
+{
+ if (ap && !drv->ap) {
+ wpa_driver_test_close_test_socket(drv);
+ wpa_driver_test_attach(drv, drv->test_dir, 1);
+ drv->ap = 1;
+ } else if (!ap && drv->ap) {
+ wpa_driver_test_close_test_socket(drv);
+ wpa_driver_test_attach(drv, drv->test_dir, 0);
+ drv->ap = 0;
}
- if (key) {
- wpa_hexdump(MSG_DEBUG, " key", key, key_len);
- }
+
return 0;
}
@@ -239,7 +1480,8 @@ static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr,
static int wpa_driver_test_associate(
void *priv, struct wpa_driver_associate_params *params)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
__func__, priv, params->freq, params->pairwise_suite,
@@ -264,8 +1506,23 @@ static int wpa_driver_test_associate(
} else
drv->assoc_wpa_ie_len = 0;
+ wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
+
+ drv->ibss = params->mode == IEEE80211_MODE_IBSS;
+ dbss->privacy = params->key_mgmt_suite &
+ (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_WPA_NONE |
+ WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_PSK_SHA256);
+ if (params->wep_key_len[params->wep_tx_keyidx])
+ dbss->privacy = 1;
+
#ifdef DRIVER_TEST_UNIX
- if (drv->test_dir && params->bssid) {
+ if (drv->test_dir && params->bssid &&
+ params->mode != IEEE80211_MODE_IBSS) {
os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
drv->hostapd_addr.sun_family = AF_UNIX;
os_snprintf(drv->hostapd_addr.sun_path,
@@ -276,8 +1533,20 @@ static int wpa_driver_test_associate(
}
#endif /* DRIVER_TEST_UNIX */
- if (drv->test_socket >= 0 &&
- (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
+ if (params->mode == IEEE80211_MODE_AP) {
+ os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
+ dbss->ssid_len = params->ssid_len;
+ os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN);
+ if (params->wpa_ie && params->wpa_ie_len) {
+ dbss->ie = os_malloc(params->wpa_ie_len);
+ if (dbss->ie) {
+ os_memcpy(dbss->ie, params->wpa_ie,
+ params->wpa_ie_len);
+ dbss->ielen = params->wpa_ie_len;
+ }
+ }
+ } else if (drv->test_socket >= 0 &&
+ (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
char cmd[200], *pos, *end;
int ret;
end = cmd + sizeof(cmd);
@@ -311,10 +1580,22 @@ static int wpa_driver_test_associate(
return -1;
}
- os_memcpy(drv->ssid, params->ssid, params->ssid_len);
- drv->ssid_len = params->ssid_len;
+ os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
+ dbss->ssid_len = params->ssid_len;
} else {
drv->associated = 1;
+ if (params->mode == IEEE80211_MODE_IBSS) {
+ os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
+ dbss->ssid_len = params->ssid_len;
+ if (params->bssid)
+ os_memcpy(dbss->bssid, params->bssid,
+ ETH_ALEN);
+ else {
+ os_get_random(dbss->bssid, ETH_ALEN);
+ dbss->bssid[0] &= ~0x01;
+ dbss->bssid[0] |= 0x02;
+ }
+ }
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
}
@@ -324,17 +1605,17 @@ static int wpa_driver_test_associate(
static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
{
- struct wpa_driver_test_data *drv = priv;
- os_memcpy(bssid, drv->bssid, ETH_ALEN);
+ struct test_driver_bss *dbss = priv;
+ os_memcpy(bssid, dbss->bssid, ETH_ALEN);
return 0;
}
static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
{
- struct wpa_driver_test_data *drv = priv;
- os_memcpy(ssid, drv->ssid, 32);
- return drv->ssid_len;
+ struct test_driver_bss *dbss = priv;
+ os_memcpy(ssid, dbss->ssid, 32);
+ return dbss->ssid_len;
}
@@ -363,10 +1644,11 @@ static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
int reason_code)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
__func__, MAC2STR(addr), reason_code);
- os_memset(drv->bssid, 0, ETH_ALEN);
+ os_memset(dbss->bssid, 0, ETH_ALEN);
drv->associated = 0;
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
return wpa_driver_test_send_disassoc(drv);
@@ -376,16 +1658,36 @@ static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
static int wpa_driver_test_disassociate(void *priv, const u8 *addr,
int reason_code)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
__func__, MAC2STR(addr), reason_code);
- os_memset(drv->bssid, 0, ETH_ALEN);
+ os_memset(dbss->bssid, 0, ETH_ALEN);
drv->associated = 0;
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
return wpa_driver_test_send_disassoc(drv);
}
+static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
+{
+ const u8 *end, *pos;
+
+ pos = (const u8 *) (res + 1);
+ end = pos + res->ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
struct sockaddr *from,
socklen_t fromlen,
@@ -396,6 +1698,7 @@ static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
size_t len;
u8 *ie_pos, *ie_start, *ie_end;
#define MAX_IE_LEN 1000
+ const u8 *ds_params;
wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
if (drv->num_scanres >= MAX_SCAN_RESULTS) {
@@ -464,8 +1767,16 @@ static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
pos = pos2 + 1;
while (*pos == ' ')
pos++;
- if (os_strncmp(pos, "PRIVACY", 7) == 0)
+ if (os_strstr(pos, "PRIVACY"))
res->caps |= IEEE80211_CAP_PRIVACY;
+ if (os_strstr(pos, "IBSS"))
+ res->caps |= IEEE80211_CAP_IBSS;
+ }
+
+ ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS);
+ if (ds_params && ds_params[1] > 0) {
+ if (ds_params[2] >= 1 && ds_params[2] <= 13)
+ res->freq = 2407 + ds_params[2] * 5;
}
os_free(drv->scanres[drv->num_scanres]);
@@ -478,8 +1789,12 @@ static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
socklen_t fromlen,
const char *data)
{
+ struct test_driver_bss *bss;
+
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
/* ASSOCRESP BSSID <res> */
- if (hwaddr_aton(data, drv->bssid)) {
+ if (hwaddr_aton(data, bss->bssid)) {
wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
"assocresp");
}
@@ -509,15 +1824,20 @@ static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
socklen_t fromlen,
const u8 *data, size_t data_len)
{
- const u8 *src = drv->bssid;
+ const u8 *src;
+ struct test_driver_bss *bss;
+
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
if (data_len > 14) {
/* Skip Ethernet header */
src = data + ETH_ALEN;
data += 14;
data_len -= 14;
- }
- wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len);
+ } else
+ src = bss->bssid;
+
+ drv_event_eapol_rx(drv->ctx, src, data, data_len);
}
@@ -526,11 +1846,113 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
socklen_t fromlen,
const u8 *data, size_t data_len)
{
-#ifdef CONFIG_CLIENT_MLME
- struct ieee80211_rx_status rx_status;
- os_memset(&rx_status, 0, sizeof(rx_status));
- wpa_supplicant_sta_rx(drv->ctx, data, data_len, &rx_status);
-#endif /* CONFIG_CLIENT_MLME */
+ int freq = 0, own_freq;
+ union wpa_event_data event;
+ struct test_driver_bss *bss;
+
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+ if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) {
+ size_t pos;
+ for (pos = 5; pos < data_len; pos++) {
+ if (data[pos] == ' ')
+ break;
+ }
+ if (pos < data_len) {
+ freq = atoi((const char *) &data[5]);
+ wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
+ "freq %d MHz", bss->ifname, freq);
+ pos++;
+ data += pos;
+ data_len -= pos;
+ }
+ }
+
+ if (drv->remain_on_channel_freq)
+ own_freq = drv->remain_on_channel_freq;
+ else
+ own_freq = drv->current_freq;
+
+ if (freq && own_freq && freq != own_freq) {
+ wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
+ "another frequency %d MHz (own %d MHz)",
+ bss->ifname, freq, own_freq);
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.mlme_rx.buf = data;
+ event.mlme_rx.len = data_len;
+ event.mlme_rx.freq = freq;
+ wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
+
+ if (drv->probe_req_report && data_len >= 24) {
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ mgmt = (const struct ieee80211_mgmt *) data;
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ 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.ie = mgmt->u.probe_req.variable;
+ event.rx_probe_req.ie_len =
+ data_len - (mgmt->u.probe_req.variable - data);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
+ &event);
+ }
+ }
+}
+
+
+static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const u8 *data, size_t data_len)
+{
+ char buf[512], *pos, *end;
+ int ret;
+ struct test_driver_bss *bss;
+
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+ /* data: optional [ STA-addr | ' ' | IEs(hex) ] */
+
+ if (!drv->ibss)
+ return;
+
+ pos = buf;
+ end = buf + sizeof(buf);
+
+ /* reply: SCANRESP BSSID SSID IEs */
+ ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+ MAC2STR(bss->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos,
+ bss->ssid, bss->ssid_len);
+ ret = snprintf(pos, end - pos, " ");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie,
+ drv->assoc_wpa_ie_len);
+
+ if (bss->privacy) {
+ ret = snprintf(pos, end - pos, " PRIVACY");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ }
+
+ ret = snprintf(pos, end - pos, " IBSS");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+
+ sendto(drv->test_socket, buf, pos - buf, 0,
+ (struct sockaddr *) from, fromlen);
}
@@ -544,6 +1966,11 @@ static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
socklen_t fromlen = sizeof(from);
const size_t buflen = 2000;
+ if (drv->ap) {
+ test_driver_receive_unix(sock, eloop_ctx, sock_ctx);
+ return;
+ }
+
buf = os_malloc(buflen);
if (buf == NULL)
return;
@@ -576,6 +2003,10 @@ static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "MLME ", 5) == 0) {
wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
(const u8 *) buf + 5, res - 5);
+ } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
+ wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from,
+ fromlen,
+ (const u8 *) buf + 5, res - 5);
} else {
wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
(u8 *) buf, res);
@@ -588,32 +2019,34 @@ static void * wpa_driver_test_init2(void *ctx, const char *ifname,
void *global_priv)
{
struct wpa_driver_test_data *drv;
+ struct wpa_driver_test_global *global = global_priv;
+ struct test_driver_bss *bss;
- drv = os_zalloc(sizeof(*drv));
+ drv = test_alloc_data(ctx, ifname);
if (drv == NULL)
return NULL;
+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
drv->global = global_priv;
- drv->ctx = ctx;
drv->test_socket = -1;
/* Set dummy BSSID and SSID for testing. */
- drv->bssid[0] = 0x02;
- drv->bssid[1] = 0x00;
- drv->bssid[2] = 0x00;
- drv->bssid[3] = 0x00;
- drv->bssid[4] = 0x00;
- drv->bssid[5] = 0x01;
- os_memcpy(drv->ssid, "test", 5);
- drv->ssid_len = 4;
+ bss->bssid[0] = 0x02;
+ bss->bssid[1] = 0x00;
+ bss->bssid[2] = 0x00;
+ bss->bssid[3] = 0x00;
+ bss->bssid[4] = 0x00;
+ bss->bssid[5] = 0x01;
+ os_memcpy(bss->ssid, "test", 5);
+ bss->ssid_len = 4;
+
+ if (global->bss_add_used) {
+ os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN);
+ global->bss_add_used = 0;
+ }
- /* Generate a MAC address to help testing with multiple STAs */
- drv->own_addr[0] = 0x02; /* locally administered */
- sha1_prf((const u8 *) ifname, os_strlen(ifname),
- "wpa_supplicant test mac addr generation",
- NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
- return drv;
+ return bss;
}
@@ -635,21 +2068,42 @@ static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
static void wpa_driver_test_deinit(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ struct test_client_socket *cli, *prev;
int i;
+
+ cli = drv->cli;
+ while (cli) {
+ prev = cli;
+ cli = cli->next;
+ os_free(prev);
+ }
+
+#ifdef HOSTAPD
+ /* There should be only one BSS remaining at this point. */
+ if (dl_list_len(&drv->bss) != 1)
+ wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries",
+ __func__, dl_list_len(&drv->bss));
+#endif /* HOSTAPD */
+
+ test_driver_free_bsses(drv);
+
wpa_driver_test_close_test_socket(drv);
eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
+ eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
os_free(drv->test_dir);
for (i = 0; i < MAX_SCAN_RESULTS; i++)
os_free(drv->scanres[i]);
os_free(drv->probe_req_ie);
+ wpa_trace_remove_ref(drv, ctx, drv->ctx);
os_free(drv);
}
static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
- const char *dir)
+ const char *dir, int ap)
{
#ifdef DRIVER_TEST_UNIX
static unsigned int counter = 0;
@@ -662,8 +2116,8 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
drv->own_socket_path = os_malloc(len);
if (drv->own_socket_path == NULL)
return -1;
- os_snprintf(drv->own_socket_path, len, "%s/STA-" MACSTR,
- dir, MAC2STR(drv->own_addr));
+ os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR,
+ dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr));
} else {
drv->own_socket_path = os_malloc(100);
if (drv->own_socket_path == NULL)
@@ -750,7 +2204,8 @@ static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
static int wpa_driver_test_set_param(void *priv, const char *param)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
const char *pos;
wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
@@ -790,7 +2245,7 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
end = os_strchr(drv->test_dir, ' ');
if (end)
*end = '\0';
- if (wpa_driver_test_attach(drv, drv->test_dir))
+ if (wpa_driver_test_attach(drv, drv->test_dir, 0))
return -1;
} else {
pos = os_strstr(param, "test_udp=");
@@ -805,7 +2260,7 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
if (wpa_driver_test_attach_udp(drv, dst))
return -1;
os_free(dst);
- } else if (wpa_driver_test_attach(drv, NULL))
+ } else if (wpa_driver_test_attach(drv, NULL, 0))
return -1;
}
@@ -827,7 +2282,8 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
static const u8 * wpa_driver_test_get_mac_addr(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
return drv->own_addr;
}
@@ -836,7 +2292,8 @@ static const u8 * wpa_driver_test_get_mac_addr(void *priv)
static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
const u8 *data, size_t data_len)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
char *msg;
size_t msg_len;
struct l2_ethhdr eth;
@@ -861,7 +2318,7 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
os_memcpy(msg + 6, &eth, sizeof(eth));
os_memcpy(msg + 6 + sizeof(eth), data, data_len);
- if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
+ if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
drv->test_dir == NULL) {
if (drv->hostapd_addr_udp_set) {
addr = (struct sockaddr *) &drv->hostapd_addr_udp;
@@ -908,7 +2365,8 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
os_memset(capa, 0, sizeof(*capa));
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
@@ -926,6 +2384,9 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
WPA_DRIVER_AUTH_LEAP;
if (drv->use_mlme)
capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+ capa->flags |= WPA_DRIVER_FLAGS_AP;
+ capa->max_scan_ssids = 2;
+ capa->max_remain_on_chan = 60000;
return 0;
}
@@ -947,134 +2408,15 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
}
-#ifdef CONFIG_CLIENT_MLME
-static struct wpa_hw_modes *
-wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
- struct wpa_hw_modes *modes;
-
- *num_modes = 1;
- *flags = 0;
- modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes));
- if (modes == NULL)
- return NULL;
- modes[0].mode = WPA_MODE_IEEE80211G;
- modes[0].num_channels = 1;
- modes[0].num_rates = 1;
- modes[0].channels = os_zalloc(sizeof(struct wpa_channel_data));
- modes[0].rates = os_zalloc(sizeof(struct wpa_rate_data));
- if (modes[0].channels == NULL || modes[0].rates == NULL) {
- wpa_supplicant_sta_free_hw_features(modes, *num_modes);
- return NULL;
- }
- modes[0].channels[0].chan = 1;
- modes[0].channels[0].freq = 2412;
- modes[0].channels[0].flag = WPA_CHAN_W_SCAN | WPA_CHAN_W_ACTIVE_SCAN;
- modes[0].rates[0].rate = 10;
- modes[0].rates[0].flags = WPA_RATE_BASIC | WPA_RATE_SUPPORTED |
- WPA_RATE_CCK | WPA_RATE_MANDATORY;
-
- return modes;
-}
-
-
-static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode,
+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);
- return 0;
-}
-
-
-static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
- size_t data_len)
-{
- struct wpa_driver_test_data *drv = priv;
- struct msghdr msg;
- struct iovec io[2];
- struct sockaddr_un addr;
- const u8 *dest;
- struct dirent *dent;
- DIR *dir;
-
- wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
- if (data_len < 10)
- return -1;
- dest = data + 4;
-
- io[0].iov_base = "MLME ";
- io[0].iov_len = 5;
- io[1].iov_base = (u8 *) data;
- io[1].iov_len = data_len;
-
- os_memset(&msg, 0, sizeof(msg));
- msg.msg_iov = io;
- msg.msg_iovlen = 2;
- if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
- drv->test_dir == NULL) {
- if (drv->hostapd_addr_udp_set) {
- msg.msg_name = &drv->hostapd_addr_udp;
- msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
- } else {
-#ifdef DRIVER_TEST_UNIX
- msg.msg_name = &drv->hostapd_addr;
- msg.msg_namelen = sizeof(drv->hostapd_addr);
-#endif /* DRIVER_TEST_UNIX */
- }
- } else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
- {
- dir = opendir(drv->test_dir);
- if (dir == NULL)
- return -1;
- while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
- /* Skip the file if it is not a socket.
- * Also accept DT_UNKNOWN (0) in case
- * the C library or underlying file
- * system does not support d_type. */
- if (dent->d_type != DT_SOCK &&
- dent->d_type != DT_UNKNOWN)
- continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
- if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
- continue;
- wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
- __func__, dent->d_name);
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/%s", drv->test_dir, dent->d_name);
-
- msg.msg_name = &addr;
- msg.msg_namelen = sizeof(addr);
-
- if (sendmsg(drv->test_socket, &msg, 0) < 0)
- perror("sendmsg(test_socket)");
- }
- closedir(dir);
- return 0;
- } else {
- struct stat st;
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
- if (stat(addr.sun_path, &st) < 0) {
- os_snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/STA-" MACSTR,
- drv->test_dir, MAC2STR(dest));
- }
- msg.msg_name = &addr;
- msg.msg_namelen = sizeof(addr);
- }
-
- if (sendmsg(drv->test_socket, &msg, 0) < 0) {
- perror("sendmsg(test_socket)");
- return -1;
- }
-
+ drv->current_freq = freq;
return 0;
}
@@ -1108,29 +2450,6 @@ static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
return 0;
}
-#endif /* CONFIG_CLIENT_MLME */
-
-
-static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies,
- size_t ies_len)
-{
- struct wpa_driver_test_data *drv = priv;
-
- os_free(drv->probe_req_ie);
- if (ies) {
- drv->probe_req_ie = os_malloc(ies_len);
- if (drv->probe_req_ie == NULL) {
- drv->probe_req_ie_len = 0;
- return -1;
- }
- os_memcpy(drv->probe_req_ie, ies, ies_len);
- drv->probe_req_ie_len = ies_len;
- } else {
- drv->probe_req_ie = NULL;
- drv->probe_req_ie_len = 0;
- }
- return 0;
-}
static void * wpa_driver_test_global_init(void)
@@ -1172,59 +2491,263 @@ wpa_driver_test_get_interfaces(void *global_priv)
}
+static struct hostapd_hw_modes *
+wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ struct hostapd_hw_modes *modes;
+ size_t i;
+
+ *num_modes = 3;
+ *flags = 0;
+ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+ if (modes == NULL)
+ return NULL;
+ modes[0].mode = HOSTAPD_MODE_IEEE80211G;
+ modes[0].num_channels = 11;
+ modes[0].num_rates = 12;
+ modes[0].channels =
+ os_zalloc(11 * sizeof(struct hostapd_channel_data));
+ modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
+ if (modes[0].channels == NULL || modes[0].rates == NULL)
+ goto fail;
+ for (i = 0; i < 11; i++) {
+ modes[0].channels[i].chan = i + 1;
+ modes[0].channels[i].freq = 2412 + 5 * i;
+ modes[0].channels[i].flag = 0;
+ }
+ modes[0].rates[0] = 10;
+ modes[0].rates[1] = 20;
+ modes[0].rates[2] = 55;
+ modes[0].rates[3] = 110;
+ modes[0].rates[4] = 60;
+ modes[0].rates[5] = 90;
+ modes[0].rates[6] = 120;
+ modes[0].rates[7] = 180;
+ modes[0].rates[8] = 240;
+ modes[0].rates[9] = 360;
+ modes[0].rates[10] = 480;
+ modes[0].rates[11] = 540;
+
+ modes[1].mode = HOSTAPD_MODE_IEEE80211B;
+ modes[1].num_channels = 11;
+ modes[1].num_rates = 4;
+ modes[1].channels =
+ os_zalloc(11 * sizeof(struct hostapd_channel_data));
+ modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int));
+ if (modes[1].channels == NULL || modes[1].rates == NULL)
+ goto fail;
+ for (i = 0; i < 11; i++) {
+ modes[1].channels[i].chan = i + 1;
+ modes[1].channels[i].freq = 2412 + 5 * i;
+ modes[1].channels[i].flag = 0;
+ }
+ modes[1].rates[0] = 10;
+ modes[1].rates[1] = 20;
+ modes[1].rates[2] = 55;
+ modes[1].rates[3] = 110;
+
+ modes[2].mode = HOSTAPD_MODE_IEEE80211A;
+ modes[2].num_channels = 1;
+ modes[2].num_rates = 8;
+ modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
+ modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int));
+ if (modes[2].channels == NULL || modes[2].rates == NULL)
+ goto fail;
+ modes[2].channels[0].chan = 60;
+ modes[2].channels[0].freq = 5300;
+ modes[2].channels[0].flag = 0;
+ modes[2].rates[0] = 60;
+ modes[2].rates[1] = 90;
+ modes[2].rates[2] = 120;
+ modes[2].rates[3] = 180;
+ modes[2].rates[4] = 240;
+ modes[2].rates[5] = 360;
+ modes[2].rates[6] = 480;
+ modes[2].rates[7] = 540;
+
+ return modes;
+
+fail:
+ if (modes) {
+ for (i = 0; i < *num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+ os_free(modes);
+ }
+ return NULL;
+}
+
+
+static int wpa_driver_test_set_freq(void *priv,
+ struct hostapd_freq_params *freq)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq);
+ drv->current_freq = freq->freq;
+ return 0;
+}
+
+
+static int wpa_driver_test_send_action(void *priv, unsigned int freq,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ int ret = -1;
+ u8 *buf;
+ struct ieee80211_hdr *hdr;
+
+ wpa_printf(MSG_DEBUG, "test: Send Action frame");
+
+ if ((drv->remain_on_channel_freq &&
+ freq != drv->remain_on_channel_freq) ||
+ (drv->remain_on_channel_freq == 0 &&
+ freq != (unsigned int) drv->current_freq)) {
+ wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on "
+ "unexpected channel: freq=%u MHz (current_freq=%u "
+ "MHz, remain-on-channel freq=%u MHz)",
+ freq, drv->current_freq,
+ drv->remain_on_channel_freq);
+ return -1;
+ }
+
+ buf = os_zalloc(24 + data_len);
+ if (buf == NULL)
+ return ret;
+ os_memcpy(buf + 24, data, data_len);
+ hdr = (struct ieee80211_hdr *) buf;
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+ os_memcpy(hdr->addr1, dst, ETH_ALEN);
+ 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);
+ os_free(buf);
+ return ret;
+}
+
+
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_test_data *drv = eloop_ctx;
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout");
+
+ os_memset(&data, 0, sizeof(data));
+ data.remain_on_channel.freq = drv->remain_on_channel_freq;
+ data.remain_on_channel.duration = drv->remain_on_channel_duration;
+ wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
+
+ drv->remain_on_channel_freq = 0;
+}
+
+
+static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
+ unsigned int duration)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)",
+ __func__, freq, duration);
+ if (drv->remain_on_channel_freq &&
+ drv->remain_on_channel_freq != freq) {
+ wpa_printf(MSG_DEBUG, "test: Refuse concurrent "
+ "remain_on_channel request");
+ return -1;
+ }
+
+ drv->remain_on_channel_freq = freq;
+ drv->remain_on_channel_duration = duration;
+ eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+ eloop_register_timeout(duration / 1000, (duration % 1000) * 1000,
+ test_remain_on_channel_timeout, drv, NULL);
+
+ os_memset(&data, 0, sizeof(data));
+ data.remain_on_channel.freq = freq;
+ data.remain_on_channel.duration = duration;
+ wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_test_cancel_remain_on_channel(void *priv)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ if (!drv->remain_on_channel_freq)
+ return -1;
+ drv->remain_on_channel_freq = 0;
+ eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+ return 0;
+}
+
+
+static int wpa_driver_test_probe_req_report(void *priv, int report)
+{
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
+ wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report);
+ drv->probe_req_report = report;
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_test_ops = {
"test",
"wpa_supplicant test driver",
- wpa_driver_test_get_bssid,
- wpa_driver_test_get_ssid,
- wpa_driver_test_set_wpa,
- wpa_driver_test_set_key,
- NULL /* init */,
- wpa_driver_test_deinit,
- wpa_driver_test_set_param,
- NULL /* set_countermeasures */,
- NULL /* set_drop_unencrypted */,
- wpa_driver_test_scan,
- NULL /* get_scan_results */,
- wpa_driver_test_deauthenticate,
- wpa_driver_test_disassociate,
- wpa_driver_test_associate,
- NULL /* set_auth_alg */,
- NULL /* add_pmkid */,
- NULL /* remove_pmkid */,
- NULL /* flush_pmkid */,
- wpa_driver_test_get_capa,
- NULL /* poll */,
- NULL /* get_ifname */,
- wpa_driver_test_get_mac_addr,
- wpa_driver_test_send_eapol,
- NULL /* set_operstate */,
- wpa_driver_test_mlme_setprotection,
-#ifdef CONFIG_CLIENT_MLME
- wpa_driver_test_get_hw_feature_data,
- wpa_driver_test_set_channel,
- wpa_driver_test_set_ssid,
- wpa_driver_test_set_bssid,
- wpa_driver_test_send_mlme,
- wpa_driver_test_mlme_add_sta,
- wpa_driver_test_mlme_remove_sta,
-#else /* CONFIG_CLIENT_MLME */
- NULL /* get_hw_feature_data */,
- NULL /* set_channel */,
- NULL /* set_ssid */,
- NULL /* set_bssid */,
- NULL /* send_mlme */,
- NULL /* mlme_add_sta */,
- NULL /* mlme_remove_sta */,
-#endif /* CONFIG_CLIENT_MLME */
- NULL /* update_ft_ies */,
- NULL /* send_ft_action */,
- wpa_driver_test_get_scan_results2,
- wpa_driver_test_set_probe_req_ie,
- NULL /* set_mode */,
- NULL /* set_country */,
- wpa_driver_test_global_init,
- wpa_driver_test_global_deinit,
- wpa_driver_test_init2,
- wpa_driver_test_get_interfaces
+ .hapd_init = test_driver_init,
+ .hapd_deinit = wpa_driver_test_deinit,
+ .hapd_send_eapol = test_driver_send_eapol,
+ .send_mlme = wpa_driver_test_send_mlme,
+ .set_generic_elem = test_driver_set_generic_elem,
+ .sta_deauth = test_driver_sta_deauth,
+ .sta_disassoc = test_driver_sta_disassoc,
+ .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,
+ .sta_add = test_driver_sta_add,
+ .send_ether = test_driver_send_ether,
+ .set_ap_wps_ie = test_driver_set_ap_wps_ie,
+ .get_bssid = wpa_driver_test_get_bssid,
+ .get_ssid = wpa_driver_test_get_ssid,
+ .set_key = wpa_driver_test_set_key,
+ .deinit = wpa_driver_test_deinit,
+ .set_param = wpa_driver_test_set_param,
+ .deauthenticate = wpa_driver_test_deauthenticate,
+ .disassociate = wpa_driver_test_disassociate,
+ .associate = wpa_driver_test_associate,
+ .get_capa = wpa_driver_test_get_capa,
+ .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,
+ .init2 = wpa_driver_test_init2,
+ .get_interfaces = wpa_driver_test_get_interfaces,
+ .scan2 = wpa_driver_test_scan,
+ .set_freq = wpa_driver_test_set_freq,
+ .send_action = wpa_driver_test_send_action,
+ .remain_on_channel = wpa_driver_test_remain_on_channel,
+ .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
+ .probe_req_report = wpa_driver_test_probe_req_report,
};
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index e771d37dedb78..2614f23093fac 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant - driver interaction with generic Linux Wireless Extensions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2010, 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
@@ -20,82 +20,26 @@
#include "includes.h"
#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <net/if_arp.h>
#include "wireless_copy.h"
#include "common.h"
-#include "driver.h"
#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "driver.h"
#include "driver_wext.h"
-#include "ieee802_11_defs.h"
-#include "wpa_common.h"
static int wpa_driver_wext_flush_pmkid(void *priv);
static int wpa_driver_wext_get_range(void *priv);
-static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
-
-
-static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
- int linkmode, int operstate)
-{
- struct {
- struct nlmsghdr hdr;
- struct ifinfomsg ifinfo;
- char opts[16];
- } req;
- struct rtattr *rta;
- static int nl_seq;
- ssize_t ret;
-
- os_memset(&req, 0, sizeof(req));
-
- req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- req.hdr.nlmsg_type = RTM_SETLINK;
- req.hdr.nlmsg_flags = NLM_F_REQUEST;
- req.hdr.nlmsg_seq = ++nl_seq;
- req.hdr.nlmsg_pid = 0;
-
- req.ifinfo.ifi_family = AF_UNSPEC;
- req.ifinfo.ifi_type = 0;
- req.ifinfo.ifi_index = drv->ifindex;
- req.ifinfo.ifi_flags = 0;
- req.ifinfo.ifi_change = 0;
-
- if (linkmode != -1) {
- rta = aliasing_hide_typecast(
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
- struct rtattr);
- rta->rta_type = IFLA_LINKMODE;
- rta->rta_len = RTA_LENGTH(sizeof(char));
- *((char *) RTA_DATA(rta)) = linkmode;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
- }
- if (operstate != -1) {
- rta = (struct rtattr *)
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
- rta->rta_type = IFLA_OPERSTATE;
- rta->rta_len = RTA_LENGTH(sizeof(char));
- *((char *) RTA_DATA(rta)) = operstate;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
- }
-
- wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
- linkmode, operstate);
-
- ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
- "%s (assume operstate is not supported)",
- strerror(errno));
- }
-
- return ret < 0 ? -1 : 0;
-}
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
@@ -304,6 +248,7 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
} else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
char *spos;
int bytes;
+ u8 *req_ies = NULL, *resp_ies = NULL;
spos = custom + 17;
@@ -312,12 +257,12 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
return;
bytes /= 2;
- data.assoc_info.req_ies = os_malloc(bytes);
- if (data.assoc_info.req_ies == NULL)
- return;
-
+ req_ies = os_malloc(bytes);
+ if (req_ies == NULL ||
+ hexstr2bin(spos, req_ies, bytes) < 0)
+ goto done;
+ data.assoc_info.req_ies = req_ies;
data.assoc_info.req_ies_len = bytes;
- hexstr2bin(spos, data.assoc_info.req_ies, bytes);
spos += bytes * 2;
@@ -332,19 +277,19 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
goto done;
bytes /= 2;
- data.assoc_info.resp_ies = os_malloc(bytes);
- if (data.assoc_info.resp_ies == NULL)
+ resp_ies = os_malloc(bytes);
+ if (resp_ies == NULL ||
+ hexstr2bin(spos, resp_ies, bytes) < 0)
goto done;
-
+ data.assoc_info.resp_ies = resp_ies;
data.assoc_info.resp_ies_len = bytes;
- hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
}
wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
done:
- os_free(data.assoc_info.resp_ies);
- os_free(data.assoc_info.req_ies);
+ os_free(resp_ies);
+ os_free(req_ies);
#ifdef CONFIG_PEERKEY
} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
@@ -460,24 +405,24 @@ static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
os_memset(&data, 0, sizeof(data));
if (drv->assoc_req_ies) {
data.assoc_info.req_ies = drv->assoc_req_ies;
- drv->assoc_req_ies = NULL;
data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
}
if (drv->assoc_resp_ies) {
data.assoc_info.resp_ies = drv->assoc_resp_ies;
- drv->assoc_resp_ies = NULL;
data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
}
wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
- os_free(data.assoc_info.req_ies);
- os_free(data.assoc_info.resp_ies);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
}
static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
- void *ctx, char *data, int len)
+ char *data, int len)
{
struct iw_event iwe_buf, *iwe = &iwe_buf;
char *pos, *end, *custom, *buf;
@@ -525,12 +470,13 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
drv->assoc_req_ies = NULL;
os_free(drv->assoc_resp_ies);
drv->assoc_resp_ies = NULL;
- wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
NULL);
} else {
wpa_driver_wext_event_assoc_ies(drv);
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
+ NULL);
}
break;
case IWEVMICHAELMICFAILURE:
@@ -540,7 +486,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
return;
}
wpa_driver_wext_event_wireless_michaelmicfailure(
- ctx, custom, iwe->u.data.length);
+ drv->ctx, custom, iwe->u.data.length);
break;
case IWEVCUSTOM:
if (custom + iwe->u.data.length > end) {
@@ -553,14 +499,15 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
return;
os_memcpy(buf, custom, iwe->u.data.length);
buf[iwe->u.data.length] = '\0';
- wpa_driver_wext_event_wireless_custom(ctx, buf);
+ wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
os_free(buf);
break;
case SIOCGIWSCAN:
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
- drv, ctx);
- wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ drv, drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
break;
case IWEVASSOCREQIE:
if (custom + iwe->u.data.length > end) {
@@ -597,8 +544,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
- void *ctx, char *buf, size_t len,
- int del)
+ char *buf, size_t len, int del)
{
union wpa_event_data event;
@@ -621,26 +567,18 @@ static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
drv->if_removed = 0;
}
- wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
}
static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
- struct nlmsghdr *h)
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
+ int attrlen, rta_len;
struct rtattr *attr;
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return 0;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
@@ -659,12 +597,12 @@ static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
- int ifindex, struct nlmsghdr *h)
+ int ifindex, u8 *buf, size_t len)
{
if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
return 1;
- if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) {
+ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
drv->ifindex = if_nametoindex(drv->ifname);
wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
"interface");
@@ -676,20 +614,14 @@ static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
}
-static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr * attr;
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
+ struct wpa_driver_wext_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
- if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) {
+ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
ifi->ifi_index);
return;
@@ -711,24 +643,20 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
if (drv->operstate == 1 &&
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
!(ifi->ifi_flags & IFF_RUNNING))
- wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ -1, IF_OPER_UP);
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_WIRELESS) {
wpa_driver_wext_event_wireless(
- drv, ctx, ((char *) attr) + rta_len,
+ drv, ((char *) attr) + rta_len,
attr->rta_len - rta_len);
} else if (attr->rta_type == IFLA_IFNAME) {
- wpa_driver_wext_event_link(drv, ctx,
+ wpa_driver_wext_event_link(drv,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 0);
}
@@ -737,31 +665,20 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
}
-static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
- void *ctx, struct nlmsghdr *h,
- size_t len)
+static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr * attr;
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
+ struct wpa_driver_wext_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
- wpa_driver_wext_event_link(drv, ctx,
+ wpa_driver_wext_event_link(drv,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 1);
}
@@ -770,129 +687,6 @@ static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
}
-static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
-{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- int max_events = 10;
-
-try_again:
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- perror("recvfrom(netlink)");
- return;
- }
-
- h = (struct nlmsghdr *) buf;
- while (left >= (int) sizeof(*h)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "Malformed netlink message: "
- "len=%d left=%d plen=%d",
- len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- case RTM_DELLINK:
- wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx,
- h, plen);
- break;
- }
-
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
- }
-
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
- "message", left);
- }
-
- if (--max_events > 0) {
- /*
- * Try to receive all events in one eloop call in order to
- * limit race condition on cases where AssocInfo event, Assoc
- * event, and EAPOL frames are received more or less at the
- * same time. We want to process the event messages first
- * before starting EAPOL processing.
- */
- goto try_again;
- }
-}
-
-
-static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
- const char *ifname, int *flags)
-{
- struct ifreq ifr;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
- return -1;
- }
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-/**
- * wpa_driver_wext_get_ifflags - Get interface flags (SIOCGIFFLAGS)
- * @drv: driver_wext private data
- * @flags: Pointer to returned flags value
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags)
-{
- return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
-}
-
-
-static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
- const char *ifname, int flags)
-{
- struct ifreq ifr;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("SIOCSIFFLAGS");
- return -1;
- }
- return 0;
-}
-
-
-/**
- * wpa_driver_wext_set_ifflags - Set interface flags (SIOCSIFFLAGS)
- * @drv: driver_wext private data
- * @flags: New value for flags
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
-{
- return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags);
-}
-
-
/**
* wpa_driver_wext_init - Initialize WE driver interface
* @ctx: context to be used when calling wpa_supplicant functions,
@@ -902,9 +696,10 @@ int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
*/
void * wpa_driver_wext_init(void *ctx, const char *ifname)
{
- int s;
- struct sockaddr_nl local;
struct wpa_driver_wext_data *drv;
+ struct netlink_config *cfg;
+ char path[128];
+ struct stat buf;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
@@ -912,66 +707,53 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
drv->ctx = ctx;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
+ if (stat(path, &buf) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
+ drv->cfg80211 = 1;
+ }
+
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket(PF_INET,SOCK_DGRAM)");
- os_free(drv);
- return NULL;
+ goto err1;
}
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ goto err1;
+ cfg->ctx = drv;
+ cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
+ cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ goto err2;
}
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- perror("bind(netlink)");
- close(s);
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
-
- eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
- drv->event_sock = s;
-
drv->mlme_sock = -1;
- wpa_driver_wext_finish_drv_init(drv);
+ if (wpa_driver_wext_finish_drv_init(drv) < 0)
+ goto err3;
+
+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
return drv;
+
+err3:
+ netlink_deinit(drv->netlink);
+err2:
+ close(drv->ioctl_sock);
+err1:
+ os_free(drv);
+ return NULL;
}
-static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
{
- int flags;
-
- if (wpa_driver_wext_get_ifflags(drv, &flags) != 0)
- printf("Could not get interface '%s' flags\n", drv->ifname);
- else if (!(flags & IFF_UP)) {
- if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
- printf("Could not set interface '%s' UP\n",
- drv->ifname);
- } else {
- /*
- * Wait some time to allow driver to initialize before
- * starting configuring the driver. This seems to be
- * needed at least some drivers that load firmware etc.
- * when the interface is set up.
- */
- wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
- "a second for the driver to complete "
- "initialization", drv->ifname);
- sleep(1);
- }
- }
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0)
+ return -1;
/*
* Make sure that the driver does not have any obsolete PMKID entries.
@@ -979,7 +761,9 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
wpa_driver_wext_flush_pmkid(drv);
if (wpa_driver_wext_set_mode(drv, 0) < 0) {
- printf("Could not configure driver to use managed mode\n");
+ wpa_printf(MSG_DEBUG, "Could not configure driver to use "
+ "managed mode");
+ /* Try to use it anyway */
}
wpa_driver_wext_get_range(drv);
@@ -1008,7 +792,10 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
wpa_driver_wext_alternative_ifindex(drv, ifname2);
}
- wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
+
+ return 0;
}
@@ -1022,7 +809,8 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
void wpa_driver_wext_deinit(void *priv)
{
struct wpa_driver_wext_data *drv = priv;
- int flags;
+
+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
@@ -1032,16 +820,14 @@ void wpa_driver_wext_deinit(void *priv)
*/
wpa_driver_wext_disconnect(drv);
- wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+ netlink_deinit(drv->netlink);
- eloop_unregister_read_sock(drv->event_sock);
if (drv->mlme_sock >= 0)
eloop_unregister_read_sock(drv->mlme_sock);
- if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
- (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
- close(drv->event_sock);
close(drv->ioctl_sock);
if (drv->mlme_sock >= 0)
close(drv->mlme_sock);
@@ -1069,18 +855,17 @@ void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
/**
* wpa_driver_wext_scan - Request the driver to initiate scan
* @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
- * all SSIDs (either active scan with broadcast SSID or passive
- * scan
- * @ssid_len: Length of the SSID
+ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
* Returns: 0 on success, -1 on failure
*/
-int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
int ret = 0, timeout;
struct iw_scan_req req;
+ const u8 *ssid = params->ssids[0].ssid;
+ size_t ssid_len = params->ssids[0].ssid_len;
if (ssid_len > IW_ESSID_MAX_SIZE) {
wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
@@ -1261,6 +1046,14 @@ static void wext_get_scan_qual(struct iw_event *iwe,
res->res.qual = iwe->u.qual.qual;
res->res.noise = iwe->u.qual.noise;
res->res.level = iwe->u.qual.level;
+ if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
+ res->res.flags |= WPA_SCAN_QUAL_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
+ res->res.flags |= WPA_SCAN_LEVEL_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
+ res->res.flags |= WPA_SCAN_NOISE_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_DBM)
+ res->res.flags |= WPA_SCAN_LEVEL_DBM;
}
@@ -1349,8 +1142,9 @@ static void wext_get_scan_custom(struct iw_event *iwe,
tmp = os_realloc(res->ie, res->ie_len + bytes);
if (tmp == NULL)
return;
- hexstr2bin(spos, tmp + res->ie_len, bytes);
res->ie = tmp;
+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+ return;
res->ie_len += bytes;
} else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
char *spos;
@@ -1363,8 +1157,9 @@ static void wext_get_scan_custom(struct iw_event *iwe,
tmp = os_realloc(res->ie, res->ie_len + bytes);
if (tmp == NULL)
return;
- hexstr2bin(spos, tmp + res->ie_len, bytes);
res->ie = tmp;
+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+ return;
res->ie_len += bytes;
} else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
char *spos;
@@ -1377,7 +1172,10 @@ static void wext_get_scan_custom(struct iw_event *iwe,
return;
}
bytes /= 2;
- hexstr2bin(spos, bin, bytes);
+ if (hexstr2bin(spos, bin, bytes) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
+ return;
+ }
res->res.tsf += WPA_GET_BE64(bin);
}
}
@@ -1619,6 +1417,7 @@ static int wpa_driver_wext_get_range(void *priv)
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
+ drv->capa.max_scan_ssids = 1;
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
"flags 0x%x",
@@ -1633,16 +1432,6 @@ static int wpa_driver_wext_get_range(void *priv)
}
-static int wpa_driver_wext_set_wpa(void *priv, int enabled)
-{
- struct wpa_driver_wext_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
- enabled);
-}
-
-
static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
const u8 *psk)
{
@@ -1680,7 +1469,7 @@ static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
}
-static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
+static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
const u8 *addr, int key_idx,
int set_tx, const u8 *seq,
size_t seq_len,
@@ -1800,7 +1589,7 @@ static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
* This function uses SIOCSIWENCODEEXT by default, but tries to use
* SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
*/
-int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+int wpa_driver_wext_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)
@@ -1929,17 +1718,32 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
}
if (iwr.u.mode == IW_MODE_INFRA) {
+ if (drv->cfg80211) {
+ /*
+ * cfg80211 supports SIOCSIWMLME commands, so there is
+ * no need for the random SSID hack, but clear the
+ * BSSID and SSID.
+ */
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
+ wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
+ "to 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).
*/
- wpa_driver_wext_set_bssid(drv, null_bssid);
-
for (i = 0; i < 32; i++)
ssid[i] = rand() & 0xFF;
- wpa_driver_wext_set_ssid(drv, ssid, 32);
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
+ wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
+ "BSSID/SSID to disconnect");
+ }
}
}
@@ -2051,9 +1855,9 @@ wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
if (!drv->use_crypt) {
iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
} else {
- if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ if (params->auth_alg & WPA_AUTH_ALG_OPEN)
iwr.u.encoding.flags |= IW_ENCODE_OPEN;
- if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ if (params->auth_alg & WPA_AUTH_ALG_SHARED)
iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
}
@@ -2076,6 +1880,22 @@ int wpa_driver_wext_associate(void *priv,
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ if (drv->cfg80211) {
+ /*
+ * Stop cfg80211 from trying to associate before we are done
+ * with all parameters.
+ */
+ wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
+ }
+
+ if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
+ < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+
/*
* If the driver did not support SIOCSIWAUTH, fallback to
* SIOCSIWENCODE here.
@@ -2155,11 +1975,15 @@ int wpa_driver_wext_associate(void *priv,
#endif /* CONFIG_IEEE80211W */
if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
ret = -1;
- if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ if (!drv->cfg80211 &&
+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
ret = -1;
if (params->bssid &&
wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
ret = -1;
+ if (drv->cfg80211 &&
+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
return ret;
}
@@ -2170,11 +1994,11 @@ static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
struct wpa_driver_wext_data *drv = priv;
int algs = 0, res;
- if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ if (auth_alg & WPA_AUTH_ALG_OPEN)
algs |= IW_AUTH_ALG_OPEN_SYSTEM;
- if (auth_alg & AUTH_ALG_SHARED_KEY)
+ if (auth_alg & WPA_AUTH_ALG_SHARED)
algs |= IW_AUTH_ALG_SHARED_KEY;
- if (auth_alg & AUTH_ALG_LEAP)
+ if (auth_alg & WPA_AUTH_ALG_LEAP)
algs |= IW_AUTH_ALG_LEAP;
if (algs == 0) {
/* at least one algorithm should be set */
@@ -2198,7 +2022,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
- int ret = -1, flags;
+ int ret = -1;
unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
os_memset(&iwr, 0, sizeof(iwr));
@@ -2228,9 +2052,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
goto done;
}
- if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
- (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
-
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
/* Try to set the mode again while the interface is down */
iwr.u.mode = new_mode;
if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
@@ -2238,11 +2060,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode)
else
ret = 0;
- /* Ignore return value of get_ifflags to ensure that the device
- * is always up like it was before this function was called.
- */
- (void) wpa_driver_wext_get_ifflags(drv, &flags);
- (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
}
done:
@@ -2338,8 +2156,8 @@ int wpa_driver_wext_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 wpa_driver_wext_send_oper_ifla(
- drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+ state ? IF_OPER_UP : IF_OPER_DORMANT);
}
@@ -2354,17 +2172,13 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
- .set_wpa = wpa_driver_wext_set_wpa,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
- .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
- .scan = wpa_driver_wext_scan,
+ .scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
- .set_mode = wpa_driver_wext_set_mode,
.associate = wpa_driver_wext_associate,
- .set_auth_alg = wpa_driver_wext_set_auth_alg,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index b89c2cb2fdfa8..602c7e1f689c0 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -19,7 +19,7 @@
struct wpa_driver_wext_data {
void *ctx;
- int event_sock;
+ struct netlink_data *netlink;
int ioctl_sock;
int mlme_sock;
char ifname[IFNAMSIZ + 1];
@@ -43,21 +43,21 @@ struct wpa_driver_wext_data {
char mlmedev[IFNAMSIZ + 1];
int scan_complete_events;
+
+ int cfg80211; /* whether driver is using cfg80211 */
};
-int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
-int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
int wpa_driver_wext_set_freq(void *priv, int freq);
int wpa_driver_wext_set_mode(void *priv, int mode);
-int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+int wpa_driver_wext_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);
-int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 098991a1a44d3..2b197f0ab6c72 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -1,6 +1,7 @@
/*
- * WPA Supplicant - wired Ethernet driver interface
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Wired Ethernet driver interface
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
*
* 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
@@ -17,27 +18,374 @@
#include <net/if.h>
#ifdef __linux__
#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
#include <net/if_dl.h>
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
#include "common.h"
+#include "eloop.h"
#include "driver.h"
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee8023_hdr {
+ u8 dest[6];
+ u8 src[6];
+ u16 ethertype;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
static const u8 pae_group_addr[ETH_ALEN] =
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
struct wpa_driver_wired_data {
+ char ifname[IFNAMSIZ + 1];
void *ctx;
+
+ int sock; /* raw packet socket for driver access */
+ int dhcp_sock; /* socket for dhcp packets */
+ int use_pae_group_addr;
+
int pf_sock;
- char ifname[IFNAMSIZ + 1];
int membership, multi, iff_allmulti, iff_up;
};
+/* TODO: detecting new devices should eventually be changed from using DHCP
+ * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
+ * based on ebtables, etc. */
+
+struct dhcp_message {
+ u_int8_t op;
+ u_int8_t htype;
+ u_int8_t hlen;
+ u_int8_t hops;
+ u_int32_t xid;
+ u_int16_t secs;
+ u_int16_t flags;
+ u_int32_t ciaddr;
+ u_int32_t yiaddr;
+ u_int32_t siaddr;
+ u_int32_t giaddr;
+ u_int8_t chaddr[16];
+ u_int8_t sname[64];
+ u_int8_t file[128];
+ u_int32_t cookie;
+ u_int8_t options[308]; /* 312 - cookie */
+};
+
+
+static int wired_multicast_membership(int sock, int ifindex,
+ const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+ if (setsockopt(sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+#ifdef __linux__
+static void handle_data(void *ctx, unsigned char *buf, size_t len)
+{
+#ifdef HOSTAPD
+ struct ieee8023_hdr *hdr;
+ u8 *pos, *sa;
+ size_t left;
+ union wpa_event_data event;
+
+ /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
+ * 2 byte ethertype */
+ if (len < 14) {
+ wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ hdr = (struct ieee8023_hdr *) buf;
+
+ switch (ntohs(hdr->ethertype)) {
+ case ETH_P_PAE:
+ wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
+ sa = hdr->src;
+ os_memset(&event, 0, sizeof(event));
+ event.new_sta.addr = sa;
+ wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+ drv_event_eapol_rx(ctx, sa, pos, left);
+ break;
+
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
+ ntohs(hdr->ethertype));
+ break;
+ }
+#endif /* HOSTAPD */
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ handle_data(eloop_ctx, buf, len);
+}
+
+
+static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ int len;
+ unsigned char buf[3000];
+ struct dhcp_message *msg;
+ u8 *mac_address;
+ union wpa_event_data event;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ /* must contain at least dhcp_message->chaddr */
+ if (len < 44) {
+ wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
+ return;
+ }
+
+ msg = (struct dhcp_message *) buf;
+ mac_address = (u8 *) &(msg->chaddr);
+
+ wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
+ MAC2STR(mac_address));
+
+ os_memset(&event, 0, sizeof(event));
+ event.new_sta.addr = mac_address;
+ wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event);
+}
+#endif /* __linux__ */
+
+
+static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
+{
+#ifdef __linux__
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+ struct sockaddr_in addr2;
+ int n = 1;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ /* filter multicast address */
+ if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
+ pae_group_addr, 1) < 0) {
+ wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
+ "membership");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ /* setup dhcp listen socket for sta detection */
+ if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket call failed for dhcp");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
+ NULL)) {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ os_memset(&addr2, 0, sizeof(addr2));
+ addr2.sin_family = AF_INET;
+ addr2.sin_port = htons(67);
+ addr2.sin_addr.s_addr = INADDR_ANY;
+
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
+ sizeof(n)) == -1) {
+ perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+ return -1;
+ }
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
+ sizeof(n)) == -1) {
+ perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *) &ifr, sizeof(ifr)) < 0) {
+ perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+ return -1;
+ }
+
+ if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
+ sizeof(struct sockaddr)) == -1) {
+ perror("bind");
+ return -1;
+ }
+
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static int wired_send_eapol(void *priv, const u8 *addr,
+ const u8 *data, size_t data_len, int encrypt,
+ const u8 *own_addr)
+{
+ struct wpa_driver_wired_data *drv = priv;
+ struct ieee8023_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for wired_send_eapol(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
+ ETH_ALEN);
+ os_memcpy(hdr->src, own_addr, ETH_ALEN);
+ hdr->ethertype = htons(ETH_P_PAE);
+
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, data, data_len);
+
+ res = send(drv->sock, (u8 *) hdr, len, 0);
+ os_free(hdr);
+
+ if (res < 0) {
+ perror("wired_send_eapol: send");
+ printf("wired_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static void * wired_driver_hapd_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct wpa_driver_wired_data *drv;
+
+ drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for wired driver data\n");
+ return NULL;
+ }
+
+ drv->ctx = hapd;
+ os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+ drv->use_pae_group_addr = params->use_pae_group_addr;
+
+ if (wired_init_sockets(drv, params->own_addr)) {
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wired_driver_hapd_deinit(void *priv)
+{
+ struct wpa_driver_wired_data *drv = priv;
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ if (drv->dhcp_sock >= 0)
+ close(drv->dhcp_sock);
+
+ os_free(drv);
+}
+
+
static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
{
ssid[0] = 0;
@@ -53,6 +401,14 @@ static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
}
+static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_WIRED;
+ return 0;
+}
+
+
static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
{
struct ifreq ifr;
@@ -118,7 +474,7 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
{
struct sockaddr_dl *dlp;
dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
@@ -128,9 +484,9 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
dlp->sdl_nlen = 0;
dlp->sdl_alen = ETH_ALEN;
dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
{
struct sockaddr *sap;
@@ -151,34 +507,6 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
}
-static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (drv->pf_sock == -1)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = if_nametoindex(drv->ifname);
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(drv->pf_sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- perror("setsockopt");
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
{
struct wpa_driver_wired_data *drv;
@@ -195,16 +523,18 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
if (drv->pf_sock < 0)
perror("socket(PF_PACKET)");
#else /* __linux__ */
- drv->pf_sock = -1;
+ drv->pf_sock = -1;
#endif /* __linux__ */
-
+
if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
!(flags & IFF_UP) &&
wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
drv->iff_up = 1;
}
- if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
+ if (wired_multicast_membership(drv->pf_sock,
+ if_nametoindex(drv->ifname),
+ pae_group_addr, 1) == 0) {
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
"packet socket", __func__);
drv->membership = 1;
@@ -242,7 +572,9 @@ static void wpa_driver_wired_deinit(void *priv)
int flags;
if (drv->membership &&
- wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
+ wired_multicast_membership(drv->pf_sock,
+ if_nametoindex(drv->ifname),
+ pae_group_addr, 0) < 0) {
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
"group (PACKET)", __func__);
}
@@ -271,16 +603,20 @@ static void wpa_driver_wired_deinit(void *priv)
if (drv->pf_sock != -1)
close(drv->pf_sock);
-
+
os_free(drv);
}
const struct wpa_driver_ops wpa_driver_wired_ops = {
.name = "wired",
- .desc = "wpa_supplicant wired Ethernet driver",
+ .desc = "Wired Ethernet driver",
+ .hapd_init = wired_driver_hapd_init,
+ .hapd_deinit = wired_driver_hapd_deinit,
+ .hapd_send_eapol = wired_send_eapol,
.get_ssid = wpa_driver_wired_get_ssid,
.get_bssid = wpa_driver_wired_get_bssid,
+ .get_capa = wpa_driver_wired_get_capa,
.init = wpa_driver_wired_init,
.deinit = wpa_driver_wired_deinit,
};
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index d278797d7de2f..bffbbde72b77b 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / driver interface list
+ * Driver interface list
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,6 @@ extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_PRISM54
-extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */
-#endif /* CONFIG_DRIVER_PRISM54 */
#ifdef CONFIG_DRIVER_HERMES
extern struct wpa_driver_ops wpa_driver_hermes_ops; /* driver_hermes.c */
#endif /* CONFIG_DRIVER_HERMES */
@@ -64,9 +61,6 @@ extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
#ifdef CONFIG_DRIVER_OSX
extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_PS3
-extern struct wpa_driver_ops wpa_driver_ps3_ops; /* driver_ps3.c */
-#endif /* CONFIG_DRIVER_PS3 */
#ifdef CONFIG_DRIVER_IPHONE
extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
#endif /* CONFIG_DRIVER_IPHONE */
@@ -74,9 +68,15 @@ extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
/* driver_roboswitch.c */
extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
+#endif /* CONFIG_DRIVER_NONE */
-struct wpa_driver_ops *wpa_supplicant_drivers[] =
+struct wpa_driver_ops *wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_WEXT
&wpa_driver_wext_ops,
@@ -87,9 +87,6 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] =
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_PRISM54
- &wpa_driver_prism54_ops,
-#endif /* CONFIG_DRIVER_PRISM54 */
#ifdef CONFIG_DRIVER_HERMES
&wpa_driver_hermes_ops,
#endif /* CONFIG_DRIVER_HERMES */
@@ -126,14 +123,17 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] =
#ifdef CONFIG_DRIVER_OSX
&wpa_driver_osx_ops,
#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_PS3
- &wpa_driver_ps3_ops,
-#endif /* CONFIG_DRIVER_PS3 */
#ifdef CONFIG_DRIVER_IPHONE
&wpa_driver_iphone_ops,
#endif /* CONFIG_DRIVER_IPHONE */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+ &wpa_driver_atheros_ops,
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+ &wpa_driver_none_ops,
+#endif /* CONFIG_DRIVER_NONE */
NULL
};
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
new file mode 100644
index 0000000000000..b76b22953a38e
--- /dev/null
+++ b/src/drivers/drivers.mak
@@ -0,0 +1,181 @@
+##### 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
+DRV_OBJS += ../src/utils/radiotap.o
+NEED_SME=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+DRV_LIBS += -lnl
+
+ifdef CONFIG_LIBNL20
+DRV_LIBS += -lnl-genl
+DRV_CFLAGS += -DCONFIG_LIBNL20
+endif
+endif
+
+ifdef CONFIG_DRIVER_BSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_BSD
+DRV_OBJS += ../src/drivers/driver_bsd.o
+CONFIG_L2_FREEBSD=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+DRV_CFLAGS += -DCONFIG_DRIVER_TEST
+DRV_OBJS += ../src/drivers/driver_test.o
+NEED_AP_MLME=y
+endif
+
+ifdef CONFIG_DRIVER_NONE
+DRV_CFLAGS += -DCONFIG_DRIVER_NONE
+DRV_OBJS += ../src/drivers/driver_none.o
+endif
+
+##### PURE AP DRIVERS
+
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += ../src/drivers/driver_atheros.o
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+##### PURE CLIENT DRIVERS
+
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_HERMES
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_HERMES
+DRV_WPA_OBJS += ../src/drivers/driver_hermes.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_ATMEL
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ATMEL
+DRV_WPA_OBJS += ../src/drivers/driver_atmel.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_NDISWRAPPER
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER
+DRV_WPA_OBJS += ../src/drivers/driver_ndiswrapper.o
+CONFIG_WIRELESS_EXTENSION=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_IPW
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPW
+DRV_WPA_OBJS += ../src/drivers/driver_ipw.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
+DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+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
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+DRV_WPA_OBJS += ../src/drivers/driver_wext.o
+endif
+
+ifdef NEED_NETLINK
+DRV_OBJS += ../src/drivers/netlink.o
+endif
+
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += ../src/drivers/linux_ioctl.o
+endif
+
+
+##### COMMON VARS
+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
+DRV_WPA_CFLAGS += $(DRV_CFLAGS)
+DRV_AP_CFLAGS += $(DRV_CFLAGS)
+
+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
+DRV_WPA_LIBS += $(DRV_LIBS)
+DRV_AP_LIBS += $(DRV_LIBS)
+
+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
+DRV_WPA_OBJS += $(DRV_OBJS)
+DRV_AP_OBJS += $(DRV_OBJS)
+
+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
+DRV_AP_LDFLAGS += $(DRV_LDFLAGS)
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
new file mode 100644
index 0000000000000..0d6cf5416beec
--- /dev/null
+++ b/src/drivers/linux_ioctl.c
@@ -0,0 +1,198 @@
+/*
+ * Linux ioctl helper functions for driver wrappers
+ * Copyright (c) 2002-2010, 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 "utils/includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include "utils/common.h"
+#include "linux_ioctl.h"
+
+
+int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
+{
+ struct ifreq ifr;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ if (dev_up) {
+ if (ifr.ifr_flags & IFF_UP)
+ return 0;
+ ifr.ifr_flags |= IFF_UP;
+ } else {
+ if (!(ifr.ifr_flags & IFF_UP))
+ return 0;
+ ifr.ifr_flags &= ~IFF_UP;
+ }
+
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
+ wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
+ ifname, ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+
+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
+ wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifndef SIOCBRADDBR
+#define SIOCBRADDBR 0x89a0
+#endif
+#ifndef SIOCBRDELBR
+#define SIOCBRDELBR 0x89a1
+#endif
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF 0x89a2
+#endif
+#ifndef SIOCBRDELIF
+#define SIOCBRDELIF 0x89a3
+#endif
+
+
+int linux_br_add(int sock, const char *brname)
+{
+ if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
+ brname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_del(int sock, const char *brname)
+{
+ if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
+ brname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_add_if(int sock, const char *brname, const char *ifname)
+{
+ struct ifreq ifr;
+ int ifindex;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_ifindex = ifindex;
+ if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
+ "%s: %s", ifname, brname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_del_if(int sock, const char *brname, const char *ifname)
+{
+ struct ifreq ifr;
+ int ifindex;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_ifindex = ifindex;
+ if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
+ "bridge %s: %s", ifname, brname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_get(char *brname, const char *ifname)
+{
+ char path[128], brlink[128], *pos;
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
+ ifname);
+ os_memset(brlink, 0, sizeof(brlink));
+ if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
+ return -1;
+ pos = os_strrchr(brlink, '/');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ os_strlcpy(brname, pos, IFNAMSIZ);
+ return 0;
+}
diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h
new file mode 100644
index 0000000000000..a5557383d8fe1
--- /dev/null
+++ b/src/drivers/linux_ioctl.h
@@ -0,0 +1,27 @@
+/*
+ * Linux ioctl helper functions for driver wrappers
+ * Copyright (c) 2002-2010, 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_IOCTL_H
+#define LINUX_IOCTL_H
+
+int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+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);
+int linux_br_del(int sock, const char *brname);
+int linux_br_add_if(int sock, const char *brname, const char *ifname);
+int linux_br_del_if(int sock, const char *brname, const char *ifname);
+int linux_br_get(char *brname, const char *ifname);
+
+#endif /* LINUX_IOCTL_H */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
new file mode 100644
index 0000000000000..ad15b1d62a8d8
--- /dev/null
+++ b/src/drivers/netlink.c
@@ -0,0 +1,204 @@
+/*
+ * Netlink helper functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "netlink.h"
+
+
+struct netlink_data {
+ struct netlink_config *cfg;
+ int sock;
+};
+
+
+static void netlink_receive_link(struct netlink_data *netlink,
+ void (*cb)(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len),
+ struct nlmsghdr *h)
+{
+ 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)),
+ NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
+}
+
+
+static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct netlink_data *netlink = eloop_ctx;
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
+ strerror(errno));
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (NLMSG_OK(h, left)) {
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ netlink_receive_link(netlink, netlink->cfg->newlink_cb,
+ h);
+ break;
+ case RTM_DELLINK:
+ netlink_receive_link(netlink, netlink->cfg->dellink_cb,
+ h);
+ break;
+ }
+
+ h = NLMSG_NEXT(h, left);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
+ "netlink message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+struct netlink_data * netlink_init(struct netlink_config *cfg)
+{
+ struct netlink_data *netlink;
+ struct sockaddr_nl local;
+
+ netlink = os_zalloc(sizeof(*netlink));
+ if (netlink == NULL)
+ return NULL;
+
+ netlink->cfg = cfg;
+
+ netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (netlink->sock < 0) {
+ wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
+ "socket: %s", strerror(errno));
+ netlink_deinit(netlink);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
+ {
+ wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
+ "socket: %s", strerror(errno));
+ netlink_deinit(netlink);
+ return NULL;
+ }
+
+ eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
+ NULL);
+
+ return netlink;
+}
+
+
+void netlink_deinit(struct netlink_data *netlink)
+{
+ if (netlink == NULL)
+ return;
+ if (netlink->sock >= 0) {
+ eloop_unregister_read_sock(netlink->sock);
+ close(netlink->sock);
+ }
+ os_free(netlink->cfg);
+ os_free(netlink);
+}
+
+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
+ linkmode, operstate);
+
+ ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
+ "failed: %s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
diff --git a/src/drivers/netlink.h b/src/drivers/netlink.h
new file mode 100644
index 0000000000000..bcbfbb51fdd70
--- /dev/null
+++ b/src/drivers/netlink.h
@@ -0,0 +1,33 @@
+/*
+ * Netlink helper functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef NETLINK_H
+#define NETLINK_H
+
+struct netlink_data;
+
+struct netlink_config {
+ void *ctx;
+ void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
+ size_t len);
+ void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
+ size_t len);
+};
+
+struct netlink_data * netlink_init(struct netlink_config *cfg);
+void netlink_deinit(struct netlink_data *netlink);
+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
+ int linkmode, int operstate);
+
+#endif /* NETLINK_H */
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
new file mode 100644
index 0000000000000..2ea3edeee7aae
--- /dev/null
+++ b/src/drivers/nl80211_copy.h
@@ -0,0 +1,1644 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * 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, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
+ * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ * to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ * or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ * %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ * either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ * on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ * be sent from userspace to request creation of a new virtual interface,
+ * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ * %NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ * userspace to request deletion of a virtual interface, then requires
+ * attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ * and %NL80211_ATTR_KEY_SEQ attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @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.
+ * @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
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @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_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
+ * or, if no MAC address given, all mesh paths, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ * regulatory domain.
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ * after being queried by the kernel. CRDA replies by sending a regulatory
+ * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ * current alpha2 if it found a match. It also provides
+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * regulatory rule is a nested set of attributes given by
+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * to the 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
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: 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
+ * interface is identified with %NL80211_ATTR_IFINDEX and the management
+ * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ * added to the end of the specified management frame is specified with
+ * %NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ * added to all specified management frames generated by
+ * kernel/firmware/driver.
+ * Note: This command has been removed and it is only reserved at this
+ * point to avoid re-using existing command number. The functionality this
+ * command was planned for has been provided with cleaner design with the
+ * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
+ * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @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_GET_SURVEY: get survey resuls, e.g. channel occupation
+ * or noise level
+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
+ * NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
+ *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ * has been changed and provides details of the request information
+ * that caused the change such as who initiated the regulatory request
+ * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ * to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ * has been found while world roaming thus enabling active scan or
+ * any mode of operation that initiates TX (beacons) on a channel
+ * where we would not have been able to do either before. As an example
+ * if you are world roaming (regulatory domain set to world or if your
+ * driver is using a custom world roaming regulatory domain) and while
+ * doing a passive scan on the 5 GHz band you find an AP there (if not
+ * on a DFS channel) you will now be able to actively scan for that AP
+ * or use AP mode on your card on that same channel. Note that this will
+ * never be used for channels 1-11 on the 2 GHz band as they are always
+ * enabled world wide. This beacon hint is only sent if your device had
+ * either disabled active scanning or beaconing on a channel. We send to
+ * userspace the wiphy on which we removed a restriction from
+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * the beacon hint was processed.
+ *
+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
+ * This command is used both as a command (request to authenticate) and
+ * as an event on the "mlme" multicast group indicating completion of the
+ * authentication process.
+ * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
+ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
+ * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
+ * the SSID (mainly for association, but is included in authentication
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
+ * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
+ * is used to specify the authentication type. %NL80211_ATTR_IE is used to
+ * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
+ * to be added to the frame.
+ * When used as an event, this reports reception of an Authentication
+ * frame in station and IBSS modes when the local MLME processed the
+ * frame, i.e., it was for the local STA and was received in correct
+ * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
+ * MLME SAP interface (kernel providing MLME, userspace SME). The
+ * included %NL80211_ATTR_FRAME attribute contains the management frame
+ * (including both the header and frame body, but not FCS). This event is
+ * also used to indicate if the authentication attempt timed out. In that
+ * case the %NL80211_ATTR_FRAME attribute is replaced with a
+ * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ * pending authentication timed out).
+ * @NL80211_CMD_ASSOCIATE: association request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Association and Reassociation
+ * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
+ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+ * primitives).
+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
+ * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
+ *
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ * event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ * event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ * FREQ attribute (for the initial frequency if no peer can be found)
+ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ * should be fixed rather than automatically determined. Can only be
+ * executed on a network interface that is UP, and fixed BSSID/FREQ
+ * may be rejected. Another optional parameter is the beacon interval,
+ * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ * given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ * determined by the network interface.
+ *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ * to identify the device, and the TESTDATA blob attribute to pass through
+ * to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ * requests to connect to a specified network but without separating
+ * auth and assoc steps. For this, you need to specify the SSID in a
+ * %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ * It is also sent as an event, with the BSSID and response IEs when the
+ * connection is established or failed to be established. This can be
+ * determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ * sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ * userspace that a connection was dropped by the AP or due to other
+ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ * %NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ * associated with this wiphy must be down and will follow.
+ *
+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
+ * channel for the specified amount of time. This can be used to do
+ * off-channel operations like transmit a Public Action frame and wait for
+ * a response while being associated to an AP on another channel.
+ * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
+ * radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
+ * optionally used to specify additional channel parameters.
+ * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
+ * to remain on the channel. This command is also used as an event to
+ * notify when the requested duration starts (it may take a while for the
+ * driver to schedule this time due to other concurrent needs for the
+ * radio).
+ * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
+ * that will be included with any events pertaining to this request;
+ * the cookie is also used to cancel the request.
+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
+ * pending remain-on-channel duration if the desired operation has been
+ * completed prior to expiration of the originally requested duration.
+ * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
+ * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
+ * uniquely identify the request.
+ * This command is also used as an event to notify when a requested
+ * remain-on-channel duration has expired.
+ *
+ * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
+ * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
+ * and @NL80211_ATTR_TX_RATES the set of allowed rates.
+ *
+ * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
+ * (via @NL80211_CMD_ACTION) for processing in userspace. This command
+ * requires an interface index and a match attribute containing the first
+ * few bytes of the frame that should match, e.g. a single byte for only
+ * a category match or four bytes for vendor frames including the OUI.
+ * The registration cannot be dropped, but is removed automatically
+ * when the netlink socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
+ * command is used both as a request to transmit an Action frame and as an
+ * event indicating reception of an Action frame that was not processed in
+ * kernel code, but is for us (i.e., which may need to be processed in a
+ * user space application). %NL80211_ATTR_FRAME is used to specify the
+ * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
+ * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
+ * which channel the frame is to be transmitted or was received. This
+ * channel has to be the current channel (remain-on-channel or the
+ * operational channel). 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_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
+ * transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
+ * the TX command and %NL80211_ATTR_FRAME includes the contents of the
+ * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
+ * the frame.
+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
+ * is used to configure connection quality monitoring notification trigger
+ * levels.
+ * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
+ * command is used as an event to indicate the that a trigger level was
+ * reached.
+ *
+ * @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! */
+ NL80211_CMD_UNSPEC,
+
+ NL80211_CMD_GET_WIPHY, /* can dump */
+ NL80211_CMD_SET_WIPHY,
+ NL80211_CMD_NEW_WIPHY,
+ NL80211_CMD_DEL_WIPHY,
+
+ NL80211_CMD_GET_INTERFACE, /* can dump */
+ NL80211_CMD_SET_INTERFACE,
+ NL80211_CMD_NEW_INTERFACE,
+ NL80211_CMD_DEL_INTERFACE,
+
+ NL80211_CMD_GET_KEY,
+ NL80211_CMD_SET_KEY,
+ NL80211_CMD_NEW_KEY,
+ NL80211_CMD_DEL_KEY,
+
+ NL80211_CMD_GET_BEACON,
+ NL80211_CMD_SET_BEACON,
+ NL80211_CMD_NEW_BEACON,
+ NL80211_CMD_DEL_BEACON,
+
+ NL80211_CMD_GET_STATION,
+ NL80211_CMD_SET_STATION,
+ NL80211_CMD_NEW_STATION,
+ NL80211_CMD_DEL_STATION,
+
+ NL80211_CMD_GET_MPATH,
+ NL80211_CMD_SET_MPATH,
+ NL80211_CMD_NEW_MPATH,
+ NL80211_CMD_DEL_MPATH,
+
+ NL80211_CMD_SET_BSS,
+
+ NL80211_CMD_SET_REG,
+ NL80211_CMD_REQ_SET_REG,
+
+ NL80211_CMD_GET_MESH_PARAMS,
+ NL80211_CMD_SET_MESH_PARAMS,
+
+ NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
+
+ NL80211_CMD_GET_REG,
+
+ NL80211_CMD_GET_SCAN,
+ NL80211_CMD_TRIGGER_SCAN,
+ NL80211_CMD_NEW_SCAN_RESULTS,
+ NL80211_CMD_SCAN_ABORTED,
+
+ NL80211_CMD_REG_CHANGE,
+
+ NL80211_CMD_AUTHENTICATE,
+ NL80211_CMD_ASSOCIATE,
+ NL80211_CMD_DEAUTHENTICATE,
+ NL80211_CMD_DISASSOCIATE,
+
+ NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+ NL80211_CMD_REG_BEACON_HINT,
+
+ NL80211_CMD_JOIN_IBSS,
+ NL80211_CMD_LEAVE_IBSS,
+
+ NL80211_CMD_TESTMODE,
+
+ NL80211_CMD_CONNECT,
+ NL80211_CMD_ROAM,
+ NL80211_CMD_DISCONNECT,
+
+ NL80211_CMD_SET_WIPHY_NETNS,
+
+ NL80211_CMD_GET_SURVEY,
+ NL80211_CMD_NEW_SURVEY_RESULTS,
+
+ NL80211_CMD_SET_PMKSA,
+ NL80211_CMD_DEL_PMKSA,
+ NL80211_CMD_FLUSH_PMKSA,
+
+ NL80211_CMD_REMAIN_ON_CHANNEL,
+ NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+
+ NL80211_CMD_SET_TX_BITRATE_MASK,
+
+ NL80211_CMD_REGISTER_ACTION,
+ NL80211_CMD_ACTION,
+ NL80211_CMD_ACTION_TX_STATUS,
+
+ NL80211_CMD_SET_POWER_SAVE,
+ NL80211_CMD_GET_POWER_SAVE,
+
+ NL80211_CMD_SET_CQM,
+ NL80211_CMD_NOTIFY_CQM,
+
+ /* add new commands above here */
+
+ /* used to define NL80211_CMD_MAX below */
+ __NL80211_CMD_AFTER_LAST,
+ NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ * /sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ * this attribute)
+ * NL80211_CHAN_HT20 = HT20 only
+ * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ * less than or equal to the RTS threshold; allowed range: 1..255;
+ * dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ * greater than the RTS threshold; allowed range: 1..255;
+ * dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ * length in octets for frames; allowed range: 256..8000, disable
+ * fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ * larger than or equal to this use RTS/CTS handshake); allowed range:
+ * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
+ * section 7.3.2.9; dot11CoverageClass; u8
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ * IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array 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_STA_VLAN: interface index of VLAN interface to move station
+ * to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ * given for %NL80211_CMD_GET_STATION, nested attribute containing
+ * info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ * 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_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
+ * &enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * current regulatory domain should be set to or is already set to.
+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * to query the CRDA to retrieve one regulatory domain. This attribute can
+ * also be used by userspace to query the kernel for the currently set
+ * regulatory domain. We chose an alpha2 as that is also used by the
+ * IEEE-802.11d country information element to identify a country.
+ * Users can also simply ask the wireless core to set regulatory domain
+ * to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ * rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ * rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ * supported interface types, each a flag attribute with the number
+ * of the interface mode.
+ *
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ * a single 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_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ * scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
+ * an array of command numbers (i.e. a mapping index to command number)
+ * that the driver for the given wiphy supports.
+ *
+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
+ * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
+ * NL80211_CMD_ASSOCIATE events
+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
+ * represented as a u32
+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
+ * %NL80211_CMD_DISASSOCIATE, u16
+ *
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ * a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _before_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _after_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ * cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ * for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ * is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ * used for the association (&enum nl80211_mfp, represented as a u32);
+ * this attribute can be used
+ * with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ * &struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ * request, the driver will assume that the port is unauthorized until
+ * authorized by user space. Otherwise, port is marked authorized by
+ * default in station mode.
+ *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ * We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ * event was due to the AP disconnecting the station, and not due to
+ * a local disconnect request.
+ * @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.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE 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
+ * (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_REQ_IE: (Re)association request information elements as
+ * sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ * sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ * commands to specify using a reassociate frame
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ * %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ * and join_ibss(), key information is in a nested attribute each
+ * with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
+ * dumps. This number increases whenever the object list being
+ * dumped changes, and as such userspace can verify that it has
+ * obtained a complete and consistent snapshot by verifying that
+ * all dump messages contain the same generation number. If it
+ * changed then the list changed and the dump should be repeated
+ * completely from scratch.
+ *
+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
+ *
+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
+ * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
+ * containing info as possible, see &enum survey_info.
+ *
+ * @NL80211_ATTR_PMKID: PMK material for PMKSA caching.
+ * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
+ * cache, a wiphy attribute.
+ *
+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ *
+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
+ *
+ * @NL80211_ATTR_TX_RATES: Nested set of attributes
+ * (enum nl80211_tx_rate_attributes) describing TX rates per band. The
+ * enum nl80211_band value is used as the index (nla_type() of the nested
+ * data. If a band is not included, it will be configured to allow all
+ * rates based on negotiated supported rates information. This attribute
+ * is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
+ *
+ * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
+ * at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
+ *
+ * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
+ * acknowledged by the recipient.
+ *
+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a
+ * nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
+ *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
+ * is requesting a local authentication/association state change without
+ * invoking actual management frame exchange. This can be used with
+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
+ * NL80211_CMD_DISASSOCIATE.
+ *
+ * @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! */
+ NL80211_ATTR_UNSPEC,
+
+ NL80211_ATTR_WIPHY,
+ NL80211_ATTR_WIPHY_NAME,
+
+ NL80211_ATTR_IFINDEX,
+ NL80211_ATTR_IFNAME,
+ NL80211_ATTR_IFTYPE,
+
+ NL80211_ATTR_MAC,
+
+ NL80211_ATTR_KEY_DATA,
+ NL80211_ATTR_KEY_IDX,
+ NL80211_ATTR_KEY_CIPHER,
+ NL80211_ATTR_KEY_SEQ,
+ NL80211_ATTR_KEY_DEFAULT,
+
+ NL80211_ATTR_BEACON_INTERVAL,
+ NL80211_ATTR_DTIM_PERIOD,
+ NL80211_ATTR_BEACON_HEAD,
+ NL80211_ATTR_BEACON_TAIL,
+
+ NL80211_ATTR_STA_AID,
+ NL80211_ATTR_STA_FLAGS,
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
+ NL80211_ATTR_STA_SUPPORTED_RATES,
+ NL80211_ATTR_STA_VLAN,
+ NL80211_ATTR_STA_INFO,
+
+ NL80211_ATTR_WIPHY_BANDS,
+
+ NL80211_ATTR_MNTR_FLAGS,
+
+ NL80211_ATTR_MESH_ID,
+ NL80211_ATTR_STA_PLINK_ACTION,
+ NL80211_ATTR_MPATH_NEXT_HOP,
+ NL80211_ATTR_MPATH_INFO,
+
+ NL80211_ATTR_BSS_CTS_PROT,
+ NL80211_ATTR_BSS_SHORT_PREAMBLE,
+ NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+ NL80211_ATTR_HT_CAPABILITY,
+
+ NL80211_ATTR_SUPPORTED_IFTYPES,
+
+ NL80211_ATTR_REG_ALPHA2,
+ NL80211_ATTR_REG_RULES,
+
+ NL80211_ATTR_MESH_PARAMS,
+
+ NL80211_ATTR_BSS_BASIC_RATES,
+
+ NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+ NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+ NL80211_ATTR_MGMT_SUBTYPE,
+ NL80211_ATTR_IE,
+
+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ NL80211_ATTR_SCAN_SSIDS,
+ NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
+ NL80211_ATTR_BSS,
+
+ NL80211_ATTR_REG_INITIATOR,
+ NL80211_ATTR_REG_TYPE,
+
+ NL80211_ATTR_SUPPORTED_COMMANDS,
+
+ NL80211_ATTR_FRAME,
+ NL80211_ATTR_SSID,
+ NL80211_ATTR_AUTH_TYPE,
+ NL80211_ATTR_REASON_CODE,
+
+ NL80211_ATTR_KEY_TYPE,
+
+ NL80211_ATTR_MAX_SCAN_IE_LEN,
+ NL80211_ATTR_CIPHER_SUITES,
+
+ NL80211_ATTR_FREQ_BEFORE,
+ NL80211_ATTR_FREQ_AFTER,
+
+ NL80211_ATTR_FREQ_FIXED,
+
+
+ NL80211_ATTR_WIPHY_RETRY_SHORT,
+ NL80211_ATTR_WIPHY_RETRY_LONG,
+ NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+ NL80211_ATTR_TIMED_OUT,
+
+ NL80211_ATTR_USE_MFP,
+
+ NL80211_ATTR_STA_FLAGS2,
+
+ NL80211_ATTR_CONTROL_PORT,
+
+ NL80211_ATTR_TESTDATA,
+
+ NL80211_ATTR_PRIVACY,
+
+ NL80211_ATTR_DISCONNECTED_BY_AP,
+ NL80211_ATTR_STATUS_CODE,
+
+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ NL80211_ATTR_CIPHER_SUITE_GROUP,
+ NL80211_ATTR_WPA_VERSIONS,
+ NL80211_ATTR_AKM_SUITES,
+
+ NL80211_ATTR_REQ_IE,
+ NL80211_ATTR_RESP_IE,
+
+ NL80211_ATTR_PREV_BSSID,
+
+ NL80211_ATTR_KEY,
+ NL80211_ATTR_KEYS,
+
+ NL80211_ATTR_PID,
+
+ NL80211_ATTR_4ADDR,
+
+ NL80211_ATTR_SURVEY_INFO,
+
+ NL80211_ATTR_PMKID,
+ NL80211_ATTR_MAX_NUM_PMKIDS,
+
+ NL80211_ATTR_DURATION,
+
+ NL80211_ATTR_COOKIE,
+
+ NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+
+ NL80211_ATTR_TX_RATES,
+
+ NL80211_ATTR_FRAME_MATCH,
+
+ NL80211_ATTR_ACK,
+
+ NL80211_ATTR_PS_STATE,
+
+ NL80211_ATTR_CQM,
+
+ NL80211_ATTR_LOCAL_STATE_CHANGE,
+
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+ NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/* source-level API compatibility */
+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
+#define NL80211_ATTR_SSID NL80211_ATTR_SSID
+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#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_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_REG_RULES 32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
+#define NL80211_HT_CAPABILITY_LEN 26
+
+#define NL80211_MAX_NR_CIPHER_SUITES 5
+#define NL80211_MAX_NR_AKM_SUITES 2
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @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_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+ NL80211_IFTYPE_UNSPECIFIED,
+ NL80211_IFTYPE_ADHOC,
+ NL80211_IFTYPE_STATION,
+ NL80211_IFTYPE_AP,
+ NL80211_IFTYPE_AP_VLAN,
+ NL80211_IFTYPE_WDS,
+ NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_MESH_POINT,
+
+ /* keep last */
+ __NL80211_IFTYPE_AFTER_LAST,
+ NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ */
+enum nl80211_sta_flags {
+ __NL80211_STA_FLAG_INVALID,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
+ NL80211_STA_FLAG_WME,
+ NL80211_STA_FLAG_MFP,
+
+ /* keep last */
+ __NL80211_STA_FLAG_AFTER_LAST,
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+ __u32 mask;
+ __u32 set;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+ __NL80211_RATE_INFO_INVALID,
+ NL80211_RATE_INFO_BITRATE,
+ NL80211_RATE_INFO_MCS,
+ NL80211_RATE_INFO_40_MHZ_WIDTH,
+ NL80211_RATE_INFO_SHORT_GI,
+
+ /* keep last */
+ __NL80211_RATE_INFO_AFTER_LAST,
+ NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @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.
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ * station)
+ */
+enum nl80211_sta_info {
+ __NL80211_STA_INFO_INVALID,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_LLID,
+ NL80211_STA_INFO_PLID,
+ NL80211_STA_INFO_PLINK_STATE,
+ NL80211_STA_INFO_SIGNAL,
+ NL80211_STA_INFO_TX_BITRATE,
+ NL80211_STA_INFO_RX_PACKETS,
+ NL80211_STA_INFO_TX_PACKETS,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+ NL80211_MPATH_FLAG_ACTIVE = 1<<0,
+ NL80211_MPATH_FLAG_RESOLVING = 1<<1,
+ NL80211_MPATH_FLAG_SN_VALID = 1<<2,
+ NL80211_MPATH_FLAG_FIXED = 1<<3,
+ NL80211_MPATH_FLAG_RESOLVED = 1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_ATTR_MPATH_SN: destination sequence number
+ * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
+ * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * &enum nl80211_mpath_flags;
+ * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ */
+enum nl80211_mpath_info {
+ __NL80211_MPATH_INFO_INVALID,
+ NL80211_MPATH_INFO_FRAME_QLEN,
+ NL80211_MPATH_INFO_SN,
+ NL80211_MPATH_INFO_METRIC,
+ NL80211_MPATH_INFO_EXPTIME,
+ NL80211_MPATH_INFO_FLAGS,
+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+ /* keep last */
+ __NL80211_MPATH_INFO_AFTER_LAST,
+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ * an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ * an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ * defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ */
+enum nl80211_band_attr {
+ __NL80211_BAND_ATTR_INVALID,
+ NL80211_BAND_ATTR_FREQS,
+ NL80211_BAND_ATTR_RATES,
+
+ NL80211_BAND_ATTR_HT_MCS_SET,
+ NL80211_BAND_ATTR_HT_CAPA,
+ NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+ NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+ /* keep last */
+ __NL80211_BAND_ATTR_AFTER_LAST,
+ NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ * regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ * permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ * (100 * dBm).
+ */
+enum nl80211_frequency_attr {
+ __NL80211_FREQUENCY_ATTR_INVALID,
+ NL80211_FREQUENCY_ATTR_FREQ,
+ NL80211_FREQUENCY_ATTR_DISABLED,
+ NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+ NL80211_FREQUENCY_ATTR_NO_IBSS,
+ NL80211_FREQUENCY_ATTR_RADAR,
+ NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+ /* keep last */
+ __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+ NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ * in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+ __NL80211_BITRATE_ATTR_INVALID,
+ NL80211_BITRATE_ATTR_RATE,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+ /* keep last */
+ __NL80211_BITRATE_ATTR_AFTER_LAST,
+ NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ * wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ * 802.11 country information element with regulatory information it
+ * thinks we should consider.
+ */
+enum nl80211_reg_initiator {
+ NL80211_REGDOM_SET_BY_CORE,
+ NL80211_REGDOM_SET_BY_USER,
+ NL80211_REGDOM_SET_BY_DRIVER,
+ NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ * to a specific country. When this is set you can count on the
+ * ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ * domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ * driver specific world regulatory domain. These do not apply system-wide
+ * and are only applicable to the individual devices which have requested
+ * them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ * of an intersection between two regulatory domains -- the previously
+ * set regulatory domain on the system and the last accepted regulatory
+ * domain request to be processed.
+ */
+enum nl80211_reg_type {
+ NL80211_REGDOM_TYPE_COUNTRY,
+ NL80211_REGDOM_TYPE_WORLD,
+ NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+ NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * considerations for a given frequency range. These are the
+ * &enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * rule in KHz. This is not a center of frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * in KHz. This is not a center a frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * for a given frequency range. The value is in mBi (100 * dBi).
+ * If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * a given frequency range. The value is in mBm (100 * dBm).
+ */
+enum nl80211_reg_rule_attr {
+ __NL80211_REG_RULE_ATTR_INVALID,
+ NL80211_ATTR_REG_RULE_FLAGS,
+
+ NL80211_ATTR_FREQ_RANGE_START,
+ NL80211_ATTR_FREQ_RANGE_END,
+ NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+ NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+ /* keep last */
+ __NL80211_REG_RULE_ATTR_AFTER_LAST,
+ NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+ NL80211_RRF_NO_OFDM = 1<<0,
+ NL80211_RRF_NO_CCK = 1<<1,
+ NL80211_RRF_NO_INDOOR = 1<<2,
+ NL80211_RRF_NO_OUTDOOR = 1<<3,
+ NL80211_RRF_DFS = 1<<4,
+ NL80211_RRF_PTP_ONLY = 1<<5,
+ NL80211_RRF_PTMP_ONLY = 1<<6,
+ NL80211_RRF_PASSIVE_SCAN = 1<<7,
+ NL80211_RRF_NO_IBSS = 1<<8,
+};
+
+/**
+ * enum nl80211_survey_info - survey information
+ *
+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
+ * when getting information about a survey.
+ *
+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ */
+enum nl80211_survey_info {
+ __NL80211_SURVEY_INFO_INVALID,
+ NL80211_SURVEY_INFO_FREQUENCY,
+ NL80211_SURVEY_INFO_NOISE,
+
+ /* keep last */
+ __NL80211_SURVEY_INFO_AFTER_LAST,
+ NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ * overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+ __NL80211_MNTR_FLAG_INVALID,
+ NL80211_MNTR_FLAG_FCSFAIL,
+ NL80211_MNTR_FLAG_PLCPFAIL,
+ NL80211_MNTR_FLAG_CONTROL,
+ NL80211_MNTR_FLAG_OTHER_BSS,
+ NL80211_MNTR_FLAG_COOK_FRAMES,
+
+ /* keep last */
+ __NL80211_MNTR_FLAG_AFTER_LAST,
+ NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__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
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @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_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+ __NL80211_MESHCONF_INVALID,
+ NL80211_MESHCONF_RETRY_TIMEOUT,
+ NL80211_MESHCONF_CONFIRM_TIMEOUT,
+ NL80211_MESHCONF_HOLDING_TIMEOUT,
+ NL80211_MESHCONF_MAX_PEER_LINKS,
+ NL80211_MESHCONF_MAX_RETRIES,
+ NL80211_MESHCONF_TTL,
+ NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+ NL80211_MESHCONF_PATH_REFRESH_TIME,
+ NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+ NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+ NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+ NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+ NL80211_MESHCONF_HWMP_ROOTMODE,
+
+ /* keep last */
+ __NL80211_MESHCONF_ATTR_AFTER_LAST,
+ NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_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_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ * disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+ __NL80211_TXQ_ATTR_INVALID,
+ NL80211_TXQ_ATTR_QUEUE,
+ NL80211_TXQ_ATTR_TXOP,
+ NL80211_TXQ_ATTR_CWMIN,
+ NL80211_TXQ_ATTR_CWMAX,
+ NL80211_TXQ_ATTR_AIFS,
+
+ /* keep last */
+ __NL80211_TXQ_ATTR_AFTER_LAST,
+ NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+ NL80211_TXQ_Q_VO,
+ NL80211_TXQ_Q_VI,
+ NL80211_TXQ_Q_BE,
+ NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+ NL80211_CHAN_NO_HT,
+ NL80211_CHAN_HT20,
+ NL80211_CHAN_HT40MINUS,
+ NL80211_CHAN_HT40PLUS
+};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ * raw information elements from the probe response/beacon (bin);
+ * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
+ * from a Probe Response frame; otherwise they are from a Beacon frame.
+ * However, if the driver does not indicate the source of the IEs, these
+ * IEs may be from either frame subtype.
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ * in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ * in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
+ * elements from a Beacon frame (bin); not present if no Beacon frame has
+ * yet been received
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+ __NL80211_BSS_INVALID,
+ NL80211_BSS_BSSID,
+ NL80211_BSS_FREQUENCY,
+ NL80211_BSS_TSF,
+ NL80211_BSS_BEACON_INTERVAL,
+ NL80211_BSS_CAPABILITY,
+ NL80211_BSS_INFORMATION_ELEMENTS,
+ NL80211_BSS_SIGNAL_MBM,
+ NL80211_BSS_SIGNAL_UNSPEC,
+ NL80211_BSS_STATUS,
+ NL80211_BSS_SEEN_MS_AGO,
+ NL80211_BSS_BEACON_IES,
+
+ /* keep last */
+ __NL80211_BSS_AFTER_LAST,
+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bss_status - BSS "status"
+ */
+enum nl80211_bss_status {
+ NL80211_BSS_STATUS_AUTHENTICATED,
+ NL80211_BSS_STATUS_ASSOCIATED,
+ NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
+ * enum nl80211_auth_type - AuthenticationType
+ *
+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ * trying multiple times); this is invalid in netlink -- leave out
+ * the attribute for this on CONNECT commands.
+ */
+enum nl80211_auth_type {
+ NL80211_AUTHTYPE_OPEN_SYSTEM,
+ NL80211_AUTHTYPE_SHARED_KEY,
+ NL80211_AUTHTYPE_FT,
+ NL80211_AUTHTYPE_NETWORK_EAP,
+
+ /* keep last */
+ __NL80211_AUTHTYPE_NUM,
+ NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+ NL80211_AUTHTYPE_AUTOMATIC
+};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ */
+enum nl80211_key_type {
+ NL80211_KEYTYPE_GROUP,
+ NL80211_KEYTYPE_PAIRWISE,
+ NL80211_KEYTYPE_PEERKEY,
+};
+
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+ NL80211_MFP_NO,
+ NL80211_MFP_REQUIRED,
+};
+
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1 << 0,
+ NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+ __NL80211_KEY_INVALID,
+ NL80211_KEY_DATA,
+ NL80211_KEY_IDX,
+ NL80211_KEY_CIPHER,
+ NL80211_KEY_SEQ,
+ NL80211_KEY_DEFAULT,
+ NL80211_KEY_DEFAULT_MGMT,
+
+ /* keep last */
+ __NL80211_KEY_AFTER_LAST,
+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_tx_rate_attributes - TX rate set attributes
+ * @__NL80211_TXRATE_INVALID: invalid
+ * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
+ * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
+ * 1 = 500 kbps) but without the IE length restriction (at most
+ * %NL80211_MAX_SUPP_RATES in a single array).
+ * @__NL80211_TXRATE_AFTER_LAST: internal
+ * @NL80211_TXRATE_MAX: highest TX rate attribute
+ */
+enum nl80211_tx_rate_attributes {
+ __NL80211_TXRATE_INVALID,
+ NL80211_TXRATE_LEGACY,
+
+ /* keep last */
+ __NL80211_TXRATE_AFTER_LAST,
+ NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band - Frequency band
+ * @NL80211_BAND_2GHZ - 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum nl80211_band {
+ NL80211_BAND_2GHZ,
+ NL80211_BAND_5GHZ,
+};
+
+enum nl80211_ps_state {
+ NL80211_PS_DISABLED,
+ NL80211_PS_ENABLED,
+};
+
+/**
+ * enum nl80211_attr_cqm - connection quality monitor attributes
+ * @__NL80211_ATTR_CQM_INVALID: invalid
+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
+ * the threshold for the RSSI level at which an event will be sent. Zero
+ * to disable.
+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
+ * the minimum amount the RSSI level must change after an event before a
+ * new event may be issued (to reduce effects of RSSI oscillation).
+ * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal
+ * @NL80211_ATTR_CQM_MAX: highest key attribute
+ */
+enum nl80211_attr_cqm {
+ __NL80211_ATTR_CQM_INVALID,
+ NL80211_ATTR_CQM_RSSI_THOLD,
+ NL80211_ATTR_CQM_RSSI_HYST,
+ NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+
+ /* keep last */
+ __NL80211_ATTR_CQM_AFTER_LAST,
+ NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
+ * configured threshold
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
+ * configured threshold
+ */
+enum nl80211_cqm_rssi_threshold_event {
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+};
+
+#endif /* __LINUX_NL80211_H */
diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h
index 2a31e251a0138..23eff83fadd43 100644
--- a/src/drivers/priv_netlink.h
+++ b/src/drivers/priv_netlink.h
@@ -53,8 +53,17 @@
#define NLMSG_ALIGNTO 4
#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr *) \
+ (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (int) (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
#define RTA_ALIGNTO 4
#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
diff --git a/src/drivers/radiotap.c b/src/drivers/radiotap.c
deleted file mode 100644
index 804473fa4bfb9..0000000000000
--- a/src/drivers/radiotap.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Radiotap parser
- *
- * Copyright 2007 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- *
- * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
- * I only modified some things on top to ease syncing should bugs be found.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "radiotap_iter.h"
-
-#define le16_to_cpu le_to_host16
-#define le32_to_cpu le_to_host32
-#define __le32 uint32_t
-#define ulong unsigned long
-#define unlikely(cond) (cond)
-#define get_unaligned(p) \
-({ \
- struct packed_dummy_struct { \
- typeof(*(p)) __val; \
- } __attribute__((packed)) *__ptr = (void *) (p); \
- \
- __ptr->__val; \
-})
-
-/* function prototypes and related defs are in radiotap_iter.h */
-
-/**
- * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
- * @iterator: radiotap_iterator to initialize
- * @radiotap_header: radiotap header to parse
- * @max_length: total length we can parse into (eg, whole packet length)
- *
- * Returns: 0 or a negative error code if there is a problem.
- *
- * This function initializes an opaque iterator struct which can then
- * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
- * argument which is present in the header. It knows about extended
- * present headers and handles them.
- *
- * How to use:
- * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
- * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
- * checking for a good 0 return code. Then loop calling
- * __ieee80211_radiotap_iterator_next()... it returns either 0,
- * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
- * The iterator's @this_arg member points to the start of the argument
- * associated with the current argument index that is present, which can be
- * found in the iterator's @this_arg_index member. This arg index corresponds
- * to the IEEE80211_RADIOTAP_... defines.
- *
- * Radiotap header length:
- * You can find the CPU-endian total radiotap header length in
- * iterator->max_length after executing ieee80211_radiotap_iterator_init()
- * successfully.
- *
- * Alignment Gotcha:
- * You must take care when dereferencing iterator.this_arg
- * for multibyte types... the pointer is not aligned. Use
- * get_unaligned((type *)iterator.this_arg) to dereference
- * iterator.this_arg for type "type" safely on all arches.
- *
- * Example code:
- * See Documentation/networking/radiotap-headers.txt
- */
-
-int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length)
-{
- /* Linux only supports version 0 radiotap format */
- if (radiotap_header->it_version)
- return -EINVAL;
-
- /* sanity check for allowed length and radiotap length field */
- if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
- return -EINVAL;
-
- iterator->rtheader = radiotap_header;
- iterator->max_length = le16_to_cpu(get_unaligned(
- &radiotap_header->it_len));
- iterator->arg_index = 0;
- iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
- &radiotap_header->it_present));
- iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
- iterator->this_arg = NULL;
-
- /* find payload start allowing for extended bitmap(s) */
-
- if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
- while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
- (1<<IEEE80211_RADIOTAP_EXT)) {
- iterator->arg += sizeof(u32);
-
- /*
- * check for insanity where the present bitmaps
- * keep claiming to extend up to or even beyond the
- * stated radiotap header length
- */
-
- if (((ulong)iterator->arg - (ulong)iterator->rtheader)
- > (ulong)iterator->max_length)
- return -EINVAL;
- }
-
- iterator->arg += sizeof(u32);
-
- /*
- * no need to check again for blowing past stated radiotap
- * header length, because ieee80211_radiotap_iterator_next
- * checks it before it is dereferenced
- */
- }
-
- /* we are all initialized happily */
-
- return 0;
-}
-
-
-/**
- * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
- * @iterator: radiotap_iterator to move to next arg (if any)
- *
- * Returns: 0 if there is an argument to handle,
- * -ENOENT if there are no more args or -EINVAL
- * if there is something else wrong.
- *
- * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
- * in @this_arg_index and sets @this_arg to point to the
- * payload for the field. It takes care of alignment handling and extended
- * present fields. @this_arg can be changed by the caller (eg,
- * incremented to move inside a compound argument like
- * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
- * little-endian format whatever the endianess of your CPU.
- *
- * Alignment Gotcha:
- * You must take care when dereferencing iterator.this_arg
- * for multibyte types... the pointer is not aligned. Use
- * get_unaligned((type *)iterator.this_arg) to dereference
- * iterator.this_arg for type "type" safely on all arches.
- */
-
-int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator)
-{
-
- /*
- * small length lookup table for all radiotap types we heard of
- * starting from b0 in the bitmap, so we can walk the payload
- * area of the radiotap header
- *
- * There is a requirement to pad args, so that args
- * of a given length must begin at a boundary of that length
- * -- but note that compound args are allowed (eg, 2 x u16
- * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
- * a reliable indicator of alignment requirement.
- *
- * upper nybble: content alignment for arg
- * lower nybble: content length for arg
- */
-
- static const u8 rt_sizes[] = {
- [IEEE80211_RADIOTAP_TSFT] = 0x88,
- [IEEE80211_RADIOTAP_FLAGS] = 0x11,
- [IEEE80211_RADIOTAP_RATE] = 0x11,
- [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
- [IEEE80211_RADIOTAP_FHSS] = 0x22,
- [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
- [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
- [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
- [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
- [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
- [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
- [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
- [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
- [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
- [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
- [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
- [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
- [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
- /*
- * add more here as they are defined in
- * include/net/ieee80211_radiotap.h
- */
- };
-
- /*
- * for every radiotap entry we can at
- * least skip (by knowing the length)...
- */
-
- while (iterator->arg_index < (int) sizeof(rt_sizes)) {
- int hit = 0;
- int pad;
-
- if (!(iterator->bitmap_shifter & 1))
- goto next_entry; /* arg not present */
-
- /*
- * arg is present, account for alignment padding
- * 8-bit args can be at any alignment
- * 16-bit args must start on 16-bit boundary
- * 32-bit args must start on 32-bit boundary
- * 64-bit args must start on 64-bit boundary
- *
- * note that total arg size can differ from alignment of
- * elements inside arg, so we use upper nybble of length
- * table to base alignment on
- *
- * also note: these alignments are ** relative to the
- * start of the radiotap header **. There is no guarantee
- * that the radiotap header itself is aligned on any
- * kind of boundary.
- *
- * the above is why get_unaligned() is used to dereference
- * multibyte elements from the radiotap area
- */
-
- pad = (((ulong)iterator->arg) -
- ((ulong)iterator->rtheader)) &
- ((rt_sizes[iterator->arg_index] >> 4) - 1);
-
- if (pad)
- iterator->arg +=
- (rt_sizes[iterator->arg_index] >> 4) - pad;
-
- /*
- * this is what we will return to user, but we need to
- * move on first so next call has something fresh to test
- */
- iterator->this_arg_index = iterator->arg_index;
- iterator->this_arg = iterator->arg;
- hit = 1;
-
- /* internally move on the size of this arg */
- iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
-
- /*
- * check for insanity where we are given a bitmap that
- * claims to have more arg content than the length of the
- * radiotap section. We will normally end up equalling this
- * max_length on the last arg, never exceeding it.
- */
-
- if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
- (ulong) iterator->max_length)
- return -EINVAL;
-
- next_entry:
- iterator->arg_index++;
- if (unlikely((iterator->arg_index & 31) == 0)) {
- /* completed current u32 bitmap */
- if (iterator->bitmap_shifter & 1) {
- /* b31 was set, there is more */
- /* move to next u32 bitmap */
- iterator->bitmap_shifter = le32_to_cpu(
- get_unaligned(iterator->next_bitmap));
- iterator->next_bitmap++;
- } else
- /* no more bitmaps: end */
- iterator->arg_index = sizeof(rt_sizes);
- } else /* just try the next bit */
- iterator->bitmap_shifter >>= 1;
-
- /* if we found a valid arg earlier, return it now */
- if (hit)
- return 0;
- }
-
- /* we don't know how to handle any more args, we're done */
- return -ENOENT;
-}
diff --git a/src/drivers/radiotap.h b/src/drivers/radiotap.h
deleted file mode 100644
index 508264c4cf333..0000000000000
--- a/src/drivers/radiotap.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
-/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
-
-/*-
- * Copyright (c) 2003, 2004 David Young. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
-/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn@kismetwireless.net)
- */
-
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
-
-#include <stdint.h>
-
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION 0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/* The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
- */
-struct ieee80211_radiotap_header {
- uint8_t it_version; /* Version 0. Only increases
- * for drastic changes,
- * introduction of compatible
- * new fields does not count.
- */
- uint8_t it_pad;
- uint16_t it_len; /* length of the whole
- * header in bytes, including
- * it_version, it_pad,
- * it_len, and data fields.
- */
- uint32_t it_present; /* A bitmap telling which
- * fields are present. Set bit 31
- * (0x80000000) to extend the
- * bitmap by another 32 bits.
- * Additional extensions are made
- * by setting bit 31.
- */
-};
-
-/* Name Data type Units
- * ---- --------- -----
- *
- * IEEE80211_RADIOTAP_TSFT __le64 microseconds
- *
- * Value in microseconds of the MAC's 64-bit 802.11 Time
- * Synchronization Function timer when the first bit of the
- * MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
- *
- * Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS uint16_t see below
- *
- * For frequency-hopping radios, the hop set (first byte)
- * and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE u8 500kb/s
- *
- * Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
- * one milliwatt (dBm)
- *
- * RF signal power at the antenna, decibel difference from
- * one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
- * one milliwatt (dBm)
- *
- * RF noise power at the antenna, decibel difference from one
- * milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
- *
- * RF signal power at the antenna, decibel difference from an
- * arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
- *
- * RF noise power at the antenna, decibel difference from an
- * arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
- *
- * Quality of Barker code lock. Unitless. Monotonically
- * nondecreasing with "better" lock strength. Called "Signal
- * Quality" in datasheets. (Is there a standard way to measure
- * this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
- *
- * Transmit power expressed as unitless distance from max
- * power set at factory calibration. 0 is max power.
- * Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
- *
- * Transmit power expressed as decibel distance from max power
- * set at factory calibration. 0 is max power. Monotonically
- * nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
- * one milliwatt (dBm)
- *
- * Transmit power expressed as dBm (decibels from a 1 milliwatt
- * reference). This is the absolute power level measured at
- * the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS u8 bitmap
- *
- * Properties of transmitted and received frames. See flags
- * defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
- *
- * Unitless indication of the Rx/Tx antenna for this packet.
- * The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
- *
- * Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
- *
- * Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
- *
- * Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
- *
- * Number of unicast retries a transmitted frame used.
- *
- */
-enum ieee80211_radiotap_type {
- IEEE80211_RADIOTAP_TSFT = 0,
- IEEE80211_RADIOTAP_FLAGS = 1,
- IEEE80211_RADIOTAP_RATE = 2,
- IEEE80211_RADIOTAP_CHANNEL = 3,
- IEEE80211_RADIOTAP_FHSS = 4,
- IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
- IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
- IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
- IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
- IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
- IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
- IEEE80211_RADIOTAP_ANTENNA = 11,
- IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
- IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
- IEEE80211_RADIOTAP_RX_FLAGS = 14,
- IEEE80211_RADIOTAP_TX_FLAGS = 15,
- IEEE80211_RADIOTAP_RTS_RETRIES = 16,
- IEEE80211_RADIOTAP_DATA_RETRIES = 17,
- IEEE80211_RADIOTAP_EXT = 31
-};
-
-/* Channel flags. */
-#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
-#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
-#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
-#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
-#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
-#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
-#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
-#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
-
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
- * during CFP
- */
-#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
- * with short
- * preamble
- */
-#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
- * with WEP encryption
- */
-#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
- * with fragmentation
- */
-#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
-#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
- * 802.11 header and payload
- * (to 32-bit boundary)
- */
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
-
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
- * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
-
-#endif /* IEEE80211_RADIOTAP_H */
diff --git a/src/drivers/radiotap_iter.h b/src/drivers/radiotap_iter.h
deleted file mode 100644
index 92a798a67023a..0000000000000
--- a/src/drivers/radiotap_iter.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __RADIOTAP_ITER_H
-#define __RADIOTAP_ITER_H
-
-#include "radiotap.h"
-
-/* Radiotap header iteration
- * implemented in radiotap.c
- */
-/**
- * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
- * @rtheader: pointer to the radiotap header we are walking through
- * @max_length: length of radiotap header in cpu byte ordering
- * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
- * @this_arg: pointer to current radiotap arg
- * @arg_index: internal next argument index
- * @arg: internal next argument pointer
- * @next_bitmap: internal pointer to next present u32
- * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
- */
-
-struct ieee80211_radiotap_iterator {
- struct ieee80211_radiotap_header *rtheader;
- int max_length;
- int this_arg_index;
- unsigned char *this_arg;
-
- int arg_index;
- unsigned char *arg;
- uint32_t *next_bitmap;
- uint32_t bitmap_shifter;
-};
-
-extern int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length);
-
-extern int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator);
-
-#endif /* __RADIOTAP_ITER_H */
diff --git a/src/drivers/scan_helpers.c b/src/drivers/scan_helpers.c
deleted file mode 100644
index 63387701ea9aa..0000000000000
--- a/src/drivers/scan_helpers.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * WPA Supplicant - Helper functions for scan result processing
- * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "drivers/driver.h"
-#include "ieee802_11_defs.h"
-
-
-const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
-{
- const u8 *end, *pos;
-
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
-}
-
-
-const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
- u32 vendor_type)
-{
- const u8 *end, *pos;
-
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
-}
-
-
-struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
- u32 vendor_type)
-{
- struct wpabuf *buf;
- const u8 *end, *pos;
-
- buf = wpabuf_alloc(res->ie_len);
- if (buf == NULL)
- return NULL;
-
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
- }
-
- if (wpabuf_len(buf) == 0) {
- wpabuf_free(buf);
- buf = NULL;
- }
-
- return buf;
-}
-
-
-int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
-{
- int rate = 0;
- const u8 *ie;
- int i;
-
- ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
- for (i = 0; ie && i < ie[1]; i++) {
- if ((ie[i + 2] & 0x7f) > rate)
- rate = ie[i + 2] & 0x7f;
- }
-
- ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
- for (i = 0; ie && i < ie[1]; i++) {
- if ((ie[i + 2] & 0x7f) > rate)
- rate = ie[i + 2] & 0x7f;
- }
-
- return rate;
-}
-
-
-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);
-}
-
-
-/* Compare function for sorting scan results. Return >0 if @b is considered
- * better. */
-static int wpa_scan_result_compar(const void *a, const void *b)
-{
- struct wpa_scan_res **_wa = (void *) a;
- struct wpa_scan_res **_wb = (void *) b;
- struct wpa_scan_res *wa = *_wa;
- struct wpa_scan_res *wb = *_wb;
- int wpa_a, wpa_b, maxrate_a, maxrate_b;
-
- /* WPA/WPA2 support preferred */
- wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
- wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
- wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
- wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
-
- if (wpa_b && !wpa_a)
- return 1;
- if (!wpa_b && wpa_a)
- return -1;
-
- /* privacy support preferred */
- if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
- (wb->caps & IEEE80211_CAP_PRIVACY))
- return 1;
- if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
- (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
- return -1;
-
- /* best/max rate preferred if signal level close enough XXX */
- if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) ||
- (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
- maxrate_a = wpa_scan_get_max_rate(wa);
- maxrate_b = wpa_scan_get_max_rate(wb);
- if (maxrate_a != maxrate_b)
- return maxrate_b - maxrate_a;
- }
-
- /* use freq for channel preference */
-
- /* all things being equal, use signal level; if signal levels are
- * identical, use quality values since some drivers may only report
- * that value and leave the signal level zero */
- if (wb->level == wa->level)
- return wb->qual - wa->qual;
- return wb->level - wa->level;
-}
-
-
-void wpa_scan_sort_results(struct wpa_scan_results *res)
-{
- qsort(res->res, res->num, sizeof(struct wpa_scan_res *),
- wpa_scan_result_compar);
-}
diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h
new file mode 100644
index 0000000000000..ad764663766f8
--- /dev/null
+++ b/src/drivers/wireless_copy.h
@@ -0,0 +1,1099 @@
+/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 18.
+ * 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 : 19 18.3.05
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2005 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
+/* To minimise problems in user space, I might remove those headers
+ * at some point. Jean II */
+#include <linux/types.h> /* for "caddr_t" et al */
+#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>
+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
+
+/***************************** 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 19
+
+/*
+ * 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
+ */
+
+/**************************** 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 'odd' 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)
+
+/* Even : get (world access), odd : 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) */
+
+/* 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_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 0x000F /* 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 */
+
+/* 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 */
+
+/* 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
+
+/* 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 and IW_AUTH_GROUP_CIPHER 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
+
+/* 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 - SIOCSIWCOMMIT))
+#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 */
+};
+
+/*
+ * 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;
+
+ /* 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 lenght 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)
+
+#endif /* _LINUX_WIRELESS_H */