Cumulative patch from commit 8b48e3200680f71ae083b84793e6bdc2099416d2
8b48e32 wpa_cli: Add MAC address randomization in scan
fb37588 ctrl_iface: Add MAC address randomization in scan processing
56c76fa scan: Add MAC address randomization in scan handling
86056fe nl80211: Handle MAC address randomization in scan/sched_scan
ff23ed2 driver: Add definitions for MAC address randomization in scan
7db53bb wpa_cli: Implement TDLS start/cancel channel switching commands
72b2605 nl80211: Pass TDLS channel-switch start/stop params to kernel
6b90dea TDLS: Propagate enable/disable channel-switch commands to driver
d9d3b78 TDLS: Track TDLS channel switch prohibition in BSS
4daa572 TDLS: Add channel-switch capability flag
ca16586 Sync with wireless-testing.git include/uapi/linux/nl80211.h
8c42b36 WMM AC: Reconfigure tspecs on reassociation to the same BSS
677e7a9 WMM AC: Do not fail on unknown IEs in Association Response
fecc2bb WMM AC: Delete tspecs on roaming
20fe745 WMM AC: Print user-priority in wmm_ac_status
730a0d1 nl80211: Always register management frames handler
...
209702d Add possibility to set the setband parameter
ee82e33 Do not trigger the scan during initialization on Android platforms
e69ae5f Reject new SCAN commands if there is a pending request
...
59d7148 nl80211: Provide subtype and reason code for AP SME drivers
9d4ff04 Add external EAPOL transmission option for testing purposes
61fc904 P2P: Handle improper WPS termination on GO during group formation
58b40fd P2P: Clear p2p_go_group_formation_completed on GO start
c155305 Complete sme-connect radio work when clearing connection state
debb2da P2P: Report group removal reason PSK_FAILURE in timeout case
51465a0 The master branch is now used for v2.4 development
Change-Id: I9b9cfa5c5cd4d26b2f3f5595f7c226ac60de6258
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6af7294..eeaba66 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -23,8 +23,7 @@
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
-#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
-#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_NO_IR 0x00000002
#define HOSTAPD_CHAN_RADAR 0x00000008
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
@@ -42,6 +41,12 @@
#define HOSTAPD_CHAN_VHT_50_30 0x00002000
#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
+#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
+
+/**
+ * enum reg_change_initiator - Regulatory change initiator
+ */
enum reg_change_initiator {
REGDOM_SET_BY_CORE,
REGDOM_SET_BY_USER,
@@ -50,6 +55,9 @@
REGDOM_BEACON_HINT,
};
+/**
+ * enum reg_type - Regulatory change types
+ */
enum reg_type {
REGDOM_TYPE_UNKNOWN,
REGDOM_TYPE_COUNTRY,
@@ -82,8 +90,8 @@
*/
u8 max_tx_power;
- /*
- * survey_list - Linked list of surveys
+ /**
+ * survey_list - Linked list of surveys (struct freq_survey)
*/
struct dl_list survey_list;
@@ -102,7 +110,9 @@
long double interference_factor;
#endif /* CONFIG_ACS */
- /* DFS CAC time in milliseconds */
+ /**
+ * dfs_cac_ms - DFS CAC time in milliseconds
+ */
unsigned int dfs_cac_ms;
};
@@ -170,10 +180,12 @@
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
#define IEEE80211_MODE_AP 2
+#define IEEE80211_MODE_MESH 5
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
+#define IEEE80211_CAP_RRM 0x1000
/* DMG (60 GHz) IEEE 802.11ad */
/* type - bits 0..1 */
@@ -213,6 +225,11 @@
* constructed of the IEs that are available. This field will also need to
* include SSID in IE format. All drivers are encouraged to be extended to
* report all IEs to make it easier to support future additions.
+ *
+ * This structure data is 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.
*/
struct wpa_scan_res {
unsigned int flags;
@@ -227,13 +244,7 @@
unsigned int age;
size_t ie_len;
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.
- */
+ /* Followed by ie_len + beacon_ie_len octets of IE data */
};
/**
@@ -370,6 +381,27 @@
*/
unsigned int low_priority:1;
+ /**
+ * mac_addr_rand - Requests driver to randomize MAC address
+ */
+ unsigned int mac_addr_rand:1;
+
+ /**
+ * mac_addr - MAC address used with randomization. The address cannot be
+ * a multicast one, i.e., bit 0 of byte 0 should not be set.
+ */
+ const u8 *mac_addr;
+
+ /**
+ * mac_addr_mask - MAC address mask used with randomization.
+ *
+ * Bits that are 0 in the mask should be randomized. Bits that are 1 in
+ * the mask should be taken as is from mac_addr. The mask should not
+ * allow the generation of a multicast address, i.e., bit 0 of byte 0
+ * must be set.
+ */
+ const u8 *mac_addr_mask;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -399,34 +431,95 @@
*/
int p2p;
+ /**
+ * sae_data - SAE elements for Authentication frame
+ *
+ * This buffer starts with the Authentication transaction sequence
+ * number field. If SAE is not used, this pointer is %NULL.
+ */
const u8 *sae_data;
+
+ /**
+ * sae_data_len - Length of sae_data buffer in octets
+ */
size_t sae_data_len;
-
};
+/**
+ * enum wps_mode - WPS mode
+ */
enum wps_mode {
- WPS_MODE_NONE /* no WPS provisioning being used */,
- WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
- WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
- */
+ /**
+ * WPS_MODE_NONE - No WPS provisioning being used
+ */
+ WPS_MODE_NONE,
+
+ /**
+ * WPS_MODE_OPEN - WPS provisioning with AP that is in open mode
+ */
+ WPS_MODE_OPEN,
+
+ /**
+ * WPS_MODE_PRIVACY - WPS provisioning with AP that is using protection
+ */
+ WPS_MODE_PRIVACY
};
+/**
+ * struct hostapd_freq_params - Channel parameters
+ */
struct hostapd_freq_params {
- int mode;
- int freq;
- int channel;
- /* for HT */
- int ht_enabled;
- int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
- * secondary channel below primary, 1 = HT40
- * enabled, secondary channel above primary */
+ /**
+ * mode - Mode/band (HOSTAPD_MODE_IEEE80211A, ..)
+ */
+ enum hostapd_hw_mode mode;
- /* for VHT */
+ /**
+ * freq - Primary channel center frequency in MHz
+ */
+ int freq;
+
+ /**
+ * channel - Channel number
+ */
+ int channel;
+
+ /**
+ * ht_enabled - Whether HT is enabled
+ */
+ int ht_enabled;
+
+ /**
+ * sec_channel_offset - Secondary channel offset for HT40
+ *
+ * 0 = HT40 disabled,
+ * -1 = HT40 enabled, secondary channel below primary,
+ * 1 = HT40 enabled, secondary channel above primary
+ */
+ int sec_channel_offset;
+
+ /**
+ * vht_enabled - Whether VHT is enabled
+ */
int vht_enabled;
- /* valid for both HT and VHT, center_freq2 is non-zero
- * only for bandwidth 80 and an 80+80 channel */
- int center_freq1, center_freq2;
+ /**
+ * center_freq1 - Segment 0 center frequency in MHz
+ *
+ * Valid for both HT and VHT.
+ */
+ int center_freq1;
+
+ /**
+ * center_freq2 - Segment 1 center frequency in MHz
+ *
+ * Non-zero only for bandwidth 80 and an 80+80 channel
+ */
+ int center_freq2;
+
+ /**
+ * bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
+ */
int bandwidth;
};
@@ -680,12 +773,21 @@
int disable_ht;
/**
- * HT Capabilities over-rides. Only bits set in the mask will be used,
- * and not all values are used by the kernel anyway. Currently, MCS,
- * MPDU and MSDU fields are used.
+ * htcaps - HT Capabilities over-rides
+ *
+ * Only bits set in the mask will be used, and not all values are used
+ * by the kernel anyway. Currently, MCS, MPDU and MSDU fields are used.
+ *
+ * Pointer to struct ieee80211_ht_capabilities.
*/
- const u8 *htcaps; /* struct ieee80211_ht_capabilities * */
- const u8 *htcaps_mask; /* struct ieee80211_ht_capabilities * */
+ const u8 *htcaps;
+
+ /**
+ * htcaps_mask - HT Capabilities over-rides mask
+ *
+ * Pointer to struct ieee80211_ht_capabilities.
+ */
+ const u8 *htcaps_mask;
#ifdef CONFIG_VHT_OVERRIDES
/**
@@ -699,6 +801,20 @@
const struct ieee80211_vht_capabilities *vhtcaps;
const struct ieee80211_vht_capabilities *vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+
+ /**
+ * req_key_mgmt_offload - Request key management offload for connection
+ *
+ * Request key management offload for this connection if the device
+ * supports it.
+ */
+ int req_key_mgmt_offload;
+
+ /**
+ * Flag for indicating whether this association includes support for
+ * RRM (Radio Resource Measurements)
+ */
+ int rrm_used;
};
enum hide_ssid {
@@ -895,6 +1011,14 @@
int ap_max_inactivity;
/**
+ * smps_mode - SMPS mode
+ *
+ * SMPS mode to be used by the AP, specified as the relevant bits of
+ * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
+ */
+ unsigned int smps_mode;
+
+ /**
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
@@ -910,6 +1034,33 @@
struct hostapd_freq_params *freq;
};
+struct wpa_driver_mesh_bss_params {
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+ /*
+ * TODO: Other mesh configuration parameters would go here.
+ * See NL80211_MESHCONF_* for all the mesh config parameters.
+ */
+ unsigned int flags;
+};
+
+struct wpa_driver_mesh_join_params {
+ const u8 *meshid;
+ int meshid_len;
+ const int *basic_rates;
+ const u8 *ies;
+ int ie_len;
+ int freq;
+ int beacon_int;
+ int max_peer_links;
+ enum ht_mode ht_mode;
+ struct wpa_driver_mesh_bss_params conf;
+#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
+#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
+#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
+#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
+ unsigned int flags;
+};
+
/**
* struct wpa_driver_capa - Driver capability information
*/
@@ -922,6 +1073,7 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FT 0x00000020
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK 0x00000040
#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK 0x00000080
+ /** Bitfield of supported key management suites */
unsigned int key_mgmt;
#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
@@ -937,94 +1089,121 @@
#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256 0x00000400
#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256 0x00000800
#define WPA_DRIVER_CAPA_ENC_GTK_NOT_USED 0x00001000
+ /** Bitfield of supported cipher suites */
unsigned int enc;
#define WPA_DRIVER_AUTH_OPEN 0x00000001
#define WPA_DRIVER_AUTH_SHARED 0x00000002
#define WPA_DRIVER_AUTH_LEAP 0x00000004
+ /** Bitfield of supported IEEE 802.11 authentication algorithms */
unsigned int auth;
-/* Driver generated WPA/RSN IE */
+/** Driver generated WPA/RSN IE */
#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
-/* Driver needs static WEP key setup after association command */
+/** Driver needs static WEP key setup after association command */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-/* Driver takes care of all DFS operations */
+/** Driver takes care of all DFS operations */
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
-/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+/** 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
+/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
-/* Driver provides separate commands for authentication and association (SME in
+/** Driver provides separate commands for authentication and association (SME in
* wpa_supplicant). */
#define WPA_DRIVER_FLAGS_SME 0x00000020
-/* Driver supports AP mode */
+/** Driver supports AP mode */
#define WPA_DRIVER_FLAGS_AP 0x00000040
-/* Driver needs static WEP key setup after association has been completed */
+/** Driver needs static WEP key setup after association has been completed */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080
-/* Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+/** Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
#define WPA_DRIVER_FLAGS_HT_2040_COEX 0x00000100
-/* Driver supports concurrent P2P operations */
+/** Driver supports concurrent P2P operations */
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200
-/*
+/**
* Driver uses the initial interface as a dedicated management interface, i.e.,
* it cannot be used for P2P group operations or non-P2P purposes.
*/
#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400
-/* This interface is P2P capable (P2P GO or P2P Client) */
+/** This interface is P2P capable (P2P GO or P2P Client) */
#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800
-/* Driver supports station and key removal when stopping an AP */
+/** Driver supports station and key removal when stopping an AP */
#define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT 0x00001000
-/*
+/**
* Driver uses the initial interface for P2P management interface and non-P2P
* purposes (e.g., connect to infra AP), but this interface cannot be used for
* P2P group operations.
*/
#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000
-/*
+/**
* Driver is known to use sane error codes, i.e., when it indicates that
* something (e.g., association) fails, there was indeed a failure and the
* operation does not end up getting completed successfully later.
*/
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
-/* Driver supports off-channel TX */
+/** Driver supports off-channel TX */
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
-/* Driver indicates TX status events for EAPOL Data frames */
+/** Driver indicates TX status events for EAPOL Data frames */
#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000
-/* Driver indicates TX status events for Deauth/Disassoc frames */
+/** Driver indicates TX status events for Deauth/Disassoc frames */
#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000
-/* Driver supports roaming (BSS selection) in firmware */
+/** Driver supports roaming (BSS selection) in firmware */
#define WPA_DRIVER_FLAGS_BSS_SELECTION 0x00040000
-/* Driver supports operating as a TDLS peer */
+/** Driver supports operating as a TDLS peer */
#define WPA_DRIVER_FLAGS_TDLS_SUPPORT 0x00080000
-/* Driver requires external TDLS setup/teardown/discovery */
+/** Driver requires external TDLS setup/teardown/discovery */
#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP 0x00100000
-/* Driver indicates support for Probe Response offloading in AP mode */
+/** Driver indicates support for Probe Response offloading in AP mode */
#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000
-/* Driver supports U-APSD in AP mode */
+/** Driver supports U-APSD in AP mode */
#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
-/* Driver supports inactivity timer in AP mode */
+/** Driver supports inactivity timer in AP mode */
#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
-/* Driver expects user space implementation of MLME in AP mode */
+/** Driver expects user space implementation of MLME in AP mode */
#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000
-/* Driver supports SAE with user space SME */
+/** Driver supports SAE with user space SME */
#define WPA_DRIVER_FLAGS_SAE 0x02000000
-/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+/** Driver makes use of OBSS scan mechanism in wpa_supplicant */
#define WPA_DRIVER_FLAGS_OBSS_SCAN 0x04000000
-/* Driver supports IBSS (Ad-hoc) mode */
+/** Driver supports IBSS (Ad-hoc) mode */
#define WPA_DRIVER_FLAGS_IBSS 0x08000000
-/* Driver supports radar detection */
+/** Driver supports radar detection */
#define WPA_DRIVER_FLAGS_RADAR 0x10000000
-/* Driver supports a dedicated interface for P2P Device */
+/** Driver supports a dedicated interface for P2P Device */
#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE 0x20000000
-/* Driver supports QoS Mapping */
+/** Driver supports QoS Mapping */
#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000
-/* Driver supports CSA in AP mode */
+/** Driver supports CSA in AP mode */
#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000
- unsigned int flags;
+/** Driver supports mesh */
+#define WPA_DRIVER_FLAGS_MESH 0x0000000100000000ULL
+/** Driver support ACS offload */
+#define WPA_DRIVER_FLAGS_ACS_OFFLOAD 0x0000000200000000ULL
+/** Driver supports key management offload */
+#define WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD 0x0000000400000000ULL
+/** Driver supports TDLS channel switching */
+#define WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH 0x0000000800000000ULL
+ u64 flags;
+#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
+#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
+ unsigned int smps_modes;
+
+ unsigned int wmm_ac_supported:1;
+
+ unsigned int mac_addr_rand_scan_supported:1;
+ unsigned int mac_addr_rand_sched_scan_supported:1;
+
+ /** Maximum number of supported active probe SSIDs */
int max_scan_ssids;
+
+ /** Maximum number of supported active probe SSIDs for sched_scan */
int max_sched_scan_ssids;
+
+ /** Whether sched_scan (offloaded scanning) is supported */
int sched_scan_supported;
+
+ /** Maximum number of supported match sets for sched_scan */
int max_match_sets;
/**
@@ -1042,13 +1221,13 @@
* probe_resp_offloads - Bitmap of supported protocols by the driver
* for Probe Response offloading.
*/
-/* Driver Probe Response offloading support for WPS ver. 1 */
+/** Driver Probe Response offloading support for WPS ver. 1 */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS 0x00000001
-/* Driver Probe Response offloading support for WPS ver. 2 */
+/** Driver Probe Response offloading support for WPS ver. 2 */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2 0x00000002
-/* Driver Probe Response offloading support for P2P */
+/** Driver Probe Response offloading support for P2P */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P 0x00000004
-/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+/** Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads;
@@ -1069,6 +1248,24 @@
unsigned int extended_capa_len;
struct wowlan_triggers wowlan_triggers;
+
+/** Driver adds the DS Params Set IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES 0x00000001
+/** Driver adds the WFA TPC IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES 0x00000002
+/** Driver handles quiet period requests */
+#define WPA_DRIVER_FLAGS_QUIET 0x00000004
+/**
+ * Driver is capable of inserting the current TX power value into the body of
+ * transmitted frames.
+ * Background: Some Action frames include a TPC Report IE. This IE contains a
+ * TX power field, which has to be updated by lower layers. One such Action
+ * frame is Link Measurement Report (part of RRM). Another is TPC Report (part
+ * of spectrum management). Note that this insertion takes place at a fixed
+ * offset, namely the 6th byte in the Action frame body.
+ */
+#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
+ u32 rrm_flags;
};
@@ -1098,6 +1295,10 @@
int vht_opmode_enabled;
u8 vht_opmode;
u32 flags; /* bitmask of WPA_STA_* flags */
+ u32 flags_mask; /* unset bits in flags */
+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
const u8 *ext_capab;
@@ -1159,16 +1360,19 @@
* WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
* abstracted P2P Device function in the driver
*/
- WPA_IF_P2P_DEVICE
+ WPA_IF_P2P_DEVICE,
+
+ /*
+ * WPA_IF_MESH - Mesh interface
+ */
+ WPA_IF_MESH,
};
struct wpa_init_params {
void *global_priv;
const u8 *bssid;
const char *ifname;
- const u8 *ssid;
- size_t ssid_len;
- const char *test_socket;
+ const char *driver_params;
int use_pae_group_addr;
char **bridge;
size_t num_bridge;
@@ -1197,6 +1401,7 @@
#define WPA_STA_SHORT_PREAMBLE BIT(2)
#define WPA_STA_MFP BIT(3)
#define WPA_STA_TDLS_PEER BIT(4)
+#define WPA_STA_AUTHENTICATED BIT(5)
enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -1311,6 +1516,23 @@
TDLS_PEER_WMM = BIT(2),
};
+/* valid info in the wmm_params struct */
+enum wmm_params_valid_info {
+ WMM_PARAMS_UAPSD_QUEUES_INFO = BIT(0),
+};
+
+/**
+ * struct wmm_params - WMM parameterss configured for this association
+ * @info_bitmap: Bitmap of valid wmm_params info; indicates what fields
+ * of the struct contain valid information.
+ * @uapsd_queues: Bitmap of ACs configured for uapsd (valid only if
+ * %WMM_PARAMS_UAPSD_QUEUES_INFO is set)
+ */
+struct wmm_params {
+ u8 info_bitmap;
+ u8 uapsd_queues;
+};
+
#ifdef CONFIG_MACSEC
struct macsec_init_params {
Boolean always_include_sci;
@@ -1319,6 +1541,26 @@
};
#endif /* CONFIG_MACSEC */
+enum drv_br_port_attr {
+ DRV_BR_PORT_ATTR_PROXYARP,
+ DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+};
+
+enum drv_br_net_param {
+ DRV_BR_NET_PARAM_GARP_ACCEPT,
+};
+
+struct drv_acs_params {
+ /* Selected mode (HOSTAPD_MODE_*) */
+ enum hostapd_hw_mode hw_mode;
+
+ /* Indicates whether HT is enabled */
+ int ht_enabled;
+
+ /* Indicates whether HT40 is enabled */
+ int ht40_enabled;
+};
+
/**
* struct wpa_driver_ops - Driver interface API definition
@@ -1605,27 +1847,6 @@
const u8 * (*get_mac_addr)(void *priv);
/**
- * send_eapol - Optional function for sending EAPOL packets
- * @priv: private driver interface data
- * @dest: Destination MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Size of the EAPOL packet
- *
- * Returns: 0 on success, -1 on failure
- *
- * This optional function can be used to override l2_packet operations
- * 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 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);
-
- /**
* set_operstate - Sets device operating state to DORMANT or UP
* @priv: private driver interface data
* @state: 0 = dormant, 1 = up
@@ -1700,22 +1921,6 @@
size_t ies_len);
/**
- * send_ft_action - Send FT Action frame (IEEE 802.11r)
- * @priv: Private driver interface data
- * @action: Action field value
- * @target_ap: Target AP address
- * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
- * @ies_len: Length of FT IEs in bytes
- * Returns: 0 on success, -1 on failure
- *
- * The supplicant uses this callback to request the driver to transmit
- * an FT Action frame (action category 6) for over-the-DS fast BSS
- * transition.
- */
- int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
- const u8 *ies, size_t ies_len);
-
- /**
* get_scan_results2 - Fetch the latest scan results
* @priv: private driver interface data
*
@@ -2547,6 +2752,45 @@
u8 qos_map_set_len);
/**
+ * br_add_ip_neigh - Add a neigh to the bridge ip neigh table
+ * @priv: Private driver interface data
+ * @version: IP version of the IP address, 4 or 6
+ * @ipaddr: IP address for the neigh entry
+ * @prefixlen: IP address prefix length
+ * @addr: Corresponding MAC address
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_add_ip_neigh)(void *priv, u8 version, const u8 *ipaddr,
+ int prefixlen, const u8 *addr);
+
+ /**
+ * br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table
+ * @priv: Private driver interface data
+ * @version: IP version of the IP address, 4 or 6
+ * @ipaddr: IP address for the neigh entry
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_delete_ip_neigh)(void *priv, u8 version, const u8 *ipaddr);
+
+ /**
+ * br_port_set_attr - Set a bridge port attribute
+ * @attr: Bridge port attribute to set
+ * @val: Value to be set
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_port_set_attr)(void *priv, enum drv_br_port_attr attr,
+ unsigned int val);
+
+ /**
+ * br_port_set_attr - Set a bridge network parameter
+ * @param: Bridge parameter to set
+ * @val: Value to be set
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_set_net_param)(void *priv, enum drv_br_net_param param,
+ unsigned int val);
+
+ /**
* set_wowlan - Set wake-on-wireless triggers
* @priv: Private driver interface data
* @triggers: wowlan triggers
@@ -2751,6 +2995,55 @@
int (*switch_channel)(void *priv, struct csa_settings *settings);
/**
+ * add_tx_ts - Add traffic stream
+ * @priv: Private driver interface data
+ * @tsid: Traffic stream ID
+ * @addr: Receiver address
+ * @user_prio: User priority of the traffic stream
+ * @admitted_time: Admitted time for this TS in units of
+ * 32 microsecond periods (per second).
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*add_tx_ts)(void *priv, u8 tsid, const u8 *addr, u8 user_prio,
+ u16 admitted_time);
+
+ /**
+ * del_tx_ts - Delete traffic stream
+ * @priv: Private driver interface data
+ * @tsid: Traffic stream ID
+ * @addr: Receiver address
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*del_tx_ts)(void *priv, u8 tsid, const u8 *addr);
+
+ /**
+ * Enable channel-switching with TDLS peer
+ * @priv: Private driver interface data
+ * @addr: MAC address of the TDLS peer
+ * @oper_class: Operating class of the switch channel
+ * @params: Channel specification
+ * Returns: 0 on success, -1 on failure
+ *
+ * The function indicates to driver that it can start switching to a
+ * different channel with a specified TDLS peer. The switching is
+ * assumed on until canceled with tdls_disable_channel_switch().
+ */
+ int (*tdls_enable_channel_switch)(
+ void *priv, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+
+ /**
+ * Disable channel switching with TDLS peer
+ * @priv: Private driver interface data
+ * @addr: MAC address of the TDLS peer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function indicates to the driver that it should stop switching
+ * with a given TDLS peer.
+ */
+ int (*tdls_disable_channel_switch)(void *priv, const u8 *addr);
+
+ /**
* start_dfs_cac - Listen for radar interference on the channel
* @priv: Private driver interface data
* @freq: Channel parameters
@@ -3023,6 +3316,40 @@
*/
int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
#endif /* CONFIG_MACSEC */
+
+ /**
+ * init_mesh - Driver specific initialization for mesh
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*init_mesh)(void *priv);
+
+ /**
+ * join_mesh - Join a mesh network
+ * @priv: Private driver interface data
+ * @params: Mesh configuration parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*join_mesh)(void *priv,
+ struct wpa_driver_mesh_join_params *params);
+
+ /**
+ * leave_mesh - Leave a mesh network
+ * @priv: Private driver interface data
+ * Returns 0 on success, -1 on failure
+ */
+ int (*leave_mesh)(void *priv);
+
+ /**
+ * do_acs - Automatically select channel
+ * @priv: Private driver interface data
+ * @params: Parameters for ACS
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to offload ACS to the driver if the driver
+ * indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
+ */
+ int (*do_acs)(void *priv, struct drv_acs_params *params);
};
@@ -3211,11 +3538,6 @@
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,
@@ -3255,13 +3577,6 @@
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
@@ -3289,9 +3604,7 @@
* 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.
+ * deliver the receive EAPOL frames from the driver.
*/
EVENT_EAPOL_RX,
@@ -3498,7 +3811,20 @@
* to reduce issues due to interference or internal co-existence
* information in the driver.
*/
- EVENT_AVOID_FREQUENCIES
+ EVENT_AVOID_FREQUENCIES,
+
+ /**
+ * EVENT_NEW_PEER_CANDIDATE - new (unknown) mesh peer notification
+ */
+ EVENT_NEW_PEER_CANDIDATE,
+
+ /**
+ * EVENT_ACS_CHANNEL_SELECTED - Received selected channels by ACS
+ *
+ * Indicates a pair of primary and secondary channels chosen by ACS
+ * in device.
+ */
+ EVENT_ACS_CHANNEL_SELECTED,
};
@@ -3618,9 +3944,62 @@
unsigned int freq;
/**
+ * wmm_params - WMM parameters used in this association.
+ */
+ struct wmm_params wmm_params;
+
+ /**
* addr - Station address (for AP mode)
*/
const u8 *addr;
+
+ /**
+ * The following is the key management offload information
+ * @authorized
+ * @key_replay_ctr
+ * @key_replay_ctr_len
+ * @ptk_kck
+ * @ptk_kek_len
+ * @ptk_kek
+ * @ptk_kek_len
+ */
+
+ /**
+ * authorized - Status of key management offload,
+ * 1 = successful
+ */
+ int authorized;
+
+ /**
+ * key_replay_ctr - Key replay counter value last used
+ * in a valid EAPOL-Key frame
+ */
+ const u8 *key_replay_ctr;
+
+ /**
+ * key_replay_ctr_len - The length of key_replay_ctr
+ */
+ size_t key_replay_ctr_len;
+
+ /**
+ * ptk_kck - The derived PTK KCK
+ */
+ const u8 *ptk_kck;
+
+ /**
+ * ptk_kek_len - The length of ptk_kck
+ */
+ size_t ptk_kck_len;
+
+ /**
+ * ptk_kek - The derived PTK KEK
+ */
+ const u8 *ptk_kek;
+
+ /**
+ * ptk_kek_len - The length of ptk_kek
+ */
+ size_t ptk_kek_len;
} assoc_info;
/**
@@ -3830,15 +4209,6 @@
} 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 {
@@ -3922,17 +4292,6 @@
} 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 {
@@ -4112,7 +4471,7 @@
* survey_results - Survey result data for EVENT_SURVEY
* @freq_filter: Requested frequency survey filter, 0 if request
* was for all survey data
- * @survey_list: Linked list of survey data
+ * @survey_list: Linked list of survey data (struct freq_survey)
*/
struct survey_results {
unsigned int freq_filter;
@@ -4137,6 +4496,31 @@
* This is used as the data with EVENT_AVOID_FREQUENCIES.
*/
struct wpa_freq_range_list freq_range;
+
+ /**
+ * struct mesh_peer
+ *
+ * @peer: Peer address
+ * @ies: Beacon IEs
+ * @ie_len: Length of @ies
+ *
+ * Notification of new candidate mesh peer.
+ */
+ struct mesh_peer {
+ const u8 *peer;
+ const u8 *ies;
+ size_t ie_len;
+ } mesh_peer;
+
+ /**
+ * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
+ * @pri_channel: Selected primary channel
+ * @sec_channel: Selected secondary channel
+ */
+ struct acs_selected_channels {
+ u8 pri_channel;
+ u8 sec_channel;
+ } acs_selected_channels;
};
/**
@@ -4198,6 +4582,13 @@
/* Convert chan_width to a string for logging and control interfaces */
const char * channel_width_to_string(enum chan_width width);
+int ht_supported(const struct hostapd_hw_modes *mode);
+int vht_supported(const struct hostapd_hw_modes *mode);
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+ const struct wpa_driver_capa *capa);
+
/* NULL terminated array of linked in driver wrappers */
extern struct wpa_driver_ops *wpa_drivers[];
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index b569a0a..350d505 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -224,10 +224,10 @@
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);
+ wpa_printf(MSG_INFO,
+ "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s",
+ __func__, drv->iface, op, athr_get_param_name(op),
+ arg, strerror(errno));
return -1;
}
return 0;
@@ -290,14 +290,15 @@
}
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);
+ wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", 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);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key length to %u", v);
return -1;
}
}
@@ -319,7 +320,8 @@
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);
+ wpa_printf(MSG_INFO,
+ "Unable to set pairwise key ciphers to 0x%x", v);
return -1;
}
@@ -327,8 +329,9 @@
__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);
+ wpa_printf(MSG_INFO,
+ "Unable to set key management algorithms to 0x%x",
+ params->wpa_key_mgmt);
return -1;
}
@@ -345,13 +348,14 @@
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
- printf("Unable to set RSN capabilities to 0x%x\n", v);
+ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+ 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);
+ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
return -1;
}
return 0;
@@ -518,14 +522,14 @@
#endif /* ATH_GCM_SUPPORT */
#endif /* CONFIG_IEEE80211W */
default:
- printf("%s: unknown/unsupported algorithm %d\n",
- __func__, alg);
+ wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
+ __func__, alg);
return -1;
}
if (key_len > sizeof(wk.ik_keydata)) {
- printf("%s: key length %lu too big\n", __func__,
- (unsigned long) key_len);
+ wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__,
+ (unsigned long) key_len);
return -3;
}
@@ -636,7 +640,8 @@
return 0;
}
- printf("Failed to get station stats information element.\n");
+ wpa_printf(MSG_INFO,
+ "Failed to get station stats information element");
return -1;
}
@@ -769,145 +774,6 @@
return ret;
}
-#ifdef CONFIG_WPS
-static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct atheros_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.da = mgmt->da;
- event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
- wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_IEEE80211R
-static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct atheros_driver_data *drv = ctx;
- union wpa_event_data event;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- u16 stype;
- int ielen;
- const u8 *iebuf;
-
- /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
- if (len < IEEE80211_HDRLEN)
- return;
- mgmt = (const struct ieee80211_mgmt *) buf;
-
- fc = le_to_host16(mgmt->frame_control);
-
- if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
- return;
- stype = WLAN_FC_GET_STYPE(fc);
-
- wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
- (int) len);
-
- if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
- __func__);
- return;
- }
- switch (stype) {
- case WLAN_FC_STYPE_ASSOC_REQ:
- if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
- break;
- ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
- iebuf = mgmt->u.assoc_req.variable;
- drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
- break;
- case WLAN_FC_STYPE_REASSOC_REQ:
- if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
- break;
- ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
- iebuf = mgmt->u.reassoc_req.variable;
- drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
- break;
- case WLAN_FC_STYPE_ACTION:
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = buf;
- event.rx_mgmt.frame_len = len;
- wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
- break;
- case WLAN_FC_STYPE_AUTH:
- if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
- break;
- os_memset(&event, 0, sizeof(event));
- os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
- os_memcpy(event.auth.bssid, mgmt->bssid, 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);
- event.auth.auth_transaction =
- le_to_host16(mgmt->u.auth.auth_transaction);
- event.auth.ies = mgmt->u.auth.variable;
- event.auth.ies_len = len - IEEE80211_HDRLEN -
- sizeof(mgmt->u.auth);
- wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
- break;
- default:
- break;
- }
-}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_HS20
-static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct atheros_driver_data *drv = ctx;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- union wpa_event_data event;
-
- /* Send the Action frame for HS20 processing */
-
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
- sizeof(mgmt->u.action.u.public_action))
- 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_ACTION ||
- mgmt->u.action.category != WLAN_ACTION_PUBLIC)
- return;
-
- wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
-
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = (const u8 *) mgmt;
- event.rx_mgmt.frame_len = len;
- wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-}
-
-#endif /* CONFIG_HS20 */
-
-
static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
u8 qos_map_set_len)
{
@@ -947,9 +813,9 @@
}
if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
- perror("ioctl[IEEE80211_IOCTL_DBGREQ]");
- wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map",
- __func__, drv->iface);
+ wpa_printf(MSG_ERROR,
+ "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s",
+ __func__, drv->iface, strerror(errno));
return -1;
}
#endif /* CONFIG_ATHEROS_QOS_MAP */
@@ -957,30 +823,47 @@
return 0;
}
-#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
-static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) || defined(CONFIG_HS20)
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct atheros_driver_data *drv = ctx;
- union wpa_event_data event;
const struct ieee80211_mgmt *mgmt;
- u16 fc;
- u16 stype;
+ union wpa_event_data event;
+ u16 fc, stype;
+ int ielen;
+ const u8 *iebuf;
- /* Do 11R processing for WNM ACTION frames */
if (len < IEEE80211_HDRLEN)
return;
+
mgmt = (const struct ieee80211_mgmt *) buf;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
return;
+
stype = WLAN_FC_GET_STYPE(fc);
wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
(int) len);
+ if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.da = mgmt->da;
+ event.rx_probe_req.bssid = mgmt->bssid;
+ event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+ event.rx_probe_req.ie_len =
+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+ return;
+ }
+
if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
__func__);
@@ -988,36 +871,47 @@
}
switch (stype) {
+ case WLAN_FC_STYPE_ASSOC_REQ:
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req))
+ break;
+ ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+ iebuf = mgmt->u.assoc_req.variable;
+ drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
+ break;
+ case WLAN_FC_STYPE_REASSOC_REQ:
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req))
+ break;
+ ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+ iebuf = mgmt->u.reassoc_req.variable;
+ drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
+ break;
case WLAN_FC_STYPE_ACTION:
os_memset(&event, 0, sizeof(event));
event.rx_mgmt.frame = buf;
event.rx_mgmt.frame_len = len;
wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
break;
+ case WLAN_FC_STYPE_AUTH:
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
+ break;
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ os_memcpy(event.auth.bssid, mgmt->bssid, 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);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - IEEE80211_HDRLEN -
+ sizeof(mgmt->u.auth);
+ wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
+ break;
default:
break;
}
}
-#endif /* CONFIG_WNM */
-
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM)
-static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
-#ifdef CONFIG_WPS
- atheros_raw_recv_wps(ctx, src_addr, buf, len);
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
- atheros_raw_recv_11r(ctx, src_addr, buf, len);
-#endif /* CONFIG_IEEE80211R */
-#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
- atheros_raw_recv_11v(ctx, src_addr, buf, len);
-#endif /* CONFIG_WNM */
-#ifdef CONFIG_HS20
- atheros_raw_recv_hs20(ctx, src_addr, buf, len);
-#endif /* CONFIG_HS20 */
-}
-#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+#endif
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -1606,8 +1500,9 @@
sizeof(range->enc_capa);
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
- free(range);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
+ os_free(range);
return -1;
} else if (iwr.u.data.length >= minlen &&
range->we_version_compiled >= 18) {
@@ -1667,8 +1562,9 @@
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);
+ wpa_printf(MSG_INFO,
+ "EAPOL frame discarded, cannot malloc temp buffer of size %lu!",
+ (unsigned long) len);
return -1;
}
}
@@ -1705,14 +1601,16 @@
drv = os_zalloc(sizeof(struct atheros_driver_data));
if (drv == NULL) {
- printf("Could not allocate memory for atheros driver data\n");
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for atheros driver data");
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]");
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
goto bad;
}
memcpy(drv->iface, params->ifname, sizeof(drv->iface));
@@ -1720,7 +1618,8 @@
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)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
goto bad;
}
drv->ifindex = ifr.ifr_ifindex;
@@ -1756,8 +1655,9 @@
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");
+ wpa_printf(MSG_ERROR,
+ "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
goto bad;
}
@@ -1823,8 +1723,8 @@
iwr.u.essid.length = len + 1;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
- printf("len=%d\n", len);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
+ len, strerror(errno));
return -1;
}
return 0;
@@ -1844,7 +1744,8 @@
IW_ESSID_MAX_SIZE : len;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+ strerror(errno));
ret = -1;
} else
ret = iwr.u.essid.length;
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index ca64d5c..c377970 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -264,7 +264,8 @@
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
return -1;
}
@@ -279,7 +280,8 @@
}
if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
return -1;
}
@@ -404,22 +406,24 @@
v = IEEE80211_CIPHER_NONE;
break;
default:
- printf("Unknown group key cipher %u\n",
- params->wpa_group);
+ wpa_printf(MSG_INFO, "Unknown group key cipher %u",
+ 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]);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key cipher to %u (%s)",
+ 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);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key length to %u", v);
return -1;
}
}
@@ -433,7 +437,8 @@
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);
+ wpa_printf(MSG_INFO,
+ "Unable to set pairwise key ciphers to 0x%x", v);
return -1;
}
@@ -441,8 +446,9 @@
__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);
+ wpa_printf(MSG_INFO,
+ "Unable to set key management algorithms to 0x%x",
+ params->wpa_key_mgmt);
return -1;
}
@@ -452,14 +458,15 @@
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);
+ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+ 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);
+ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
return -1;
}
return 0;
@@ -507,7 +514,8 @@
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");
+ wpa_printf(MSG_INFO,
+ "Failed to get WPA/RSN information element");
goto no_ie;
}
iebuf = ie.wpa_ie;
@@ -594,7 +602,7 @@
int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
+ wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
strerror(errno));
len = 2048;
}
@@ -652,7 +660,7 @@
wk.ik_keyix = idx;
if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
- printf("Failed to get encryption.\n");
+ wpa_printf(MSG_INFO, "Failed to get encryption");
return -1;
}
@@ -734,7 +742,7 @@
n = read(sock, drv->event_buf, drv->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
return;
}
@@ -814,7 +822,8 @@
drv->hapd = hapd;
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
goto bad;
}
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -832,7 +841,8 @@
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
if (drv->route < 0) {
- perror("socket(PF_ROUTE,SOCK_RAW)");
+ wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
+ strerror(errno));
goto bad;
}
eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
@@ -1189,7 +1199,7 @@
n = read(sock, drv->event_buf, drv->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
return;
}
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 77e6905..f897c11 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -44,14 +44,12 @@
E2S(ASSOC_REJECT);
E2S(AUTH_TIMED_OUT);
E2S(ASSOC_TIMED_OUT);
- E2S(FT_RRB_RX);
E2S(WPS_BUTTON_PUSHED);
E2S(TX_STATUS);
E2S(RX_FROM_UNKNOWN);
E2S(RX_MGMT);
E2S(REMAIN_ON_CHANNEL);
E2S(CANCEL_REMAIN_ON_CHANNEL);
- E2S(MLME_RX);
E2S(RX_PROBE_REQ);
E2S(NEW_STA);
E2S(EAPOL_RX);
@@ -79,6 +77,8 @@
E2S(SURVEY);
E2S(SCAN_STARTED);
E2S(AVOID_FREQUENCIES);
+ E2S(NEW_PEER_CANDIDATE);
+ E2S(ACS_CHANNEL_SELECTED);
}
return "UNKNOWN";
@@ -105,3 +105,115 @@
return "unknown";
}
}
+
+
+int ht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports HT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * IEEE Std 802.11n-2009 20.1.1:
+ * An HT non-AP STA shall support all EQM rates for one spatial stream.
+ */
+ return mode->mcs_set[0] == 0xff;
+}
+
+
+int vht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports VHT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
+ * TODO: Verify if this complies with the standard
+ */
+ return (mode->vht_mcs_set[0] & 0x3) != 3;
+}
+
+
+static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
+ int capa_trigger, u8 *param_trigger)
+{
+ if (os_strcmp(start, trigger) != 0)
+ return 0;
+ if (!capa_trigger)
+ return 0;
+
+ *param_trigger = 1;
+ return 1;
+}
+
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+ const struct wpa_driver_capa *capa)
+{
+ struct wowlan_triggers *triggers;
+ char *start, *end, *buf;
+ int last;
+
+ if (!wowlan_triggers)
+ return NULL;
+
+ buf = os_strdup(wowlan_triggers);
+ if (buf == NULL)
+ return NULL;
+
+ triggers = os_zalloc(sizeof(*triggers));
+ if (triggers == NULL)
+ goto out;
+
+#define CHECK_TRIGGER(trigger) \
+ wpa_check_wowlan_trigger(start, #trigger, \
+ capa->wowlan_triggers.trigger, \
+ &triggers->trigger)
+
+ start = buf;
+ while (*start != '\0') {
+ while (isblank(*start))
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (!isblank(*end) && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+
+ if (!CHECK_TRIGGER(any) &&
+ !CHECK_TRIGGER(disconnect) &&
+ !CHECK_TRIGGER(magic_pkt) &&
+ !CHECK_TRIGGER(gtk_rekey_failure) &&
+ !CHECK_TRIGGER(eap_identity_req) &&
+ !CHECK_TRIGGER(four_way_handshake) &&
+ !CHECK_TRIGGER(rfkill_release)) {
+ wpa_printf(MSG_DEBUG,
+ "Unknown/unsupported wowlan trigger '%s'",
+ start);
+ os_free(triggers);
+ triggers = NULL;
+ goto out;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+#undef CHECK_TRIGGER
+
+out:
+ os_free(buf);
+ return triggers;
+}
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 16f5563..84b98fb 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -214,7 +214,7 @@
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -229,19 +229,21 @@
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (drv->sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_ERROR, "Could not register read socket");
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)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
return -1;
}
@@ -256,7 +258,7 @@
addr.sll_ifindex);
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -361,9 +363,9 @@
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");
+ wpa_printf(MSG_INFO,
+ "Setting MTU failed - trying to survive with current value: ioctl[SIOCSIFMTU]: %s",
+ strerror(errno));
}
}
@@ -383,7 +385,8 @@
iwr.u.data.length = len;
if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ wpa_printf(MSG_ERROR, "ioctl[PRISM2_IOCTL_HOSTAPD]: %s",
+ strerror(errno));
return -1;
}
@@ -497,7 +500,8 @@
*i++ = value;
if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ wpa_printf(MSG_ERROR, "ioctl[PRISM2_IOCTL_PRISM2_PARAM]: %s",
+ strerror(errno));
return -1;
}
@@ -554,8 +558,8 @@
iwr.u.essid.length = len + 1;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
- printf("len=%d\n", len);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
+ len, strerror(errno));
return -1;
}
@@ -919,8 +923,9 @@
sizeof(range->enc_capa);
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
- free(range);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
+ os_free(range);
return -1;
} else if (iwr.u.data.length >= minlen &&
range->we_version_compiled >= 18) {
@@ -975,23 +980,25 @@
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
- free(drv);
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
+ os_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);
+ wpa_printf(MSG_ERROR,
+ "Could not enable hostapd mode for interface %s",
+ drv->iface);
close(drv->ioctl_sock);
- free(drv);
+ os_free(drv);
return NULL;
}
if (hostap_init_sockets(drv, params->own_addr) ||
hostap_wireless_event_init(drv)) {
close(drv->ioctl_sock);
- free(drv);
+ os_free(drv);
return NULL;
}
@@ -1060,7 +1067,8 @@
iwr.u.freq.e = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+ strerror(errno));
return -1;
}
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index cf24799..3eae2f8 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -91,7 +91,7 @@
if (setsockopt(sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt");
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
return -1;
}
return 0;
@@ -131,14 +131,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -155,7 +156,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -163,7 +164,8 @@
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -180,14 +182,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_print(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifmr, 0, sizeof(ifmr));
os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- perror("ioctl[SIOCGIFMEDIA]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -211,7 +214,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -245,7 +248,8 @@
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -323,7 +327,7 @@
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
- perror("socket(PF_PACKET)");
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
#else /* __linux__ */
drv->pf_sock = -1;
#endif /* __linux__ */
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
deleted file mode 100644
index 1635c1f..0000000
--- a/src/drivers/driver_madwifi.c
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
- * hostapd - driver interaction with MADWIFI 802.11 driver
- * Copyright (c) 2004, Sam Leffler <sam@errno.com>
- * Copyright (c) 2004, Video54 Technologies
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- *
- * This driver wrapper is only for hostapd AP mode functionality. Station
- * (wpa_supplicant) operations with madwifi are supported by the driver_wext.c
- * wrapper.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "linux_wext.h"
-
-/*
- * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
- */
-#undef WME_OUI_TYPE
-
-#include <include/compat.h>
-#include <net80211/ieee80211.h>
-#ifdef WME_NUM_AC
-/* Assume this is built against BSD branch of madwifi driver. */
-#define MADWIFI_BSD
-#include <net80211/_ieee80211.h>
-#endif /* WME_NUM_AC */
-#include <net80211/ieee80211_crypto.h>
-#include <net80211/ieee80211_ioctl.h>
-
-#ifdef 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 */
-
-#define WPA_KEY_RSC_LEN 8
-
-#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) ARRAY_SIZE(opnames) &&
- 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) {
- wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
- return -1;
- }
- if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
- wpa_printf(MSG_WARNING, "Error configuring WPA state!");
- return -1;
- }
- if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
- (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
- wpa_printf(MSG_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 || is_broadcast_ether_addr(addr)) {
- 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.da = mgmt->da;
- event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
- 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,
- const struct wpabuf *assocresp)
-{
- 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 int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
- struct madwifi_driver_data *drv = priv;
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
- iwr.u.freq.m = freq->channel;
- iwr.u.freq.e = 0;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
- return -1;
- }
-
- return 0;
-}
-
-static void
-madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
-{
- 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, 0);
-
- 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, u32 flags)
-{
- 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);
-}
-
-
-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,
- .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,
- .set_freq = madwifi_set_freq,
-};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4c8f29f..8527e90 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -11,67 +11,35 @@
*/
#include "includes.h"
-#include <sys/ioctl.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <net/if.h>
#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#ifdef CONFIG_LIBNL3_ROUTE
#include <netlink/route/neighbour.h>
#endif /* CONFIG_LIBNL3_ROUTE */
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
-#include <linux/filter.h>
#include <linux/errqueue.h>
-#include "nl80211_copy.h"
#include "common.h"
#include "eloop.h"
-#include "utils/list.h"
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "l2_packet/l2_packet.h"
#include "netlink.h"
+#include "linux_defines.h"
#include "linux_ioctl.h"
#include "radiotap.h"
#include "radiotap_iter.h"
#include "rfkill.h"
-#include "driver.h"
+#include "driver_nl80211.h"
-#ifndef SO_WIFI_STATUS
-# if defined(__sparc__)
-# define SO_WIFI_STATUS 0x0025
-# elif defined(__parisc__)
-# define SO_WIFI_STATUS 0x4022
-# else
-# define SO_WIFI_STATUS 41
-# endif
-# define SCM_WIFI_STATUS SO_WIFI_STATUS
-#endif
-
-#ifndef SO_EE_ORIGIN_TXSTATUS
-#define SO_EE_ORIGIN_TXSTATUS 4
-#endif
-
-#ifndef PACKET_TX_TIMESTAMP
-#define PACKET_TX_TIMESTAMP 16
-#endif
-
-#ifdef ANDROID
-#include "android_drv.h"
-#endif /* ANDROID */
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#else
+#ifndef CONFIG_LIBNL20
/*
* libnl 1.1 has a bug, it tries to allocate socket numbers densely
* but when you free a socket again it will mess up its bitmap and
@@ -116,12 +84,10 @@
#ifdef ANDROID
/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
-static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
-{
- return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
-}
#undef nl_socket_set_nonblocking
#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+
+#define genl_ctrl_resolve android_genl_ctrl_resolve
#endif /* ANDROID */
@@ -181,374 +147,41 @@
}
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
-#endif
-#ifndef IFF_DORMANT
-#define IFF_DORMANT 0x20000 /* driver signals dormant */
-#endif
-
-#ifndef IF_OPER_DORMANT
-#define IF_OPER_DORMANT 5
-#endif
-#ifndef IF_OPER_UP
-#define IF_OPER_UP 6
-#endif
-
-struct nl80211_global {
- struct dl_list interfaces;
- int if_add_ifindex;
- u64 if_add_wdevid;
- int if_add_wdevid_set;
- struct netlink_data *netlink;
- struct nl_cb *nl_cb;
- struct nl_handle *nl;
- int nl80211_id;
- int ioctl_sock; /* socket for ioctl() use */
-
- struct nl_handle *nl_event;
-};
-
-struct nl80211_wiphy_data {
- struct dl_list list;
- struct dl_list bsss;
- struct dl_list drvs;
-
- struct nl_handle *nl_beacons;
- struct nl_cb *nl_cb;
-
- int wiphy_idx;
-};
-
static void nl80211_global_deinit(void *priv);
-struct i802_bss {
- struct wpa_driver_nl80211_data *drv;
- struct i802_bss *next;
- int ifindex;
- u64 wdev_id;
- char ifname[IFNAMSIZ + 1];
- char brname[IFNAMSIZ];
- unsigned int beacon_set:1;
- unsigned int added_if_into_bridge:1;
- unsigned int added_bridge:1;
- unsigned int in_deinit:1;
- unsigned int wdev_id_set:1;
- unsigned int added_if:1;
- unsigned int static_ap:1;
-
- u8 addr[ETH_ALEN];
-
- int freq;
- int bandwidth;
- int if_dynamic;
-
- void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt;
- struct nl_cb *nl_cb;
-
- struct nl80211_wiphy_data *wiphy_data;
- struct dl_list wiphy_list;
-};
-
-struct wpa_driver_nl80211_data {
- struct nl80211_global *global;
- struct dl_list list;
- struct dl_list wiphy_list;
- char phyname[32];
- u8 perm_addr[ETH_ALEN];
- void *ctx;
- int ifindex;
- int if_removed;
- int if_disabled;
- int ignore_if_down_event;
- struct rfkill_data *rfkill;
- struct wpa_driver_capa capa;
- u8 *extended_capa, *extended_capa_mask;
- unsigned int extended_capa_len;
- int has_capability;
-
- int operstate;
-
- int scan_complete_events;
- enum scan_states {
- NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
- SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
- SCHED_SCAN_RESULTS
- } scan_state;
-
- struct nl_cb *nl_cb;
-
- u8 auth_bssid[ETH_ALEN];
- u8 auth_attempt_bssid[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u8 prev_bssid[ETH_ALEN];
- int associated;
- u8 ssid[32];
- size_t ssid_len;
- enum nl80211_iftype nlmode;
- enum nl80211_iftype ap_scan_as_station;
- unsigned int assoc_freq;
-
- int monitor_sock;
- int monitor_ifidx;
- int monitor_refcount;
-
- unsigned int disabled_11b_rates:1;
- unsigned int pending_remain_on_chan:1;
- unsigned int in_interface_list:1;
- unsigned int device_ap_sme:1;
- unsigned int poll_command_supported:1;
- unsigned int data_tx_status:1;
- unsigned int scan_for_auth:1;
- unsigned int retry_auth:1;
- unsigned int use_monitor:1;
- unsigned int ignore_next_local_disconnect:1;
- unsigned int ignore_next_local_deauth:1;
- unsigned int allow_p2p_device:1;
- unsigned int hostapd:1;
- unsigned int start_mode_ap:1;
- unsigned int start_iface_up:1;
- unsigned int test_use_roc_tx:1;
- unsigned int ignore_deauth_event:1;
- unsigned int roaming_vendor_cmd_avail:1;
- unsigned int dfs_vendor_cmd_avail:1;
- unsigned int have_low_prio_scan:1;
- unsigned int force_connect_cmd:1;
- unsigned int addr_changed:1;
-
- u64 remain_on_chan_cookie;
- u64 send_action_cookie;
-
- unsigned int last_mgmt_freq;
-
- struct wpa_driver_scan_filter *filter_ssids;
- size_t num_filter_ssids;
-
- struct i802_bss *first_bss;
-
- int eapol_tx_sock;
-
- int eapol_sock; /* socket for EAPOL frames */
-
- struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
-
- int default_if_indices[16];
- int *if_indices;
- int num_if_indices;
-
- /* From failed authentication command */
- int auth_freq;
- u8 auth_bssid_[ETH_ALEN];
- u8 auth_ssid[32];
- size_t auth_ssid_len;
- int auth_alg;
- u8 *auth_ie;
- size_t auth_ie_len;
- u8 auth_wep_key[4][16];
- size_t auth_wep_key_len[4];
- int auth_wep_tx_keyidx;
- int auth_local_state_change;
- int auth_p2p;
-};
-
-
static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
- void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
- enum nl80211_iftype nlmode);
static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
struct hostapd_freq_params *freq);
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
- const u8 *set_addr, int first);
-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);
+ const u8 *set_addr, int first,
+ const char *driver_params);
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len, u64 *cookie,
int no_cck, int no_ack, int offchanok);
-static int nl80211_register_frame(struct i802_bss *bss,
- struct nl_handle *hl_handle,
- u16 type, const u8 *match, size_t match_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report);
-#ifdef ANDROID
-static int android_pno_start(struct i802_bss *bss,
- struct wpa_driver_scan_params *params);
-static int android_pno_stop(struct i802_bss *bss);
-extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
- size_t buf_len);
-#endif /* ANDROID */
-#ifdef ANDROID_P2P
-#ifdef ANDROID_P2P_STUB
-int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) {
- return 0;
-}
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) {
- return 0;
-}
-int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) {
- return -1;
-}
-int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
- const struct wpabuf *proberesp,
- const struct wpabuf *assocresp) {
- return 0;
-}
-#else /* ANDROID_P2P_STUB */
-int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
-int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
-int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
- const struct wpabuf *proberesp,
- const struct wpabuf *assocresp);
-#endif /* ANDROID_P2P_STUB */
-#endif /* ANDROID_P2P */
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(struct i802_bss *bss,
- enum wpa_driver_if_type type,
- const char *ifname);
static int nl80211_set_channel(struct i802_bss *bss,
struct hostapd_freq_params *freq, int set_chan);
static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
int ifindex, int disabled);
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
-static int wpa_driver_nl80211_authenticate_retry(
- struct wpa_driver_nl80211_data *drv);
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+ int reset_mode);
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
static int i802_set_iface_flags(struct i802_bss *bss, int up);
-
-
-static const char * nl80211_command_to_string(enum nl80211_commands cmd)
-{
-#define C2S(x) case x: return #x;
- switch (cmd) {
- C2S(NL80211_CMD_UNSPEC)
- C2S(NL80211_CMD_GET_WIPHY)
- C2S(NL80211_CMD_SET_WIPHY)
- C2S(NL80211_CMD_NEW_WIPHY)
- C2S(NL80211_CMD_DEL_WIPHY)
- C2S(NL80211_CMD_GET_INTERFACE)
- C2S(NL80211_CMD_SET_INTERFACE)
- C2S(NL80211_CMD_NEW_INTERFACE)
- C2S(NL80211_CMD_DEL_INTERFACE)
- C2S(NL80211_CMD_GET_KEY)
- C2S(NL80211_CMD_SET_KEY)
- C2S(NL80211_CMD_NEW_KEY)
- C2S(NL80211_CMD_DEL_KEY)
- C2S(NL80211_CMD_GET_BEACON)
- C2S(NL80211_CMD_SET_BEACON)
- C2S(NL80211_CMD_START_AP)
- C2S(NL80211_CMD_STOP_AP)
- C2S(NL80211_CMD_GET_STATION)
- C2S(NL80211_CMD_SET_STATION)
- C2S(NL80211_CMD_NEW_STATION)
- C2S(NL80211_CMD_DEL_STATION)
- C2S(NL80211_CMD_GET_MPATH)
- C2S(NL80211_CMD_SET_MPATH)
- C2S(NL80211_CMD_NEW_MPATH)
- C2S(NL80211_CMD_DEL_MPATH)
- C2S(NL80211_CMD_SET_BSS)
- C2S(NL80211_CMD_SET_REG)
- C2S(NL80211_CMD_REQ_SET_REG)
- C2S(NL80211_CMD_GET_MESH_CONFIG)
- C2S(NL80211_CMD_SET_MESH_CONFIG)
- C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
- C2S(NL80211_CMD_GET_REG)
- C2S(NL80211_CMD_GET_SCAN)
- C2S(NL80211_CMD_TRIGGER_SCAN)
- C2S(NL80211_CMD_NEW_SCAN_RESULTS)
- C2S(NL80211_CMD_SCAN_ABORTED)
- C2S(NL80211_CMD_REG_CHANGE)
- C2S(NL80211_CMD_AUTHENTICATE)
- C2S(NL80211_CMD_ASSOCIATE)
- C2S(NL80211_CMD_DEAUTHENTICATE)
- C2S(NL80211_CMD_DISASSOCIATE)
- C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
- C2S(NL80211_CMD_REG_BEACON_HINT)
- C2S(NL80211_CMD_JOIN_IBSS)
- C2S(NL80211_CMD_LEAVE_IBSS)
- C2S(NL80211_CMD_TESTMODE)
- C2S(NL80211_CMD_CONNECT)
- C2S(NL80211_CMD_ROAM)
- C2S(NL80211_CMD_DISCONNECT)
- C2S(NL80211_CMD_SET_WIPHY_NETNS)
- C2S(NL80211_CMD_GET_SURVEY)
- C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
- C2S(NL80211_CMD_SET_PMKSA)
- C2S(NL80211_CMD_DEL_PMKSA)
- C2S(NL80211_CMD_FLUSH_PMKSA)
- C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
- C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
- C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
- C2S(NL80211_CMD_REGISTER_FRAME)
- C2S(NL80211_CMD_FRAME)
- C2S(NL80211_CMD_FRAME_TX_STATUS)
- C2S(NL80211_CMD_SET_POWER_SAVE)
- C2S(NL80211_CMD_GET_POWER_SAVE)
- C2S(NL80211_CMD_SET_CQM)
- C2S(NL80211_CMD_NOTIFY_CQM)
- C2S(NL80211_CMD_SET_CHANNEL)
- C2S(NL80211_CMD_SET_WDS_PEER)
- C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
- C2S(NL80211_CMD_JOIN_MESH)
- C2S(NL80211_CMD_LEAVE_MESH)
- C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
- C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
- C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
- C2S(NL80211_CMD_GET_WOWLAN)
- C2S(NL80211_CMD_SET_WOWLAN)
- C2S(NL80211_CMD_START_SCHED_SCAN)
- C2S(NL80211_CMD_STOP_SCHED_SCAN)
- C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
- C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
- C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
- C2S(NL80211_CMD_PMKSA_CANDIDATE)
- C2S(NL80211_CMD_TDLS_OPER)
- C2S(NL80211_CMD_TDLS_MGMT)
- C2S(NL80211_CMD_UNEXPECTED_FRAME)
- C2S(NL80211_CMD_PROBE_CLIENT)
- C2S(NL80211_CMD_REGISTER_BEACONS)
- C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
- C2S(NL80211_CMD_SET_NOACK_MAP)
- C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
- C2S(NL80211_CMD_START_P2P_DEVICE)
- C2S(NL80211_CMD_STOP_P2P_DEVICE)
- C2S(NL80211_CMD_CONN_FAILED)
- C2S(NL80211_CMD_SET_MCAST_RATE)
- C2S(NL80211_CMD_SET_MAC_ACL)
- C2S(NL80211_CMD_RADAR_DETECT)
- C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
- C2S(NL80211_CMD_UPDATE_FT_IES)
- C2S(NL80211_CMD_FT_EVENT)
- C2S(NL80211_CMD_CRIT_PROTOCOL_START)
- C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
- C2S(NL80211_CMD_GET_COALESCE)
- C2S(NL80211_CMD_SET_COALESCE)
- C2S(NL80211_CMD_CHANNEL_SWITCH)
- C2S(NL80211_CMD_VENDOR)
- C2S(NL80211_CMD_SET_QOS_MAP)
- default:
- return "NL80211_CMD_UNKNOWN";
- }
-#undef C2S
-}
+static int nl80211_set_param(void *priv, const char *param);
/* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
+enum chan_width convert2width(int width)
{
switch (width) {
case NL80211_CHAN_WIDTH_20_NOHT:
@@ -568,14 +201,14 @@
}
-static int is_ap_interface(enum nl80211_iftype nlmode)
+int is_ap_interface(enum nl80211_iftype nlmode)
{
return nlmode == NL80211_IFTYPE_AP ||
nlmode == NL80211_IFTYPE_P2P_GO;
}
-static int is_sta_interface(enum nl80211_iftype nlmode)
+int is_sta_interface(enum nl80211_iftype nlmode)
{
return nlmode == NL80211_IFTYPE_STATION ||
nlmode == NL80211_IFTYPE_P2P_CLIENT;
@@ -589,8 +222,8 @@
}
-static struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
- int ifindex)
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex)
{
struct i802_bss *bss;
@@ -603,7 +236,13 @@
}
-static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+static int is_mesh_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_MESH_POINT;
+}
+
+
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
{
if (drv->associated)
os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
@@ -612,17 +251,6 @@
}
-struct nl80211_bss_info_arg {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_scan_results *res;
- unsigned int assoc_freq;
- unsigned int ibss_freq;
- u8 assoc_bssid[ETH_ALEN];
-};
-
-static int bss_info_handler(struct nl_msg *msg, void *arg);
-
-
/* nl80211 code */
static int ack_handler(struct nl_msg *msg, void *arg)
{
@@ -653,6 +281,28 @@
}
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+ /*
+ * Clear nlmsg data, e.g., to make sure key material is not left in
+ * heap memory for unnecessarily long time.
+ */
+ if (msg) {
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ void *data = nlmsg_data(hdr);
+ /*
+ * This would use nlmsg_datalen() or the older nlmsg_len() if
+ * only libnl were to maintain a stable API.. Neither will work
+ * with all released versions, so just calculate the length
+ * here.
+ */
+ int len = hdr->nlmsg_len - NLMSG_HDRLEN;
+
+ os_memset(data, 0, len);
+ }
+}
+
+
static int send_and_recv(struct nl80211_global *global,
struct nl_handle *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
@@ -661,6 +311,9 @@
struct nl_cb *cb;
int err = -ENOMEM;
+ if (!msg)
+ return -ENOMEM;
+
cb = nl_cb_clone(global->nl_cb);
if (!cb)
goto out;
@@ -689,25 +342,17 @@
}
out:
nl_cb_put(cb);
+ if (!valid_handler && valid_data == (void *) -1)
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return err;
}
-static int send_and_recv_msgs_global(struct nl80211_global *global,
- struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
-{
- return send_and_recv(global, global->nl, msg, valid_handler,
- valid_data);
-}
-
-
-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)
+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->global, drv->global->nl, msg,
valid_handler, valid_data);
@@ -720,19 +365,6 @@
};
-static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
-{
- if (bss->wdev_id_set)
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
- else
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-
static int family_handler(struct nl_msg *msg, void *arg)
{
struct family_data *res = arg;
@@ -768,35 +400,93 @@
const char *family, const char *group)
{
struct nl_msg *msg;
- int ret = -1;
+ int ret;
struct family_data res = { group, -ENOENT };
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
- 0, 0, CTRL_CMD_GETFAMILY, 0);
- NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+ if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
+ 0, 0, CTRL_CMD_GETFAMILY, 0) ||
+ nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
+ nlmsg_free(msg);
+ return -1;
+ }
- ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
- msg = NULL;
+ ret = send_and_recv(global, global->nl, msg, family_handler, &res);
if (ret == 0)
ret = res.id;
-
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
-static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
- struct nl_msg *msg, int flags, uint8_t cmd)
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd)
{
return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
0, flags, cmd, 0);
}
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+ if (bss->wdev_id_set)
+ return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+ return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+}
+
+
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
+ nl80211_set_iface_id(msg, bss) < 0) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static struct nl_msg *
+nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
+ int flags, uint8_t cmd)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ if (!nl80211_cmd(drv, msg, flags, cmd) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+ uint8_t cmd)
+{
+ return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
+}
+
+
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+ return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
+}
+
+
struct wiphy_idx_data {
int wiphy_idx;
enum nl80211_iftype nlmode;
@@ -827,7 +517,7 @@
}
-static int nl80211_get_wiphy_index(struct i802_bss *bss)
+int nl80211_get_wiphy_index(struct i802_bss *bss)
{
struct nl_msg *msg;
struct wiphy_idx_data data = {
@@ -835,20 +525,11 @@
.macaddr = NULL,
};
- msg = nlmsg_alloc();
- if (!msg)
- return NL80211_IFTYPE_UNSPECIFIED;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return -1;
if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
return data.wiphy_idx;
- msg = NULL;
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -861,20 +542,11 @@
.macaddr = NULL,
};
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return NL80211_IFTYPE_UNSPECIFIED;
if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
return data.nlmode;
- msg = NULL;
-nla_put_failure:
- nlmsg_free(msg);
return NL80211_IFTYPE_UNSPECIFIED;
}
@@ -886,19 +558,10 @@
.macaddr = bss->addr,
};
- msg = nlmsg_alloc();
- if (!msg)
- return NL80211_IFTYPE_UNSPECIFIED;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return -1;
return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
-
-nla_put_failure:
- nlmsg_free(msg);
- return NL80211_IFTYPE_UNSPECIFIED;
}
@@ -906,27 +569,24 @@
struct nl80211_wiphy_data *w)
{
struct nl_msg *msg;
- int ret = -1;
+ int ret;
msg = nlmsg_alloc();
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
-
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
+ nlmsg_free(msg);
+ return -1;
+ }
ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
"failed: ret=%d (%s)",
ret, strerror(-ret));
- goto nla_put_failure;
}
- ret = 0;
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -1104,7 +764,7 @@
static void wpa_driver_nl80211_event_newlink(
- struct wpa_driver_nl80211_data *drv, char *ifname)
+ struct wpa_driver_nl80211_data *drv, const char *ifname)
{
union wpa_event_data event;
@@ -1130,7 +790,7 @@
static void wpa_driver_nl80211_event_dellink(
- struct wpa_driver_nl80211_data *drv, char *ifname)
+ struct wpa_driver_nl80211_data *drv, const char *ifname)
{
union wpa_event_data event;
@@ -1190,7 +850,7 @@
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
- wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
+ wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
return 1;
}
@@ -1281,6 +941,7 @@
drv->first_bss->ifname) > 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event since interface %s is up", namebuf);
+ drv->ignore_if_down_event = 0;
return;
}
wpa_printf(MSG_DEBUG, "nl80211: Interface down");
@@ -1368,11 +1029,25 @@
wpa_driver_nl80211_event_newlink(drv, ifname);
if (ifi->ifi_family == AF_BRIDGE && brid) {
+ struct i802_bss *bss;
+
/* device has been added to bridge */
- if_indextoname(brid, namebuf);
+ if (!if_indextoname(brid, namebuf)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not find bridge ifname for ifindex %u",
+ brid);
+ return;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
brid, namebuf);
add_ifidx(drv, brid);
+
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if (os_strcmp(ifname, bss->ifname) == 0) {
+ os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
+ break;
+ }
+ }
}
}
@@ -1442,73 +1117,31 @@
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);
+
+ if (!if_indextoname(brid, namebuf)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not find bridge ifname for ifindex %u",
+ brid);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remove ifindex %u for bridge %s",
+ brid, namebuf);
+ }
del_ifidx(drv, brid);
}
}
-static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
-
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- drv->force_connect_cmd) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore auth event when using driver SME");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24 + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
- "frame");
- return;
- }
-
- os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
- os_memset(drv->auth_attempt_bssid, 0, 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.auth_transaction =
- le_to_host16(mgmt->u.auth.auth_transaction);
- 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);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
-}
-
-
-static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
{
struct nl_msg *msg;
int ret;
struct nl80211_bss_info_arg arg;
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
- msg = NULL;
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
@@ -1520,804 +1153,10 @@
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
"(%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return drv->assoc_freq;
}
-static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 status;
-
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- drv->force_connect_cmd) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore assoc event when using driver SME");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Associate event");
- 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;
- }
-
- status = le_to_host16(mgmt->u.assoc_resp.status_code);
- if (status != WLAN_STATUS_SUCCESS) {
- os_memset(&event, 0, sizeof(event));
- event.assoc_reject.bssid = mgmt->bssid;
- 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;
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
- return;
- }
-
- drv->associated = 1;
- os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
- os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
-
- 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);
- }
-
- event.assoc_info.freq = drv->assoc_freq;
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-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)
-{
- union wpa_event_data event;
- u16 status_code;
-
- 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;
- }
-
- status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
-
- if (cmd == NL80211_CMD_CONNECT) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
- status_code, drv->ignore_next_local_disconnect);
- } else if (cmd == NL80211_CMD_ROAM) {
- wpa_printf(MSG_DEBUG, "nl80211: Roam event");
- }
-
- os_memset(&event, 0, sizeof(event));
- if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
- if (addr)
- event.assoc_reject.bssid = nla_data(addr);
- if (drv->ignore_next_local_disconnect) {
- drv->ignore_next_local_disconnect = 0;
- if (!event.assoc_reject.bssid ||
- (os_memcmp(event.assoc_reject.bssid,
- drv->auth_attempt_bssid,
- ETH_ALEN) != 0)) {
- /*
- * Ignore the event that came without a BSSID or
- * for the old connection since this is likely
- * not relevant to the new Connect command.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore connection failure event triggered during reassociation");
- return;
- }
- }
- 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 = status_code;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
- return;
- }
-
- drv->associated = 1;
- if (addr) {
- os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
- os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
- }
-
- 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);
- }
-
- event.assoc_info.freq = nl80211_get_assoc_freq(drv);
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
- struct nlattr *reason, struct nlattr *addr,
- struct nlattr *by_ap)
-{
- union wpa_event_data data;
- unsigned int locally_generated = by_ap == NULL;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- /*
- * Avoid reporting two disassociation events that could
- * confuse the core code.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event when using userspace SME");
- return;
- }
-
- if (drv->ignore_next_local_disconnect) {
- drv->ignore_next_local_disconnect = 0;
- if (locally_generated) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event triggered during reassociation");
- return;
- }
- wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
- "disconnect but got another disconnect "
- "event first");
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
- nl80211_mark_disconnected(drv);
- os_memset(&data, 0, sizeof(data));
- if (reason)
- data.deauth_info.reason_code = nla_get_u16(reason);
- data.deauth_info.locally_generated = by_ap == NULL;
- wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
-}
-
-
-static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
-{
- int freq1 = 0;
-
- switch (convert2width(width)) {
- case CHAN_WIDTH_20_NOHT:
- case CHAN_WIDTH_20:
- return 0;
- case CHAN_WIDTH_40:
- freq1 = cf1 - 10;
- break;
- case CHAN_WIDTH_80:
- freq1 = cf1 - 30;
- break;
- case CHAN_WIDTH_160:
- freq1 = cf1 - 70;
- break;
- case CHAN_WIDTH_UNKNOWN:
- case CHAN_WIDTH_80P80:
- /* FIXME: implement this */
- return 0;
- }
-
- return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
-}
-
-
-static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *ifindex, struct nlattr *freq,
- struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2)
-{
- struct i802_bss *bss;
- union wpa_event_data data;
- int ht_enabled = 1;
- int chan_offset = 0;
- int ifidx;
-
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
-
- if (!freq)
- return;
-
- ifidx = nla_get_u32(ifindex);
- bss = get_bss_ifindex(drv, ifidx);
- if (bss == NULL) {
- wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
- ifidx);
- return;
- }
-
- if (type) {
- switch (nla_get_u32(type)) {
- case NL80211_CHAN_NO_HT:
- ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- chan_offset = -1;
- break;
- }
- } else if (bw && cf1) {
- /* This can happen for example with VHT80 ch switch */
- chan_offset = calculate_chan_offset(nla_get_u32(bw),
- nla_get_u32(freq),
- nla_get_u32(cf1),
- cf2 ? nla_get_u32(cf2) : 0);
- } else {
- wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
- }
-
- os_memset(&data, 0, sizeof(data));
- data.ch_switch.freq = nla_get_u32(freq);
- data.ch_switch.ht_enabled = ht_enabled;
- data.ch_switch.ch_offset = chan_offset;
- if (bw)
- data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
- if (cf1)
- data.ch_switch.cf1 = nla_get_u32(cf1);
- if (cf2)
- data.ch_switch.cf2 = nla_get_u32(cf2);
-
- bss->freq = data.ch_switch.freq;
-
- wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
-}
-
-
-static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *addr)
-{
- union wpa_event_data event;
- enum wpa_event_type ev;
-
- if (nla_len(addr) != ETH_ALEN)
- return;
-
- wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
- cmd, MAC2STR((u8 *) nla_data(addr)));
-
- if (cmd == NL80211_CMD_AUTHENTICATE)
- ev = EVENT_AUTH_TIMED_OUT;
- else if (cmd == NL80211_CMD_ASSOCIATE)
- ev = EVENT_ASSOC_TIMED_OUT;
- else
- return;
-
- 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 void mlme_event_mgmt(struct i802_bss *bss,
- struct nlattr *freq, struct nlattr *sig,
- const u8 *frame, size_t len)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 fc, stype;
- int ssi_signal = 0;
- int rx_freq = 0;
-
- wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
- return;
- }
-
- fc = le_to_host16(mgmt->frame_control);
- stype = WLAN_FC_GET_STYPE(fc);
-
- if (sig)
- ssi_signal = (s32) nla_get_u32(sig);
-
- os_memset(&event, 0, sizeof(event));
- if (freq) {
- event.rx_mgmt.freq = nla_get_u32(freq);
- rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: RX frame sa=" MACSTR
- " freq=%d ssi_signal=%d stype=%u (%s) len=%u",
- MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc),
- (unsigned int) len);
- event.rx_mgmt.frame = frame;
- event.rx_mgmt.frame_len = len;
- event.rx_mgmt.ssi_signal = ssi_signal;
- event.rx_mgmt.drv_priv = bss;
- wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
- struct nlattr *cookie, const u8 *frame,
- size_t len, struct nlattr *ack)
-{
- union wpa_event_data event;
- const struct ieee80211_hdr *hdr;
- u16 fc;
-
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
- if (!is_ap_interface(drv->nlmode)) {
- u64 cookie_val;
-
- if (!cookie)
- return;
-
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0%llx%s (ack=%d)",
- (long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
- " (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
- return;
- }
-
- hdr = (const struct ieee80211_hdr *) frame;
- fc = le_to_host16(hdr->frame_control);
-
- 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 mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
- enum wpa_event_type type,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- const u8 *bssid = NULL;
- u16 reason_code = 0;
-
- if (type == EVENT_DEAUTH)
- wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
- else
- wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
-
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len >= 24) {
- bssid = mgmt->bssid;
-
- if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- !drv->associated &&
- os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
- /*
- * Avoid issues with some roaming cases where
- * disconnection event for the old AP may show up after
- * we have started connection with the new AP.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
- MAC2STR(bssid),
- MAC2STR(drv->auth_attempt_bssid));
- return;
- }
-
- 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;
- }
- }
-
- nl80211_mark_disconnected(drv);
- 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);
-
- if (type == EVENT_DISASSOC) {
- event.disassoc_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
- event.disassoc_info.addr = bssid;
- event.disassoc_info.reason_code = reason_code;
- if (frame + len > mgmt->u.disassoc.variable) {
- event.disassoc_info.ie = mgmt->u.disassoc.variable;
- event.disassoc_info.ie_len = frame + len -
- mgmt->u.disassoc.variable;
- }
- } else {
- if (drv->ignore_deauth_event) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
- drv->ignore_deauth_event = 0;
- return;
- }
- event.deauth_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
- if (drv->ignore_next_local_deauth) {
- drv->ignore_next_local_deauth = 0;
- if (event.deauth_info.locally_generated) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
- return;
- }
- wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
- }
- event.deauth_info.addr = bssid;
- event.deauth_info.reason_code = reason_code;
- if (frame + len > mgmt->u.deauth.variable) {
- event.deauth_info.ie = mgmt->u.deauth.variable;
- event.deauth_info.ie_len = frame + len -
- mgmt->u.deauth.variable;
- }
- }
-
- wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
- enum wpa_event_type type,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 reason_code = 0;
-
- if (type == EVENT_UNPROT_DEAUTH)
- wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
- else
- wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
-
- if (len < 24)
- return;
-
- mgmt = (const struct ieee80211_mgmt *) frame;
-
- 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);
-
- if (type == EVENT_UNPROT_DISASSOC) {
- event.unprot_disassoc.sa = mgmt->sa;
- event.unprot_disassoc.da = mgmt->da;
- event.unprot_disassoc.reason_code = reason_code;
- } else {
- event.unprot_deauth.sa = mgmt->sa;
- event.unprot_deauth.da = mgmt->da;
- event.unprot_deauth.reason_code = reason_code;
- }
-
- wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event(struct i802_bss *bss,
- enum nl80211_commands cmd, struct nlattr *frame,
- struct nlattr *addr, struct nlattr *timed_out,
- struct nlattr *freq, struct nlattr *ack,
- struct nlattr *cookie, struct nlattr *sig)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- const u8 *data;
- size_t len;
-
- if (timed_out && addr) {
- mlme_timeout_event(drv, cmd, addr);
- return;
- }
-
- if (frame == NULL) {
- wpa_printf(MSG_DEBUG,
- "nl80211: MLME event %d (%s) without frame data",
- cmd, nl80211_command_to_string(cmd));
- return;
- }
-
- data = nla_data(frame);
- len = nla_len(frame);
- if (len < 4 + 2 * ETH_ALEN) {
- wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
- MACSTR ") - too short",
- cmd, nl80211_command_to_string(cmd), bss->ifname,
- MAC2STR(bss->addr));
- return;
- }
- wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
- ") A1=" MACSTR " A2=" MACSTR, cmd,
- nl80211_command_to_string(cmd), bss->ifname,
- MAC2STR(bss->addr), MAC2STR(data + 4),
- MAC2STR(data + 4 + ETH_ALEN));
- if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
- os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
- os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
- wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
- "for foreign address", bss->ifname);
- return;
- }
- wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
- nla_data(frame), nla_len(frame));
-
- 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_FRAME:
- mlme_event_mgmt(bss, freq, sig, nla_data(frame),
- nla_len(frame));
- break;
- case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
- nla_len(frame), ack);
- break;
- case NL80211_CMD_UNPROT_DEAUTHENTICATE:
- mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
- nla_data(frame), nla_len(frame));
- break;
- default:
- break;
- }
-}
-
-
-static void mlme_event_michael_mic_failure(struct i802_bss *bss,
- struct nlattr *tb[])
-{
- union wpa_event_data data;
-
- 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;
-
- 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);
- }
-
- wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-}
-
-
-static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- unsigned int freq;
-
- 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));
-
- freq = nl80211_get_assoc_freq(drv);
- if (freq) {
- wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
- freq);
- drv->first_bss->freq = freq;
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
- int cancel_event, struct nlattr *tb[])
-{
- unsigned int freq, chan_type, duration;
- union wpa_event_data data;
- u64 cookie;
-
- if (tb[NL80211_ATTR_WIPHY_FREQ])
- freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
- else
- freq = 0;
-
- if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
- chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- else
- chan_type = 0;
-
- if (tb[NL80211_ATTR_DURATION])
- duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
- else
- duration = 0;
-
- if (tb[NL80211_ATTR_COOKIE])
- cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
- else
- cookie = 0;
-
- 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");
-
- if (cookie != drv->remain_on_chan_cookie)
- return; /* not for us */
-
- if (cancel_event)
- drv->pending_remain_on_chan = 0;
-
- 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 mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- union wpa_event_data data;
-
- os_memset(&data, 0, sizeof(data));
-
- if (tb[NL80211_ATTR_IE]) {
- data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
- data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
- }
-
- if (tb[NL80211_ATTR_IE_RIC]) {
- data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
- data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
- }
-
- if (tb[NL80211_ATTR_MAC])
- os_memcpy(data.ft_ies.target_ap,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
- MAC2STR(data.ft_ies.target_ap));
-
- wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
-}
-
-
-static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
- struct nlattr *tb[])
-{
- 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;
-
- if (drv->scan_for_auth) {
- drv->scan_for_auth = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
- "cfg80211 BSS entry");
- wpa_driver_nl80211_authenticate_retry(drv);
- return;
- }
-
- os_memset(&event, 0, sizeof(event));
- info = &event.scan_info;
- info->aborted = aborted;
-
- 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);
- wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
- wpa_ssid_txt(s->ssid, s->ssid_len));
- info->num_ssids++;
- if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
- break;
- }
- }
- if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
- char msg[200], *pos, *end;
- int res;
-
- pos = msg;
- end = pos + sizeof(msg);
- *pos = '\0';
-
- nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
- {
- freqs[num_freqs] = nla_get_u32(nl);
- res = os_snprintf(pos, end - pos, " %d",
- freqs[num_freqs]);
- if (res > 0 && end - pos > res)
- pos += res;
- num_freqs++;
- if (num_freqs == MAX_REPORT_FREQS - 1)
- break;
- }
- info->freqs = freqs;
- info->num_freqs = num_freqs;
- wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
- msg);
- }
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
-}
-
-
static int get_link_signal(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -2372,27 +1211,21 @@
}
-static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
- struct wpa_signal_info *sig)
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig)
{
struct nl_msg *msg;
sig->current_signal = -9999;
sig->current_txrate = 0;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(drv, msg, get_link_signal, sig);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -2440,946 +1273,16 @@
}
-static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
- struct wpa_signal_info *sig_change)
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig_change)
{
struct nl_msg *msg;
sig_change->current_noise = 9999;
sig_change->frequency = drv->assoc_freq;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
-}
-
-
-static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
- static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
- [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
- [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
- };
- struct wpa_scan_results *scan_results = arg;
- struct wpa_scan_res *scan_res;
- size_t i;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (!tb[NL80211_ATTR_SURVEY_INFO]) {
- wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
- return NL_SKIP;
- }
-
- if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
- tb[NL80211_ATTR_SURVEY_INFO],
- survey_policy)) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
- "attributes");
- return NL_SKIP;
- }
-
- if (!sinfo[NL80211_SURVEY_INFO_NOISE])
- return NL_SKIP;
-
- if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
- return NL_SKIP;
-
- for (i = 0; i < scan_results->num; ++i) {
- scan_res = scan_results->res[i];
- if (!scan_res)
- continue;
- if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
- scan_res->freq)
- continue;
- if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
- continue;
- scan_res->noise = (s8)
- nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
- scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
- }
-
- return NL_SKIP;
-}
-
-
-static int nl80211_get_noise_for_scan_results(
- struct wpa_driver_nl80211_data *drv,
- struct wpa_scan_results *scan_res)
-{
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
- scan_res);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
-}
-
-
-static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- 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 },
- [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
- };
- struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
- enum nl80211_cqm_rssi_threshold_event event;
- union wpa_event_data ed;
- struct wpa_signal_info sig;
- int res;
-
- 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;
- }
-
- os_memset(&ed, 0, sizeof(ed));
-
- if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
- if (!tb[NL80211_ATTR_MAC])
- return;
- os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
- ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
- return;
- }
-
- if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
- return;
- event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
-
- 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;
-
- res = nl80211_get_link_signal(drv, &sig);
- if (res == 0) {
- ed.signal_change.current_signal = sig.current_signal;
- ed.signal_change.current_txrate = sig.current_txrate;
- wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
- sig.current_signal, sig.current_txrate);
- }
-
- res = nl80211_get_link_noise(drv, &sig);
- if (res == 0) {
- ed.signal_change.current_noise = sig.current_noise;
- wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
- sig.current_noise);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
-}
-
-
-static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- u8 *addr;
- union wpa_event_data data;
-
- if (tb[NL80211_ATTR_MAC] == NULL)
- return;
- addr = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
-
- if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
- u8 *ies = NULL;
- size_t ies_len = 0;
- if (tb[NL80211_ATTR_IE]) {
- ies = nla_data(tb[NL80211_ATTR_IE]);
- ies_len = nla_len(tb[NL80211_ATTR_IE]);
- }
- wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
- drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
- return;
- }
-
- if (drv->nlmode != NL80211_IFTYPE_ADHOC)
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
-}
-
-
-static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- u8 *addr;
- union wpa_event_data data;
-
- if (tb[NL80211_ATTR_MAC] == NULL)
- return;
- addr = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
- MAC2STR(addr));
-
- if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
- drv_event_disassoc(drv->ctx, addr);
- return;
- }
-
- if (drv->nlmode != NL80211_IFTYPE_ADHOC)
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
-}
-
-
-static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
- static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
- [NL80211_REKEY_DATA_KEK] = {
- .minlen = NL80211_KEK_LEN,
- .maxlen = NL80211_KEK_LEN,
- },
- [NL80211_REKEY_DATA_KCK] = {
- .minlen = NL80211_KCK_LEN,
- .maxlen = NL80211_KCK_LEN,
- },
- [NL80211_REKEY_DATA_REPLAY_CTR] = {
- .minlen = NL80211_REPLAY_CTR_LEN,
- .maxlen = NL80211_REPLAY_CTR_LEN,
- },
- };
- union wpa_event_data data;
-
- if (!tb[NL80211_ATTR_MAC])
- return;
- if (!tb[NL80211_ATTR_REKEY_DATA])
- return;
- if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
- tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
- return;
- if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
- return;
-
- os_memset(&data, 0, sizeof(data));
- data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
- MAC2STR(data.driver_gtk_rekey.bssid));
- data.driver_gtk_rekey.replay_ctr =
- nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
- wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
- data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
- wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
-}
-
-
-static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
- static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
- [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
- [NL80211_PMKSA_CANDIDATE_BSSID] = {
- .minlen = ETH_ALEN,
- .maxlen = ETH_ALEN,
- },
- [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
- };
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
-
- if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
- return;
- if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
- tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
- return;
- if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
- !cand[NL80211_PMKSA_CANDIDATE_BSSID])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.pmkid_candidate.bssid,
- nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
- data.pmkid_candidate.index =
- nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
- data.pmkid_candidate.preauth =
- cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
- wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
-}
-
-
-static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.client_poll.addr,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
-}
-
-
-static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
- switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
- case NL80211_TDLS_SETUP:
- wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
- MACSTR, MAC2STR(data.tdls.peer));
- data.tdls.oper = TDLS_REQUEST_SETUP;
- break;
- case NL80211_TDLS_TEARDOWN:
- wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
- MACSTR, MAC2STR(data.tdls.peer));
- data.tdls.oper = TDLS_REQUEST_TEARDOWN;
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
- "event");
- return;
- }
- if (tb[NL80211_ATTR_REASON_CODE]) {
- data.tdls.reason_code =
- nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
-}
-
-
-static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
-}
-
-
-static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
- u32 reason;
-
- wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.connect_failed_reason.addr,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
- switch (reason) {
- case NL80211_CONN_FAIL_MAX_CLIENTS:
- wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
- data.connect_failed_reason.code = MAX_CLIENT_REACHED;
- break;
- case NL80211_CONN_FAIL_BLOCKED_CLIENT:
- wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
- " tried to connect",
- MAC2STR(data.connect_failed_reason.addr));
- data.connect_failed_reason.code = BLOCKED_CLIENT;
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
- "%u", reason);
- return;
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
-}
-
-
-static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
- enum nl80211_radar_event event_type;
-
- if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
- return;
-
- os_memset(&data, 0, sizeof(data));
- data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
- event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
-
- /* Check HT params */
- if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- data.dfs_event.ht_enabled = 1;
- data.dfs_event.chan_offset = 0;
-
- switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
- case NL80211_CHAN_NO_HT:
- data.dfs_event.ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- data.dfs_event.chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- data.dfs_event.chan_offset = -1;
- break;
- }
- }
-
- /* Get VHT params */
- if (tb[NL80211_ATTR_CHANNEL_WIDTH])
- data.dfs_event.chan_width =
- convert2width(nla_get_u32(
- tb[NL80211_ATTR_CHANNEL_WIDTH]));
- if (tb[NL80211_ATTR_CENTER_FREQ1])
- data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
- if (tb[NL80211_ATTR_CENTER_FREQ2])
- data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
-
- wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
- data.dfs_event.freq, data.dfs_event.ht_enabled,
- data.dfs_event.chan_offset, data.dfs_event.chan_width,
- data.dfs_event.cf1, data.dfs_event.cf2);
-
- switch (event_type) {
- case NL80211_RADAR_DETECTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
- break;
- case NL80211_RADAR_CAC_FINISHED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
- break;
- case NL80211_RADAR_CAC_ABORTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
- break;
- case NL80211_RADAR_NOP_FINISHED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
- "received", event_type);
- break;
- }
-}
-
-
-static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
- int wds)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data event;
-
- if (!tb[NL80211_ATTR_MAC])
- return;
-
- os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.bssid = bss->addr;
- event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
- event.rx_from_unknown.wds = wds;
-
- wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
- const u8 *data, size_t len)
-{
- u32 i, count;
- union wpa_event_data event;
- struct wpa_freq_range *range = NULL;
- const struct qca_avoid_freq_list *freq_range;
-
- freq_range = (const struct qca_avoid_freq_list *) data;
- if (len < sizeof(freq_range->count))
- return;
-
- count = freq_range->count;
- if (len < sizeof(freq_range->count) +
- count * sizeof(struct qca_avoid_freq_range)) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
- (unsigned int) len);
- return;
- }
-
- if (count > 0) {
- range = os_calloc(count, sizeof(struct wpa_freq_range));
- if (range == NULL)
- return;
- }
-
- os_memset(&event, 0, sizeof(event));
- for (i = 0; i < count; i++) {
- unsigned int idx = event.freq_range.num;
- range[idx].min = freq_range->range[i].start_freq;
- range[idx].max = freq_range->range[i].end_freq;
- wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
- range[idx].min, range[idx].max);
- if (range[idx].min > range[idx].max) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
- continue;
- }
- event.freq_range.num++;
- }
- event.freq_range.range = range;
-
- wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
-
- os_free(range);
-}
-
-
-static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
- u32 subcmd, u8 *data, size_t len)
-{
- switch (subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
- qca_nl80211_avoid_freq(drv, data, len);
- break;
- default:
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore unsupported QCA vendor event %u",
- subcmd);
- break;
- }
-}
-
-
-static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- u32 vendor_id, subcmd, wiphy = 0;
- int wiphy_idx;
- u8 *data = NULL;
- size_t len = 0;
-
- if (!tb[NL80211_ATTR_VENDOR_ID] ||
- !tb[NL80211_ATTR_VENDOR_SUBCMD])
- return;
-
- vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
- subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
-
- if (tb[NL80211_ATTR_WIPHY])
- wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
-
- wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
- wiphy, vendor_id, subcmd);
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
- len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
- wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
- }
-
- wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
- if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
- wiphy, wiphy_idx);
- return;
- }
-
- switch (vendor_id) {
- case OUI_QCA:
- nl80211_vendor_event_qca(drv, subcmd, data, len);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
- break;
- }
-}
-
-
-static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- union wpa_event_data data;
- enum nl80211_reg_initiator init;
-
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
-
- if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
- return;
-
- os_memset(&data, 0, sizeof(data));
- init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
- wpa_printf(MSG_DEBUG, " * initiator=%d", init);
- switch (init) {
- case NL80211_REGDOM_SET_BY_CORE:
- data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
- break;
- case NL80211_REGDOM_SET_BY_USER:
- data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
- break;
- case NL80211_REGDOM_SET_BY_DRIVER:
- data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
- break;
- case NL80211_REGDOM_SET_BY_COUNTRY_IE:
- data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
- break;
- }
-
- if (tb[NL80211_ATTR_REG_TYPE]) {
- enum nl80211_reg_type type;
- type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
- wpa_printf(MSG_DEBUG, " * type=%d", type);
- switch (type) {
- case NL80211_REGDOM_TYPE_COUNTRY:
- data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
- break;
- case NL80211_REGDOM_TYPE_WORLD:
- data.channel_list_changed.type = REGDOM_TYPE_WORLD;
- break;
- case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
- data.channel_list_changed.type =
- REGDOM_TYPE_CUSTOM_WORLD;
- break;
- case NL80211_REGDOM_TYPE_INTERSECTION:
- data.channel_list_changed.type =
- REGDOM_TYPE_INTERSECTION;
- break;
- }
- }
-
- if (tb[NL80211_ATTR_REG_ALPHA2]) {
- os_strlcpy(data.channel_list_changed.alpha2,
- nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
- sizeof(data.channel_list_changed.alpha2));
- wpa_printf(MSG_DEBUG, " * alpha2=%s",
- data.channel_list_changed.alpha2);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
-}
-
-
-static void do_process_drv_event(struct i802_bss *bss, int cmd,
- struct nlattr **tb)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
- cmd, nl80211_command_to_string(cmd), bss->ifname);
-
- if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
- (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
- cmd == NL80211_CMD_SCAN_ABORTED)) {
- wpa_driver_nl80211_set_mode(drv->first_bss,
- drv->ap_scan_as_station);
- drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- }
-
- switch (cmd) {
- case NL80211_CMD_TRIGGER_SCAN:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
- drv->scan_state = SCAN_STARTED;
- if (drv->scan_for_auth) {
- /*
- * Cannot indicate EVENT_SCAN_STARTED here since we skip
- * EVENT_SCAN_RESULTS in scan_for_auth case and the
- * upper layer implementation could get confused about
- * scanning state.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
- break;
- }
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
- break;
- case NL80211_CMD_START_SCHED_SCAN:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
- drv->scan_state = SCHED_SCAN_STARTED;
- break;
- case NL80211_CMD_SCHED_SCAN_STOPPED:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
- drv->scan_state = SCHED_SCAN_STOPPED;
- wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
- break;
- case NL80211_CMD_NEW_SCAN_RESULTS:
- wpa_dbg(drv->ctx, MSG_DEBUG,
- "nl80211: New scan results available");
- drv->scan_state = SCAN_COMPLETED;
- drv->scan_complete_events = 1;
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
- send_scan_event(drv, 0, tb);
- break;
- case NL80211_CMD_SCHED_SCAN_RESULTS:
- wpa_dbg(drv->ctx, MSG_DEBUG,
- "nl80211: New sched scan results available");
- drv->scan_state = SCHED_SCAN_RESULTS;
- send_scan_event(drv, 0, tb);
- break;
- case NL80211_CMD_SCAN_ABORTED:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
- drv->scan_state = SCAN_ABORTED;
- /*
- * Need to indicate that scan results are available in order
- * not to make wpa_supplicant stop its scanning.
- */
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
- 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_FRAME_TX_STATUS:
- case NL80211_CMD_UNPROT_DEAUTHENTICATE:
- case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event(bss, 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],
- tb[NL80211_ATTR_RX_SIGNAL_DBM]);
- break;
- case NL80211_CMD_CONNECT:
- case NL80211_CMD_ROAM:
- mlme_event_connect(drv, cmd,
- tb[NL80211_ATTR_STATUS_CODE],
- tb[NL80211_ATTR_MAC],
- tb[NL80211_ATTR_REQ_IE],
- tb[NL80211_ATTR_RESP_IE]);
- break;
- case NL80211_CMD_CH_SWITCH_NOTIFY:
- mlme_event_ch_switch(drv,
- tb[NL80211_ATTR_IFINDEX],
- tb[NL80211_ATTR_WIPHY_FREQ],
- tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
- tb[NL80211_ATTR_CHANNEL_WIDTH],
- tb[NL80211_ATTR_CENTER_FREQ1],
- tb[NL80211_ATTR_CENTER_FREQ2]);
- break;
- case NL80211_CMD_DISCONNECT:
- mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
- tb[NL80211_ATTR_MAC],
- tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
- break;
- case NL80211_CMD_MICHAEL_MIC_FAILURE:
- mlme_event_michael_mic_failure(bss, 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;
- case NL80211_CMD_REG_CHANGE:
- nl80211_reg_change_event(drv, tb);
- break;
- case NL80211_CMD_REG_BEACON_HINT:
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
- os_memset(&data, 0, sizeof(data));
- data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- &data);
- break;
- case NL80211_CMD_NEW_STATION:
- nl80211_new_station_event(drv, tb);
- break;
- case NL80211_CMD_DEL_STATION:
- nl80211_del_station_event(drv, tb);
- break;
- case NL80211_CMD_SET_REKEY_OFFLOAD:
- nl80211_rekey_offload_event(drv, tb);
- break;
- case NL80211_CMD_PMKSA_CANDIDATE:
- nl80211_pmksa_candidate_event(drv, tb);
- break;
- case NL80211_CMD_PROBE_CLIENT:
- nl80211_client_probe_event(drv, tb);
- break;
- case NL80211_CMD_TDLS_OPER:
- nl80211_tdls_oper_event(drv, tb);
- break;
- case NL80211_CMD_CONN_FAILED:
- nl80211_connect_failed_event(drv, tb);
- break;
- case NL80211_CMD_FT_EVENT:
- mlme_event_ft_event(drv, tb);
- break;
- case NL80211_CMD_RADAR_DETECT:
- nl80211_radar_event(drv, tb);
- break;
- case NL80211_CMD_STOP_AP:
- nl80211_stop_ap(drv, tb);
- break;
- case NL80211_CMD_VENDOR:
- nl80211_vendor_event(drv, tb);
- break;
- default:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
- "(cmd=%d)", cmd);
- break;
- }
-}
-
-
-static int process_drv_event(struct nl_msg *msg, void *arg)
-{
- struct wpa_driver_nl80211_data *drv = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct i802_bss *bss;
- int ifidx = -1;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_IFINDEX]) {
- ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-
- for (bss = drv->first_bss; bss; bss = bss->next)
- if (ifidx == -1 || ifidx == bss->ifindex) {
- do_process_drv_event(bss, gnlh->cmd, tb);
- return NL_SKIP;
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
- gnlh->cmd, ifidx);
- } else if (tb[NL80211_ATTR_WDEV]) {
- u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
- wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
- for (bss = drv->first_bss; bss; bss = bss->next) {
- if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
- do_process_drv_event(bss, gnlh->cmd, tb);
- return NL_SKIP;
- }
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
- gnlh->cmd, (long long unsigned int) wdev_id);
- }
-
- return NL_SKIP;
-}
-
-
-static int process_global_event(struct nl_msg *msg, void *arg)
-{
- struct nl80211_global *global = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct wpa_driver_nl80211_data *drv, *tmp;
- int ifidx = -1;
- struct i802_bss *bss;
- u64 wdev_id = 0;
- int wdev_id_set = 0;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_IFINDEX])
- ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- else if (tb[NL80211_ATTR_WDEV]) {
- wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
- wdev_id_set = 1;
- }
-
- dl_list_for_each_safe(drv, tmp, &global->interfaces,
- struct wpa_driver_nl80211_data, list) {
- for (bss = drv->first_bss; bss; bss = bss->next) {
- if ((ifidx == -1 && !wdev_id_set) ||
- ifidx == bss->ifindex ||
- (wdev_id_set && bss->wdev_id_set &&
- wdev_id == bss->wdev_id)) {
- do_process_drv_event(bss, gnlh->cmd, tb);
- return NL_SKIP;
- }
- }
- }
-
- return NL_SKIP;
-}
-
-
-static int process_bss_event(struct nl_msg *msg, void *arg)
-{
- struct i802_bss *bss = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
- gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
- bss->ifname);
-
- switch (gnlh->cmd) {
- case NL80211_CMD_FRAME:
- case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event(bss, 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],
- tb[NL80211_ATTR_RX_SIGNAL_DBM]);
- break;
- case NL80211_CMD_UNEXPECTED_FRAME:
- nl80211_spurious_frame(bss, tb, 0);
- break;
- case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
- nl80211_spurious_frame(bss, tb, 1);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
- "(cmd=%d)", gnlh->cmd);
- break;
- }
-
- return NL_SKIP;
}
@@ -3423,15 +1326,14 @@
alpha2[1] = alpha2_arg[1];
alpha2[2] = '\0';
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
-
- NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
+ nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
+ nlmsg_free(msg);
+ return -EINVAL;
+ }
if (send_and_recv_msgs(drv, msg, NULL, NULL))
return -EINVAL;
return 0;
-nla_put_failure:
- nlmsg_free(msg);
- return -EINVAL;
}
@@ -3473,709 +1375,6 @@
}
-static int protocol_feature_handler(struct nl_msg *msg, void *arg)
-{
- u32 *feat = arg;
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
- *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
-
- return NL_SKIP;
-}
-
-
-static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
-{
- u32 feat = 0;
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
- if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
- return feat;
-
- msg = NULL;
-nla_put_failure:
- nlmsg_free(msg);
- return 0;
-}
-
-
-struct wiphy_info_data {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_driver_capa *capa;
-
- unsigned int num_multichan_concurrent;
-
- unsigned int error:1;
- unsigned int device_ap_sme:1;
- unsigned int poll_command_supported:1;
- unsigned int data_tx_status:1;
- unsigned int monitor_supported:1;
- unsigned int auth_supported:1;
- unsigned int connect_supported:1;
- unsigned int p2p_go_supported:1;
- unsigned int p2p_client_supported:1;
- unsigned int p2p_concurrent:1;
- unsigned int channel_switch_supported:1;
- unsigned int set_qos_map_supported:1;
- unsigned int have_low_prio_scan:1;
-};
-
-
-static unsigned int probe_resp_offload_support(int supp_protocols)
-{
- unsigned int prot = 0;
-
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
-
- return prot;
-}
-
-
-static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- struct nlattr *nl_mode;
- int i;
-
- if (tb == NULL)
- return;
-
- nla_for_each_nested(nl_mode, tb, i) {
- switch (nla_type(nl_mode)) {
- case NL80211_IFTYPE_AP:
- info->capa->flags |= WPA_DRIVER_FLAGS_AP;
- break;
- case NL80211_IFTYPE_ADHOC:
- info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
- break;
- case NL80211_IFTYPE_P2P_DEVICE:
- info->capa->flags |=
- WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
- break;
- case NL80211_IFTYPE_P2P_GO:
- info->p2p_go_supported = 1;
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- info->p2p_client_supported = 1;
- break;
- case NL80211_IFTYPE_MONITOR:
- info->monitor_supported = 1;
- break;
- }
- }
-}
-
-
-static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
- struct nlattr *nl_combi)
-{
- struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
- struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
- struct nlattr *nl_limit, *nl_mode;
- int err, rem_limit, rem_mode;
- int combination_has_p2p = 0, combination_has_mgd = 0;
- static struct nla_policy
- iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
- [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
- [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
- [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
- [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
- [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
- },
- iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
- [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
- [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
- };
-
- err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
- nl_combi, iface_combination_policy);
- if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
- !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
- !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
- return 0; /* broken combination */
-
- if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
- info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
-
- nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
- rem_limit) {
- err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
- nl_limit, iface_limit_policy);
- if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
- return 0; /* broken combination */
-
- nla_for_each_nested(nl_mode,
- tb_limit[NL80211_IFACE_LIMIT_TYPES],
- rem_mode) {
- int ift = nla_type(nl_mode);
- if (ift == NL80211_IFTYPE_P2P_GO ||
- ift == NL80211_IFTYPE_P2P_CLIENT)
- combination_has_p2p = 1;
- if (ift == NL80211_IFTYPE_STATION)
- combination_has_mgd = 1;
- }
- if (combination_has_p2p && combination_has_mgd)
- break;
- }
-
- if (combination_has_p2p && combination_has_mgd) {
- unsigned int num_channels =
- nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
-
- info->p2p_concurrent = 1;
- if (info->num_multichan_concurrent < num_channels)
- info->num_multichan_concurrent = num_channels;
- }
-
- return 0;
-}
-
-
-static void wiphy_info_iface_comb(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- struct nlattr *nl_combi;
- int rem_combi;
-
- if (tb == NULL)
- return;
-
- nla_for_each_nested(nl_combi, tb, rem_combi) {
- if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
- break;
- }
-}
-
-
-static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- struct nlattr *nl_cmd;
- int i;
-
- if (tb == NULL)
- return;
-
- nla_for_each_nested(nl_cmd, tb, i) {
- switch (nla_get_u32(nl_cmd)) {
- case NL80211_CMD_AUTHENTICATE:
- info->auth_supported = 1;
- break;
- case NL80211_CMD_CONNECT:
- info->connect_supported = 1;
- break;
- case NL80211_CMD_START_SCHED_SCAN:
- info->capa->sched_scan_supported = 1;
- break;
- case NL80211_CMD_PROBE_CLIENT:
- info->poll_command_supported = 1;
- break;
- case NL80211_CMD_CHANNEL_SWITCH:
- info->channel_switch_supported = 1;
- break;
- case NL80211_CMD_SET_QOS_MAP:
- info->set_qos_map_supported = 1;
- break;
- }
- }
-}
-
-
-static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- int i, num;
- u32 *ciphers;
-
- if (tb == NULL)
- return;
-
- num = nla_len(tb) / sizeof(u32);
- ciphers = nla_data(tb);
- for (i = 0; i < num; i++) {
- u32 c = ciphers[i];
-
- wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
- c >> 24, (c >> 16) & 0xff,
- (c >> 8) & 0xff, c & 0xff);
- switch (c) {
- case WLAN_CIPHER_SUITE_CCMP_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
- break;
- case WLAN_CIPHER_SUITE_GCMP_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
- break;
- case WLAN_CIPHER_SUITE_GCMP:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
- break;
- case WLAN_CIPHER_SUITE_WEP40:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
- break;
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
- break;
- case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
- break;
- }
- }
-}
-
-
-static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
- struct nlattr *tb)
-{
- if (tb)
- capa->max_remain_on_chan = nla_get_u32(tb);
-}
-
-
-static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
- struct nlattr *ext_setup)
-{
- if (tdls == NULL)
- return;
-
- wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
- capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
-
- if (ext_setup) {
- wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
- capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
- }
-}
-
-
-static void wiphy_info_feature_flags(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- u32 flags;
- struct wpa_driver_capa *capa = info->capa;
-
- if (tb == NULL)
- return;
-
- flags = nla_get_u32(tb);
-
- if (flags & NL80211_FEATURE_SK_TX_STATUS)
- info->data_tx_status = 1;
-
- if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
- capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
-
- if (flags & NL80211_FEATURE_SAE)
- capa->flags |= WPA_DRIVER_FLAGS_SAE;
-
- if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
- capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
-
- if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
- capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
-
- if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
- info->have_low_prio_scan = 1;
-}
-
-
-static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
- struct nlattr *tb)
-{
- u32 protocols;
-
- if (tb == NULL)
- return;
-
- protocols = nla_get_u32(tb);
- wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
- "mode");
- capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
- capa->probe_resp_offloads = probe_resp_offload_support(protocols);
-}
-
-
-static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
- struct nlattr *tb)
-{
- struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
-
- if (tb == NULL)
- return;
-
- if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
- tb, NULL))
- return;
-
- if (triggers[NL80211_WOWLAN_TRIG_ANY])
- capa->wowlan_triggers.any = 1;
- if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
- capa->wowlan_triggers.disconnect = 1;
- if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
- capa->wowlan_triggers.magic_pkt = 1;
- if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
- capa->wowlan_triggers.gtk_rekey_failure = 1;
- if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
- capa->wowlan_triggers.eap_identity_req = 1;
- if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
- capa->wowlan_triggers.four_way_handshake = 1;
- if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
- capa->wowlan_triggers.rfkill_release = 1;
-}
-
-
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct wiphy_info_data *info = arg;
- struct wpa_driver_capa *capa = info->capa;
- struct wpa_driver_nl80211_data *drv = info->drv;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_WIPHY_NAME])
- os_strlcpy(drv->phyname,
- nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
- sizeof(drv->phyname));
- if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
- capa->max_scan_ssids =
- nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
-
- if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
- capa->max_sched_scan_ssids =
- nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
-
- if (tb[NL80211_ATTR_MAX_MATCH_SETS])
- capa->max_match_sets =
- nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
-
- if (tb[NL80211_ATTR_MAC_ACL_MAX])
- capa->max_acl_mac_addrs =
- nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
-
- wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
- wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
- wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
- wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
-
- if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
- wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
- "off-channel TX");
- capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
- }
-
- if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
- wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
- capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
- }
-
- wiphy_info_max_roc(capa,
- tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
-
- if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
- capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
-
- wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
- tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
-
- if (tb[NL80211_ATTR_DEVICE_AP_SME])
- info->device_ap_sme = 1;
-
- wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
- wiphy_info_probe_resp_offload(capa,
- tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
-
- if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
- drv->extended_capa == NULL) {
- drv->extended_capa =
- os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- if (drv->extended_capa) {
- os_memcpy(drv->extended_capa,
- nla_data(tb[NL80211_ATTR_EXT_CAPA]),
- nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- drv->extended_capa_len =
- nla_len(tb[NL80211_ATTR_EXT_CAPA]);
- }
- drv->extended_capa_mask =
- os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- if (drv->extended_capa_mask) {
- os_memcpy(drv->extended_capa_mask,
- nla_data(tb[NL80211_ATTR_EXT_CAPA]),
- nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- } else {
- os_free(drv->extended_capa);
- drv->extended_capa = NULL;
- drv->extended_capa_len = 0;
- }
- }
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- struct nlattr *nl;
- int rem;
-
- nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
- struct nl80211_vendor_cmd_info *vinfo;
- if (nla_len(nl) != sizeof(*vinfo)) {
- wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
- continue;
- }
- vinfo = nla_data(nl);
- switch (vinfo->subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
- drv->roaming_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
- drv->dfs_vendor_cmd_avail = 1;
- break;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
- vinfo->vendor_id, vinfo->subcmd);
- }
- }
-
- if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
- struct nlattr *nl;
- int rem;
-
- nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
- struct nl80211_vendor_cmd_info *vinfo;
- if (nla_len(nl) != sizeof(*vinfo)) {
- wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
- continue;
- }
- vinfo = nla_data(nl);
- wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
- vinfo->vendor_id, vinfo->subcmd);
- }
- }
-
- wiphy_info_wowlan_triggers(capa,
- tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
-
- if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
- capa->max_stations =
- nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
-
- return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
- struct wiphy_info_data *info)
-{
- u32 feat;
- struct nl_msg *msg;
-
- os_memset(info, 0, sizeof(*info));
- info->capa = &drv->capa;
- info->drv = drv;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- feat = get_nl80211_protocol_features(drv);
- if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
- else
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
-
- NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
-
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
- return -1;
-
- 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");
- info->error = 1;
- }
-
- if (info->p2p_go_supported && info->p2p_client_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- if (info->p2p_concurrent) {
- wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
- "interface (driver advertised support)");
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
- }
- if (info->num_multichan_concurrent > 1) {
- wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
- "concurrent (driver advertised support)");
- drv->capa.num_multichan_concurrent =
- info->num_multichan_concurrent;
- }
-
- /* default to 5000 since early versions of mac80211 don't set it */
- if (!drv->capa.max_remain_on_chan)
- drv->capa.max_remain_on_chan = 5000;
-
- if (info->channel_switch_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
-
- return 0;
-nla_put_failure:
- nlmsg_free(msg);
- return -1;
-}
-
-
-static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
-{
- struct wiphy_info_data info;
- if (wpa_driver_nl80211_get_info(drv, &info))
- return -1;
-
- if (info.error)
- return -1;
-
- drv->has_capability = 1;
- 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.auth = WPA_DRIVER_AUTH_OPEN |
- WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
-
- drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
- drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
- drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-
- /*
- * As all cfg80211 drivers must support cases where the AP interface is
- * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
- * case that the user space daemon has crashed, they must be able to
- * cleanup all stations and key entries in the AP tear down flow. Thus,
- * this flag can/should always be set for cfg80211 drivers.
- */
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
-
- if (!info.device_ap_sme) {
- drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
-
- /*
- * No AP SME is currently assumed to also indicate no AP MLME
- * in the driver/firmware.
- */
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
- }
-
- drv->device_ap_sme = info.device_ap_sme;
- drv->poll_command_supported = info.poll_command_supported;
- drv->data_tx_status = info.data_tx_status;
- if (info.set_qos_map_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
- drv->have_low_prio_scan = info.have_low_prio_scan;
-
- /*
- * If poll command and tx status are supported, mac80211 is new enough
- * to have everything we need to not need monitor interfaces.
- */
- drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-
- if (drv->device_ap_sme && drv->use_monitor) {
- /*
- * Non-mac80211 drivers may not support monitor interface.
- * Make sure we do not get stuck with incorrect capability here
- * by explicitly testing this.
- */
- if (!info.monitor_supported) {
- wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
- "with device_ap_sme since no monitor mode "
- "support detected");
- drv->use_monitor = 0;
- }
- }
-
- /*
- * If we aren't going to use monitor interfaces, but the
- * driver doesn't support data TX status, we won't get TX
- * status for EAPOL frames.
- */
- if (!drv->use_monitor && !info.data_tx_status)
- drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-
- return 0;
-}
-
-
-#ifdef ANDROID
-static int android_genl_ctrl_resolve(struct nl_handle *handle,
- const char *name)
-{
- /*
- * Android ICS has very minimal genl_ctrl_resolve() implementation, so
- * need to work around that.
- */
- struct nl_cache *cache = NULL;
- struct genl_family *nl80211 = NULL;
- int id = -1;
-
- if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto fail;
- }
-
- nl80211 = genl_ctrl_search_by_name(cache, name);
- if (nl80211 == NULL)
- goto fail;
-
- id = genl_family_get_id(nl80211);
-
-fail:
- if (nl80211)
- genl_family_put(nl80211);
- if (cache)
- nl_cache_free(cache);
-
- return id;
-}
-#define genl_ctrl_resolve android_genl_ctrl_resolve
-#endif /* ANDROID */
-
-
static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
{
int ret;
@@ -4262,23 +1461,6 @@
}
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
-{
- drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!drv->nl_cb) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
- return -1;
- }
-
- nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
- no_seq_check, NULL);
- nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
- process_drv_event, drv);
-
- return 0;
-}
-
-
static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
{
wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -4385,7 +1567,8 @@
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
void *global_priv, int hostapd,
- const u8 *set_addr)
+ const u8 *set_addr,
+ const char *driver_params)
{
struct wpa_driver_nl80211_data *drv;
struct rfkill_config *rcfg;
@@ -4418,11 +1601,6 @@
drv->eapol_tx_sock = -1;
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- if (wpa_driver_nl80211_init_nl(drv)) {
- os_free(drv);
- return NULL;
- }
-
if (nl80211_init_bss(bss))
goto failed;
@@ -4442,7 +1620,7 @@
if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
drv->start_iface_up = 1;
- if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
+ if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
goto failed;
drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -4491,7 +1669,8 @@
static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
void *global_priv)
{
- return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+ return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
+ NULL);
}
@@ -4501,54 +1680,42 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret;
char buf[30];
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
buf[0] = '\0';
wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
type, fc2str(type), nl_handle, buf);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
- NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
+ nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
+ nlmsg_free(msg);
+ return -1;
+ }
ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
"failed (type=%u): ret=%d (%s)",
type, ret, strerror(-ret));
wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
match, match_len);
- goto nla_put_failure;
}
- ret = 0;
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
-
if (bss->nl_mgmt) {
wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
"already on! (nl_mgmt=%p)", bss->nl_mgmt);
return -1;
}
- bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+ bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
if (bss->nl_mgmt == NULL)
return -1;
@@ -4667,6 +1834,57 @@
ret = -1;
#endif /* CONFIG_HS20 */
+ /* WMM-AC ADDTS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
+ ret = -1;
+
+ /* WMM-AC DELTS */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Neighbor Report Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Link Measurement Request */
+ if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
+ (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
+ ret = -1;
+
+ nl80211_mgmt_handle_register_eloop(bss);
+
+ return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
+{
+ int ret = 0;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Subscribe to mgmt frames with mesh handle %p",
+ bss->nl_mgmt);
+
+ /* Auth frames for mesh SAE */
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4),
+ NULL, 0) < 0)
+ ret = -1;
+
+ /* Mesh peering open */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
+ ret = -1;
+ /* Mesh peering confirm */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
+ ret = -1;
+ /* Mesh peering close */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
+ ret = -1;
+
nl80211_mgmt_handle_register_eloop(bss);
return ret;
@@ -4675,29 +1893,16 @@
static int nl80211_register_spurious_class3(struct i802_bss *bss)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
- ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
- msg = NULL;
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
+ ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
"failed: ret=%d (%s)",
ret, strerror(-ret));
- goto nla_put_failure;
}
- ret = 0;
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -4792,56 +1997,31 @@
static void nl80211_del_p2pdev(struct i802_bss *bss)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
bss->ifname, (long long unsigned int) bss->wdev_id,
strerror(-ret));
-
-nla_put_failure:
- nlmsg_free(msg);
}
static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- if (start)
- nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
- else
- nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
-
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
+ msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
+ NL80211_CMD_STOP_P2P_DEVICE);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
start ? "Start" : "Stop",
bss->ifname, (long long unsigned int) bss->wdev_id,
strerror(-ret));
-
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -4863,7 +2043,8 @@
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
- const u8 *set_addr, int first)
+ const u8 *set_addr, int first,
+ const char *driver_params)
{
struct i802_bss *bss = drv->first_bss;
int send_rfkill_event = 0;
@@ -4884,6 +2065,9 @@
if (wpa_driver_nl80211_capa(drv))
return -1;
+ if (driver_params && nl80211_set_param(bss, driver_params) < 0)
+ return -1;
+
wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
bss->ifname, drv->phyname);
@@ -4951,19 +2135,10 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -4978,6 +2153,9 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
+ bss->ifname, drv->disabled_11b_rates);
+
bss->in_deinit = 1;
if (drv->data_tx_status)
eloop_unregister_read_sock(drv->eapol_tx_sock);
@@ -4996,6 +2174,11 @@
nl80211_handle_destroy(drv->rtnl_sk);
}
if (bss->added_bridge) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+ 0) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Could not set bridge %s down",
+ bss->brname);
if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"bridge %s: %s",
@@ -5029,7 +2212,11 @@
(void) i802_set_iface_flags(bss, 0);
if (drv->addr_changed) {
- linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+ 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not set interface down to restore permanent MAC address");
+ }
if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
drv->perm_addr) < 0) {
wpa_printf(MSG_DEBUG,
@@ -5046,7 +2233,6 @@
nl80211_mgmt_unsubscribe(bss, "deinit");
nl80211_del_p2pdev(bss);
}
- nl_cb_put(drv->nl_cb);
nl80211_destroy_bss(drv->first_bss);
@@ -5064,720 +2250,6 @@
}
-/**
- * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
- * @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
- * generate a scan completed event if the driver does not report this.
- */
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
- if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
- wpa_driver_nl80211_set_mode(drv->first_bss,
- drv->ap_scan_as_station);
- drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- }
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static struct nl_msg *
-nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
- struct wpa_driver_scan_params *params, u64 *wdev_id)
-{
- struct nl_msg *msg;
- size_t i;
- u32 scan_flags = 0;
-
- msg = nlmsg_alloc();
- if (!msg)
- return NULL;
-
- nl80211_cmd(drv, msg, 0, cmd);
-
- if (!wdev_id)
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- else
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
-
- if (params->num_ssids) {
- struct nlattr *ssids;
-
- ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
- if (ssids == NULL)
- goto fail;
- 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);
- if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid) < 0)
- goto fail;
- }
- nla_nest_end(msg, ssids);
- }
-
- if (params->extra_ies) {
- wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
- params->extra_ies, params->extra_ies_len);
- if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies) < 0)
- goto fail;
- }
-
- if (params->freqs) {
- struct nlattr *freqs;
- freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
- if (freqs == NULL)
- goto fail;
- for (i = 0; params->freqs[i]; i++) {
- wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
- "MHz", params->freqs[i]);
- if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
- goto fail;
- }
- nla_nest_end(msg, freqs);
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- if (params->only_new_results) {
- wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
- scan_flags |= NL80211_SCAN_FLAG_FLUSH;
- }
-
- if (params->low_priority && drv->have_low_prio_scan) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
- scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
- }
-
- if (scan_flags)
- NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags);
-
- return msg;
-
-fail:
-nla_put_failure:
- nlmsg_free(msg);
- return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @bss: 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(struct i802_bss *bss,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = -1, timeout;
- struct nl_msg *msg = NULL;
-
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
- drv->scan_for_auth = 0;
-
- msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
- bss->wdev_id_set ? &bss->wdev_id : NULL);
- if (!msg)
- return -1;
-
- if (params->p2p_probe) {
- struct nlattr *rates;
-
- wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
-
- rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
- if (rates == NULL)
- goto nla_put_failure;
-
- /*
- * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
- * by masking out everything else apart from the OFDM rates 6,
- * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
- * rates are left enabled.
- */
- NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
- "\x0c\x12\x18\x24\x30\x48\x60\x6c");
- nla_nest_end(msg, rates);
-
- NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
- }
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
- "(%s)", ret, strerror(-ret));
- if (drv->hostapd && is_ap_interface(drv->nlmode)) {
- enum nl80211_iftype old_mode = drv->nlmode;
-
- /*
- * mac80211 does not allow scan requests in AP mode, so
- * try to do this in station mode.
- */
- if (wpa_driver_nl80211_set_mode(
- bss, NL80211_IFTYPE_STATION))
- goto nla_put_failure;
-
- if (wpa_driver_nl80211_scan(bss, params)) {
- wpa_driver_nl80211_set_mode(bss, drv->nlmode);
- goto nla_put_failure;
- }
-
- /* Restore AP mode when processing scan results */
- drv->ap_scan_as_station = old_mode;
- ret = 0;
- } else
- goto nla_put_failure;
- }
-
- drv->scan_state = SCAN_REQUESTED;
- /* Not all drivers generate "scan completed" wireless event, so try to
- * read results after a timeout. */
- timeout = 10;
- if (drv->scan_complete_events) {
- /*
- * The driver seems to deliver events to notify when scan is
- * complete, so use longer timeout to avoid race conditions
- * with scanning and following association request.
- */
- timeout = 30;
- }
- wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
- "seconds", ret, timeout);
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
- drv, drv->ctx);
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_sched_scan(void *priv,
- struct wpa_driver_scan_params *params,
- u32 interval)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = -1;
- struct nl_msg *msg;
- size_t i;
-
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
-
-#ifdef ANDROID
- if (!drv->capa.sched_scan_supported)
- return android_pno_start(bss, params);
-#endif /* ANDROID */
-
- msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
- bss->wdev_id_set ? &bss->wdev_id : NULL);
- if (!msg)
- goto nla_put_failure;
-
- NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
-
- if ((drv->num_filter_ssids &&
- (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
- params->filter_rssi) {
- struct nlattr *match_sets;
- match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
- if (match_sets == NULL)
- goto nla_put_failure;
-
- for (i = 0; i < drv->num_filter_ssids; i++) {
- struct nlattr *match_set_ssid;
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "nl80211: Sched scan filter SSID",
- drv->filter_ssids[i].ssid,
- drv->filter_ssids[i].ssid_len);
-
- match_set_ssid = nla_nest_start(msg, i + 1);
- if (match_set_ssid == NULL)
- goto nla_put_failure;
- NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
- drv->filter_ssids[i].ssid_len,
- drv->filter_ssids[i].ssid);
- if (params->filter_rssi)
- NLA_PUT_U32(msg,
- NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
- params->filter_rssi);
-
- nla_nest_end(msg, match_set_ssid);
- }
-
- /*
- * Due to backward compatibility code, newer kernels treat this
- * matchset (with only an RSSI filter) as the default for all
- * other matchsets, unless it's the only one, in which case the
- * matchset will actually allow all SSIDs above the RSSI.
- */
- if (params->filter_rssi) {
- struct nlattr *match_set_rssi;
- match_set_rssi = nla_nest_start(msg, 0);
- if (match_set_rssi == NULL)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
- params->filter_rssi);
- wpa_printf(MSG_MSGDUMP,
- "nl80211: Sched scan RSSI filter %d dBm",
- params->filter_rssi);
- nla_nest_end(msg, match_set_rssi);
- }
-
- nla_nest_end(msg, match_sets);
- }
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-
- /* TODO: if we get an error here, we should fall back to normal scan */
-
- msg = NULL;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
- "ret=%d (%s)", ret, strerror(-ret));
- goto nla_put_failure;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
- "scan interval %d msec", ret, interval);
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_stop_sched_scan(void *priv)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0;
- struct nl_msg *msg;
-
-#ifdef ANDROID
- if (!drv->capa.sched_scan_supported)
- return android_pno_stop(bss);
-#endif /* ANDROID */
-
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
- "ret=%d (%s)", ret, strerror(-ret));
- goto nla_put_failure;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-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;
-}
-
-
-static int bss_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *bss[NL80211_BSS_MAX + 1];
- static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
- [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
- [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
- [NL80211_BSS_TSF] = { .type = NLA_U64 },
- [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
- [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
- [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
- [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
- [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
- [NL80211_BSS_STATUS] = { .type = NLA_U32 },
- [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
- [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
- };
- 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, *beacon_ie;
- size_t ie_len, beacon_ie_len;
- u8 *pos;
- size_t i;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
- if (!tb[NL80211_ATTR_BSS])
- return NL_SKIP;
- if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
- bss_policy))
- return NL_SKIP;
- if (bss[NL80211_BSS_STATUS]) {
- enum nl80211_bss_status status;
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->assoc_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
- _arg->assoc_freq);
- }
- if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->ibss_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
- _arg->ibss_freq);
- }
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_BSSID]) {
- os_memcpy(_arg->assoc_bssid,
- nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: Associated with "
- MACSTR, MAC2STR(_arg->assoc_bssid));
- }
- }
- if (!res)
- return NL_SKIP;
- if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
- ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
- ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
- } else {
- ie = NULL;
- ie_len = 0;
- }
- 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;
- }
-
- 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])
- os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
- ETH_ALEN);
- if (bss[NL80211_BSS_FREQUENCY])
- r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- if (bss[NL80211_BSS_BEACON_INTERVAL])
- r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
- if (bss[NL80211_BSS_CAPABILITY])
- r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
- 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_QUAL_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;
- 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;
- }
- }
-
- /*
- * cfg80211 maintains separate BSS table entries for APs if the same
- * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
- * not use frequency as a separate key in the BSS table, so filter out
- * duplicated entries. Prefer associated BSS entry in such a case in
- * order to get the correct frequency into the BSS table. Similarly,
- * prefer newer entries over older.
- */
- for (i = 0; i < res->num; i++) {
- const u8 *s1, *s2;
- if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
- continue;
-
- s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
- res->res[i]->ie_len, WLAN_EID_SSID);
- s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
- if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
- os_memcmp(s1, s2, 2 + s1[1]) != 0)
- continue;
-
- /* Same BSSID,SSID was already included in scan results */
- wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
- "for " MACSTR, MAC2STR(r->bssid));
-
- if (((r->flags & WPA_SCAN_ASSOCIATED) &&
- !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
- r->age < res->res[i]->age) {
- os_free(res->res[i]);
- res->res[i] = r;
- } else
- os_free(r);
- return NL_SKIP;
- }
-
- tmp = os_realloc_array(res->res, res->num + 1,
- sizeof(struct wpa_scan_res *));
- if (tmp == NULL) {
- os_free(r);
- return NL_SKIP;
- }
- tmp[res->num++] = r;
- res->res = tmp;
-
- return NL_SKIP;
-}
-
-
-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 (is_sta_interface(drv->nlmode) &&
- 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 (is_sta_interface(drv->nlmode) &&
- !drv->associated) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(not associated) does not match "
- "with BSS state");
- clear_state_mismatch(drv, r->bssid);
- } else if (is_sta_interface(drv->nlmode) &&
- 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 struct wpa_scan_results *
-nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
-{
- 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 NULL;
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
-
- 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, "nl80211: Received scan results (%lu "
- "BSSes)", (unsigned long) res->num);
- nl80211_get_noise_for_scan_results(drv, res);
- return res;
- }
- wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
- "(%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
- wpa_scan_results_free(res);
- return NULL;
-}
-
-
-/**
- * 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 i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct wpa_scan_results *res;
-
- res = nl80211_get_scan_results(drv);
- if (res)
- wpa_driver_nl80211_check_bss_status(drv, res);
- return res;
-}
-
-
-static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
-{
- struct wpa_scan_results *res;
- size_t i;
-
- res = nl80211_get_scan_results(drv);
- if (res == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
- return;
- }
-
- 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]" : "");
- }
-
- wpa_scan_results_free(res);
-}
-
-
static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
{
switch (alg) {
@@ -5869,6 +2341,35 @@
}
+static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
+ const u8 *key, size_t key_len)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
+ return 0;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
+ nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -1;
+ }
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Key management set key failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
@@ -5897,33 +2398,44 @@
}
#endif /* CONFIG_TDLS */
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
+ if (alg == WPA_ALG_PMK &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
+ __func__);
+ ret = issue_key_mgmt_set_key(drv, key, key_len);
+ return ret;
+ }
if (alg == WPA_ALG_NONE) {
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
+ if (!msg)
+ return -ENOBUFS;
} else {
- nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
- NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
+ nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
+ wpa_alg_to_cipher_suite(alg, key_len)))
+ goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len));
}
if (seq && seq_len) {
- NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
+ if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
+ goto fail;
wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
}
if (addr && !is_broadcast_ether_addr(addr)) {
wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
- NL80211_KEYTYPE_GROUP);
+ if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
+ NL80211_KEYTYPE_GROUP))
+ goto fail;
}
} else if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
@@ -5931,15 +2443,15 @@
wpa_printf(MSG_DEBUG, " broadcast key");
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types)
- goto nla_put_failure;
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ if (!types ||
+ nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ goto fail;
nla_nest_end(msg, types);
}
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+ goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
@@ -5956,32 +2468,28 @@
!is_broadcast_ether_addr(addr))
return ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
- if (alg == WPA_ALG_IGTK)
- NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
- else
- NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
+ nla_put_flag(msg, alg == WPA_ALG_IGTK ?
+ NL80211_ATTR_KEY_DEFAULT_MGMT :
+ NL80211_ATTR_KEY_DEFAULT))
+ goto fail;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types)
- goto nla_put_failure;
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ if (!types ||
+ nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ goto fail;
nla_nest_end(msg, types);
} else if (addr) {
struct nlattr *types;
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types)
- goto nla_put_failure;
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+ if (!types ||
+ nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+ goto fail;
nla_nest_end(msg, types);
}
@@ -5993,7 +2501,8 @@
"err=%d %s)", ret, strerror(-ret));
return ret;
-nla_put_failure:
+fail:
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -6008,26 +2517,25 @@
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);
+ if (defkey && alg == WPA_ALG_IGTK) {
+ if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
+ return -1;
+ } else if (defkey) {
+ if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
+ return -1;
+ }
- NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
-
- NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len));
-
- if (seq && seq_len)
- NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
-
- NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
+ if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER,
+ wpa_alg_to_cipher_suite(alg, key_len)) ||
+ (seq && seq_len &&
+ nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
+ nla_put(msg, NL80211_KEY_DATA, key_len, key))
+ return -1;
nla_nest_end(msg, key_attr);
return 0;
- nla_put_failure:
- return -1;
}
@@ -6052,77 +2560,60 @@
if (!privacy)
return 0;
- NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+ return -ENOBUFS;
nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
if (!nl_keys)
- goto nla_put_failure;
+ return -ENOBUFS;
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
nl_key = nla_nest_start(msg, i);
- if (!nl_key)
- goto nla_put_failure;
-
- 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);
-
- NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
-
- if (i == params->wep_tx_keyidx)
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+ if (!nl_key ||
+ nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+ params->wep_key[i]) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER,
+ params->wep_key_len[i] == 5 ?
+ WLAN_CIPHER_SUITE_WEP40 :
+ WLAN_CIPHER_SUITE_WEP104) ||
+ nla_put_u8(msg, NL80211_KEY_IDX, i) ||
+ (i == params->wep_tx_keyidx &&
+ nla_put_flag(msg, NL80211_KEY_DEFAULT)))
+ return -ENOBUFS;
nla_nest_end(msg, nl_key);
}
nla_nest_end(msg, nl_keys);
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
- const u8 *addr, int cmd, u16 reason_code,
- int local_state_change)
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change)
{
- int ret = -1;
+ int ret;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ (local_state_change &&
+ nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, cmd);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
- if (addr)
- 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);
- msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
reason_code, ret, strerror(-ret));
- goto nla_put_failure;
}
- ret = 0;
-
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -6155,7 +2646,7 @@
if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
nl80211_mark_disconnected(drv);
- return nl80211_leave_ibss(drv);
+ return nl80211_leave_ibss(drv, 1);
}
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
return wpa_driver_nl80211_disconnect(drv, reason_code);
@@ -6219,6 +2710,25 @@
}
+static void nl80211_unmask_11b_rates(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
+ return;
+
+ /*
+ * Looks like we failed to unmask 11b rates previously. This could
+ * happen, e.g., if the interface was down at the point in time when a
+ * P2P group was terminated.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
+ bss->ifname);
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+}
+
+
static int wpa_driver_nl80211_authenticate(
struct i802_bss *bss, struct wpa_driver_auth_params *params)
{
@@ -6230,6 +2740,8 @@
int count = 0;
int is_retry;
+ nl80211_unmask_11b_rates(bss);
+
is_retry = drv->retry_auth;
drv->retry_auth = 0;
drv->ignore_deauth_event = 0;
@@ -6248,14 +2760,12 @@
return -1;
retry:
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
+ if (!msg)
+ goto fail;
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
@@ -6268,36 +2778,38 @@
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;
- }
+ params->wep_key[i], params->wep_key_len[i]))
+ goto fail;
}
- 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 (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
}
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+ goto fail;
}
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 (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid))
+ goto fail;
}
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->ie &&
+ nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
+ goto fail;
if (params->sae_data) {
wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
params->sae_data_len);
- NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
- params->sae_data);
+ if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+ params->sae_data))
+ goto fail;
}
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
type = NL80211_AUTHTYPE_OPEN_SYSTEM;
@@ -6310,12 +2822,14 @@
else if (params->auth_alg & WPA_AUTH_ALG_SAE)
type = NL80211_AUTHTYPE_SAE;
else
- goto nla_put_failure;
+ goto fail;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
if (params->local_state_change) {
wpa_printf(MSG_DEBUG, " * Local state change only");
- NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+ if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6383,21 +2897,18 @@
wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
&event);
}
-
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Authentication request send successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
- "successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
-static int wpa_driver_nl80211_authenticate_retry(
- struct wpa_driver_nl80211_data *drv)
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
{
struct wpa_driver_auth_params params;
struct i802_bss *bss = drv->first_bss;
@@ -6435,726 +2946,6 @@
}
-struct phy_info_arg {
- u16 *num_modes;
- struct hostapd_hw_modes *modes;
- int last_mode, last_chan_idx;
-};
-
-static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
- struct nlattr *ampdu_factor,
- struct nlattr *ampdu_density,
- struct nlattr *mcs_set)
-{
- if (capa)
- mode->ht_capab = nla_get_u16(capa);
-
- if (ampdu_factor)
- mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
-
- if (ampdu_density)
- mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
-
- if (mcs_set && nla_len(mcs_set) >= 16) {
- u8 *mcs;
- mcs = nla_data(mcs_set);
- os_memcpy(mode->mcs_set, mcs, 16);
- }
-}
-
-
-static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
- struct nlattr *capa,
- struct nlattr *mcs_set)
-{
- if (capa)
- mode->vht_capab = nla_get_u32(capa);
-
- if (mcs_set && nla_len(mcs_set) >= 8) {
- u8 *mcs;
- mcs = nla_data(mcs_set);
- os_memcpy(mode->vht_mcs_set, mcs, 8);
- }
-}
-
-
-static void phy_info_freq(struct hostapd_hw_modes *mode,
- struct hostapd_channel_data *chan,
- struct nlattr *tb_freq[])
-{
- u8 channel;
- chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
- chan->flag = 0;
- chan->dfs_cac_ms = 0;
- if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
- chan->chan = channel;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- chan->flag |= HOSTAPD_CHAN_DISABLED;
- if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
- chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS;
- if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
- chan->flag |= HOSTAPD_CHAN_RADAR;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
- enum nl80211_dfs_state state =
- nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
-
- switch (state) {
- case NL80211_DFS_USABLE:
- chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
- break;
- case NL80211_DFS_AVAILABLE:
- chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
- break;
- case NL80211_DFS_UNAVAILABLE:
- chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
- break;
- }
- }
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
- chan->dfs_cac_ms = nla_get_u32(
- tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
- }
-}
-
-
-static int phy_info_freqs(struct phy_info_arg *phy_info,
- struct hostapd_hw_modes *mode, struct nlattr *tb)
-{
- 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_NO_IR] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
- [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
- };
- int new_channels = 0;
- struct hostapd_channel_data *channel;
- struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
- struct nlattr *nl_freq;
- int rem_freq, idx;
-
- if (tb == NULL)
- return NL_OK;
-
- nla_for_each_nested(nl_freq, tb, 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;
- new_channels++;
- }
-
- channel = os_realloc_array(mode->channels,
- mode->num_channels + new_channels,
- sizeof(struct hostapd_channel_data));
- if (!channel)
- return NL_SKIP;
-
- mode->channels = channel;
- mode->num_channels += new_channels;
-
- idx = phy_info->last_chan_idx;
-
- nla_for_each_nested(nl_freq, tb, 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;
- phy_info_freq(mode, &mode->channels[idx], tb_freq);
- idx++;
- }
- phy_info->last_chan_idx = idx;
-
- return NL_OK;
-}
-
-
-static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
-{
- static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
- [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
- [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
- { .type = NLA_FLAG },
- };
- struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
- struct nlattr *nl_rate;
- int rem_rate, idx;
-
- if (tb == NULL)
- return NL_OK;
-
- nla_for_each_nested(nl_rate, tb, 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_calloc(mode->num_rates, sizeof(int));
- if (!mode->rates)
- return NL_SKIP;
-
- idx = 0;
-
- nla_for_each_nested(nl_rate, tb, 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] = nla_get_u32(
- tb_rate[NL80211_BITRATE_ATTR_RATE]);
- idx++;
- }
-
- return NL_OK;
-}
-
-
-static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
-{
- struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
- struct hostapd_hw_modes *mode;
- int ret;
-
- if (phy_info->last_mode != nl_band->nla_type) {
- mode = os_realloc_array(phy_info->modes,
- *phy_info->num_modes + 1,
- sizeof(*mode));
- if (!mode)
- return NL_SKIP;
- phy_info->modes = mode;
-
- mode = &phy_info->modes[*(phy_info->num_modes)];
- os_memset(mode, 0, sizeof(*mode));
- mode->mode = NUM_HOSTAPD_MODES;
- mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
- HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
-
- /*
- * Unsupported VHT MCS stream is defined as value 3, so the VHT
- * MCS RX/TX map must be initialized with 0xffff to mark all 8
- * possible streams as unsupported. This will be overridden if
- * driver advertises VHT support.
- */
- mode->vht_mcs_set[0] = 0xff;
- mode->vht_mcs_set[1] = 0xff;
- mode->vht_mcs_set[4] = 0xff;
- mode->vht_mcs_set[5] = 0xff;
-
- *(phy_info->num_modes) += 1;
- phy_info->last_mode = nl_band->nla_type;
- phy_info->last_chan_idx = 0;
- } else
- mode = &phy_info->modes[*(phy_info->num_modes) - 1];
-
- nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
- nla_len(nl_band), NULL);
-
- phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
- tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
- phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
- tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
- if (ret != NL_OK)
- return ret;
- ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
- if (ret != NL_OK)
- return ret;
-
- return NL_OK;
-}
-
-
-static int phy_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct phy_info_arg *phy_info = arg;
- struct nlattr *nl_band;
- int rem_band;
-
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
- return NL_SKIP;
-
- nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
- {
- int res = phy_info_band(phy_info, nl_band);
- if (res != NL_OK)
- return res;
- }
-
- return NL_SKIP;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
- u16 *num_modes)
-{
- u16 m;
- struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
- int i, mode11g_idx = -1;
-
- /* heuristic to set up modes */
- for (m = 0; m < *num_modes; m++) {
- if (!modes[m].num_channels)
- continue;
- if (modes[m].channels[0].freq < 4000) {
- modes[m].mode = HOSTAPD_MODE_IEEE80211B;
- for (i = 0; i < modes[m].num_rates; i++) {
- if (modes[m].rates[i] > 200) {
- modes[m].mode = HOSTAPD_MODE_IEEE80211G;
- break;
- }
- }
- } else if (modes[m].channels[0].freq > 50000)
- modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
- else
- modes[m].mode = HOSTAPD_MODE_IEEE80211A;
- }
-
- /* 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_array(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");
-
- return modes;
-}
-
-
-static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
- int end)
-{
- int c;
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if (chan->freq - 10 >= start && chan->freq + 10 <= end)
- chan->flag |= HOSTAPD_CHAN_HT40;
- }
-}
-
-
-static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
- int end)
-{
- int c;
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if (!(chan->flag & HOSTAPD_CHAN_HT40))
- continue;
- if (chan->freq - 30 >= start && chan->freq - 10 <= end)
- chan->flag |= HOSTAPD_CHAN_HT40MINUS;
- if (chan->freq + 10 >= start && chan->freq + 30 <= end)
- chan->flag |= HOSTAPD_CHAN_HT40PLUS;
- }
-}
-
-
-static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
- struct phy_info_arg *results)
-{
- u16 m;
-
- for (m = 0; m < *results->num_modes; m++) {
- int c;
- struct hostapd_hw_modes *mode = &results->modes[m];
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if ((u32) chan->freq - 10 >= start &&
- (u32) chan->freq + 10 <= end)
- chan->max_tx_power = max_eirp;
- }
- }
-}
-
-
-static void nl80211_reg_rule_ht40(u32 start, u32 end,
- struct phy_info_arg *results)
-{
- u16 m;
-
- for (m = 0; m < *results->num_modes; m++) {
- if (!(results->modes[m].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- continue;
- nl80211_set_ht40_mode(&results->modes[m], start, end);
- }
-}
-
-
-static void nl80211_reg_rule_sec(struct nlattr *tb[],
- struct phy_info_arg *results)
-{
- u32 start, end, max_bw;
- u16 m;
-
- if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
- return;
-
- start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
- end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
- max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-
- if (max_bw < 20)
- return;
-
- for (m = 0; m < *results->num_modes; m++) {
- if (!(results->modes[m].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- continue;
- nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
- }
-}
-
-
-static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
- int end)
-{
- int c;
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if (chan->freq - 10 >= start && chan->freq + 70 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_10_70;
-
- if (chan->freq - 30 >= start && chan->freq + 50 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_30_50;
-
- if (chan->freq - 50 >= start && chan->freq + 30 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_50_30;
-
- if (chan->freq - 70 >= start && chan->freq + 10 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_70_10;
- }
-}
-
-
-static void nl80211_reg_rule_vht(struct nlattr *tb[],
- struct phy_info_arg *results)
-{
- u32 start, end, max_bw;
- u16 m;
-
- if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
- return;
-
- start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
- end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
- max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-
- if (max_bw < 80)
- return;
-
- for (m = 0; m < *results->num_modes; m++) {
- if (!(results->modes[m].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- continue;
- /* TODO: use a real VHT support indication */
- if (!results->modes[m].vht_capab)
- continue;
-
- nl80211_set_vht_mode(&results->modes[m], start, end);
- }
-}
-
-
-static const char * dfs_domain_name(enum nl80211_dfs_regions region)
-{
- switch (region) {
- case NL80211_DFS_UNSET:
- return "DFS-UNSET";
- case NL80211_DFS_FCC:
- return "DFS-FCC";
- case NL80211_DFS_ETSI:
- return "DFS-ETSI";
- case NL80211_DFS_JP:
- return "DFS-JP";
- default:
- return "DFS-invalid";
- }
-}
-
-
-static int nl80211_get_reg(struct nl_msg *msg, void *arg)
-{
- struct phy_info_arg *results = arg;
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *nl_rule;
- struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
- int rem_rule;
- static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
- [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
- [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
- [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
- [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
- [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
- [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
- };
-
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
- if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
- !tb_msg[NL80211_ATTR_REG_RULES]) {
- wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
- "available");
- return NL_SKIP;
- }
-
- if (tb_msg[NL80211_ATTR_DFS_REGION]) {
- enum nl80211_dfs_regions dfs_domain;
- dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
- (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
- dfs_domain_name(dfs_domain));
- } else {
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
- (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
- }
-
- nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
- {
- u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
- nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_rule), nla_len(nl_rule), reg_policy);
- if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
- tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
- continue;
- start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
- end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
- if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
- max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
- if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
- max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
- if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
- flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
-
- wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
- start, end, max_bw, max_eirp,
- flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
- flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
- flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
- flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
- "",
- flags & NL80211_RRF_DFS ? " (DFS)" : "",
- flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
- flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
- flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
- if (max_bw >= 40)
- nl80211_reg_rule_ht40(start, end, results);
- if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
- nl80211_reg_rule_max_eirp(start, end, max_eirp,
- results);
- }
-
- nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
- {
- nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_rule), nla_len(nl_rule), reg_policy);
- nl80211_reg_rule_sec(tb_rule, results);
- }
-
- nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
- {
- nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_rule), nla_len(nl_rule), reg_policy);
- nl80211_reg_rule_vht(tb_rule, results);
- }
-
- return NL_SKIP;
-}
-
-
-static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
- struct phy_info_arg *results)
-{
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
- return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
- u32 feat;
- 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,
- .modes = NULL,
- .last_mode = -1,
- };
-
- *num_modes = 0;
- *flags = 0;
-
- msg = nlmsg_alloc();
- if (!msg)
- return NULL;
-
- feat = get_nl80211_protocol_features(drv);
- if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
- else
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
-
- NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
- nl80211_set_regulatory_flags(drv, &result);
- return wpa_driver_nl80211_postprocess_modes(result.modes,
- num_modes);
- }
- msg = NULL;
- nla_put_failure:
- nlmsg_free(msg);
- return NULL;
-}
-
-
-static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
- const void *data, size_t len,
- int encrypt, int noack)
-{
- __u8 rtap_hdr[] = {
- 0x00, 0x00, /* radiotap version */
- 0x0e, 0x00, /* radiotap length */
- 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
- 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 */
- };
- struct iovec iov[2] = {
- {
- .iov_base = &rtap_hdr,
- .iov_len = sizeof(rtap_hdr),
- },
- {
- .iov_base = (void *) data,
- .iov_len = len,
- }
- };
- struct msghdr msg = {
- .msg_name = NULL,
- .msg_namelen = 0,
- .msg_iov = iov,
- .msg_iovlen = 2,
- .msg_control = NULL,
- .msg_controllen = 0,
- .msg_flags = 0,
- };
- int res;
- u16 txflags = 0;
-
- if (encrypt)
- rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
-
- if (drv->monitor_sock < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
- "for %s", __func__);
- return -1;
- }
-
- if (noack)
- txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
- WPA_PUT_LE16(&rtap_hdr[12], txflags);
-
- res = sendmsg(drv->monitor_sock, &msg, 0);
- if (res < 0) {
- wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-
static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
const void *data, size_t len,
int encrypt, int noack,
@@ -7178,10 +2969,9 @@
}
if (drv->use_monitor) {
- wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+ wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
freq, bss->freq);
- return wpa_driver_nl80211_send_mntr(drv, data, len,
- encrypt, noack);
+ return nl80211_send_monitor(drv, data, len, encrypt, noack);
}
wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
@@ -7287,22 +3077,18 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
-
- if (cts >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
- if (preamble >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
- if (slot >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
- if (ht_opmode >= 0)
- NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
- if (ap_isolate >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
+ (cts >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
+ (preamble >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
+ (slot >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
+ (ht_opmode >= 0 &&
+ nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
+ (ap_isolate >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)))
+ goto fail;
if (basic_rates) {
u8 rates[NL80211_MAX_SUPP_RATES];
@@ -7313,13 +3099,13 @@
i++)
rates[rates_len++] = basic_rates[i] / 5;
- NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+ if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
+ rates))
+ goto fail;
}
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -7333,7 +3119,7 @@
struct nl_msg *msg;
struct nlattr *acl;
unsigned int i;
- int ret = 0;
+ int ret;
if (!(drv->capa.max_acl_mac_addrs))
return -ENOTSUP;
@@ -7341,40 +3127,33 @@
if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
return -ENOTSUP;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
+ nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
+ (acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS)) == NULL) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
- NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
- NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
-
- acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
- if (acl == NULL)
- goto nla_put_failure;
-
- for (i = 0; i < params->num_mac_acl; i++)
- NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+ for (i = 0; i < params->num_mac_acl; i++) {
+ if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+ }
nla_nest_end(msg, acl);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
ret, strerror(-ret));
}
-nla_put_failure:
- nlmsg_free(msg);
-
return ret;
}
@@ -7388,75 +3167,81 @@
u8 cmd = NL80211_CMD_NEW_BEACON;
int ret;
int beacon_set;
- int ifindex = if_nametoindex(bss->ifname);
int num_suites;
+ int smps_mode;
u32 suites[10], suite;
u32 ver;
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;
- nl80211_cmd(drv, msg, 0, cmd);
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
params->head, params->head_len);
- NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
params->tail, params->tail_len);
- NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
- wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
- NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
params->ssid, params->ssid_len);
- NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
- params->ssid);
+ if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+ nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
+ params->head) ||
+ nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
+ params->tail) ||
+ nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ params->beacon_int) ||
+ nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+ goto fail;
if (params->proberesp && params->proberesp_len) {
wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
params->proberesp, params->proberesp_len);
- NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
- params->proberesp);
+ if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+ params->proberesp))
+ goto fail;
}
switch (params->hide_ssid) {
case NO_SSID_HIDING:
wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
- NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
- NL80211_HIDDEN_SSID_NOT_IN_USE);
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_NOT_IN_USE))
+ goto fail;
break;
case HIDDEN_SSID_ZERO_LEN:
wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
- NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
- NL80211_HIDDEN_SSID_ZERO_LEN);
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_LEN))
+ goto fail;
break;
case HIDDEN_SSID_ZERO_CONTENTS:
wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
- NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
- NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS))
+ goto fail;
break;
}
wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
- if (params->privacy)
- NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ if (params->privacy &&
+ nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
(WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
/* Leave out the attribute */
- } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
- NL80211_AUTHTYPE_SHARED_KEY);
- else
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
- NL80211_AUTHTYPE_OPEN_SYSTEM);
+ } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_SHARED_KEY))
+ goto fail;
+ } else {
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_OPEN_SYSTEM))
+ goto fail;
+ }
wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
ver = 0;
@@ -7464,8 +3249,9 @@
ver |= NL80211_WPA_VERSION_1;
if (params->wpa_version & WPA_PROTO_RSN)
ver |= NL80211_WPA_VERSION_2;
- if (ver)
- NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ if (ver &&
+ nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
params->key_mgmt_suites);
@@ -7474,56 +3260,82 @@
suites[num_suites++] = WLAN_AKM_SUITE_8021X;
if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
suites[num_suites++] = WLAN_AKM_SUITE_PSK;
- if (num_suites) {
- NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
- num_suites * sizeof(u32), suites);
- }
+ if (num_suites &&
+ nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+ suites))
+ goto fail;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
- params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
suites, ARRAY_SIZE(suites));
- if (num_suites) {
- NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
- num_suites * sizeof(u32), suites);
- }
+ if (num_suites &&
+ nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ num_suites * sizeof(u32), suites))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
params->group_cipher);
suite = wpa_cipher_to_cipher_suite(params->group_cipher);
- if (suite)
- NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite);
+ if (suite &&
+ nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
+ goto fail;
+
+ switch (params->smps_mode) {
+ case HT_CAP_INFO_SMPS_DYNAMIC:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
+ smps_mode = NL80211_SMPS_DYNAMIC;
+ break;
+ case HT_CAP_INFO_SMPS_STATIC:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
+ smps_mode = NL80211_SMPS_STATIC;
+ break;
+ default:
+ /* invalid - fallback to smps off */
+ case HT_CAP_INFO_SMPS_DISABLED:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
+ smps_mode = NL80211_SMPS_OFF;
+ break;
+ }
+ if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+ goto fail;
if (params->beacon_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
params->beacon_ies);
- NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
- wpabuf_head(params->beacon_ies));
+ if (nla_put(msg, NL80211_ATTR_IE,
+ wpabuf_len(params->beacon_ies),
+ wpabuf_head(params->beacon_ies)))
+ goto fail;
}
if (params->proberesp_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
params->proberesp_ies);
- NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
- wpabuf_len(params->proberesp_ies),
- wpabuf_head(params->proberesp_ies));
+ if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+ wpabuf_len(params->proberesp_ies),
+ wpabuf_head(params->proberesp_ies)))
+ goto fail;
}
if (params->assocresp_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
params->assocresp_ies);
- NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
- wpabuf_len(params->assocresp_ies),
- wpabuf_head(params->assocresp_ies));
+ if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ wpabuf_len(params->assocresp_ies),
+ wpabuf_head(params->assocresp_ies)))
+ goto fail;
}
if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
params->ap_max_inactivity);
- NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
- params->ap_max_inactivity);
+ if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+ params->ap_max_inactivity))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7561,65 +3373,67 @@
}
}
return ret;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
static int nl80211_put_freq_params(struct nl_msg *msg,
- struct hostapd_freq_params *freq)
+ const struct hostapd_freq_params *freq)
{
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+ return -ENOBUFS;
+
if (freq->vht_enabled) {
+ enum nl80211_chan_width cw;
+
switch (freq->bandwidth) {
case 20:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_20);
+ cw = NL80211_CHAN_WIDTH_20;
break;
case 40:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_40);
+ cw = NL80211_CHAN_WIDTH_40;
break;
case 80:
if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80P80);
+ cw = NL80211_CHAN_WIDTH_80P80;
else
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80);
+ cw = NL80211_CHAN_WIDTH_80;
break;
case 160:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_160);
+ cw = NL80211_CHAN_WIDTH_160;
break;
default:
return -EINVAL;
}
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
- if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
- freq->center_freq2);
+
+ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
+ freq->center_freq1) ||
+ (freq->center_freq2 &&
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
+ freq->center_freq2)))
+ return -ENOBUFS;
} else if (freq->ht_enabled) {
+ enum nl80211_channel_type ct;
+
switch (freq->sec_channel_offset) {
case -1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40MINUS);
+ ct = NL80211_CHAN_HT40MINUS;
break;
case 1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40PLUS);
+ ct = NL80211_CHAN_HT40PLUS;
break;
default:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT20);
+ ct = NL80211_CHAN_HT20;
break;
}
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
+ return -ENOBUFS;
}
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
@@ -7634,27 +3448,21 @@
"nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
freq->freq, freq->ht_enabled, freq->vht_enabled,
freq->bandwidth, freq->center_freq1, freq->center_freq2);
- msg = nlmsg_alloc();
- if (!msg)
+
+ msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ NL80211_CMD_SET_WIPHY);
+ if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
- NL80211_CMD_SET_WIPHY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- if (nl80211_put_freq_params(msg, freq) < 0)
- goto nla_put_failure;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret == 0) {
bss->freq = freq->freq;
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
"%d (%s)", freq->freq, ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -7673,11 +3481,40 @@
f |= BIT(NL80211_STA_FLAG_MFP);
if (flags & WPA_STA_TDLS_PEER)
f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (flags & WPA_STA_AUTHENTICATED)
+ f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
return f;
}
+#ifdef CONFIG_MESH
+static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
+{
+ switch (state) {
+ case PLINK_LISTEN:
+ return NL80211_PLINK_LISTEN;
+ case PLINK_OPEN_SENT:
+ return NL80211_PLINK_OPN_SNT;
+ case PLINK_OPEN_RCVD:
+ return NL80211_PLINK_OPN_RCVD;
+ case PLINK_CNF_RCVD:
+ return NL80211_PLINK_CNF_RCVD;
+ case PLINK_ESTAB:
+ return NL80211_PLINK_ESTAB;
+ case PLINK_HOLDING:
+ return NL80211_PLINK_HOLDING;
+ case PLINK_BLOCKED:
+ return NL80211_PLINK_BLOCKED;
+ default:
+ wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
+ state);
+ }
+ return -1;
+}
+#endif /* CONFIG_MESH */
+
+
static int wpa_driver_nl80211_sta_add(void *priv,
struct hostapd_sta_add_params *params)
{
@@ -7691,25 +3528,57 @@
!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
return -EOPNOTSUPP;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
params->set ? "Set" : "Add", MAC2STR(params->addr));
- nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
- NL80211_CMD_NEW_STATION);
+ msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
+ NL80211_CMD_NEW_STATION);
+ if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+ goto fail;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
- params->supp_rates);
- wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates,
- params->supp_rates_len);
+ if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
+ wpa_hexdump(MSG_DEBUG, " * supported rates",
+ params->supp_rates, params->supp_rates_len);
+ wpa_printf(MSG_DEBUG, " * capability=0x%x",
+ params->capability);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
+ params->supp_rates_len, params->supp_rates) ||
+ nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
+ params->capability))
+ goto fail;
+
+ if (params->ht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
+ (u8 *) params->ht_capabilities,
+ sizeof(*params->ht_capabilities));
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
+ sizeof(*params->ht_capabilities),
+ params->ht_capabilities))
+ goto fail;
+ }
+
+ if (params->vht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
+ (u8 *) params->vht_capabilities,
+ sizeof(*params->vht_capabilities));
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
+ sizeof(*params->vht_capabilities),
+ params->vht_capabilities))
+ goto fail;
+ }
+
+ if (params->ext_capab) {
+ wpa_hexdump(MSG_DEBUG, " * ext_capab",
+ params->ext_capab, params->ext_capab_len);
+ if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+ params->ext_capab_len, params->ext_capab))
+ goto fail;
+ }
+ }
if (!params->set) {
if (params->aid) {
wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
+ goto fail;
} else {
/*
* cfg80211 validates that AID is non-zero, so we have
@@ -7717,85 +3586,71 @@
* a dummy STA entry is used for now.
*/
wpa_printf(MSG_DEBUG, " * aid=1 (TDLS workaround)");
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
+ goto fail;
}
wpa_printf(MSG_DEBUG, " * listen_interval=%u",
params->listen_interval);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
- params->listen_interval);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval))
+ goto fail;
} else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
- NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
- }
- if (params->ht_capabilities) {
- wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
- (u8 *) params->ht_capabilities,
- sizeof(*params->ht_capabilities));
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
- sizeof(*params->ht_capabilities),
- params->ht_capabilities);
- }
-
- if (params->vht_capabilities) {
- wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
- (u8 *) params->vht_capabilities,
- sizeof(*params->vht_capabilities));
- NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
- sizeof(*params->vht_capabilities),
- params->vht_capabilities);
+ if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
+ goto fail;
}
if (params->vht_opmode_enabled) {
wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
- NLA_PUT_U8(msg, NL80211_ATTR_OPMODE_NOTIF,
- params->vht_opmode);
- }
-
- wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
-
- if (params->ext_capab) {
- wpa_hexdump(MSG_DEBUG, " * ext_capab",
- params->ext_capab, params->ext_capab_len);
- NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
- params->ext_capab_len, params->ext_capab);
+ if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
+ params->vht_opmode))
+ goto fail;
}
if (params->supp_channels) {
wpa_hexdump(MSG_DEBUG, " * supported channels",
params->supp_channels, params->supp_channels_len);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
- params->supp_channels_len, params->supp_channels);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+ params->supp_channels_len, params->supp_channels))
+ goto fail;
}
if (params->supp_oper_classes) {
wpa_hexdump(MSG_DEBUG, " * supported operating classes",
params->supp_oper_classes,
params->supp_oper_classes_len);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
- params->supp_oper_classes_len,
- params->supp_oper_classes);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+ params->supp_oper_classes_len,
+ params->supp_oper_classes))
+ goto fail;
}
os_memset(&upd, 0, sizeof(upd));
- upd.mask = sta_flags_nl80211(params->flags);
- upd.set = upd.mask;
+ upd.set = sta_flags_nl80211(params->flags);
+ upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
upd.set, upd.mask);
- NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+ if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+ goto fail;
+
+#ifdef CONFIG_MESH
+ if (params->plink_state &&
+ nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
+ sta_plink_state_nl80211(params->plink_state)))
+ goto fail;
+#endif /* CONFIG_MESH */
if (params->flags & WPA_STA_WMM) {
struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
- if (!wme)
- goto nla_put_failure;
-
wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
- NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
- params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
- NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
- (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
- WMM_QOSINFO_STA_SP_MASK);
+ if (!wme ||
+ nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
+ params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
+ nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
+ (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
+ WMM_QOSINFO_STA_SP_MASK))
+ goto fail;
nla_nest_end(msg, wme);
}
@@ -7807,7 +3662,7 @@
strerror(-ret));
if (ret == -EEXIST)
ret = 0;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -7850,21 +3705,26 @@
}
-static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
+ int deauth, u16 reason_code)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ (deauth == 0 &&
+ nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+ WLAN_FC_STYPE_DISASSOC)) ||
+ (deauth == 1 &&
+ nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+ WLAN_FC_STYPE_DEAUTH)) ||
+ (reason_code &&
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
@@ -7877,14 +3737,10 @@
if (ret == -ENOENT)
return 0;
return ret;
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
- int ifidx)
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
{
struct nl_msg *msg;
struct wpa_driver_nl80211_data *drv2;
@@ -7896,18 +3752,9 @@
struct wpa_driver_nl80211_data, list)
del_ifidx(drv2, ifidx);
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
-
+ msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return;
- msg = NULL;
- nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
}
@@ -7955,40 +3802,37 @@
wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
iftype, nl80211_iftype_str(iftype));
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
- NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
+ if (!msg ||
+ nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
+ nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
+ goto fail;
if (iftype == NL80211_IFTYPE_MONITOR) {
struct nlattr *flags;
flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
- if (!flags)
- goto nla_put_failure;
-
- NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
+ if (!flags ||
+ nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
+ goto fail;
nla_nest_end(msg, flags);
} else if (wds) {
- NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
+ if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
+ goto fail;
}
/*
* Tell cfg80211 that the interface belongs to the socket that created
* it, and the interface should be deleted when the socket is closed.
*/
- NLA_PUT_FLAG(msg, NL80211_ATTR_IFACE_SOCKET_OWNER);
+ if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+ goto fail;
ret = send_and_recv_msgs(drv, msg, handler, arg);
msg = NULL;
if (ret) {
- nla_put_failure:
+ fail:
nlmsg_free(msg);
wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
ifname, ret, strerror(-ret));
@@ -8027,11 +3871,11 @@
}
-static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
- const char *ifname, enum nl80211_iftype iftype,
- const u8 *addr, int wds,
- int (*handler)(struct nl_msg *, void *),
- void *arg, int use_existing)
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg, int use_existing)
{
int ret;
@@ -8065,426 +3909,17 @@
wds, handler, arg);
}
- if (ret >= 0 && is_p2p_net_interface(iftype))
+ if (ret >= 0 && is_p2p_net_interface(iftype)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s created for P2P - disable 11b rates",
+ ifname);
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)
-{
- struct ieee80211_hdr *hdr = (void *)buf;
- u16 fc;
- union wpa_event_data event;
-
- if (len < sizeof(*hdr))
- return;
-
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
- event.rx_from_unknown.addr = hdr->addr2;
- event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
- (WLAN_FC_FROMDS | WLAN_FC_TODS);
- wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-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) {
- wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
- strerror(errno));
- return;
- }
-
- if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
- wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
- return;
- }
-
- while (1) {
- ret = ieee80211_radiotap_iterator_next(&iter);
- if (ret == -ENOENT)
- break;
- if (ret) {
- wpa_printf(MSG_INFO, "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((*(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_DBM_ANTSIGNAL:
- ssi_signal = (s8) *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.
- *
- * For now allow all To DS data frames through.
- */
- /* load the IEEE 802.11 frame control field */
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
- /* mask off frame type, version and DS status */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
- /* accept frame if version 0, type 2 and To DS, fall through otherwise
- */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
-
-#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 = ARRAY_SIZE(msock_filter_insns),
- .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))) {
- wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
- strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-
-static void nl80211_remove_monitor_interface(
- struct wpa_driver_nl80211_data *drv)
-{
- if (drv->monitor_refcount > 0)
- drv->monitor_refcount--;
- wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
- drv->monitor_refcount);
- if (drv->monitor_refcount > 0)
- return;
-
- if (drv->monitor_ifidx >= 0) {
- nl80211_remove_iface(drv, drv->monitor_ifidx);
- drv->monitor_ifidx = -1;
- }
- 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;
-
- if (drv->monitor_ifidx >= 0) {
- drv->monitor_refcount++;
- wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
- drv->monitor_refcount);
- return 0;
- }
-
- if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
- /*
- * P2P interface name is of the format p2p-%s-%d. For monitor
- * interface name corresponding to P2P GO, replace "p2p-" with
- * "mon-" to retain the same interface name length and to
- * indicate that it is a monitor interface.
- */
- snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
- } else {
- /* Non-P2P interface with AP functionality. */
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
- }
-
- buf[IFNAMSIZ - 1] = '\0';
-
- drv->monitor_ifidx =
- nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
- 0, NULL, NULL, 0);
-
- if (drv->monitor_ifidx == -EOPNOTSUPP) {
- /*
- * This is backward compatibility for a few versions of
- * the kernel only that didn't advertise the right
- * attributes for the only driver that then supported
- * AP mode w/o monitor -- ath6kl.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
- "monitor interface type - try to run without it");
- drv->device_ap_sme = 1;
- }
-
- if (drv->monitor_ifidx < 0)
- return -1;
-
- if (linux_set_iface_flags(drv->global->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) {
- wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
- strerror(errno));
- 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) {
- wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
- strerror(errno));
- goto error;
- }
-
- optlen = sizeof(optval);
- optval = 20;
- if (setsockopt
- (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
- strerror(errno));
- goto error;
- }
-
- if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
- drv, NULL)) {
- wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
- goto error;
- }
-
- drv->monitor_refcount++;
- return 0;
- error:
- nl80211_remove_monitor_interface(drv);
- return -1;
-}
-
-
static int nl80211_setup_ap(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -8643,7 +4078,6 @@
int flags_or, int flags_and)
{
struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *flags;
struct nl80211_sta_flag_update upd;
@@ -8653,47 +4087,38 @@
bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
!!(total_flags & WPA_STA_AUTHORIZED));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
/*
* Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
* can be removed eventually.
*/
flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
- if (!flags)
- goto nla_put_failure;
- if (total_flags & WPA_STA_AUTHORIZED)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
-
- if (total_flags & WPA_STA_WMM)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
-
- if (total_flags & WPA_STA_SHORT_PREAMBLE)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
-
- if (total_flags & WPA_STA_MFP)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
-
- if (total_flags & WPA_STA_TDLS_PEER)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
+ if (!flags ||
+ ((total_flags & WPA_STA_AUTHORIZED) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
+ ((total_flags & WPA_STA_WMM) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
+ ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
+ ((total_flags & WPA_STA_MFP) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
+ ((total_flags & WPA_STA_TDLS_PEER) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
+ goto fail;
nla_nest_end(msg, flags);
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);
+ if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+ goto fail;
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -8728,36 +4153,29 @@
}
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+ int reset_mode)
{
struct nl_msg *msg;
- int ret = -1;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
"(%s)", ret, strerror(-ret));
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Leave IBSS request sent successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
-
-nla_put_failure:
- if (wpa_driver_nl80211_set_mode(drv->first_bss,
+ if (reset_mode &&
+ wpa_driver_nl80211_set_mode(drv->first_bss,
NL80211_IFTYPE_STATION)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"station mode");
}
- nlmsg_free(msg);
return ret;
}
@@ -8778,20 +4196,14 @@
}
retry:
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
- goto nla_put_failure;
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
+ params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
+ goto fail;
wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
params->ssid, params->ssid_len);
- NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
- params->ssid);
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+ goto fail;
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
drv->ssid_len = params->ssid_len;
@@ -8804,22 +4216,24 @@
wpa_printf(MSG_DEBUG, " * center_freq2=%d", params->freq.center_freq2);
wpa_printf(MSG_DEBUG, " * bandwidth=%d", params->freq.bandwidth);
if (nl80211_put_freq_params(msg, ¶ms->freq) < 0)
- goto nla_put_failure;
+ goto fail;
if (params->beacon_int > 0) {
wpa_printf(MSG_DEBUG, " * beacon_int=%d", params->beacon_int);
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL,
- params->beacon_int);
+ if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ params->beacon_int))
+ goto fail;
}
ret = nl80211_set_conn_keys(params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
if (params->bssid && params->fixed_bssid) {
wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
MAC2STR(params->bssid));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
}
if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -8827,15 +4241,17 @@
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
wpa_printf(MSG_DEBUG, " * control port");
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+ if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+ goto fail;
}
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);
+ if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8847,17 +4263,16 @@
if (ret == -EALREADY && count == 1) {
wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
"forced leave");
- nl80211_leave_ibss(drv);
+ nl80211_leave_ibss(drv, 0);
nlmsg_free(msg);
goto retry;
}
-
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Join IBSS request sent successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -8867,56 +4282,61 @@
struct wpa_driver_associate_params *params,
struct nl_msg *msg)
{
- 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 (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ return -1;
}
if (params->bssid_hint) {
wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
MAC2STR(params->bssid_hint));
- NLA_PUT(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
- params->bssid_hint);
+ if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
+ params->bssid_hint))
+ return -1;
}
if (params->freq.freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq.freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+ params->freq.freq))
+ return -1;
drv->assoc_freq = params->freq.freq;
} else
drv->assoc_freq = 0;
if (params->freq_hint) {
wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
- params->freq_hint);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
+ params->freq_hint))
+ return -1;
}
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
- NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
- params->bg_scan_period);
+ if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+ params->bg_scan_period))
+ return -1;
}
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 (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid))
+ return -1;
if (params->ssid_len > sizeof(drv->ssid))
- goto nla_put_failure;
+ return -1;
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->wpa_ie &&
+ nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
+ return -1;
if (params->wpa_proto) {
enum nl80211_wpa_versions ver = 0;
@@ -8927,13 +4347,16 @@
ver |= NL80211_WPA_VERSION_2;
wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
- NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+ return -1;
}
if (params->pairwise_suite != WPA_CIPHER_NONE) {
u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
- NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+ if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ cipher))
+ return -1;
}
if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
@@ -8946,7 +4369,8 @@
} else if (params->group_suite != WPA_CIPHER_NONE) {
u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
- NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+ if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
+ return -1;
}
if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -8956,7 +4380,8 @@
params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
@@ -8981,47 +4406,67 @@
case WPA_KEY_MGMT_OSEN:
mgmt = WLAN_AKM_SUITE_OSEN;
break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
+ break;
case WPA_KEY_MGMT_PSK:
default:
mgmt = WLAN_AKM_SUITE_PSK;
break;
}
wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
- NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+ if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
+ return -1;
}
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+ if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+ return -1;
- if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
- NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ return -1;
- if (params->disable_ht)
- NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+ if (params->rrm_used) {
+ u32 drv_rrm_flags = drv->capa.rrm_flags;
+ if (!(drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
+ !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) ||
+ nla_put_flag(msg, NL80211_ATTR_USE_RRM))
+ return -1;
+ }
+
+ if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+ return -1;
if (params->htcaps && params->htcaps_mask) {
int sz = sizeof(struct ieee80211_ht_capabilities);
wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
params->htcaps_mask, sz);
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
- params->htcaps_mask);
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+ params->htcaps) ||
+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+ params->htcaps_mask))
+ return -1;
}
#ifdef CONFIG_VHT_OVERRIDES
if (params->disable_vht) {
wpa_printf(MSG_DEBUG, " * VHT disabled");
- NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+ if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+ return -1;
}
if (params->vhtcaps && params->vhtcaps_mask) {
int sz = sizeof(struct ieee80211_vht_capabilities);
wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
- NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
params->vhtcaps_mask, sz);
- NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
- params->vhtcaps_mask);
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+ params->vhtcaps) ||
+ nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask))
+ return -1;
}
#endif /* CONFIG_VHT_OVERRIDES */
@@ -9029,8 +4474,6 @@
wpa_printf(MSG_DEBUG, " * P2P group");
return 0;
-nla_put_failure:
- return -1;
}
@@ -9043,16 +4486,24 @@
int ret;
int algs;
- msg = nlmsg_alloc();
+ if (params->req_key_mgmt_offload && params->psk &&
+ (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
+ ret = issue_key_mgmt_set_key(drv, params->psk, 32);
+ if (ret)
+ return ret;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
if (!msg)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
-
ret = nl80211_connect_common(drv, params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
algs = 0;
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
@@ -9076,27 +4527,28 @@
else if (params->auth_alg & WPA_AUTH_ALG_FT)
type = NL80211_AUTHTYPE_FT;
else
- goto nla_put_failure;
+ goto fail;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
skip_auth_type:
ret = nl80211_set_conn_keys(params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
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;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect request send successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
@@ -9139,9 +4591,11 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret;
+ int ret = -1;
struct nl_msg *msg;
+ nl80211_unmask_11b_rates(bss);
+
if (params->mode == IEEE80211_MODE_AP)
return wpa_driver_nl80211_ap(drv, params);
@@ -9159,23 +4613,22 @@
nl80211_mark_disconnected(drv);
- msg = nlmsg_alloc();
+ wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
+ drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
if (!msg)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
- drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
-
ret = nl80211_connect_common(drv, params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
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);
+ if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+ params->prev_bssid))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -9185,13 +4638,12 @@
"nl80211: MLME command failed (assoc): ret=%d (%s)",
ret, strerror(-ret));
nl80211_dump_scan(drv);
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Association request send successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Association request send "
- "successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -9206,20 +4658,15 @@
wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
ifindex, mode, nl80211_iftype_str(mode));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
+ goto fail;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (!ret)
return 0;
-nla_put_failure:
+fail:
nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
" %d (%s)", ifindex, mode, ret, strerror(-ret));
@@ -9281,7 +4728,7 @@
* on a frequency that the mode is disallowed in.
*/
if (desired_freq_params) {
- res = i802_set_freq(bss, desired_freq_params);
+ res = nl80211_set_channel(bss, desired_freq_params, 0);
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Failed to set frequency on interface");
@@ -9322,10 +4769,17 @@
return ret;
}
- if (is_p2p_net_interface(nlmode))
+ if (is_p2p_net_interface(nlmode)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode change to P2P - disable 11b rates",
+ bss->ifname);
nl80211_disable_11b_rates(drv, drv->ifindex, 1);
- else if (drv->disabled_11b_rates)
+ } else if (drv->disabled_11b_rates) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
+ bss->ifname);
nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+ }
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
@@ -9339,7 +4793,12 @@
nl80211_mgmt_unsubscribe(bss, "mode change");
}
+ if (is_mesh_interface(nlmode) &&
+ nl80211_mgmt_subscribe_mesh(bss))
+ return -1;
+
if (!bss->in_deinit && !is_ap_interface(nlmode) &&
+ !is_mesh_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)
wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
"frame processing - ignore for now");
@@ -9348,37 +4807,8 @@
}
-static int dfs_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- int *dfs_capability_ptr = arg;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
- struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
-
- nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
- nla_data(nl_vend), nla_len(nl_vend), NULL);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
- u32 val;
- val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
- wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
- val);
- *dfs_capability_ptr = val;
- }
- }
-
- return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
- enum nl80211_iftype nlmode)
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode)
{
return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
}
@@ -9397,9 +4827,6 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
- int dfs_capability = 0;
- int ret = 0;
if (!drv->has_capability)
return -1;
@@ -9410,37 +4837,7 @@
capa->extended_capa_len = drv->extended_capa_len;
}
- if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
- !drv->allow_p2p_device) {
- wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
- capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
- }
-
- if (drv->dfs_vendor_cmd_avail == 1) {
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
- QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY);
-
- ret = send_and_recv_msgs(drv, msg, dfs_info_handler,
- &dfs_capability);
- if (!ret) {
- if (dfs_capability)
- capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
- }
- }
-
- return ret;
-
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
+ return 0;
}
@@ -9464,7 +4861,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
- int ret = -ENOBUFS;
+ int ret;
if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
@@ -9474,28 +4871,21 @@
wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
- 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);
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
+ nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (!ret)
return 0;
- nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
ret, strerror(-ret));
return ret;
@@ -9546,23 +4936,18 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
-
- 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));
+ msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
+ NL80211_CMD_GET_KEY);
+ if (!msg ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
memset(seq, 0, 6);
return send_and_recv_msgs(drv, msg, get_key_handler, seq);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -9571,28 +4956,23 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -ENOBUFS;
+ int ret;
u32 val;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
if (rts >= 2347)
val = (u32) -1;
else
val = rts;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (!ret)
return 0;
-nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
"%d (%s)", rts, ret, strerror(-ret));
return ret;
@@ -9604,28 +4984,23 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -ENOBUFS;
+ int ret;
u32 val;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
if (frag >= 2346)
val = (u32) -1;
else
val = frag;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (!ret)
return 0;
-nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
"%d: %d (%s)", frag, ret, strerror(-ret));
return ret;
@@ -9635,33 +5010,22 @@
static int i802_flush(void *priv)
{
struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int res;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
bss->ifname);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
/*
* XXX: FIX! this needs to flush all VLANs too
*/
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
-
- res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
+ res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
if (res) {
wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
"(%s)", res, strerror(-res));
}
return res;
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -9724,23 +5088,17 @@
struct hostap_sta_driver_data *data,
const u8 *addr)
{
- 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;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
- return send_and_recv_msgs(drv, msg, get_sta_handler, data);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
+ return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
}
@@ -9752,43 +5110,45 @@
struct nl_msg *msg;
struct nlattr *txq, *params;
- msg = nlmsg_alloc();
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-
- 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;
+ goto fail;
/* We are only sending parameters for a single TXQ at a time */
params = nla_nest_start(msg, 1);
if (!params)
- goto nla_put_failure;
+ goto fail;
switch (queue) {
case 0:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
+ goto fail;
break;
case 1:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
+ goto fail;
break;
case 2:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
+ goto fail;
break;
case 3:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
+ goto fail;
break;
}
/* 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);
+ if (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))
+ goto fail;
nla_nest_end(msg, params);
@@ -9797,7 +5157,7 @@
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return 0;
msg = NULL;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return -1;
}
@@ -9808,34 +5168,26 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -ENOBUFS;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
+ int ret;
wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
", ifname=%s[%d], vlan_id=%d)",
bss->ifname, if_nametoindex(bss->ifname),
MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
- 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));
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
MAC2STR(addr), ifname, vlan_id, ret,
strerror(-ret));
}
- nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -9869,8 +5221,11 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
if (drv->device_ap_sme)
- return wpa_driver_nl80211_sta_remove(bss, addr);
+ return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -9893,8 +5248,11 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
if (drv->device_ap_sme)
- return wpa_driver_nl80211_sta_remove(bss, addr);
+ return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -9922,7 +5280,7 @@
if (!drv->if_indices[i])
continue;
res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
break;
pos += res;
}
@@ -10071,12 +5429,12 @@
struct i802_bss *bss,
const char *brname, const char *ifname)
{
- int ifindex;
+ int br_ifindex;
char in_br[IFNAMSIZ];
os_strlcpy(bss->brname, brname, IFNAMSIZ);
- ifindex = if_nametoindex(brname);
- if (ifindex == 0) {
+ br_ifindex = if_nametoindex(brname);
+ if (br_ifindex == 0) {
/*
* Bridge was configured, but the bridge device does
* not exist. Try to add it now.
@@ -10088,8 +5446,10 @@
return -1;
}
bss->added_bridge = 1;
- add_ifidx(drv, if_nametoindex(brname));
+ br_ifindex = if_nametoindex(brname);
+ add_ifidx(drv, br_ifindex);
}
+ bss->br_ifindex = br_ifindex;
if (linux_br_get(in_br, ifname) == 0) {
if (os_strcmp(in_br, brname) == 0)
@@ -10133,7 +5493,7 @@
bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
params->global_priv, 1,
- params->bssid);
+ params->bssid, params->driver_params);
if (bss == NULL)
return NULL;
@@ -10143,10 +5503,12 @@
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
params->ifname, brname);
br_ifindex = if_nametoindex(brname);
+ os_strlcpy(bss->brname, brname, IFNAMSIZ);
} else {
brname[0] = '\0';
br_ifindex = 0;
}
+ bss->br_ifindex = br_ifindex;
for (i = 0; i < params->num_bridge; i++) {
if (params->bridge[i]) {
@@ -10157,16 +5519,21 @@
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 (params->num_bridge && params->bridge[0] &&
- i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
- goto failed;
+ if (params->num_bridge && params->bridge[0]) {
+ if (i802_check_bridge(drv, bss, params->bridge[0],
+ params->ifname) < 0)
+ goto failed;
+ if (os_strcmp(params->bridge[0], brname) != 0)
+ br_added = 1;
+ }
+
+ if (!br_added && br_ifindex &&
+ (params->num_bridge == 0 || !params->bridge[0]))
+ add_ifidx(drv, br_ifindex);
#ifdef CONFIG_LIBNL3_ROUTE
if (bss->added_if_into_bridge) {
@@ -10236,12 +5603,14 @@
return NL80211_IFTYPE_P2P_GO;
case WPA_IF_P2P_DEVICE:
return NL80211_IFTYPE_P2P_DEVICE;
+ case WPA_IF_MESH:
+ return NL80211_IFTYPE_MESH_POINT;
}
return -1;
}
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
{
@@ -10255,8 +5624,7 @@
}
-static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
- u8 *new_addr)
+static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
{
unsigned int idx;
@@ -10273,13 +5641,13 @@
if (idx == 64)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
+ wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
MACSTR, MAC2STR(new_addr));
return 0;
}
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
struct wdev_info {
@@ -10366,10 +5734,10 @@
}
}
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
if (!addr &&
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
- type == WPA_IF_P2P_GO)) {
+ type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
/* Enforce unique P2P Interface Address */
u8 new_addr[ETH_ALEN];
@@ -10381,8 +5749,9 @@
}
if (nl80211_addr_in_use(drv->global, new_addr)) {
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
- "for P2P group interface");
- if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
+ "for %s interface", type == WPA_IF_MESH ?
+ "mesh" : "P2P group");
+ if (nl80211_vif_addr(drv, new_addr) < 0) {
if (added)
nl80211_remove_iface(drv, ifidx);
return -1;
@@ -10396,7 +5765,7 @@
}
os_memcpy(if_addr, new_addr, ETH_ALEN);
}
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -10560,31 +5929,21 @@
u64 cookie;
int ret = -1;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
"no_ack=%d offchanok=%d",
freq, wait, no_cck, no_ack, offchanok);
wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
- if (freq)
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
- if (wait)
- NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
- if (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
- drv->test_use_roc_tx))
- NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
- if (no_cck)
- NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
- if (no_ack)
- NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
-
- NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
+ (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+ (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
+ (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+ drv->test_use_roc_tx) &&
+ nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
+ (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
+ (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
+ nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
+ goto fail;
cookie = 0;
ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
@@ -10593,16 +5952,16 @@
wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
"(%s) (freq=%u wait=%u)", ret, strerror(-ret),
freq, wait);
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
+ "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+ (long long unsigned int) cookie);
+
+ if (cookie_out)
+ *cookie_out = no_ack ? (u64) -1 : cookie;
}
- wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
- "cookie 0x%llx", no_ack ? " (no ACK)" : "",
- (long long unsigned int) cookie);
- if (cookie_out)
- *cookie_out = no_ack ? (u64) -1 : cookie;
-
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -10661,26 +6020,18 @@
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return;
-
wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
(long long unsigned int) drv->send_action_cookie);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie)) {
+ nlmsg_free(msg);
+ return;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
"(%s)", ret, strerror(-ret));
-
- nla_put_failure:
- nlmsg_free(msg);
}
@@ -10693,21 +6044,15 @@
int ret;
u64 cookie;
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+ nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- 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);
- msg = NULL;
if (ret == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
"0x%llx for freq=%u MHz duration=%u",
@@ -10719,8 +6064,6 @@
wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
"(freq=%d duration=%u): %d (%s)",
freq, duration, ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -10742,25 +6085,18 @@
"0x%llx",
(long long unsigned int) drv->remain_on_chan_cookie);
- msg = nlmsg_alloc();
- if (!msg)
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
+ if (!msg ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
"%d (%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -10825,16 +6161,19 @@
struct nlattr *bands, *band;
int ret;
- msg = nlmsg_alloc();
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
+ ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
+ "no NL80211_TXRATE_LEGACY constraint");
+
+ msg = nl80211_ifindex_msg(drv, ifindex, 0,
+ NL80211_CMD_SET_TX_BITRATE_MASK);
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-
bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
if (!bands)
- goto nla_put_failure;
+ goto fail;
/*
* Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
@@ -10842,18 +6181,15 @@
* rates. All 5 GHz rates are left enabled.
*/
band = nla_nest_start(msg, NL80211_BAND_2GHZ);
- if (!band)
- goto nla_put_failure;
- if (disabled) {
- NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
- "\x0c\x12\x18\x24\x30\x48\x60\x6c");
- }
+ if (!band ||
+ (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
+ goto fail;
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));
@@ -10862,7 +6198,7 @@
return ret;
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -1;
}
@@ -10875,6 +6211,7 @@
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(drv);
+ bss->beacon_set = 0;
/*
* If the P2P GO interface was dynamically added, then it is
@@ -10926,86 +6263,26 @@
}
-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;
- const u8 *own_addr = bss->addr;
-
- 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, 0,
- drv->bssid, own_addr, drv->bssid,
- data, data_len, 0);
- 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;
struct nlattr *cqm;
- int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
"hysteresis=%d", threshold, hysteresis);
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
+ !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
+ nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
+ nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
- cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
- if (cqm == NULL)
- goto nla_put_failure;
-
- NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
- NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+ }
nla_nest_end(msg, cqm);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
}
@@ -11042,18 +6319,8 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
return send_and_recv_msgs(drv, msg, get_channel_width, sig);
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -11142,12 +6409,6 @@
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
}
-
- if (os_strstr(param, "p2p_device=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- drv->allow_p2p_device = 1;
- }
#endif /* CONFIG_P2P */
if (os_strstr(param, "use_monitor=1")) {
@@ -11258,22 +6519,14 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(bss->drv, msg, 0, cmd);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
- if (pmkid)
- NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
- if (bssid)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+ if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+ (pmkid && nla_put(msg, NL80211_ATTR_PMKID, 16, pmkid)) ||
+ (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -11444,7 +6697,7 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int err = -ENOBUFS;
+ int err;
union wpa_event_data data;
struct survey_results *survey_results;
@@ -11453,13 +6706,9 @@
dl_list_init(&survey_results->survey_list);
- msg = nlmsg_alloc();
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ return -ENOBUFS;
if (freq)
data.survey_results.freq_filter = freq;
@@ -11470,16 +6719,12 @@
survey_results);
} while (err > 0);
- if (err) {
+ if (err)
wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
- goto out_clean;
- }
+ else
+ wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
- wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
-
-out_clean:
clean_survey_results(survey_results);
-nla_put_failure:
return err;
}
@@ -11492,29 +6737,20 @@
struct nlattr *replay_nested;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
+ !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
+ nla_put(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek) ||
+ nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
+ nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+ replay_ctr)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
return;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
- replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
- if (!replay_nested)
- goto nla_put_failure;
-
- NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
- NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
- NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
- replay_ctr);
+ }
nla_nest_end(msg, replay_nested);
- send_and_recv_msgs(drv, msg, NULL, NULL);
- return;
- nla_put_failure:
- nlmsg_free(msg);
+ send_and_recv_msgs(drv, msg, NULL, (void *) -1);
}
@@ -11568,19 +6804,13 @@
return;
}
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
return;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ }
send_and_recv_msgs(drv, msg, NULL, NULL);
- return;
- nla_put_failure:
- nlmsg_free(msg);
}
@@ -11588,18 +6818,13 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
- enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
+ nla_put_u32(msg, NL80211_ATTR_PS_STATE,
+ enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -11646,24 +6871,17 @@
return -1;
}
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
+ nl80211_put_freq_params(msg, freq) < 0) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- if (nl80211_put_freq_params(msg, freq) < 0)
- goto nla_put_failure;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
"%d (%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -11684,16 +6902,12 @@
if (!dst)
return -EINVAL;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
- NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
- NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
- NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code))
+ goto fail;
if (peer_capab) {
/*
* The internal enum tdls_peer_capability definition is
@@ -11701,15 +6915,18 @@
* nl80211_tdls_peer_capability, so no conversion is needed
* here.
*/
- NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab);
+ if (nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
+ peer_capab))
+ goto fail;
}
- if (initiator)
- NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_INITIATOR);
- NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+ if ((initiator &&
+ nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
+ nla_put(msg, NL80211_ATTR_IE, len, buf))
+ goto fail;
return send_and_recv_msgs(drv, msg, NULL, NULL);
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -11749,158 +6966,75 @@
return -EINVAL;
}
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
- NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+ " oper_class=%u freq=%u",
+ MAC2STR(addr), oper_class, params->freq);
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+ (ret = nl80211_put_freq_params(msg, params))) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+ return ret;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+ MAC2STR(addr));
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not build TDLS cancel chan switch");
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
}
#endif /* CONFIG TDLS */
-#ifdef ANDROID
-
-typedef struct android_wifi_priv_cmd {
- char *buf;
- int used_len;
- int total_len;
-} android_wifi_priv_cmd;
-
-static int drv_errors = 0;
-
-static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
-{
- drv_errors++;
- if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
- drv_errors = 0;
- wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
- }
-}
-
-
-static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct ifreq ifr;
- android_wifi_priv_cmd priv_cmd;
- char buf[MAX_DRV_CMD_SIZE];
- int ret;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_memset(&priv_cmd, 0, sizeof(priv_cmd));
- os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
-
- os_memset(buf, 0, sizeof(buf));
- os_strlcpy(buf, cmd, sizeof(buf));
-
- priv_cmd.buf = buf;
- priv_cmd.used_len = sizeof(buf);
- priv_cmd.total_len = sizeof(buf);
- ifr.ifr_data = &priv_cmd;
-
- ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
- if (ret < 0) {
- wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
- __func__);
- wpa_driver_send_hang_msg(drv);
- return ret;
- }
-
- drv_errors = 0;
- return 0;
-}
-
-
-static int android_pno_start(struct i802_bss *bss,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct ifreq ifr;
- android_wifi_priv_cmd priv_cmd;
- int ret = 0, i = 0, bp;
- char buf[WEXT_PNO_MAX_COMMAND_SIZE];
-
- bp = WEXT_PNOSETUP_HEADER_SIZE;
- os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
- buf[bp++] = WEXT_PNO_TLV_PREFIX;
- buf[bp++] = WEXT_PNO_TLV_VERSION;
- buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
- buf[bp++] = WEXT_PNO_TLV_RESERVED;
-
- while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
- /* Check that there is enough space needed for 1 more SSID, the
- * other sections and null termination */
- if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
- WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
- break;
- wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- buf[bp++] = WEXT_PNO_SSID_SECTION;
- buf[bp++] = params->ssids[i].ssid_len;
- os_memcpy(&buf[bp], params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- bp += params->ssids[i].ssid_len;
- i++;
- }
-
- buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
- os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
- WEXT_PNO_SCAN_INTERVAL);
- bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
-
- buf[bp++] = WEXT_PNO_REPEAT_SECTION;
- os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
- WEXT_PNO_REPEAT);
- bp += WEXT_PNO_REPEAT_LENGTH;
-
- buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
- os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
- WEXT_PNO_MAX_REPEAT);
- bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
-
- memset(&ifr, 0, sizeof(ifr));
- memset(&priv_cmd, 0, sizeof(priv_cmd));
- os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
-
- priv_cmd.buf = buf;
- priv_cmd.used_len = bp;
- priv_cmd.total_len = bp;
- ifr.ifr_data = &priv_cmd;
-
- ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
-
- if (ret < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
- ret);
- wpa_driver_send_hang_msg(drv);
- return ret;
- }
-
- drv_errors = 0;
-
- return android_priv_cmd(bss, "PNOFORCE 1");
-}
-
-
-static int android_pno_stop(struct i802_bss *bss)
-{
- return android_priv_cmd(bss, "PNOFORCE 0");
-}
-
-#endif /* ANDROID */
-
-
static int driver_nl80211_set_key(const char *ifname, void *priv,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
@@ -11964,7 +7098,7 @@
static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_sta_remove(bss, addr);
+ return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
}
@@ -12014,15 +7148,13 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
u16 mdid = WPA_GET_LE16(md);
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
- nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
- NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
+ nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
+ nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
@@ -12031,10 +7163,6 @@
}
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12103,14 +7231,14 @@
bss->added_bridge ? "added_bridge=1\n" : "",
bss->in_deinit ? "in_deinit=1\n" : "",
bss->if_dynamic ? "if_dynamic=1\n" : "");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
if (bss->wdev_id_set) {
res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
(unsigned long long) bss->wdev_id);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -12132,7 +7260,7 @@
"monitor_refcount=%d\n"
"last_mgmt_freq=%u\n"
"eapol_tx_sock=%d\n"
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
MAC2STR(drv->perm_addr),
drv->ifindex,
@@ -12168,9 +7296,8 @@
drv->ignore_next_local_disconnect ?
"ignore_next_local_disconnect=1\n" : "",
drv->ignore_next_local_deauth ?
- "ignore_next_local_deauth=1\n" : "",
- drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
- if (res < 0 || res >= end - pos)
+ "ignore_next_local_deauth=1\n" : "");
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -12179,7 +7306,8 @@
"capa.key_mgmt=0x%x\n"
"capa.enc=0x%x\n"
"capa.auth=0x%x\n"
- "capa.flags=0x%x\n"
+ "capa.flags=0x%llx\n"
+ "capa.rrm_flags=0x%x\n"
"capa.max_scan_ssids=%d\n"
"capa.max_sched_scan_ssids=%d\n"
"capa.sched_scan_supported=%d\n"
@@ -12188,11 +7316,14 @@
"capa.max_stations=%u\n"
"capa.probe_resp_offloads=0x%x\n"
"capa.max_acl_mac_addrs=%u\n"
- "capa.num_multichan_concurrent=%u\n",
+ "capa.num_multichan_concurrent=%u\n"
+ "capa.mac_addr_rand_sched_scan_supported=%d\n"
+ "capa.mac_addr_rand_scan_supported=%d\n",
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
- drv->capa.flags,
+ (unsigned long long) drv->capa.flags,
+ drv->capa.rrm_flags,
drv->capa.max_scan_ssids,
drv->capa.max_sched_scan_ssids,
drv->capa.sched_scan_supported,
@@ -12201,8 +7332,10 @@
drv->capa.max_stations,
drv->capa.probe_resp_offloads,
drv->capa.max_acl_mac_addrs,
- drv->capa.num_multichan_concurrent);
- if (res < 0 || res >= end - pos)
+ drv->capa.num_multichan_concurrent,
+ drv->capa.mac_addr_rand_sched_scan_supported,
+ drv->capa.mac_addr_rand_scan_supported);
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -12213,35 +7346,27 @@
static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
{
- if (settings->head)
- NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
- settings->head_len, settings->head);
-
- if (settings->tail)
- NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
- settings->tail_len, settings->tail);
-
- if (settings->beacon_ies)
- NLA_PUT(msg, NL80211_ATTR_IE,
- settings->beacon_ies_len, settings->beacon_ies);
-
- if (settings->proberesp_ies)
- NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
- settings->proberesp_ies_len, settings->proberesp_ies);
-
- if (settings->assocresp_ies)
- NLA_PUT(msg,
- NL80211_ATTR_IE_ASSOC_RESP,
- settings->assocresp_ies_len, settings->assocresp_ies);
-
- if (settings->probe_resp)
- NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
- settings->probe_resp_len, settings->probe_resp);
+ if ((settings->head &&
+ nla_put(msg, NL80211_ATTR_BEACON_HEAD,
+ settings->head_len, settings->head)) ||
+ (settings->tail &&
+ nla_put(msg, NL80211_ATTR_BEACON_TAIL,
+ settings->tail_len, settings->tail)) ||
+ (settings->beacon_ies &&
+ nla_put(msg, NL80211_ATTR_IE,
+ settings->beacon_ies_len, settings->beacon_ies)) ||
+ (settings->proberesp_ies &&
+ nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+ settings->proberesp_ies_len, settings->proberesp_ies)) ||
+ (settings->assocresp_ies &&
+ nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ settings->assocresp_ies_len, settings->assocresp_ies)) ||
+ (settings->probe_resp &&
+ nla_put(msg, NL80211_ATTR_PROBE_RESP,
+ settings->probe_resp_len, settings->probe_resp)))
+ return -ENOBUFS;
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
@@ -12283,20 +7408,14 @@
settings->cs_count)))
return -EINVAL;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
- ret = nl80211_put_freq_params(msg, &settings->freq_params);
- if (ret)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
+ nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
+ settings->cs_count) ||
+ (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
+ (settings->block_tx &&
+ nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
goto error;
- if (settings->block_tx)
- NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
-
/* beacon_after params */
ret = set_beacon_data(msg, &settings->beacon_after);
if (ret)
@@ -12305,18 +7424,18 @@
/* beacon_csa params */
beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
if (!beacon_csa)
- goto nla_put_failure;
+ goto fail;
ret = set_beacon_data(msg, &settings->beacon_csa);
if (ret)
goto error;
- NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
- settings->counter_offset_beacon);
-
- if (settings->beacon_csa.probe_resp)
- NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
- settings->counter_offset_presp);
+ if (nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+ settings->counter_offset_beacon) ||
+ (settings->beacon_csa.probe_resp &&
+ nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+ settings->counter_offset_presp)))
+ goto fail;
nla_nest_end(msg, beacon_csa);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -12326,7 +7445,7 @@
}
return ret;
-nla_put_failure:
+fail:
ret = -ENOBUFS;
error:
nlmsg_free(msg);
@@ -12335,6 +7454,66 @@
}
+static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
+ u8 user_priority, u16 admitted_time)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
+ tsid, admitted_time, user_priority);
+
+ if (!is_sta_interface(drv->nlmode))
+ return -ENOTSUP;
+
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
+ nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
+
+ if (!is_sta_interface(drv->nlmode))
+ return -ENOTSUP;
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
+ nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int cmd_reply_handler(struct nl_msg *msg, void *arg)
{
@@ -12397,16 +7576,16 @@
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
#ifdef CONFIG_TESTING_OPTIONS
if (vendor_id == 0xffffffff) {
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
nl80211_cmd(drv, msg, 0, subcmd);
if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
0)
- goto nla_put_failure;
+ goto fail;
ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
@@ -12415,13 +7594,12 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, vendor_id);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd);
- if (data)
- NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, data_len, data);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
+ (data &&
+ nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
+ goto fail;
ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
if (ret)
@@ -12429,7 +7607,7 @@
ret);
return ret;
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -12443,26 +7621,20 @@
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
qos_map_set, qos_map_set_len);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
+ nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12475,33 +7647,28 @@
struct nlattr *wowlan_triggers;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WOWLAN);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- wowlan_triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
- if (!wowlan_triggers)
- goto nla_put_failure;
-
- if (triggers->any)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
- if (triggers->disconnect)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
- if (triggers->magic_pkt)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
- if (triggers->gtk_rekey_failure)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
- if (triggers->eap_identity_req)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
- if (triggers->four_way_handshake)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
- if (triggers->rfkill_release)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+ !(wowlan_triggers = nla_nest_start(msg,
+ NL80211_ATTR_WOWLAN_TRIGGERS)) ||
+ (triggers->any &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+ (triggers->disconnect &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+ (triggers->magic_pkt &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+ (triggers->gtk_rekey_failure &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+ (triggers->eap_identity_req &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+ (triggers->four_way_handshake &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+ (triggers->rfkill_release &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
nla_nest_end(msg, wowlan_triggers);
@@ -12510,10 +7677,6 @@
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12532,32 +7695,22 @@
return -1;
}
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
- QCA_NL80211_VENDOR_SUBCMD_ROAMING);
-
- params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
- if (!params)
- goto nla_put_failure;
- NLA_PUT_U32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
- allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
- QCA_ROAMING_NOT_ALLOWED);
- if (bssid)
- NLA_PUT(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
+ allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
+ QCA_ROAMING_NOT_ALLOWED) ||
+ (bssid &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
+ nlmsg_free(msg);
+ return -1;
+ }
nla_nest_end(msg, params);
return send_and_recv_msgs(drv, msg, NULL, NULL);
-
- nla_put_failure:
- nlmsg_free(msg);
- return -1;
}
@@ -12601,6 +7754,502 @@
}
+#ifdef CONFIG_MESH
+
+static int wpa_driver_nl80211_init_mesh(void *priv)
+{
+ if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to set interface into mesh mode");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+ struct wpa_driver_mesh_join_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
+ if (!msg)
+ goto fail;
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+ goto fail;
+ }
+
+ if (params->ht_mode) {
+ unsigned int ht_value;
+ char *ht_mode = "";
+
+ switch (params->ht_mode) {
+ default:
+ case CHAN_NO_HT:
+ ht_value = NL80211_CHAN_NO_HT;
+ ht_mode = "NOHT";
+ break;
+ case CHAN_HT20:
+ ht_value = NL80211_CHAN_HT20;
+ ht_mode = "HT20";
+ break;
+ case CHAN_HT40PLUS:
+ ht_value = NL80211_CHAN_HT40PLUS;
+ ht_mode = "HT40+";
+ break;
+ case CHAN_HT40MINUS:
+ ht_value = NL80211_CHAN_HT40MINUS;
+ ht_mode = "HT40-";
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " * ht_mode=%s", ht_mode);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value))
+ goto fail;
+ }
+
+ if (params->basic_rates) {
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
+ if (params->basic_rates[i] < 0)
+ break;
+ rates[rates_len++] = params->basic_rates[i] / 5;
+ }
+
+ if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
+ rates))
+ goto fail;
+ }
+
+ if (params->meshid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->meshid, params->meshid_len);
+ if (nla_put(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
+ params->meshid))
+ goto fail;
+ }
+
+ if (params->beacon_int > 0) {
+ wpa_printf(MSG_DEBUG, " * beacon_int=%d", params->beacon_int);
+ if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ params->beacon_int))
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
+ if (!container)
+ goto fail;
+
+ if (params->ies) {
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
+ if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
+ params->ies))
+ goto fail;
+ }
+ /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
+ if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
+ if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
+ goto fail;
+ }
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
+ goto fail;
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
+ goto fail;
+ nla_nest_end(msg, container);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+ if (!container)
+ goto fail;
+
+ if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+ nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
+ goto fail;
+ if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ params->max_peer_links))
+ goto fail;
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ ret = 0;
+ bss->freq = params->freq;
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_leave_mesh(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: mesh leave request send successfully");
+ }
+
+ if (wpa_driver_nl80211_set_mode(drv->first_bss,
+ NL80211_IFTYPE_STATION)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to set interface into station mode");
+ }
+ return ret;
+}
+
+#endif /* CONFIG_MESH */
+
+
+static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr, int prefixlen,
+ const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_ipaddr = NULL;
+ struct nl_addr *nl_lladdr = NULL;
+ int family, addrsize;
+ int res;
+
+ if (!ipaddr || prefixlen == 0 || !addr)
+ return -EINVAL;
+
+ if (bss->br_ifindex == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: bridge must be set before adding an ip neigh to it");
+ return -1;
+ }
+
+ if (!drv->rtnl_sk) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+ return -1;
+ }
+
+ if (version == 4) {
+ family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+ family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+ rn = rtnl_neigh_alloc();
+ if (rn == NULL)
+ return -ENOMEM;
+
+ /* set the destination ip address for neigh */
+ nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+ if (nl_ipaddr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
+ res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: neigh set destination addr failed");
+ goto errout;
+ }
+
+ /* set the corresponding lladdr for neigh */
+ nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
+ if (nl_lladdr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ rtnl_neigh_set_lladdr(rn, nl_lladdr);
+
+ rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+ rtnl_neigh_set_state(rn, NUD_PERMANENT);
+
+ res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Adding bridge ip neigh failed: %s",
+ strerror(errno));
+ }
+errout:
+ if (nl_lladdr)
+ nl_addr_put(nl_lladdr);
+ if (nl_ipaddr)
+ nl_addr_put(nl_ipaddr);
+ if (rn)
+ rtnl_neigh_put(rn);
+ return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+ return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_ipaddr;
+ int family, addrsize;
+ int res;
+
+ if (!ipaddr)
+ return -EINVAL;
+
+ if (version == 4) {
+ family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+ family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+ if (bss->br_ifindex == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: bridge must be set to delete an ip neigh");
+ return -1;
+ }
+
+ if (!drv->rtnl_sk) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+ return -1;
+ }
+
+ rn = rtnl_neigh_alloc();
+ if (rn == NULL)
+ return -ENOMEM;
+
+ /* set the destination ip address for neigh */
+ nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+ if (nl_ipaddr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: neigh set destination addr failed");
+ goto errout;
+ }
+
+ rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+
+ res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Deleting bridge ip neigh failed: %s",
+ strerror(errno));
+ }
+errout:
+ if (nl_ipaddr)
+ nl_addr_put(nl_ipaddr);
+ if (rn)
+ rtnl_neigh_put(rn);
+ return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+ return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int linux_write_system_file(const char *path, unsigned int val)
+{
+ char buf[50];
+ int fd, len;
+
+ len = os_snprintf(buf, sizeof(buf), "%u\n", val);
+ if (os_snprintf_error(sizeof(buf), len))
+ return -1;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ if (write(fd, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to write Linux system file: %s with the value of %d",
+ path, val);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
+
+static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
+{
+ switch (attr) {
+ case DRV_BR_PORT_ATTR_PROXYARP:
+ return "proxyarp";
+ case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
+ return "hairpin_mode";
+ }
+
+ return NULL;
+}
+
+
+static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
+ unsigned int val)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ const char *attr_txt;
+
+ attr_txt = drv_br_port_attr_str(attr);
+ if (attr_txt == NULL)
+ return -EINVAL;
+
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
+ bss->ifname, attr_txt);
+
+ if (linux_write_system_file(path, val))
+ return -1;
+
+ return 0;
+}
+
+
+static const char * drv_br_net_param_str(enum drv_br_net_param param)
+{
+ switch (param) {
+ case DRV_BR_NET_PARAM_GARP_ACCEPT:
+ return "arp_accept";
+ }
+
+ return NULL;
+}
+
+
+static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
+ unsigned int val)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ const char *param_txt;
+ int ip_version = 4;
+
+ param_txt = drv_br_net_param_str(param);
+ if (param_txt == NULL)
+ return -EINVAL;
+
+ switch (param) {
+ case DRV_BR_NET_PARAM_GARP_ACCEPT:
+ ip_version = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
+ ip_version, bss->brname, param_txt);
+
+ if (linux_write_system_file(path, val))
+ return -1;
+
+ return 0;
+}
+
+
+static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
+{
+ switch (hw_mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return QCA_ACS_MODE_IEEE80211B;
+ case HOSTAPD_MODE_IEEE80211G:
+ return QCA_ACS_MODE_IEEE80211G;
+ case HOSTAPD_MODE_IEEE80211A:
+ return QCA_ACS_MODE_IEEE80211A;
+ case HOSTAPD_MODE_IEEE80211AD:
+ return QCA_ACS_MODE_IEEE80211AD;
+ default:
+ return -1;
+ }
+}
+
+
+static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int ret;
+ int mode;
+
+ mode = hw_mode_to_qca_acs(params->hw_mode);
+ if (mode < 0)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
+ (params->ht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
+ (params->ht40_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, data);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to invoke driver ACS function: %s",
+ strerror(errno));
+ }
+ return ret;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -12628,7 +8277,7 @@
.if_add = wpa_driver_nl80211_if_add,
.if_remove = driver_nl80211_if_remove,
.send_mlme = driver_nl80211_send_mlme,
- .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+ .get_hw_feature_data = nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = driver_nl80211_sta_remove,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
@@ -12657,7 +8306,6 @@
.deinit_ap = wpa_driver_nl80211_deinit_ap,
.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
.resume = wpa_driver_nl80211_resume,
- .send_ft_action = nl80211_send_ft_action,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
@@ -12675,6 +8323,8 @@
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
+ .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+ .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
#endif /* CONFIG_TDLS */
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
@@ -12694,4 +8344,16 @@
.set_wowlan = nl80211_set_wowlan,
.roaming = nl80211_roaming,
.set_mac_addr = nl80211_set_mac_addr,
+#ifdef CONFIG_MESH
+ .init_mesh = wpa_driver_nl80211_init_mesh,
+ .join_mesh = wpa_driver_nl80211_join_mesh,
+ .leave_mesh = wpa_driver_nl80211_leave_mesh,
+#endif /* CONFIG_MESH */
+ .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
+ .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
+ .br_port_set_attr = wpa_driver_br_port_set_attr,
+ .br_set_net_param = wpa_driver_br_set_net_param,
+ .add_tx_ts = nl80211_add_ts,
+ .del_tx_ts = nl80211_del_ts,
+ .do_acs = wpa_driver_do_acs,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
new file mode 100644
index 0000000..6892b31
--- /dev/null
+++ b/src/drivers/driver_nl80211.h
@@ -0,0 +1,271 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - definitions
+ * Copyright (c) 2002-2014, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_NL80211_H
+#define DRIVER_NL80211_H
+
+#include "nl80211_copy.h"
+#include "utils/list.h"
+#include "driver.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
+struct nl80211_global {
+ struct dl_list interfaces;
+ int if_add_ifindex;
+ u64 if_add_wdevid;
+ int if_add_wdevid_set;
+ struct netlink_data *netlink;
+ struct nl_cb *nl_cb;
+ struct nl_handle *nl;
+ int nl80211_id;
+ int ioctl_sock; /* socket for ioctl() use */
+
+ struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+ struct dl_list list;
+ struct dl_list bsss;
+ struct dl_list drvs;
+
+ struct nl_handle *nl_beacons;
+ struct nl_cb *nl_cb;
+
+ int wiphy_idx;
+};
+
+struct i802_bss {
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *next;
+ int ifindex;
+ int br_ifindex;
+ u64 wdev_id;
+ char ifname[IFNAMSIZ + 1];
+ char brname[IFNAMSIZ];
+ unsigned int beacon_set:1;
+ unsigned int added_if_into_bridge:1;
+ unsigned int added_bridge:1;
+ unsigned int in_deinit:1;
+ unsigned int wdev_id_set:1;
+ unsigned int added_if:1;
+ unsigned int static_ap:1;
+
+ u8 addr[ETH_ALEN];
+
+ int freq;
+ int bandwidth;
+ int if_dynamic;
+
+ void *ctx;
+ struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_cb *nl_cb;
+
+ struct nl80211_wiphy_data *wiphy_data;
+ struct dl_list wiphy_list;
+};
+
+struct wpa_driver_nl80211_data {
+ struct nl80211_global *global;
+ struct dl_list list;
+ struct dl_list wiphy_list;
+ char phyname[32];
+ u8 perm_addr[ETH_ALEN];
+ void *ctx;
+ int ifindex;
+ int if_removed;
+ int if_disabled;
+ int ignore_if_down_event;
+ struct rfkill_data *rfkill;
+ struct wpa_driver_capa capa;
+ u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+ int has_capability;
+
+ int operstate;
+
+ int scan_complete_events;
+ enum scan_states {
+ NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+ SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+ SCHED_SCAN_RESULTS
+ } scan_state;
+
+ u8 auth_bssid[ETH_ALEN];
+ u8 auth_attempt_bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 prev_bssid[ETH_ALEN];
+ int associated;
+ u8 ssid[32];
+ size_t ssid_len;
+ enum nl80211_iftype nlmode;
+ enum nl80211_iftype ap_scan_as_station;
+ unsigned int assoc_freq;
+
+ int monitor_sock;
+ int monitor_ifidx;
+ int monitor_refcount;
+
+ unsigned int disabled_11b_rates:1;
+ unsigned int pending_remain_on_chan:1;
+ unsigned int in_interface_list:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int scan_for_auth:1;
+ unsigned int retry_auth:1;
+ unsigned int use_monitor:1;
+ unsigned int ignore_next_local_disconnect:1;
+ unsigned int ignore_next_local_deauth:1;
+ unsigned int hostapd:1;
+ unsigned int start_mode_ap:1;
+ unsigned int start_iface_up:1;
+ unsigned int test_use_roc_tx:1;
+ unsigned int ignore_deauth_event:1;
+ unsigned int roaming_vendor_cmd_avail:1;
+ unsigned int dfs_vendor_cmd_avail:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int force_connect_cmd:1;
+ unsigned int addr_changed:1;
+ unsigned int get_features_vendor_cmd_avail:1;
+
+ u64 remain_on_chan_cookie;
+ u64 send_action_cookie;
+
+ unsigned int last_mgmt_freq;
+
+ struct wpa_driver_scan_filter *filter_ssids;
+ size_t num_filter_ssids;
+
+ struct i802_bss *first_bss;
+
+ int eapol_tx_sock;
+
+ int eapol_sock; /* socket for EAPOL frames */
+
+ struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ /* From failed authentication command */
+ int auth_freq;
+ u8 auth_bssid_[ETH_ALEN];
+ u8 auth_ssid[32];
+ size_t auth_ssid_len;
+ int auth_alg;
+ u8 *auth_ie;
+ size_t auth_ie_len;
+ u8 auth_wep_key[4][16];
+ size_t auth_wep_key_len[4];
+ int auth_wep_tx_keyidx;
+ int auth_local_state_change;
+ int auth_p2p;
+};
+
+struct nl_msg;
+
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd);
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+ uint8_t cmd);
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+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);
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg, int use_existing);
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+enum chan_width convert2width(int width);
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv);
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex);
+int is_ap_interface(enum nl80211_iftype nlmode);
+int is_sta_interface(enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig);
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig_change);
+int nl80211_get_wiphy_index(struct i802_bss *bss);
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change);
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack);
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv);
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
+
+int process_global_event(struct nl_msg *msg, void *arg);
+int process_bss_event(struct nl_msg *msg, void *arg);
+
+#ifdef ANDROID
+int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
+int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+ size_t buf_len);
+
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
+#endif /* ANDROID */
+
+
+/* driver_nl80211_scan.c */
+
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+ unsigned int assoc_freq;
+ unsigned int ibss_freq;
+ u8 assoc_bssid[ETH_ALEN];
+};
+
+int bss_info_handler(struct nl_msg *msg, void *arg);
+void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+int wpa_driver_nl80211_sched_scan(void *priv,
+ struct wpa_driver_scan_params *params,
+ u32 interval);
+int wpa_driver_nl80211_stop_sched_scan(void *priv);
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+
+#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
new file mode 100644
index 0000000..3cc9a65
--- /dev/null
+++ b/src/drivers/driver_nl80211_android.c
@@ -0,0 +1,220 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Android specific
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "driver_nl80211.h"
+#include "android_drv.h"
+
+
+typedef struct android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+ drv_errors++;
+ if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv_errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ char buf[MAX_DRV_CMD_SIZE];
+ int ret;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ os_memset(buf, 0, sizeof(buf));
+ os_strlcpy(buf, cmd, sizeof(buf));
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = sizeof(buf);
+ priv_cmd.total_len = sizeof(buf);
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+ __func__);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+ return 0;
+}
+
+
+int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ int ret = 0, i = 0, bp;
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+ while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+ /* Check that there is enough space needed for 1 more SSID, the
+ * other sections and null termination */
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+ WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+ break;
+ wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
+ buf[bp++] = params->ssids[i].ssid_len;
+ os_memcpy(&buf[bp], params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ bp += params->ssids[i].ssid_len;
+ i++;
+ }
+
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+ WEXT_PNO_SCAN_INTERVAL);
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_REPEAT);
+ bp += WEXT_PNO_REPEAT_LENGTH;
+
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_MAX_REPEAT);
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = bp;
+ priv_cmd.total_len = bp;
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+ ret);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+
+ return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+int android_pno_stop(struct i802_bss *bss)
+{
+ return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+
+#ifdef ANDROID_P2P
+#ifdef ANDROID_P2P_STUB
+
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
+{
+ return 0;
+}
+
+
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
+{
+ return 0;
+}
+
+
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
+{
+ return -1;
+}
+
+
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp)
+{
+ return 0;
+}
+
+#endif /* ANDROID_P2P_STUB */
+#endif /* ANDROID_P2P */
+
+
+int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+ return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+
+
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
+{
+ /*
+ * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+ * need to work around that.
+ */
+ struct nl_cache *cache = NULL;
+ struct genl_family *nl80211 = NULL;
+ int id = -1;
+
+ if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto fail;
+ }
+
+ nl80211 = genl_ctrl_search_by_name(cache, name);
+ if (nl80211 == NULL)
+ goto fail;
+
+ id = genl_family_get_id(nl80211);
+
+fail:
+ if (nl80211)
+ genl_family_put(nl80211);
+ if (cache)
+ nl_cache_free(cache);
+
+ return id;
+}
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
new file mode 100644
index 0000000..6661a89
--- /dev/null
+++ b/src/drivers/driver_nl80211_capa.c
@@ -0,0 +1,1519 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Capabilities
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "driver_nl80211.h"
+
+
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+ u32 *feat = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+ *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+ return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+ u32 feat = 0;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return 0;
+
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) {
+ nlmsg_free(msg);
+ return 0;
+ }
+
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ return feat;
+
+ return 0;
+}
+
+
+struct wiphy_info_data {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_driver_capa *capa;
+
+ unsigned int num_multichan_concurrent;
+
+ unsigned int error:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int monitor_supported:1;
+ unsigned int auth_supported:1;
+ unsigned int connect_supported:1;
+ unsigned int p2p_go_supported:1;
+ unsigned int p2p_client_supported:1;
+ unsigned int p2p_concurrent:1;
+ unsigned int channel_switch_supported:1;
+ unsigned int set_qos_map_supported:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int wmm_ac_supported:1;
+ unsigned int mac_addr_rand_scan_supported:1;
+ unsigned int mac_addr_rand_sched_scan_supported:1;
+};
+
+
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+ unsigned int prot = 0;
+
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+ return prot;
+}
+
+
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_mode;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_mode, tb, i) {
+ switch (nla_type(nl_mode)) {
+ case NL80211_IFTYPE_AP:
+ info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ info->capa->flags |=
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ info->p2p_go_supported = 1;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ info->p2p_client_supported = 1;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ info->monitor_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+ struct nlattr *nl_combi)
+{
+ struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+ struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+ struct nlattr *nl_limit, *nl_mode;
+ int err, rem_limit, rem_mode;
+ int combination_has_p2p = 0, combination_has_mgd = 0;
+ static struct nla_policy
+ iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+ [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+ [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+ [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
+ },
+ iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+ [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+ [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+ };
+
+ err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+ nl_combi, iface_combination_policy);
+ if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+ !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+ !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+ return 0; /* broken combination */
+
+ if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+ info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
+ nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
+ rem_limit) {
+ err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
+ nl_limit, iface_limit_policy);
+ if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+ return 0; /* broken combination */
+
+ nla_for_each_nested(nl_mode,
+ tb_limit[NL80211_IFACE_LIMIT_TYPES],
+ rem_mode) {
+ int ift = nla_type(nl_mode);
+ if (ift == NL80211_IFTYPE_P2P_GO ||
+ ift == NL80211_IFTYPE_P2P_CLIENT)
+ combination_has_p2p = 1;
+ if (ift == NL80211_IFTYPE_STATION)
+ combination_has_mgd = 1;
+ }
+ if (combination_has_p2p && combination_has_mgd)
+ break;
+ }
+
+ if (combination_has_p2p && combination_has_mgd) {
+ unsigned int num_channels =
+ nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
+
+ info->p2p_concurrent = 1;
+ if (info->num_multichan_concurrent < num_channels)
+ info->num_multichan_concurrent = num_channels;
+ }
+
+ return 0;
+}
+
+
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_combi;
+ int rem_combi;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_combi, tb, rem_combi) {
+ if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+ break;
+ }
+}
+
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_cmd;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_cmd, tb, i) {
+ switch (nla_get_u32(nl_cmd)) {
+ case NL80211_CMD_AUTHENTICATE:
+ info->auth_supported = 1;
+ break;
+ case NL80211_CMD_CONNECT:
+ info->connect_supported = 1;
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ info->capa->sched_scan_supported = 1;
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ info->poll_command_supported = 1;
+ break;
+ case NL80211_CMD_CHANNEL_SWITCH:
+ info->channel_switch_supported = 1;
+ break;
+ case NL80211_CMD_SET_QOS_MAP:
+ info->set_qos_map_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ int i, num;
+ u32 *ciphers;
+
+ if (tb == NULL)
+ return;
+
+ num = nla_len(tb) / sizeof(u32);
+ ciphers = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 c = ciphers[i];
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+ c >> 24, (c >> 16) & 0xff,
+ (c >> 8) & 0xff, c & 0xff);
+ switch (c) {
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ if (tb)
+ capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+ struct nlattr *ext_setup)
+{
+ if (tdls == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+ if (ext_setup) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+ }
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ u32 flags;
+ struct wpa_driver_capa *capa = info->capa;
+
+ if (tb == NULL)
+ return;
+
+ flags = nla_get_u32(tb);
+
+ if (flags & NL80211_FEATURE_SK_TX_STATUS)
+ info->data_tx_status = 1;
+
+ if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+ capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+ if (flags & NL80211_FEATURE_SAE)
+ capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+ if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+ capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+
+ if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+ capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
+
+ if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH;
+ }
+
+ if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
+ info->have_low_prio_scan = 1;
+
+ if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)
+ info->mac_addr_rand_scan_supported = 1;
+
+ if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
+ info->mac_addr_rand_sched_scan_supported = 1;
+
+ if (flags & NL80211_FEATURE_STATIC_SMPS)
+ capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
+
+ if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
+ capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
+
+ if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
+ info->wmm_ac_supported = 1;
+
+ if (flags & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES;
+
+ if (flags & NL80211_FEATURE_WFA_TPC_IE_IN_PROBES)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES;
+
+ if (flags & NL80211_FEATURE_QUIET)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_QUIET;
+
+ if (flags & NL80211_FEATURE_TX_POWER_INSERTION)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ u32 protocols;
+
+ if (tb == NULL)
+ return;
+
+ protocols = nla_get_u32(tb);
+ wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
+ "mode");
+ capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+ capa->probe_resp_offloads = probe_resp_offload_support(protocols);
+}
+
+
+static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
+
+ if (tb == NULL)
+ return;
+
+ if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
+ tb, NULL))
+ return;
+
+ if (triggers[NL80211_WOWLAN_TRIG_ANY])
+ capa->wowlan_triggers.any = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
+ capa->wowlan_triggers.disconnect = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
+ capa->wowlan_triggers.magic_pkt = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
+ capa->wowlan_triggers.gtk_rekey_failure = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
+ capa->wowlan_triggers.eap_identity_req = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
+ capa->wowlan_triggers.four_way_handshake = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
+ capa->wowlan_triggers.rfkill_release = 1;
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_info_data *info = arg;
+ struct wpa_driver_capa *capa = info->capa;
+ struct wpa_driver_nl80211_data *drv = info->drv;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_WIPHY_NAME])
+ os_strlcpy(drv->phyname,
+ nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+ sizeof(drv->phyname));
+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+ capa->max_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+ capa->max_sched_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+ capa->max_match_sets =
+ nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
+ if (tb[NL80211_ATTR_MAC_ACL_MAX])
+ capa->max_acl_mac_addrs =
+ nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
+ wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
+ wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
+ wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
+ wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
+
+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+ "off-channel TX");
+ capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+ }
+
+ if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+ capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+ }
+
+ wiphy_info_max_roc(capa,
+ tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+
+ if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+ capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+ wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+ tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
+
+ if (tb[NL80211_ATTR_DEVICE_AP_SME])
+ info->device_ap_sme = 1;
+
+ wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_probe_resp_offload(capa,
+ tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+ if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+ drv->extended_capa == NULL) {
+ drv->extended_capa =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa) {
+ os_memcpy(drv->extended_capa,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ drv->extended_capa_len =
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ }
+ drv->extended_capa_mask =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa_mask) {
+ os_memcpy(drv->extended_capa_mask,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ } else {
+ os_free(drv->extended_capa);
+ drv->extended_capa = NULL;
+ drv->extended_capa_len = 0;
+ }
+ }
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl;
+ int rem;
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
+ struct nl80211_vendor_cmd_info *vinfo;
+ if (nla_len(nl) != sizeof(*vinfo)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+ continue;
+ }
+ vinfo = nla_data(nl);
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+ drv->dfs_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
+ vinfo->vendor_id, vinfo->subcmd);
+ }
+ }
+
+ if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
+ struct nlattr *nl;
+ int rem;
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
+ struct nl80211_vendor_cmd_info *vinfo;
+ if (nla_len(nl) != sizeof(*vinfo)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+ continue;
+ }
+ vinfo = nla_data(nl);
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
+ vinfo->vendor_id, vinfo->subcmd);
+ }
+ }
+
+ wiphy_info_wowlan_triggers(capa,
+ tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
+
+ if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
+ capa->max_stations =
+ nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
+ struct wiphy_info_data *info)
+{
+ u32 feat;
+ struct nl_msg *msg;
+ int flags = 0;
+
+ os_memset(info, 0, sizeof(*info));
+ info->capa = &drv->capa;
+ info->drv = drv;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ flags = NLM_F_DUMP;
+ msg = nl80211_cmd_msg(drv->first_bss, flags, NL80211_CMD_GET_WIPHY);
+ if (!msg || nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ return -1;
+
+ 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");
+ info->error = 1;
+ }
+
+ if (info->p2p_go_supported && info->p2p_client_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+ if (info->p2p_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+ "interface (driver advertised support)");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+ }
+ if (info->num_multichan_concurrent > 1) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ drv->capa.num_multichan_concurrent =
+ info->num_multichan_concurrent;
+ }
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+ wpa_printf(MSG_DEBUG, "nl80211: use P2P_DEVICE support");
+
+ /* default to 5000 since early versions of mac80211 don't set it */
+ if (!drv->capa.max_remain_on_chan)
+ drv->capa.max_remain_on_chan = 5000;
+
+ if (info->channel_switch_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+ drv->capa.wmm_ac_supported = info->wmm_ac_supported;
+
+ drv->capa.mac_addr_rand_sched_scan_supported =
+ info->mac_addr_rand_sched_scan_supported;
+ drv->capa.mac_addr_rand_scan_supported =
+ info->mac_addr_rand_scan_supported;
+
+ return 0;
+}
+
+
+static int dfs_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int *dfs_capability_ptr = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
+ u32 val;
+ val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
+ wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
+ val);
+ *dfs_capability_ptr = val;
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int dfs_capability = 0;
+ int ret;
+
+ if (!drv->dfs_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+ if (!ret && dfs_capability)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+}
+
+
+struct features_info {
+ u8 *flags;
+ size_t flags_len;
+};
+
+
+static int features_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct features_info *info = arg;
+ struct nlattr *nl_vend, *attr;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (nl_vend) {
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
+ if (attr) {
+ info->flags = nla_data(attr);
+ info->flags_len = nla_len(attr);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static int check_feature(enum qca_wlan_vendor_features feature,
+ struct features_info *info)
+{
+ size_t idx = feature / 8;
+
+ return (idx < info->flags_len) &&
+ (info->flags[idx] & BIT(feature % 8));
+}
+
+
+static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct features_info info;
+ int ret;
+
+ if (!drv->get_features_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ os_memset(&info, 0, sizeof(info));
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+ if (ret || !info.flags)
+ return;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+}
+
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+{
+ struct wiphy_info_data info;
+ if (wpa_driver_nl80211_get_info(drv, &info))
+ return -1;
+
+ if (info.error)
+ return -1;
+
+ drv->has_capability = 1;
+ 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.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+ /*
+ * As all cfg80211 drivers must support cases where the AP interface is
+ * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
+ * case that the user space daemon has crashed, they must be able to
+ * cleanup all stations and key entries in the AP tear down flow. Thus,
+ * this flag can/should always be set for cfg80211 drivers.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
+
+ if (!info.device_ap_sme) {
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+ /*
+ * No AP SME is currently assumed to also indicate no AP MLME
+ * in the driver/firmware.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+ }
+
+ drv->device_ap_sme = info.device_ap_sme;
+ drv->poll_command_supported = info.poll_command_supported;
+ drv->data_tx_status = info.data_tx_status;
+ if (info.set_qos_map_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
+ drv->have_low_prio_scan = info.have_low_prio_scan;
+
+ /*
+ * If poll command and tx status are supported, mac80211 is new enough
+ * to have everything we need to not need monitor interfaces.
+ */
+ drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
+
+ if (drv->device_ap_sme && drv->use_monitor) {
+ /*
+ * Non-mac80211 drivers may not support monitor interface.
+ * Make sure we do not get stuck with incorrect capability here
+ * by explicitly testing this.
+ */
+ if (!info.monitor_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+ "with device_ap_sme since no monitor mode "
+ "support detected");
+ drv->use_monitor = 0;
+ }
+ }
+
+ /*
+ * If we aren't going to use monitor interfaces, but the
+ * driver doesn't support data TX status, we won't get TX
+ * status for EAPOL frames.
+ */
+ if (!drv->use_monitor && !info.data_tx_status)
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+ qca_nl80211_check_dfs_capa(drv);
+ qca_nl80211_get_features(drv);
+
+ return 0;
+}
+
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct hostapd_hw_modes *modes;
+ int last_mode, last_chan_idx;
+};
+
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+ struct nlattr *ampdu_factor,
+ struct nlattr *ampdu_density,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->ht_capab = nla_get_u16(capa);
+
+ if (ampdu_factor)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
+
+ if (ampdu_density)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+ if (mcs_set && nla_len(mcs_set) >= 16) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->mcs_set, mcs, 16);
+ }
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *capa,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->vht_capab = nla_get_u32(capa);
+
+ if (mcs_set && nla_len(mcs_set) >= 8) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->vht_mcs_set, mcs, 8);
+ }
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+ struct hostapd_channel_data *chan,
+ struct nlattr *tb_freq[])
+{
+ u8 channel;
+ chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ chan->flag = 0;
+ chan->dfs_cac_ms = 0;
+ if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+ chan->chan = channel;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->flag |= HOSTAPD_CHAN_DISABLED;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
+ chan->flag |= HOSTAPD_CHAN_NO_IR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ chan->flag |= HOSTAPD_CHAN_RADAR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY])
+ chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
+ chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+ enum nl80211_dfs_state state =
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+ switch (state) {
+ case NL80211_DFS_USABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+ break;
+ case NL80211_DFS_AVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+ break;
+ case NL80211_DFS_UNAVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+ break;
+ }
+ }
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
+ chan->dfs_cac_ms = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
+ }
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+ struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ 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_NO_IR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+ };
+ int new_channels = 0;
+ struct hostapd_channel_data *channel;
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ struct nlattr *nl_freq;
+ int rem_freq, idx;
+
+ if (tb == NULL)
+ return NL_OK;
+
+ nla_for_each_nested(nl_freq, tb, 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;
+ new_channels++;
+ }
+
+ channel = os_realloc_array(mode->channels,
+ mode->num_channels + new_channels,
+ sizeof(struct hostapd_channel_data));
+ if (!channel)
+ return NL_SKIP;
+
+ mode->channels = channel;
+ mode->num_channels += new_channels;
+
+ idx = phy_info->last_chan_idx;
+
+ nla_for_each_nested(nl_freq, tb, 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;
+ phy_info_freq(mode, &mode->channels[idx], tb_freq);
+ idx++;
+ }
+ phy_info->last_chan_idx = idx;
+
+ return NL_OK;
+}
+
+
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+ { .type = NLA_FLAG },
+ };
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ struct nlattr *nl_rate;
+ int rem_rate, idx;
+
+ if (tb == NULL)
+ return NL_OK;
+
+ nla_for_each_nested(nl_rate, tb, 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_calloc(mode->num_rates, sizeof(int));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb, 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] = nla_get_u32(
+ tb_rate[NL80211_BITRATE_ATTR_RATE]);
+ idx++;
+ }
+
+ return NL_OK;
+}
+
+
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ struct hostapd_hw_modes *mode;
+ int ret;
+
+ if (phy_info->last_mode != nl_band->nla_type) {
+ mode = os_realloc_array(phy_info->modes,
+ *phy_info->num_modes + 1,
+ sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ os_memset(mode, 0, sizeof(*mode));
+ mode->mode = NUM_HOSTAPD_MODES;
+ mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+ HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+ /*
+ * Unsupported VHT MCS stream is defined as value 3, so the VHT
+ * MCS RX/TX map must be initialized with 0xffff to mark all 8
+ * possible streams as unsupported. This will be overridden if
+ * driver advertises VHT support.
+ */
+ mode->vht_mcs_set[0] = 0xff;
+ mode->vht_mcs_set[1] = 0xff;
+ mode->vht_mcs_set[4] = 0xff;
+ mode->vht_mcs_set[5] = 0xff;
+
+ *(phy_info->num_modes) += 1;
+ phy_info->last_mode = nl_band->nla_type;
+ phy_info->last_chan_idx = 0;
+ } else
+ mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+ tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+ phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+ tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+ ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ if (ret != NL_OK)
+ return ret;
+ ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+ if (ret != NL_OK)
+ return ret;
+
+ return NL_OK;
+}
+
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+ struct nlattr *nl_band;
+ int rem_band;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+ {
+ int res = phy_info_band(phy_info, nl_band);
+ if (res != NL_OK)
+ return res;
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+ u16 *num_modes)
+{
+ u16 m;
+ struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+ int i, mode11g_idx = -1;
+
+ /* heuristic to set up modes */
+ for (m = 0; m < *num_modes; m++) {
+ if (!modes[m].num_channels)
+ continue;
+ if (modes[m].channels[0].freq < 4000) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+ for (i = 0; i < modes[m].num_rates; i++) {
+ if (modes[m].rates[i] > 200) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+ break;
+ }
+ }
+ } else if (modes[m].channels[0].freq > 50000)
+ modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 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_array(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");
+
+ return modes;
+}
+
+
+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40;
+ }
+}
+
+
+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (!(chan->flag & HOSTAPD_CHAN_HT40))
+ continue;
+ if (chan->freq - 30 >= start && chan->freq - 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40MINUS;
+ if (chan->freq + 10 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40PLUS;
+ }
+}
+
+
+static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
+ struct phy_info_arg *results)
+{
+ u16 m;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ int c;
+ struct hostapd_hw_modes *mode = &results->modes[m];
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if ((u32) chan->freq - 10 >= start &&
+ (u32) chan->freq + 10 <= end)
+ chan->max_tx_power = max_eirp;
+ }
+ }
+}
+
+
+static void nl80211_reg_rule_ht40(u32 start, u32 end,
+ struct phy_info_arg *results)
+{
+ u16 m;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ nl80211_set_ht40_mode(&results->modes[m], start, end);
+ }
+}
+
+
+static void nl80211_reg_rule_sec(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 20)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
+ }
+}
+
+
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+ if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+ if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+ if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+ }
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 80)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ /* TODO: use a real VHT support indication */
+ if (!results->modes[m].vht_capab)
+ continue;
+
+ nl80211_set_vht_mode(&results->modes[m], start, end);
+ }
+}
+
+
+static const char * dfs_domain_name(enum nl80211_dfs_regions region)
+{
+ switch (region) {
+ case NL80211_DFS_UNSET:
+ return "DFS-UNSET";
+ case NL80211_DFS_FCC:
+ return "DFS-FCC";
+ case NL80211_DFS_ETSI:
+ return "DFS-ETSI";
+ case NL80211_DFS_JP:
+ return "DFS-JP";
+ default:
+ return "DFS-invalid";
+ }
+}
+
+
+static int nl80211_get_reg(struct nl_msg *msg, void *arg)
+{
+ struct phy_info_arg *results = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *nl_rule;
+ struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
+ int rem_rule;
+ static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
+ !tb_msg[NL80211_ATTR_REG_RULES]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
+ "available");
+ return NL_SKIP;
+ }
+
+ if (tb_msg[NL80211_ATTR_DFS_REGION]) {
+ enum nl80211_dfs_regions dfs_domain;
+ dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
+ dfs_domain_name(dfs_domain));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
+ continue;
+ start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+ if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+ max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+ if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
+ flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
+ start, end, max_bw, max_eirp,
+ flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
+ flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
+ flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
+ flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
+ "",
+ flags & NL80211_RRF_DFS ? " (DFS)" : "",
+ flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
+ flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
+ flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
+ if (max_bw >= 40)
+ nl80211_reg_rule_ht40(start, end, results);
+ if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ nl80211_reg_rule_max_eirp(start, end, max_eirp,
+ results);
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_sec(tb_rule, results);
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_vht(tb_rule, results);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+ struct phy_info_arg *results)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+}
+
+
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ u32 feat;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int nl_flags = 0;
+ struct nl_msg *msg;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ .last_mode = -1,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl_flags = NLM_F_DUMP;
+ if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ nl80211_set_regulatory_flags(drv, &result);
+ return wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
+ }
+
+ return NULL;
+}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
new file mode 100644
index 0000000..85769d8
--- /dev/null
+++ b/src/drivers/driver_nl80211_event.c
@@ -0,0 +1,1948 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Event processing
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "driver_nl80211.h"
+
+
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ C2S(NL80211_CMD_GET_COALESCE)
+ C2S(NL80211_CMD_SET_COALESCE)
+ C2S(NL80211_CMD_CHANNEL_SWITCH)
+ C2S(NL80211_CMD_VENDOR)
+ C2S(NL80211_CMD_SET_QOS_MAP)
+ C2S(NL80211_CMD_ADD_TX_TS)
+ C2S(NL80211_CMD_DEL_TX_TS)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+#undef C2S
+}
+
+
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore auth event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+ os_memset(drv->auth_attempt_bssid, 0, 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.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ 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);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
+}
+
+
+static int nl80211_parse_wmm_params(struct nlattr *wmm_attr,
+ struct wmm_params *wmm_params)
+{
+ struct nlattr *wmm_info[NL80211_STA_WME_MAX + 1];
+ static struct nla_policy wme_policy[NL80211_STA_WME_MAX + 1] = {
+ [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
+ };
+
+ if (!wmm_attr) {
+ wpa_printf(MSG_DEBUG, "nl80211: WMM data missing");
+ return -1;
+ }
+
+ if (nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
+ wme_policy)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to parse nested attributes");
+ return -1;
+ }
+
+ if (!wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
+ return -1;
+
+ wmm_params->uapsd_queues =
+ nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]);
+ wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO;
+
+ return 0;
+}
+
+
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len, struct nlattr *wmm)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 status;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore assoc event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Associate event");
+ 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;
+ }
+
+ status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ if (status != WLAN_STATUS_SUCCESS) {
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_reject.bssid = mgmt->bssid;
+ 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;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+ os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
+
+ 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);
+ }
+
+ event.assoc_info.freq = drv->assoc_freq;
+
+ nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+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,
+ struct nlattr *authorized,
+ struct nlattr *key_replay_ctr,
+ struct nlattr *ptk_kck,
+ struct nlattr *ptk_kek)
+{
+ union wpa_event_data event;
+ u16 status_code;
+
+ 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;
+ }
+
+ status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
+
+ if (cmd == NL80211_CMD_CONNECT) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
+ status_code, drv->ignore_next_local_disconnect);
+ } else if (cmd == NL80211_CMD_ROAM) {
+ wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
+ if (addr)
+ event.assoc_reject.bssid = nla_data(addr);
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (!event.assoc_reject.bssid ||
+ (os_memcmp(event.assoc_reject.bssid,
+ drv->auth_attempt_bssid,
+ ETH_ALEN) != 0)) {
+ /*
+ * Ignore the event that came without a BSSID or
+ * for the old connection since this is likely
+ * not relevant to the new Connect command.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore connection failure event triggered during reassociation");
+ return;
+ }
+ }
+ 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 = status_code;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ if (addr) {
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ }
+
+ 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);
+ }
+
+ event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
+ if (authorized && nla_get_u8(authorized)) {
+ event.assoc_info.authorized = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
+ }
+ if (key_replay_ctr) {
+ event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr);
+ event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr);
+ }
+ if (ptk_kck) {
+ event.assoc_info.ptk_kck = nla_data(ptk_kck);
+ event.assoc_info.ptk_kck_len = nla_len(ptk_kck);
+ }
+ if (ptk_kek) {
+ event.assoc_info.ptk_kek = nla_data(ptk_kek);
+ event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *reason, struct nlattr *addr,
+ struct nlattr *by_ap)
+{
+ union wpa_event_data data;
+ unsigned int locally_generated = by_ap == NULL;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two disassociation events that could
+ * confuse the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event when using userspace SME");
+ return;
+ }
+
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event triggered during reassociation");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+ "disconnect but got another disconnect "
+ "event first");
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+ nl80211_mark_disconnected(drv);
+ os_memset(&data, 0, sizeof(data));
+ if (reason)
+ data.deauth_info.reason_code = nla_get_u16(reason);
+ data.deauth_info.locally_generated = by_ap == NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
+{
+ int freq1 = 0;
+
+ switch (convert2width(width)) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 0;
+ case CHAN_WIDTH_40:
+ freq1 = cf1 - 10;
+ break;
+ case CHAN_WIDTH_80:
+ freq1 = cf1 - 30;
+ break;
+ case CHAN_WIDTH_160:
+ freq1 = cf1 - 70;
+ break;
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_80P80:
+ /* FIXME: implement this */
+ return 0;
+ }
+
+ return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
+{
+ struct i802_bss *bss;
+ union wpa_event_data data;
+ int ht_enabled = 1;
+ int chan_offset = 0;
+ int ifidx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+ if (!freq)
+ return;
+
+ ifidx = nla_get_u32(ifindex);
+ bss = get_bss_ifindex(drv, ifidx);
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
+ }
+
+ if (type) {
+ enum nl80211_channel_type ch_type = nla_get_u32(type);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type);
+ switch (ch_type) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+ } else if (bw && cf1) {
+ /* This can happen for example with VHT80 ch switch */
+ chan_offset = calculate_chan_offset(nla_get_u32(bw),
+ nla_get_u32(freq),
+ nla_get_u32(cf1),
+ cf2 ? nla_get_u32(cf2) : 0);
+ } else {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
+ }
+
+ os_memset(&data, 0, sizeof(data));
+ data.ch_switch.freq = nla_get_u32(freq);
+ data.ch_switch.ht_enabled = ht_enabled;
+ data.ch_switch.ch_offset = chan_offset;
+ if (bw)
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ if (cf1)
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
+
+ bss->freq = data.ch_switch.freq;
+
+ wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
+{
+ union wpa_event_data event;
+ enum wpa_event_type ev;
+
+ if (nla_len(addr) != ETH_ALEN)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+ cmd, MAC2STR((u8 *) nla_data(addr)));
+
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ ev = EVENT_AUTH_TIMED_OUT;
+ else if (cmd == NL80211_CMD_ASSOCIATE)
+ ev = EVENT_ASSOC_TIMED_OUT;
+ else
+ return;
+
+ 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 void mlme_event_mgmt(struct i802_bss *bss,
+ struct nlattr *freq, struct nlattr *sig,
+ const u8 *frame, size_t len)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 fc, stype;
+ int ssi_signal = 0;
+ int rx_freq = 0;
+
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+ return;
+ }
+
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (sig)
+ ssi_signal = (s32) nla_get_u32(sig);
+
+ os_memset(&event, 0, sizeof(event));
+ if (freq) {
+ event.rx_mgmt.freq = nla_get_u32(freq);
+ rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: RX frame sa=" MACSTR
+ " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
+ MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc,
+ le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
+ (unsigned int) len);
+ event.rx_mgmt.frame = frame;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.drv_priv = bss;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *cookie, const u8 *frame,
+ size_t len, struct nlattr *ack)
+{
+ union wpa_event_data event;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
+ if (!is_ap_interface(drv->nlmode)) {
+ u64 cookie_val;
+
+ if (!cookie)
+ return;
+
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+ " cookie=0%llx%s (ack=%d)",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)", ack != NULL);
+ if (cookie_val != drv->send_action_cookie)
+ return;
+ }
+
+ hdr = (const struct ieee80211_hdr *) frame;
+ fc = le_to_host16(hdr->frame_control);
+
+ 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 mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ const u8 *bssid = NULL;
+ u16 reason_code = 0;
+
+ if (type == EVENT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len >= 24) {
+ bssid = mgmt->bssid;
+
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ !drv->associated &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ return;
+ }
+
+ 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;
+ }
+ }
+
+ nl80211_mark_disconnected(drv);
+ 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);
+
+ if (type == EVENT_DISASSOC) {
+ event.disassoc_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ event.disassoc_info.addr = bssid;
+ event.disassoc_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.disassoc.variable) {
+ event.disassoc_info.ie = mgmt->u.disassoc.variable;
+ event.disassoc_info.ie_len = frame + len -
+ mgmt->u.disassoc.variable;
+ }
+ } else {
+ if (drv->ignore_deauth_event) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
+ drv->ignore_deauth_event = 0;
+ return;
+ }
+ event.deauth_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ if (drv->ignore_next_local_deauth) {
+ drv->ignore_next_local_deauth = 0;
+ if (event.deauth_info.locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
+ }
+ event.deauth_info.addr = bssid;
+ event.deauth_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.deauth.variable) {
+ event.deauth_info.ie = mgmt->u.deauth.variable;
+ event.deauth_info.ie_len = frame + len -
+ mgmt->u.deauth.variable;
+ }
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 reason_code = 0;
+
+ if (type == EVENT_UNPROT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
+ if (len < 24)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+
+ 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);
+
+ if (type == EVENT_UNPROT_DISASSOC) {
+ event.unprot_disassoc.sa = mgmt->sa;
+ event.unprot_disassoc.da = mgmt->da;
+ event.unprot_disassoc.reason_code = reason_code;
+ } else {
+ event.unprot_deauth.sa = mgmt->sa;
+ event.unprot_deauth.da = mgmt->da;
+ event.unprot_deauth.reason_code = reason_code;
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event(struct i802_bss *bss,
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie, struct nlattr *sig,
+ struct nlattr *wmm)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const u8 *data;
+ size_t len;
+
+ if (timed_out && addr) {
+ mlme_timeout_event(drv, cmd, addr);
+ return;
+ }
+
+ if (frame == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLME event %d (%s) without frame data",
+ cmd, nl80211_command_to_string(cmd));
+ return;
+ }
+
+ data = nla_data(frame);
+ len = nla_len(frame);
+ if (len < 4 + 2 * ETH_ALEN) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+ MACSTR ") - too short",
+ cmd, nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr));
+ return;
+ }
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+ ") A1=" MACSTR " A2=" MACSTR, cmd,
+ nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr), MAC2STR(data + 4),
+ MAC2STR(data + 4 + ETH_ALEN));
+ if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+ os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+ "for foreign address", bss->ifname);
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
+ nla_data(frame), nla_len(frame));
+
+ 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), wmm);
+ 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_FRAME:
+ mlme_event_mgmt(bss, freq, sig, nla_data(frame),
+ nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
+ break;
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ 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;
+
+ 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);
+ }
+
+ wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ unsigned int freq;
+
+ 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));
+
+ freq = nl80211_get_assoc_freq(drv);
+ if (freq) {
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
+ freq);
+ drv->first_bss->freq = freq;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
+ int cancel_event, struct nlattr *tb[])
+{
+ unsigned int freq, chan_type, duration;
+ union wpa_event_data data;
+ u64 cookie;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ else
+ freq = 0;
+
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+ chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ else
+ chan_type = 0;
+
+ if (tb[NL80211_ATTR_DURATION])
+ duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
+ else
+ duration = 0;
+
+ if (tb[NL80211_ATTR_COOKIE])
+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ else
+ cookie = 0;
+
+ 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");
+
+ if (cookie != drv->remain_on_chan_cookie)
+ return; /* not for us */
+
+ if (cancel_event)
+ drv->pending_remain_on_chan = 0;
+
+ 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 mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (tb[NL80211_ATTR_IE]) {
+ data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+
+ if (tb[NL80211_ATTR_IE_RIC]) {
+ data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+ data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+ }
+
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(data.ft_ies.target_ap,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+ MAC2STR(data.ft_ies.target_ap));
+
+ wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+ struct nlattr *tb[])
+{
+ 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;
+
+ if (drv->scan_for_auth) {
+ drv->scan_for_auth = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+ "cfg80211 BSS entry");
+ wpa_driver_nl80211_authenticate_retry(drv);
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->aborted = aborted;
+
+ 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);
+ wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+ wpa_ssid_txt(s->ssid, s->ssid_len));
+ info->num_ssids++;
+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ char msg[200], *pos, *end;
+ int res;
+
+ pos = msg;
+ end = pos + sizeof(msg);
+ *pos = '\0';
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+ {
+ freqs[num_freqs] = nla_get_u32(nl);
+ res = os_snprintf(pos, end - pos, " %d",
+ freqs[num_freqs]);
+ if (!os_snprintf_error(end - pos, res))
+ pos += res;
+ num_freqs++;
+ if (num_freqs == MAX_REPORT_FREQS - 1)
+ break;
+ }
+ info->freqs = freqs;
+ info->num_freqs = num_freqs;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+ msg);
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ 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 },
+ [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+ };
+ struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+ enum nl80211_cqm_rssi_threshold_event event;
+ union wpa_event_data ed;
+ struct wpa_signal_info sig;
+ int res;
+
+ 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;
+ }
+
+ os_memset(&ed, 0, sizeof(ed));
+
+ if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+ os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+ return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+ return;
+ event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+
+ 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;
+
+ res = nl80211_get_link_signal(drv, &sig);
+ if (res == 0) {
+ ed.signal_change.current_signal = sig.current_signal;
+ ed.signal_change.current_txrate = sig.current_txrate;
+ wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
+ sig.current_signal, sig.current_txrate);
+ }
+
+ res = nl80211_get_link_noise(drv, &sig);
+ if (res == 0) {
+ ed.signal_change.current_noise = sig.current_noise;
+ wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
+ sig.current_noise);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
+}
+
+
+static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ const u8 *addr;
+ union wpa_event_data data;
+
+ if (drv->nlmode != NL80211_IFTYPE_MESH_POINT)
+ return;
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+ return;
+
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+ MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ data.mesh_peer.peer = addr;
+ data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]);
+ wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data);
+}
+
+
+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
+ struct i802_bss *bss,
+ struct nlattr **tb)
+{
+ u8 *addr;
+ union wpa_event_data data;
+
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return;
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
+
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+ u8 *ies = NULL;
+ size_t ies_len = 0;
+ if (tb[NL80211_ATTR_IE]) {
+ ies = nla_data(tb[NL80211_ATTR_IE]);
+ ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+ wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
+ drv_event_assoc(bss->ctx, addr, ies, ies_len, 0);
+ return;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
+ wpa_supplicant_event(bss->ctx, EVENT_IBSS_RSN_START, &data);
+}
+
+
+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u8 *addr;
+ union wpa_event_data data;
+
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return;
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
+ MAC2STR(addr));
+
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+ drv_event_disassoc(drv->ctx, addr);
+ return;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+}
+
+
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+ static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+ [NL80211_REKEY_DATA_KEK] = {
+ .minlen = NL80211_KEK_LEN,
+ .maxlen = NL80211_KEK_LEN,
+ },
+ [NL80211_REKEY_DATA_KCK] = {
+ .minlen = NL80211_KCK_LEN,
+ .maxlen = NL80211_KCK_LEN,
+ },
+ [NL80211_REKEY_DATA_REPLAY_CTR] = {
+ .minlen = NL80211_REPLAY_CTR_LEN,
+ .maxlen = NL80211_REPLAY_CTR_LEN,
+ },
+ };
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+ if (!tb[NL80211_ATTR_REKEY_DATA])
+ return;
+ if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+ tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+ return;
+ if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+ MAC2STR(data.driver_gtk_rekey.bssid));
+ data.driver_gtk_rekey.replay_ctr =
+ nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+ data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+ static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+ [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+ [NL80211_PMKSA_CANDIDATE_BSSID] = {
+ .minlen = ETH_ALEN,
+ .maxlen = ETH_ALEN,
+ },
+ [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+ };
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
+ if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
+ return;
+ if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+ tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
+ return;
+ if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+ !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid,
+ nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+ data.pmkid_candidate.index =
+ nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+ data.pmkid_candidate.preauth =
+ cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.client_poll.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+ case NL80211_TDLS_SETUP:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_SETUP;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+ "event");
+ return;
+ }
+ if (tb[NL80211_ATTR_REASON_CODE]) {
+ data.tdls.reason_code =
+ nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ u32 reason;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.connect_failed_reason.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+ switch (reason) {
+ case NL80211_CONN_FAIL_MAX_CLIENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+ data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+ break;
+ case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+ wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+ " tried to connect",
+ MAC2STR(data.connect_failed_reason.addr));
+ data.connect_failed_reason.code = BLOCKED_CLIENT;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+ "%u", reason);
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ enum nl80211_radar_event event_type;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+ /* Check HT params */
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ data.dfs_event.ht_enabled = 1;
+ data.dfs_event.chan_offset = 0;
+
+ switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ data.dfs_event.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ data.dfs_event.chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ data.dfs_event.chan_offset = -1;
+ break;
+ }
+ }
+
+ /* Get VHT params */
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+ data.dfs_event.freq, data.dfs_event.ht_enabled,
+ data.dfs_event.chan_offset, data.dfs_event.chan_width,
+ data.dfs_event.cf1, data.dfs_event.cf2);
+
+ switch (event_type) {
+ case NL80211_RADAR_DETECTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+ break;
+ case NL80211_RADAR_CAC_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+ break;
+ case NL80211_RADAR_NOP_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+ "received", event_type);
+ break;
+ }
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+ int wds)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data event;
+
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = bss->addr;
+ event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+ event.rx_from_unknown.wds = wds;
+
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ u32 i, count;
+ union wpa_event_data event;
+ struct wpa_freq_range *range = NULL;
+ const struct qca_avoid_freq_list *freq_range;
+
+ freq_range = (const struct qca_avoid_freq_list *) data;
+ if (len < sizeof(freq_range->count))
+ return;
+
+ count = freq_range->count;
+ if (len < sizeof(freq_range->count) +
+ count * sizeof(struct qca_avoid_freq_range)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
+ (unsigned int) len);
+ return;
+ }
+
+ if (count > 0) {
+ range = os_calloc(count, sizeof(struct wpa_freq_range));
+ if (range == NULL)
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ for (i = 0; i < count; i++) {
+ unsigned int idx = event.freq_range.num;
+ range[idx].min = freq_range->range[i].start_freq;
+ range[idx].max = freq_range->range[i].end_freq;
+ wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
+ range[idx].min, range[idx].max);
+ if (range[idx].min > range[idx].max) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
+ continue;
+ }
+ event.freq_range.num++;
+ }
+ event.freq_range.range = range;
+
+ wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
+
+ os_free(range);
+}
+
+
+static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS channel selection vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
+ (struct nlattr *) data, len, NULL))
+ return;
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.acs_selected_channels.pri_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+ event.acs_selected_channels.sec_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
+}
+
+
+static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1];
+ u8 *bssid;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Key management roam+auth vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX,
+ (struct nlattr *) data, len, NULL))
+ return;
+ if (!tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] ||
+ nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED])
+ return;
+
+ bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]);
+ wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid));
+
+ mlme_event_connect(drv, NL80211_CMD_ROAM, NULL,
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]);
+}
+
+
+static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
+ u32 subcmd, u8 *data, size_t len)
+{
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+ qca_nl80211_avoid_freq(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
+ qca_nl80211_key_mgmt_auth(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ qca_nl80211_acs_select_ch(drv, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore unsupported QCA vendor event %u",
+ subcmd);
+ break;
+ }
+}
+
+
+static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u32 vendor_id, subcmd, wiphy = 0;
+ int wiphy_idx;
+ u8 *data = NULL;
+ size_t len = 0;
+
+ if (!tb[NL80211_ATTR_VENDOR_ID] ||
+ !tb[NL80211_ATTR_VENDOR_SUBCMD])
+ return;
+
+ vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
+ subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
+
+ if (tb[NL80211_ATTR_WIPHY])
+ wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
+ wiphy, vendor_id, subcmd);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
+ len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
+ }
+
+ wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
+ if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
+ wiphy, wiphy_idx);
+ return;
+ }
+
+ switch (vendor_id) {
+ case OUI_QCA:
+ nl80211_vendor_event_qca(drv, subcmd, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
+ break;
+ }
+}
+
+
+static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+ enum nl80211_reg_initiator init;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+
+ if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
+ wpa_printf(MSG_DEBUG, " * initiator=%d", init);
+ switch (init) {
+ case NL80211_REGDOM_SET_BY_CORE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ break;
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
+ break;
+ }
+
+ if (tb[NL80211_ATTR_REG_TYPE]) {
+ enum nl80211_reg_type type;
+ type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
+ wpa_printf(MSG_DEBUG, " * type=%d", type);
+ switch (type) {
+ case NL80211_REGDOM_TYPE_COUNTRY:
+ data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
+ break;
+ case NL80211_REGDOM_TYPE_WORLD:
+ data.channel_list_changed.type = REGDOM_TYPE_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_CUSTOM_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_INTERSECTION:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_INTERSECTION;
+ break;
+ }
+ }
+
+ if (tb[NL80211_ATTR_REG_ALPHA2]) {
+ os_strlcpy(data.channel_list_changed.alpha2,
+ nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
+ sizeof(data.channel_list_changed.alpha2));
+ wpa_printf(MSG_DEBUG, " * alpha2=%s",
+ data.channel_list_changed.alpha2);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+ struct nlattr **tb)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+ cmd, nl80211_command_to_string(cmd), bss->ifname);
+
+ if (cmd == NL80211_CMD_ROAM &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ /*
+ * Device will use roam+auth vendor event to indicate
+ * roaming, so ignore the regular roam event.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
+ cmd);
+ return;
+ }
+
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+ (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+ cmd == NL80211_CMD_SCAN_ABORTED)) {
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ }
+
+ switch (cmd) {
+ case NL80211_CMD_TRIGGER_SCAN:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+ drv->scan_state = SCAN_STARTED;
+ if (drv->scan_for_auth) {
+ /*
+ * Cannot indicate EVENT_SCAN_STARTED here since we skip
+ * EVENT_SCAN_RESULTS in scan_for_auth case and the
+ * upper layer implementation could get confused about
+ * scanning state.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
+ break;
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+ drv->scan_state = SCHED_SCAN_STARTED;
+ break;
+ case NL80211_CMD_SCHED_SCAN_STOPPED:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+ drv->scan_state = SCHED_SCAN_STOPPED;
+ wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+ break;
+ case NL80211_CMD_NEW_SCAN_RESULTS:
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New scan results available");
+ drv->scan_state = SCAN_COMPLETED;
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ send_scan_event(drv, 0, tb);
+ break;
+ case NL80211_CMD_SCHED_SCAN_RESULTS:
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New sched scan results available");
+ drv->scan_state = SCHED_SCAN_RESULTS;
+ send_scan_event(drv, 0, tb);
+ break;
+ case NL80211_CMD_SCAN_ABORTED:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+ drv->scan_state = SCAN_ABORTED;
+ /*
+ * Need to indicate that scan results are available in order
+ * not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ 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_FRAME_TX_STATUS:
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event(bss, 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],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM],
+ tb[NL80211_ATTR_STA_WME]);
+ break;
+ case NL80211_CMD_CONNECT:
+ case NL80211_CMD_ROAM:
+ mlme_event_connect(drv, cmd,
+ tb[NL80211_ATTR_STATUS_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_REQ_IE],
+ tb[NL80211_ATTR_RESP_IE],
+ NULL, NULL, NULL, NULL);
+ break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2]);
+ break;
+ case NL80211_CMD_DISCONNECT:
+ mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
+ break;
+ case NL80211_CMD_MICHAEL_MIC_FAILURE:
+ mlme_event_michael_mic_failure(bss, 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;
+ case NL80211_CMD_REG_CHANGE:
+ nl80211_reg_change_event(drv, tb);
+ break;
+ case NL80211_CMD_REG_BEACON_HINT:
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+ os_memset(&data, 0, sizeof(data));
+ data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+ &data);
+ break;
+ case NL80211_CMD_NEW_STATION:
+ nl80211_new_station_event(drv, bss, tb);
+ break;
+ case NL80211_CMD_DEL_STATION:
+ nl80211_del_station_event(drv, tb);
+ break;
+ case NL80211_CMD_SET_REKEY_OFFLOAD:
+ nl80211_rekey_offload_event(drv, tb);
+ break;
+ case NL80211_CMD_PMKSA_CANDIDATE:
+ nl80211_pmksa_candidate_event(drv, tb);
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ nl80211_client_probe_event(drv, tb);
+ break;
+ case NL80211_CMD_TDLS_OPER:
+ nl80211_tdls_oper_event(drv, tb);
+ break;
+ case NL80211_CMD_CONN_FAILED:
+ nl80211_connect_failed_event(drv, tb);
+ break;
+ case NL80211_CMD_FT_EVENT:
+ mlme_event_ft_event(drv, tb);
+ break;
+ case NL80211_CMD_RADAR_DETECT:
+ nl80211_radar_event(drv, tb);
+ break;
+ case NL80211_CMD_STOP_AP:
+ nl80211_stop_ap(drv, tb);
+ break;
+ case NL80211_CMD_VENDOR:
+ nl80211_vendor_event(drv, tb);
+ break;
+ case NL80211_CMD_NEW_PEER_CANDIDATE:
+ nl80211_new_peer_candidate(drv, tb);
+ break;
+ default:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", cmd);
+ break;
+ }
+}
+
+
+int process_global_event(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_global *global = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wpa_driver_nl80211_data *drv, *tmp;
+ int ifidx = -1;
+ struct i802_bss *bss;
+ u64 wdev_id = 0;
+ int wdev_id_set = 0;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX])
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ else if (tb[NL80211_ATTR_WDEV]) {
+ wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wdev_id_set = 1;
+ }
+
+ dl_list_for_each_safe(drv, tmp, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if ((ifidx == -1 && !wdev_id_set) ||
+ ifidx == bss->ifindex ||
+ (wdev_id_set && bss->wdev_id_set &&
+ wdev_id == bss->wdev_id)) {
+ do_process_drv_event(bss, gnlh->cmd, tb);
+ return NL_SKIP;
+ }
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)",
+ gnlh->cmd, ifidx, (long long unsigned int) wdev_id);
+ }
+
+ return NL_SKIP;
+}
+
+
+int process_bss_event(struct nl_msg *msg, void *arg)
+{
+ struct i802_bss *bss = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+ gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+ bss->ifname);
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_FRAME:
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event(bss, 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],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM],
+ tb[NL80211_ATTR_STA_WME]);
+ break;
+ case NL80211_CMD_UNEXPECTED_FRAME:
+ nl80211_spurious_frame(bss, tb, 0);
+ break;
+ case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+ nl80211_spurious_frame(bss, tb, 1);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", gnlh->cmd);
+ break;
+ }
+
+ return NL_SKIP;
+}
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
new file mode 100644
index 0000000..45385da
--- /dev/null
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -0,0 +1,491 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface
+ * Copyright (c) 2002-2014, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "linux_ioctl.h"
+#include "radiotap_iter.h"
+#include "driver_nl80211.h"
+
+
+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)
+{
+ struct ieee80211_hdr *hdr = (void *)buf;
+ u16 fc;
+ union wpa_event_data event;
+
+ if (len < sizeof(*hdr))
+ return;
+
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+ event.rx_from_unknown.addr = hdr->addr2;
+ event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+ (WLAN_FC_FROMDS | WLAN_FC_TODS);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+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) {
+ wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+ strerror(errno));
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
+ return;
+ }
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ wpa_printf(MSG_INFO, "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((*(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_DBM_ANTSIGNAL:
+ ssi_signal = (s8) *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.
+ *
+ * For now allow all To DS data frames through.
+ */
+ /* load the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
+ /* mask off frame type, version and DS status */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
+ /* accept frame if version 0, type 2 and To DS, fall through otherwise
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
+
+#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 = ARRAY_SIZE(msock_filter_insns),
+ .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))) {
+ wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ if (drv->monitor_refcount > 0)
+ drv->monitor_refcount--;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+ drv->monitor_refcount);
+ if (drv->monitor_refcount > 0)
+ return;
+
+ if (drv->monitor_ifidx >= 0) {
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ drv->monitor_ifidx = -1;
+ }
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ drv->monitor_sock = -1;
+ }
+}
+
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
+
+ if (drv->monitor_ifidx >= 0) {
+ drv->monitor_refcount++;
+ wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+ drv->monitor_refcount);
+ return 0;
+ }
+
+ if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
+ /*
+ * P2P interface name is of the format p2p-%s-%d. For monitor
+ * interface name corresponding to P2P GO, replace "p2p-" with
+ * "mon-" to retain the same interface name length and to
+ * indicate that it is a monitor interface.
+ */
+ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
+ } else {
+ /* Non-P2P interface with AP functionality. */
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+ }
+
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+ 0, NULL, NULL, 0);
+
+ if (drv->monitor_ifidx == -EOPNOTSUPP) {
+ /*
+ * This is backward compatibility for a few versions of
+ * the kernel only that didn't advertise the right
+ * attributes for the only driver that then supported
+ * AP mode w/o monitor -- ath6kl.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
+ "monitor interface type - try to run without it");
+ drv->device_ap_sme = 1;
+ }
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (linux_set_iface_flags(drv->global->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) {
+ wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+ strerror(errno));
+ 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) {
+ wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
+ goto error;
+ }
+
+ drv->monitor_refcount++;
+ return 0;
+ error:
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+}
+
+
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack)
+{
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ 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 */
+ };
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+ int res;
+ u16 txflags = 0;
+
+ if (encrypt)
+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+ if (drv->monitor_sock < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
+ "for %s", __func__);
+ return -1;
+ }
+
+ if (noack)
+ txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+ WPA_PUT_LE16(&rtap_hdr[12], txflags);
+
+ res = sendmsg(drv->monitor_sock, &msg, 0);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
new file mode 100644
index 0000000..7538d60
--- /dev/null
+++ b/src/drivers/driver_nl80211_scan.c
@@ -0,0 +1,796 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "driver_nl80211.h"
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *scan_results = arg;
+ struct wpa_scan_res *scan_res;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+ "attributes");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ for (i = 0; i < scan_results->num; ++i) {
+ scan_res = scan_results->res[i];
+ if (!scan_res)
+ continue;
+ if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ scan_res->freq)
+ continue;
+ if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ scan_res->noise = (s8)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_results *scan_res)
+{
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+ scan_res);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @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
+ * generate a scan completed event if the driver does not report this.
+ */
+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 != NL80211_IFTYPE_UNSPECIFIED) {
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ }
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static struct nl_msg *
+nl80211_scan_common(struct i802_bss *bss, u8 cmd,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ size_t i;
+ u32 scan_flags = 0;
+
+ msg = nl80211_cmd_msg(bss, 0, cmd);
+ if (!msg)
+ return NULL;
+
+ if (params->num_ssids) {
+ struct nlattr *ssids;
+
+ ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+ if (ssids == NULL)
+ goto fail;
+ 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);
+ if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid))
+ goto fail;
+ }
+ nla_nest_end(msg, ssids);
+ }
+
+ if (params->extra_ies) {
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies))
+ goto fail;
+ }
+
+ if (params->freqs) {
+ struct nlattr *freqs;
+ freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+ if (freqs == NULL)
+ goto fail;
+ for (i = 0; params->freqs[i]; i++) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+ "MHz", params->freqs[i]);
+ if (nla_put_u32(msg, i + 1, params->freqs[i]))
+ goto fail;
+ }
+ nla_nest_end(msg, freqs);
+ }
+
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ if (params->only_new_results) {
+ wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
+ scan_flags |= NL80211_SCAN_FLAG_FLUSH;
+ }
+
+ if (params->low_priority && drv->have_low_prio_scan) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
+ scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+ }
+
+ if (params->mac_addr_rand) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
+ scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
+
+ if (params->mac_addr) {
+ wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
+ MAC2STR(params->mac_addr));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
+ params->mac_addr))
+ goto fail;
+ }
+
+ if (params->mac_addr_mask) {
+ wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
+ MACSTR, MAC2STR(params->mac_addr_mask));
+ if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
+ params->mac_addr_mask))
+ goto fail;
+ }
+ }
+
+ if (scan_flags &&
+ nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+ goto fail;
+
+ return msg;
+
+fail:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, timeout;
+ struct nl_msg *msg = NULL;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+ drv->scan_for_auth = 0;
+
+ msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
+ if (!msg)
+ return -1;
+
+ if (params->p2p_probe) {
+ struct nlattr *rates;
+
+ wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+ rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+ if (rates == NULL)
+ goto fail;
+
+ /*
+ * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+ * by masking out everything else apart from the OFDM rates 6,
+ * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+ * rates are left enabled.
+ */
+ if (nla_put(msg, NL80211_BAND_2GHZ, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
+ goto fail;
+ nla_nest_end(msg, rates);
+
+ if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
+ goto fail;
+ }
+
+ 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));
+ if (drv->hostapd && is_ap_interface(drv->nlmode)) {
+ enum nl80211_iftype old_mode = drv->nlmode;
+
+ /*
+ * mac80211 does not allow scan requests in AP mode, so
+ * try to do this in station mode.
+ */
+ if (wpa_driver_nl80211_set_mode(
+ bss, NL80211_IFTYPE_STATION))
+ goto fail;
+
+ if (wpa_driver_nl80211_scan(bss, params)) {
+ wpa_driver_nl80211_set_mode(bss, drv->nlmode);
+ goto fail;
+ }
+
+ /* Restore AP mode when processing scan results */
+ drv->ap_scan_as_station = old_mode;
+ ret = 0;
+ } else
+ goto fail;
+ }
+
+ drv->scan_state = SCAN_REQUESTED;
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 10;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver events to notify when scan is
+ * complete, so use longer timeout to avoid race conditions
+ * with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_sched_scan(void *priv,
+ struct wpa_driver_scan_params *params,
+ u32 interval)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+ size_t i;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+ msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+ goto fail;
+
+ if ((drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+ params->filter_rssi) {
+ struct nlattr *match_sets;
+ match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+ if (match_sets == NULL)
+ goto fail;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ struct nlattr *match_set_ssid;
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID",
+ drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len);
+
+ match_set_ssid = nla_nest_start(msg, i + 1);
+ if (match_set_ssid == NULL ||
+ nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ drv->filter_ssids[i].ssid_len,
+ drv->filter_ssids[i].ssid) ||
+ (params->filter_rssi &&
+ nla_put_u32(msg,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi)))
+ goto fail;
+
+ nla_nest_end(msg, match_set_ssid);
+ }
+
+ /*
+ * Due to backward compatibility code, newer kernels treat this
+ * matchset (with only an RSSI filter) as the default for all
+ * other matchsets, unless it's the only one, in which case the
+ * matchset will actually allow all SSIDs above the RSSI.
+ */
+ if (params->filter_rssi) {
+ struct nlattr *match_set_rssi;
+ match_set_rssi = nla_nest_start(msg, 0);
+ if (match_set_rssi == NULL ||
+ nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi))
+ goto fail;
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan RSSI filter %d dBm",
+ params->filter_rssi);
+ nla_nest_end(msg, match_set_rssi);
+ }
+
+ nla_nest_end(msg, match_sets);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ /* TODO: if we get an error here, we should fall back to normal scan */
+
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+ "ret=%d (%s)", ret, strerror(-ret));
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+ "scan interval %d msec", ret, interval);
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret;
+ struct nl_msg *msg;
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_stop(bss);
+#endif /* ANDROID */
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Sched scan stop failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Sched scan stop sent");
+ }
+
+ 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;
+}
+
+
+int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
+ [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ };
+ 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, *beacon_ie;
+ size_t ie_len, beacon_ie_len;
+ u8 *pos;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS])
+ return NL_SKIP;
+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy))
+ return NL_SKIP;
+ if (bss[NL80211_BSS_STATUS]) {
+ enum nl80211_bss_status status;
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ _arg->assoc_freq =
+ nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ _arg->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ _arg->ibss_freq =
+ nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+ _arg->ibss_freq);
+ }
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(_arg->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(_arg->assoc_bssid));
+ }
+ }
+ if (!res)
+ return NL_SKIP;
+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ } else {
+ ie = NULL;
+ ie_len = 0;
+ }
+ 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;
+ }
+
+ 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])
+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+ ETH_ALEN);
+ if (bss[NL80211_BSS_FREQUENCY])
+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ if (bss[NL80211_BSS_BEACON_INTERVAL])
+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+ if (bss[NL80211_BSS_CAPABILITY])
+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+ 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_QUAL_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;
+ 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;
+ }
+ }
+
+ /*
+ * cfg80211 maintains separate BSS table entries for APs if the same
+ * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
+ * not use frequency as a separate key in the BSS table, so filter out
+ * duplicated entries. Prefer associated BSS entry in such a case in
+ * order to get the correct frequency into the BSS table. Similarly,
+ * prefer newer entries over older.
+ */
+ for (i = 0; i < res->num; i++) {
+ const u8 *s1, *s2;
+ if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
+ continue;
+
+ s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
+ res->res[i]->ie_len, WLAN_EID_SSID);
+ s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
+ if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
+ os_memcmp(s1, s2, 2 + s1[1]) != 0)
+ continue;
+
+ /* Same BSSID,SSID was already included in scan results */
+ wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
+ "for " MACSTR, MAC2STR(r->bssid));
+
+ if (((r->flags & WPA_SCAN_ASSOCIATED) &&
+ !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
+ r->age < res->res[i]->age) {
+ os_free(res->res[i]);
+ res->res[i] = r;
+ } else
+ os_free(r);
+ return NL_SKIP;
+ }
+
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return NL_SKIP;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+
+ return NL_SKIP;
+}
+
+
+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 (is_sta_interface(drv->nlmode) &&
+ 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 (is_sta_interface(drv->nlmode) &&
+ !drv->associated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Local state "
+ "(not associated) does not match "
+ "with BSS state");
+ clear_state_mismatch(drv, r->bssid);
+ } else if (is_sta_interface(drv->nlmode) &&
+ 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 struct wpa_scan_results *
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
+{
+ 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 NULL;
+ if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
+ NL80211_CMD_GET_SCAN))) {
+ wpa_scan_results_free(res);
+ return NULL;
+ }
+
+ arg.drv = drv;
+ arg.res = res;
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+ "BSSes)", (unsigned long) res->num);
+ nl80211_get_noise_for_scan_results(drv, res);
+ return res;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ wpa_scan_results_free(res);
+ return NULL;
+}
+
+
+/**
+ * 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
+ */
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct wpa_scan_results *res;
+
+ res = nl80211_get_scan_results(drv);
+ if (res)
+ wpa_driver_nl80211_check_bss_status(drv, res);
+ return res;
+}
+
+
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+ struct wpa_scan_results *res;
+ size_t i;
+
+ res = nl80211_get_scan_results(drv);
+ if (res == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
+ return;
+ }
+
+ 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]" : "");
+ }
+
+ wpa_scan_results_free(res);
+}
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
index d75c14b..6ff3eae 100644
--- a/src/drivers/driver_none.c
+++ b/src/drivers/driver_none.c
@@ -74,13 +74,6 @@
}
-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)",
@@ -89,5 +82,4 @@
.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_privsep.c b/src/drivers/driver_privsep.c
index ed88e71..de23fbd 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -35,7 +35,7 @@
(struct sockaddr *) &drv->priv_addr,
sizeof(drv->priv_addr));
if (res < 0)
- perror("sendto");
+ wpa_printf(MSG_ERROR, "sendto: %s", strerror(errno));
return res < 0 ? -1 : 0;
}
@@ -59,7 +59,8 @@
msg.msg_namelen = sizeof(drv->priv_addr);
if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
- perror("sendmsg(cmd_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(cmd_socket): %s",
+ strerror(errno));
return -1;
}
@@ -74,14 +75,15 @@
tv.tv_usec = 0;
res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
- perror("select");
+ wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
return -1;
}
if (FD_ISSET(drv->cmd_socket, &rfds)) {
res = recv(drv->cmd_socket, reply, *reply_len, 0);
if (res < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s",
+ strerror(errno));
return -1;
}
*reply_len = res;
@@ -228,7 +230,7 @@
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,
+ __func__, priv, params->freq.freq, params->pairwise_suite,
params->group_suite, params->key_mgmt_suite,
params->auth_alg, params->mode);
@@ -241,7 +243,9 @@
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
os_memcpy(data->ssid, params->ssid, params->ssid_len);
data->ssid_len = params->ssid_len;
- data->freq = params->freq;
+ data->hwmode = params->freq.mode;
+ data->freq = params->freq.freq;
+ data->channel = params->freq.channel;
data->pairwise_suite = params->pairwise_suite;
data->group_suite = params->group_suite;
data->key_mgmt_suite = params->key_mgmt_suite;
@@ -439,7 +443,8 @@
res = recvfrom(sock, buf, buflen, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(priv_socket)");
+ wpa_printf(MSG_ERROR, "recvfrom(priv_socket): %s",
+ strerror(errno));
os_free(buf);
return;
}
@@ -629,7 +634,7 @@
drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->priv_socket < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_socket_path);
drv->own_socket_path = NULL;
return -1;
@@ -640,7 +645,9 @@
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("privsep-set-params priv-sock: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "privsep-set-params priv-sock: bind(PF_UNIX): %s",
+ strerror(errno));
close(drv->priv_socket);
drv->priv_socket = -1;
unlink(drv->own_socket_path);
@@ -654,7 +661,7 @@
drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->cmd_socket < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_cmd_path);
drv->own_cmd_path = NULL;
return -1;
@@ -665,7 +672,9 @@
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "privsep-set-params cmd-sock: bind(PF_UNIX): %s",
+ strerror(errno));
close(drv->cmd_socket);
drv->cmd_socket = -1;
unlink(drv->own_cmd_path);
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index 9ce3fa2..d3e0595 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -91,7 +91,8 @@
mii->reg_num = reg;
if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
- perror("ioctl[SIOCGMIIREG]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIREG]: %s",
+ strerror(errno));
return 0x00;
}
return mii->val_out;
@@ -108,7 +109,8 @@
mii->val_in = val;
if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
- perror("ioctl[SIOCSMIIREG");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSMIIREG]: %s",
+ strerror(errno));
}
}
@@ -394,7 +396,8 @@
os_memset(&drv->ifr, 0, sizeof(drv->ifr));
os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
- perror("ioctl[SIOCGMIIPHY]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIPHY]: %s",
+ strerror(errno));
os_free(drv);
return NULL;
}
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
deleted file mode 100644
index 66edfa7..0000000
--- a/src/drivers/driver_test.c
+++ /dev/null
@@ -1,2683 +0,0 @@
-/*
- * Testing driver interface for a simulated network driver
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/* 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 "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/un.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#define DRIVER_TEST_UNIX
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "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 "wps/wps.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 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
- struct sockaddr_un hostapd_addr;
-#endif /* DRIVER_TEST_UNIX */
- int hostapd_addr_set;
- struct sockaddr_in hostapd_addr_udp;
- int hostapd_addr_udp_set;
- char *own_socket_path;
- char *test_dir;
-#define MAX_SCAN_RESULTS 30
- struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
- size_t num_scanres;
- int use_associnfo;
- u8 assoc_wpa_ie[80];
- size_t assoc_wpa_ie_len;
- int 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, u32 flags)
-{
- 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 = ð
- 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 = ð
- 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, int noack)
-{
- 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, 0);
-}
-
-
-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,
- const struct wpabuf *assocresp)
-{
- 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,
- const char *bridge, int use_existing)
-{
- 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 || type == WPA_IF_P2P_GO ||
- type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
- 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 || type == WPA_IF_P2P_GO ||
- type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
- return test_driver_bss_remove(priv, ifname);
- 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);
- if (len < 0)
- return -1;
- wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
-
- if ((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);
- drv->global = params->global_priv;
-
- 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("test-driver-init: 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;
-
-#ifdef DRIVER_TEST_UNIX
- if (drv->associated && drv->hostapd_addr_set) {
- struct stat st;
- if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
- wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
- __func__, strerror(errno));
- drv->associated = 0;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
- }
- }
-#endif /* DRIVER_TEST_UNIX */
-
- eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-}
-
-
-static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-#ifdef DRIVER_TEST_UNIX
-static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
- const char *path)
-{
- struct dirent *dent;
- DIR *dir;
- struct sockaddr_un addr;
- char cmd[512], *pos, *end;
- int ret;
-
- dir = opendir(path);
- if (dir == NULL)
- return;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
- MAC2STR(drv->own_addr));
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- if (drv->probe_req_ie) {
- ret = os_snprintf(pos, end - pos, " ");
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
- drv->probe_req_ie_len);
- }
- 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 &&
- 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));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
- path, dent->d_name);
-
- if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("sendto(test_socket)");
- }
- }
- closedir(dir);
-}
-#endif /* DRIVER_TEST_UNIX */
-
-
-static int wpa_driver_test_scan(void *priv,
- struct wpa_driver_scan_params *params)
-{
- 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
- if (drv->test_socket >= 0 && drv->test_dir)
- wpa_driver_scan_dir(drv, drv->test_dir);
-
- if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
- sendto(drv->test_socket, "SCAN", 4, 0,
- (struct sockaddr *) &drv->hostapd_addr,
- sizeof(drv->hostapd_addr)) < 0) {
- perror("sendto(test_socket)");
- }
-#endif /* DRIVER_TEST_UNIX */
-
- if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
- sendto(drv->test_socket, "SCAN", 4, 0,
- (struct sockaddr *) &drv->hostapd_addr_udp,
- sizeof(drv->hostapd_addr_udp)) < 0) {
- perror("sendto(test_socket)");
- }
-
- eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
- drv->ctx);
- return 0;
-}
-
-
-static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct wpa_scan_results *res;
- size_t i;
-
- res = os_zalloc(sizeof(*res));
- if (res == NULL)
- return NULL;
-
- res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
- if (res->res == NULL) {
- os_free(res);
- return NULL;
- }
-
- for (i = 0; i < drv->num_scanres; i++) {
- struct wpa_scan_res *r;
- if (drv->scanres[i] == NULL)
- continue;
- r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
- if (r == NULL)
- break;
- os_memcpy(r, drv->scanres[i],
- sizeof(*r) + drv->scanres[i]->ie_len);
- res->res[res->num++] = r;
- }
-
- return res;
-}
-
-
-static int wpa_driver_test_set_key(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: 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)
- 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;
- }
-
- return 0;
-}
-
-
-static int wpa_driver_test_associate(
- void *priv, struct wpa_driver_associate_params *params)
-{
- 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.freq, params->pairwise_suite,
- params->group_suite, params->key_mgmt_suite,
- params->auth_alg, params->mode);
- wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
- if (params->bssid) {
- wpa_printf(MSG_DEBUG, " bssid=" MACSTR,
- MAC2STR(params->bssid));
- }
- if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " ssid",
- params->ssid, params->ssid_len);
- }
- if (params->wpa_ie) {
- wpa_hexdump(MSG_DEBUG, " wpa_ie",
- params->wpa_ie, params->wpa_ie_len);
- drv->assoc_wpa_ie_len = params->wpa_ie_len;
- if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
- drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
- os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
- drv->assoc_wpa_ie_len);
- } else
- drv->assoc_wpa_ie_len = 0;
-
- 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 &&
- 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,
- sizeof(drv->hostapd_addr.sun_path),
- "%s/AP-" MACSTR,
- drv->test_dir, MAC2STR(params->bssid));
- drv->hostapd_addr_set = 1;
- }
-#endif /* DRIVER_TEST_UNIX */
-
- if (params->mode == IEEE80211_MODE_AP) {
- if (params->ssid)
- 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);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
- MAC2STR(drv->own_addr));
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- if (params->ssid)
- pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
- params->ssid_len);
- ret = os_snprintf(pos, end - pos, " ");
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
- params->wpa_ie_len);
- end[-1] = '\0';
-#ifdef DRIVER_TEST_UNIX
- if (drv->hostapd_addr_set &&
- sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
- (struct sockaddr *) &drv->hostapd_addr,
- sizeof(drv->hostapd_addr)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
-#endif /* DRIVER_TEST_UNIX */
- if (drv->hostapd_addr_udp_set &&
- sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
- (struct sockaddr *) &drv->hostapd_addr_udp,
- sizeof(drv->hostapd_addr_udp)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
-
- if (params->ssid)
- 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) {
- if (params->ssid)
- 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);
- }
-
- return 0;
-}
-
-
-static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
-{
- 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 test_driver_bss *dbss = priv;
- os_memcpy(ssid, dbss->ssid, 32);
- return dbss->ssid_len;
-}
-
-
-static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
-{
-#ifdef DRIVER_TEST_UNIX
- if (drv->test_socket >= 0 &&
- sendto(drv->test_socket, "DISASSOC", 8, 0,
- (struct sockaddr *) &drv->hostapd_addr,
- sizeof(drv->hostapd_addr)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
-#endif /* DRIVER_TEST_UNIX */
- if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
- sendto(drv->test_socket, "DISASSOC", 8, 0,
- (struct sockaddr *) &drv->hostapd_addr_udp,
- sizeof(drv->hostapd_addr_udp)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
- return 0;
-}
-
-
-static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct 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(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,
- const char *data)
-{
- struct wpa_scan_res *res;
- const char *pos, *pos2;
- size_t len;
- u8 *ie_pos, *ie_start, *ie_end;
-#define MAX_IE_LEN 1000
- const u8 *ds_params;
-
- wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
- if (drv->num_scanres >= MAX_SCAN_RESULTS) {
- wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
- "result");
- return;
- }
-
- /* SCANRESP BSSID SSID IEs */
-
- res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
- if (res == NULL)
- return;
- ie_start = ie_pos = (u8 *) (res + 1);
- ie_end = ie_pos + MAX_IE_LEN;
-
- if (hwaddr_aton(data, res->bssid)) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
- os_free(res);
- return;
- }
-
- pos = data + 17;
- while (*pos == ' ')
- pos++;
- pos2 = os_strchr(pos, ' ');
- if (pos2 == NULL) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
- "in scanres");
- os_free(res);
- return;
- }
- len = (pos2 - pos) / 2;
- if (len > 32)
- len = 32;
- /*
- * Generate SSID IE from the SSID field since this IE is not included
- * in the main IE field.
- */
- *ie_pos++ = WLAN_EID_SSID;
- *ie_pos++ = len;
- if (hexstr2bin(pos, ie_pos, len) < 0) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
- os_free(res);
- return;
- }
- ie_pos += len;
-
- pos = pos2 + 1;
- pos2 = os_strchr(pos, ' ');
- if (pos2 == NULL)
- len = os_strlen(pos) / 2;
- else
- len = (pos2 - pos) / 2;
- if ((int) len > ie_end - ie_pos)
- len = ie_end - ie_pos;
- if (hexstr2bin(pos, ie_pos, len) < 0) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
- os_free(res);
- return;
- }
- ie_pos += len;
- res->ie_len = ie_pos - ie_start;
-
- if (pos2) {
- pos = pos2 + 1;
- while (*pos == ' ')
- pos++;
- if (os_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]);
- drv->scanres[drv->num_scanres++] = res;
-}
-
-
-static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const char *data)
-{
- struct test_driver_bss *bss;
-
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
- /* ASSOCRESP BSSID <res> */
- if (hwaddr_aton(data, bss->bssid)) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
- "assocresp");
- }
- if (drv->use_associnfo) {
- union wpa_event_data event;
- os_memset(&event, 0, sizeof(event));
- event.assoc_info.req_ies = drv->assoc_wpa_ie;
- event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
- }
- drv->associated = 1;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen)
-{
- drv->associated = 0;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-}
-
-
-static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const u8 *data, size_t data_len)
-{
- const u8 *src;
- 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;
- } else
- src = bss->bssid;
-
- drv_event_eapol_rx(drv->ctx, src, data, data_len);
-}
-
-
-static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const u8 *data, size_t data_len)
-{
- int freq = 0, own_freq;
- union wpa_event_data event;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- 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);
-
- mgmt = (const struct ieee80211_mgmt *) data;
- fc = le_to_host16(mgmt->frame_control);
-
- if (drv->probe_req_report && data_len >= 24) {
- 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.da = mgmt->da;
- event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- data_len - (mgmt->u.probe_req.variable - data);
- 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 (bss == NULL || !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);
-}
-
-
-static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
- void *sock_ctx)
-{
- struct wpa_driver_test_data *drv = eloop_ctx;
- char *buf;
- int res;
- struct sockaddr_storage from;
- socklen_t fromlen = sizeof(from);
- const size_t buflen = 2000;
-
- if (drv->ap) {
- test_driver_receive_unix(sock, eloop_ctx, sock_ctx);
- return;
- }
-
- buf = os_malloc(buflen);
- if (buf == NULL)
- return;
- res = recvfrom(sock, buf, buflen - 1, 0,
- (struct sockaddr *) &from, &fromlen);
- if (res < 0) {
- perror("recvfrom(test_socket)");
- os_free(buf);
- return;
- }
- buf[res] = '\0';
-
- wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
- if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
- wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
- fromlen, buf + 9);
- } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
- wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
- fromlen, buf + 10);
- } else if (os_strcmp(buf, "DISASSOC") == 0) {
- wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
- fromlen);
- } else if (os_strcmp(buf, "DEAUTH") == 0) {
- wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
- fromlen);
- } else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
- wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
- (const u8 *) buf + 6, res - 6);
- } else if (os_strncmp(buf, "MLME ", 5) == 0) {
- wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
- (const u8 *) buf + 5, res - 5);
- } else 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);
- }
- os_free(buf);
-}
-
-
-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 = 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->test_socket = -1;
-
- /* Set dummy BSSID and SSID for testing. */
- 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;
- }
-
- eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-
- return bss;
-}
-
-
-static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
-{
- if (drv->test_socket >= 0) {
- eloop_unregister_read_sock(drv->test_socket);
- close(drv->test_socket);
- drv->test_socket = -1;
- }
-
- if (drv->own_socket_path) {
- unlink(drv->own_socket_path);
- os_free(drv->own_socket_path);
- drv->own_socket_path = NULL;
- }
-}
-
-
-static void wpa_driver_test_deinit(void *priv)
-{
- struct 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, int ap)
-{
-#ifdef DRIVER_TEST_UNIX
- static unsigned int counter = 0;
- struct sockaddr_un addr;
- size_t len;
-
- os_free(drv->own_socket_path);
- if (dir) {
- len = os_strlen(dir) + 30;
- drv->own_socket_path = os_malloc(len);
- if (drv->own_socket_path == NULL)
- return -1;
- os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR,
- dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr));
- } else {
- drv->own_socket_path = os_malloc(100);
- if (drv->own_socket_path == NULL)
- return -1;
- os_snprintf(drv->own_socket_path, 100,
- "/tmp/wpa_supplicant_test-%d-%d",
- getpid(), counter++);
- }
-
- drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (drv->test_socket < 0) {
- perror("socket(PF_UNIX)");
- os_free(drv->own_socket_path);
- drv->own_socket_path = NULL;
- return -1;
- }
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
- if (bind(drv->test_socket, (struct sockaddr *) &addr,
- sizeof(addr)) < 0) {
- perror("test-driver-attach: bind(PF_UNIX)");
- close(drv->test_socket);
- unlink(drv->own_socket_path);
- os_free(drv->own_socket_path);
- drv->own_socket_path = NULL;
- return -1;
- }
-
- eloop_register_read_sock(drv->test_socket,
- wpa_driver_test_receive_unix, drv, NULL);
-
- return 0;
-#else /* DRIVER_TEST_UNIX */
- return -1;
-#endif /* DRIVER_TEST_UNIX */
-}
-
-
-static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
- char *dst)
-{
- char *pos;
-
- pos = os_strchr(dst, ':');
- if (pos == NULL)
- return -1;
- *pos++ = '\0';
- wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
-
- drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->test_socket < 0) {
- perror("socket(PF_INET)");
- return -1;
- }
-
- os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
- drv->hostapd_addr_udp.sin_family = AF_INET;
-#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
- {
- int a[4];
- u8 *pos;
- sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
- pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
- *pos++ = a[0];
- *pos++ = a[1];
- *pos++ = a[2];
- *pos++ = a[3];
- }
-#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
- inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
-#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
- drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
-
- drv->hostapd_addr_udp_set = 1;
-
- eloop_register_read_sock(drv->test_socket,
- wpa_driver_test_receive_unix, drv, NULL);
-
- return 0;
-}
-
-
-static int wpa_driver_test_set_param(void *priv, const char *param)
-{
- struct 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);
- if (param == NULL)
- return 0;
-
- wpa_driver_test_close_test_socket(drv);
-
-#ifdef DRIVER_TEST_UNIX
- pos = os_strstr(param, "test_socket=");
- if (pos) {
- const char *pos2;
- size_t len;
-
- pos += 12;
- pos2 = os_strchr(pos, ' ');
- if (pos2)
- len = pos2 - pos;
- else
- len = os_strlen(pos);
- if (len > sizeof(drv->hostapd_addr.sun_path))
- return -1;
- os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
- drv->hostapd_addr.sun_family = AF_UNIX;
- os_memcpy(drv->hostapd_addr.sun_path, pos, len);
- drv->hostapd_addr_set = 1;
- }
-#endif /* DRIVER_TEST_UNIX */
-
- pos = os_strstr(param, "test_dir=");
- if (pos) {
- char *end;
- os_free(drv->test_dir);
- drv->test_dir = os_strdup(pos + 9);
- if (drv->test_dir == NULL)
- return -1;
- end = os_strchr(drv->test_dir, ' ');
- if (end)
- *end = '\0';
- if (wpa_driver_test_attach(drv, drv->test_dir, 0))
- return -1;
- } else {
- pos = os_strstr(param, "test_udp=");
- if (pos) {
- char *dst, *epos;
- dst = os_strdup(pos + 9);
- if (dst == NULL)
- return -1;
- epos = os_strchr(dst, ' ');
- if (epos)
- *epos = '\0';
- if (wpa_driver_test_attach_udp(drv, dst))
- return -1;
- os_free(dst);
- } else if (wpa_driver_test_attach(drv, NULL, 0))
- return -1;
- }
-
- if (os_strstr(param, "use_associnfo=1")) {
- wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
- drv->use_associnfo = 1;
- }
-
- return 0;
-}
-
-
-static const u8 * wpa_driver_test_get_mac_addr(void *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;
-}
-
-
-static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
- const u8 *data, size_t data_len)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- char *msg;
- size_t msg_len;
- struct l2_ethhdr eth;
- struct sockaddr *addr;
- socklen_t alen;
-#ifdef DRIVER_TEST_UNIX
- struct sockaddr_un addr_un;
-#endif /* DRIVER_TEST_UNIX */
-
- wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
-
- os_memset(ð, 0, sizeof(eth));
- os_memcpy(eth.h_dest, dest, ETH_ALEN);
- os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
- eth.h_proto = host_to_be16(proto);
-
- msg_len = 6 + sizeof(eth) + data_len;
- msg = os_malloc(msg_len);
- if (msg == NULL)
- return -1;
- os_memcpy(msg, "EAPOL ", 6);
- os_memcpy(msg + 6, ð, sizeof(eth));
- os_memcpy(msg + 6 + sizeof(eth), data, data_len);
-
- 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;
- alen = sizeof(drv->hostapd_addr_udp);
- } else {
-#ifdef DRIVER_TEST_UNIX
- addr = (struct sockaddr *) &drv->hostapd_addr;
- alen = sizeof(drv->hostapd_addr);
-#else /* DRIVER_TEST_UNIX */
- os_free(msg);
- return -1;
-#endif /* DRIVER_TEST_UNIX */
- }
- } else {
-#ifdef DRIVER_TEST_UNIX
- struct stat st;
- os_memset(&addr_un, 0, sizeof(addr_un));
- addr_un.sun_family = AF_UNIX;
- os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
- "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
- if (stat(addr_un.sun_path, &st) < 0) {
- os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
- "%s/AP-" MACSTR,
- drv->test_dir, MAC2STR(dest));
- }
- addr = (struct sockaddr *) &addr_un;
- alen = sizeof(addr_un);
-#else /* DRIVER_TEST_UNIX */
- os_free(msg);
- return -1;
-#endif /* DRIVER_TEST_UNIX */
- }
-
- if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
- perror("sendmsg(test_socket)");
- os_free(msg);
- return -1;
- }
-
- os_free(msg);
- return 0;
-}
-
-
-static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
- WPA_DRIVER_CAPA_KEY_MGMT_FT |
- WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
- capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
- WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP |
- WPA_DRIVER_CAPA_ENC_CCMP;
- capa->auth = WPA_DRIVER_AUTH_OPEN |
- WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
- capa->flags |= WPA_DRIVER_FLAGS_AP;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- capa->max_scan_ssids = 2;
- capa->max_remain_on_chan = 60000;
-
- return 0;
-}
-
-
-static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
- int protect_type,
- int key_type)
-{
- wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
- __func__, protect_type, key_type);
-
- if (addr) {
- wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
- __func__, MAC2STR(addr));
- }
-
- return 0;
-}
-
-
-static void * wpa_driver_test_global_init(void)
-{
- struct wpa_driver_test_global *global;
-
- global = os_zalloc(sizeof(*global));
- return global;
-}
-
-
-static void wpa_driver_test_global_deinit(void *priv)
-{
- struct wpa_driver_test_global *global = priv;
- os_free(global);
-}
-
-
-static struct wpa_interface_info *
-wpa_driver_test_get_interfaces(void *global_priv)
-{
- /* struct wpa_driver_test_global *global = priv; */
- struct wpa_interface_info *iface;
-
- iface = os_zalloc(sizeof(*iface));
- if (iface == NULL)
- return iface;
- iface->ifname = os_strdup("sta0");
- iface->desc = os_strdup("test interface 0");
- iface->drv_name = "test";
- iface->next = os_zalloc(sizeof(*iface));
- if (iface->next) {
- iface->next->ifname = os_strdup("sta1");
- iface->next->desc = os_strdup("test interface 1");
- iface->next->drv_name = "test";
- }
-
- return iface;
-}
-
-
-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_calloc(*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_calloc(11, sizeof(struct hostapd_channel_data));
- modes[0].rates = os_calloc(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_calloc(11, sizeof(struct hostapd_channel_data));
- modes[1].rates = os_calloc(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_calloc(1, sizeof(struct hostapd_channel_data));
- modes[2].rates = os_calloc(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,
- unsigned int wait,
- const u8 *dst, const u8 *src,
- const u8 *bssid,
- const u8 *data, size_t data_len,
- int no_cck)
-{
- 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, 0);
- 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;
-
- drv->remain_on_channel_freq = 0;
-
- wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
-}
-
-
-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",
- .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,
- .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,
- .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,
- .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 1b3a757..a1581b8 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -78,7 +78,7 @@
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
- perror("ioctl[SIOCGIWAP]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno));
ret = -1;
}
os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
@@ -108,7 +108,7 @@
os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
- perror("ioctl[SIOCSIWAP]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno));
ret = -1;
}
@@ -134,7 +134,8 @@
iwr.u.essid.length = 32;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+ strerror(errno));
ret = -1;
} else {
ret = iwr.u.essid.length;
@@ -192,7 +193,8 @@
iwr.u.essid.length = ssid_len;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s",
+ strerror(errno));
ret = -1;
}
@@ -218,7 +220,8 @@
iwr.u.freq.e = 1;
if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+ strerror(errno));
ret = -1;
}
@@ -815,7 +818,8 @@
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
- perror("socket(PF_INET,SOCK_DGRAM)");
+ wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s",
+ strerror(errno));
goto err1;
}
@@ -1027,7 +1031,8 @@
}
if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
- perror("ioctl[SIOCSIWSCAN]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s",
+ strerror(errno));
ret = -1;
}
@@ -1082,7 +1087,8 @@
"trying larger buffer (%lu bytes)",
(unsigned long) res_buf_len);
} else {
- perror("ioctl[SIOCGIWSCAN]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s",
+ strerror(errno));
os_free(res_buf);
return NULL;
}
@@ -1533,7 +1539,8 @@
sizeof(range->enc_capa);
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
os_free(range);
return -1;
} else if (iwr.u.data.length >= minlen &&
@@ -1568,8 +1575,9 @@
drv->capa.max_scan_ssids = 1;
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
- "flags 0x%x",
- drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ "flags 0x%llx",
+ drv->capa.key_mgmt, drv->capa.enc,
+ (unsigned long long) drv->capa.flags);
} else {
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
"assuming WPA is not supported");
@@ -1612,7 +1620,8 @@
ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
if (ret < 0)
- perror("ioctl[SIOCSIWENCODEEXT] PMK");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s",
+ strerror(errno));
os_free(ext);
return ret;
@@ -1704,7 +1713,8 @@
ret = -2;
}
- perror("ioctl[SIOCSIWENCODEEXT]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s",
+ strerror(errno));
}
os_free(ext);
@@ -1778,7 +1788,8 @@
iwr.u.encoding.length = key_len;
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+ strerror(errno));
ret = -1;
}
@@ -1790,7 +1801,9 @@
iwr.u.encoding.pointer = (caddr_t) NULL;
iwr.u.encoding.length = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE] (set_tx)");
+ wpa_printf(MSG_ERROR,
+ "ioctl[SIOCSIWENCODE] (set_tx): %s",
+ strerror(errno));
ret = -1;
}
}
@@ -1839,7 +1852,8 @@
iwr.u.data.length = sizeof(mlme);
if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
- perror("ioctl[SIOCSIWMLME]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s",
+ strerror(errno));
ret = -1;
}
@@ -1862,7 +1876,8 @@
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
- perror("ioctl[SIOCGIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+ strerror(errno));
iwr.u.mode = IW_MODE_INFRA;
}
@@ -1927,7 +1942,8 @@
iwr.u.data.length = ie_len;
if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
- perror("ioctl[SIOCSIWGENIE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s",
+ strerror(errno));
ret = -1;
}
@@ -2004,7 +2020,8 @@
}
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+ strerror(errno));
ret = -1;
}
@@ -2060,12 +2077,12 @@
if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
< 0)
ret = -1;
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
- value = IW_AUTH_WPA_VERSION_DISABLED;
- else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ if (params->wpa_proto & WPA_PROTO_RSN)
value = IW_AUTH_WPA_VERSION_WPA2;
- else
+ else if (params->wpa_proto & WPA_PROTO_WPA)
value = IW_AUTH_WPA_VERSION_WPA;
+ else
+ value = IW_AUTH_WPA_VERSION_DISABLED;
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_WPA_VERSION, value) < 0)
ret = -1;
@@ -2084,7 +2101,7 @@
value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
params->pairwise_suite != WPA_CIPHER_NONE ||
params->group_suite != WPA_CIPHER_NONE ||
- params->wpa_ie_len;
+ (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA));
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_PRIVACY_INVOKED, value) < 0)
ret = -1;
@@ -2181,7 +2198,8 @@
}
if (errno != EBUSY) {
- perror("ioctl[SIOCSIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
goto done;
}
@@ -2190,7 +2208,8 @@
* down, try to set the mode again, and bring it back up.
*/
if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
- perror("ioctl[SIOCGIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+ strerror(errno));
goto done;
}
@@ -2203,7 +2222,8 @@
/* Try to set the mode again while the interface is down */
iwr.u.mode = new_mode;
if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
- perror("ioctl[SIOCSIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
else
ret = 0;
@@ -2236,7 +2256,8 @@
if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
if (errno != EOPNOTSUPP)
- perror("ioctl[SIOCSIWPMKSA]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s",
+ strerror(errno));
ret = -1;
}
@@ -2352,6 +2373,33 @@
}
+static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int res;
+ char *pos, *end;
+ unsigned char addr[ETH_ALEN];
+
+ pos = buf;
+ end = buf + buflen;
+
+ if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr))
+ return -1;
+
+ res = os_snprintf(pos, end - pos,
+ "ifindex=%d\n"
+ "ifname=%s\n"
+ "addr=" MACSTR "\n",
+ drv->ifindex,
+ drv->ifname,
+ MAC2STR(addr));
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
@@ -2372,4 +2420,5 @@
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
.signal_poll = wpa_driver_wext_signal_poll,
+ .status = wpa_driver_wext_status,
};
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 21f5e42..f95f3cc 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -100,7 +100,7 @@
if (setsockopt(sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt");
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
return -1;
}
return 0;
@@ -158,7 +158,7 @@
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -176,7 +176,7 @@
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -209,19 +209,21 @@
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
if (drv->sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_INFO, "Could not register read socket");
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)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
return -1;
}
@@ -232,7 +234,7 @@
addr.sll_ifindex);
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -247,26 +249,28 @@
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)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
+ strerror(errno));
return -1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- printf("Invalid HW-addr family 0x%04x\n",
- ifr.ifr_hwaddr.sa_family);
+ wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
+ 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");
+ wpa_printf(MSG_ERROR, "socket call failed for dhcp: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
@@ -277,12 +281,14 @@
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
sizeof(n)) == -1) {
- perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+ wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_REUSEADDR]: %s",
+ strerror(errno));
return -1;
}
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
sizeof(n)) == -1) {
- perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+ wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_BROADCAST]: %s",
+ strerror(errno));
return -1;
}
@@ -290,13 +296,15 @@
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]");
+ wpa_printf(MSG_ERROR,
+ "setsockopt[SOL_SOCKET,SO_BINDTODEVICE]: %s",
+ strerror(errno));
return -1;
}
if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
sizeof(struct sockaddr)) == -1) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -320,8 +328,9 @@
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);
+ wpa_printf(MSG_INFO,
+ "malloc() failed for wired_send_eapol(len=%lu)",
+ (unsigned long) len);
return -1;
}
@@ -337,9 +346,9 @@
os_free(hdr);
if (res < 0) {
- perror("wired_send_eapol: send");
- printf("wired_send_eapol - packet len: %lu - failed\n",
- (unsigned long) len);
+ wpa_printf(MSG_ERROR,
+ "wired_send_eapol - packet len: %lu - failed: send: %s",
+ (unsigned long) len, strerror(errno));
}
return res;
@@ -353,7 +362,8 @@
drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
if (drv == NULL) {
- printf("Could not allocate memory for wired driver data\n");
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for wired driver data");
return NULL;
}
@@ -374,11 +384,15 @@
{
struct wpa_driver_wired_data *drv = priv;
- if (drv->sock >= 0)
+ if (drv->sock >= 0) {
+ eloop_unregister_read_sock(drv->sock);
close(drv->sock);
+ }
- if (drv->dhcp_sock >= 0)
+ if (drv->dhcp_sock >= 0) {
+ eloop_unregister_read_sock(drv->dhcp_sock);
close(drv->dhcp_sock);
+ }
os_free(drv);
}
@@ -414,14 +428,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -438,7 +453,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -446,7 +461,8 @@
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -463,14 +479,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifmr, 0, sizeof(ifmr));
os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- perror("ioctl[SIOCGIFMEDIA]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -494,7 +511,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -528,7 +545,8 @@
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -551,7 +569,7 @@
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
- perror("socket(PF_PACKET)");
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
#else /* __linux__ */
drv->pf_sock = -1;
#endif /* __linux__ */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index d0e42ec..f0c3bb3 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -19,9 +19,6 @@
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
-extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
-#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
@@ -38,9 +35,6 @@
/* driver_macsec_qca.c */
extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_TEST
-extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
-#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_ROBOSWITCH
/* driver_roboswitch.c */
extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -64,9 +58,6 @@
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
- &wpa_driver_madwifi_ops,
-#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
@@ -82,9 +73,6 @@
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_TEST
- &wpa_driver_test_ops,
-#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index cdb913e..ab392bc 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -25,6 +25,10 @@
ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += ../src/drivers/driver_nl80211.o
+DRV_OBJS += ../src/drivers/driver_nl80211_capa.o
+DRV_OBJS += ../src/drivers/driver_nl80211_event.o
+DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o
+DRV_OBJS += ../src/drivers/driver_nl80211_scan.o
DRV_OBJS += ../src/utils/radiotap.o
NEED_SME=y
NEED_AP_MLME=y
@@ -72,12 +76,6 @@
DRV_OBJS += ../src/drivers/driver_openbsd.o
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
@@ -94,15 +92,6 @@
NEED_LINUX_IOCTL=y
endif
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_ATHEROS
DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
DRV_AP_OBJS += ../src/drivers/driver_atheros.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 9fa70d9..8da4c53 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -20,6 +20,11 @@
ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += src/drivers/driver_nl80211.c
+DRV_OBJS += src/drivers/driver_nl80211_android.c
+DRV_OBJS += src/drivers/driver_nl80211_capa.c
+DRV_OBJS += src/drivers/driver_nl80211_event.c
+DRV_OBJS += src/drivers/driver_nl80211_monitor.c
+DRV_OBJS += src/drivers/driver_nl80211_scan.c
DRV_OBJS += src/utils/radiotap.c
NEED_SME=y
NEED_AP_MLME=y
@@ -67,12 +72,6 @@
DRV_OBJS += src/drivers/driver_openbsd.c
endif
-ifdef CONFIG_DRIVER_TEST
-DRV_CFLAGS += -DCONFIG_DRIVER_TEST
-DRV_OBJS += src/drivers/driver_test.c
-NEED_AP_MLME=y
-endif
-
ifdef CONFIG_DRIVER_NONE
DRV_CFLAGS += -DCONFIG_DRIVER_NONE
DRV_OBJS += src/drivers/driver_none.c
@@ -89,15 +88,6 @@
NEED_LINUX_IOCTL=y
endif
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_AP_OBJS += src/drivers/driver_madwifi.c
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_ATHEROS
DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
DRV_AP_OBJS += src/drivers/driver_atheros.c
diff --git a/src/drivers/linux_defines.h b/src/drivers/linux_defines.h
new file mode 100644
index 0000000..a107479
--- /dev/null
+++ b/src/drivers/linux_defines.h
@@ -0,0 +1,46 @@
+/*
+ * Linux defines for values that are not yet included in common C libraries
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_DEFINES_H
+#define LINUX_DEFINES_H
+
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+# define SO_WIFI_STATUS 0x0025
+# elif defined(__parisc__)
+# define SO_WIFI_STATUS 0x4022
+# else
+# define SO_WIFI_STATUS 41
+# endif
+
+# define SCM_WIFI_STATUS SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS 4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP 16
+#endif
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+#endif /* LINUX_DEFINES_H */
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
index 55cf955..e7c7001 100644
--- a/src/drivers/linux_wext.h
+++ b/src/drivers/linux_wext.h
@@ -19,13 +19,13 @@
#define _LINUX_SOCKET_H
#define _LINUX_IF_H
-#include <sys/types.h>
+#include <stdint.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;
+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 */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index 2fa20b1..0e960f4 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -199,8 +199,7 @@
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));
+ req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
}
if (operstate != -1) {
rta = aliasing_hide_typecast(
@@ -209,8 +208,7 @@
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));
+ req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
}
wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 4b28dc0..b37bd5a 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -227,7 +227,11 @@
* 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.
+ * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type
+ * of disconnection indication should be sent to the station
+ * (Deauthentication or Disassociation frame and reason code for that
+ * frame).
*
* @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
* destination %NL80211_ATTR_MAC on the interface identified by
@@ -639,7 +643,18 @@
* @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
* independently of the userspace SME, send this event indicating
* %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
- * attributes determining channel width.
+ * attributes determining channel width. This indication may also be
+ * sent when a remotely-initiated switch (e.g., when a STA receives a CSA
+ * from the remote AP) is completed;
+ *
+ * @NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: Notify that a channel switch
+ * has been started on an interface, regardless of the initiator
+ * (ie. whether it was requested from a remote device or
+ * initiated on our own). It indicates that
+ * %NL80211_ATTR_IFINDEX will be on %NL80211_ATTR_WIPHY_FREQ
+ * after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's. The userspace may
+ * decide to react to this indication by requesting other
+ * interfaces to change channel as well.
*
* @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -738,6 +753,27 @@
* before removing a station entry entirely, or before disassociating
* or similar, cleanup will happen in the driver/device in this case.
*
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and
+ * bandwidth of a channel must be given.
+ * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
+ * network is determined by the network interface.
+ *
+ * @NL80211_CMD_TDLS_CHANNEL_SWITCH: Start channel-switching with a TDLS peer,
+ * identified by the %NL80211_ATTR_MAC parameter. A target channel is
+ * provided via %NL80211_ATTR_WIPHY_FREQ and other attributes determining
+ * channel width/type. The target operating class is given via
+ * %NL80211_ATTR_OPER_CLASS.
+ * The driver is responsible for continually initiating channel-switching
+ * operations and returning to the base channel for communication with the
+ * AP.
+ * @NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: Stop channel-switching with a TDLS
+ * peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
+ * when this command completes.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -912,6 +948,16 @@
NL80211_CMD_ADD_TX_TS,
NL80211_CMD_DEL_TX_TS,
+ NL80211_CMD_GET_MPP,
+
+ NL80211_CMD_JOIN_OCB,
+ NL80211_CMD_LEAVE_OCB,
+
+ NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
+
+ NL80211_CMD_TDLS_CHANNEL_SWITCH,
+ NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1606,9 +1652,9 @@
* @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
* As specified in the &enum nl80211_tdls_peer_capability.
*
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
* creation then the new interface will be owned by the netlink socket
- * that created it and will be destroyed when the socket is closed
+ * that created it and will be destroyed when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1638,6 +1684,11 @@
* @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
* &enum nl80211_smps_mode.
*
+ * @NL80211_ATTR_OPER_CLASS: operating class
+ *
+ * @NL80211_ATTR_MAC_MASK: MAC address mask
+ *
+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1973,7 +2024,7 @@
NL80211_ATTR_TDLS_PEER_CAPABILITY,
- NL80211_ATTR_IFACE_SOCKET_OWNER,
+ NL80211_ATTR_SOCKET_OWNER,
NL80211_ATTR_CSA_C_OFFSETS_TX,
NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -1990,15 +2041,21 @@
NL80211_ATTR_SMPS_MODE,
+ NL80211_ATTR_OPER_CLASS,
+
+ NL80211_ATTR_MAC_MASK,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
+ NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
/* source-level API compatibility */
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -2064,6 +2121,8 @@
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ * This mode corresponds to the MIB variable dot11OCBActivated=true
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
@@ -2083,6 +2142,7 @@
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,
+ NL80211_IFTYPE_OCB,
/* keep last */
NUM_NL80211_IFTYPES,
@@ -2631,6 +2691,11 @@
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
* base on contiguous rules and wider channels will be allowed to cross
* multiple contiguous/overlapping frequency ranges.
+ * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
+ * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
+ * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
+ * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -2643,11 +2708,18 @@
NL80211_RRF_NO_IR = 1<<7,
__NL80211_RRF_NO_IBSS = 1<<8,
NL80211_RRF_AUTO_BW = 1<<11,
+ NL80211_RRF_GO_CONCURRENT = 1<<12,
+ NL80211_RRF_NO_HT40MINUS = 1<<13,
+ NL80211_RRF_NO_HT40PLUS = 1<<14,
+ NL80211_RRF_NO_80MHZ = 1<<15,
+ NL80211_RRF_NO_160MHZ = 1<<16,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR
#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\
+ NL80211_RRF_NO_HT40PLUS)
/* For backport compatibility with older userspace */
#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
@@ -3379,6 +3451,8 @@
* interval in which %NL80211_ATTR_CQM_TXE_PKTS and
* %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
* %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
+ * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
+ * loss event
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
* @NL80211_ATTR_CQM_MAX: highest key attribute
*/
@@ -3391,6 +3465,7 @@
NL80211_ATTR_CQM_TXE_RATE,
NL80211_ATTR_CQM_TXE_PKTS,
NL80211_ATTR_CQM_TXE_INTVL,
+ NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
/* keep last */
__NL80211_ATTR_CQM_AFTER_LAST,
@@ -3403,9 +3478,7 @@
* configured threshold
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
* configured threshold
- * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
- * (Note that deauth/disassoc will still follow if the AP is not
- * available. This event might get used as roaming event, etc.)
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
*/
enum nl80211_cqm_rssi_threshold_event {
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
@@ -3545,6 +3618,25 @@
* @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only,
* the TCP connection ran out of tokens to use for data to send to the
* service
+ * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network
+ * is detected. This is a nested attribute that contains the
+ * same attributes used with @NL80211_CMD_START_SCHED_SCAN. It
+ * specifies how the scan is performed (e.g. the interval and the
+ * channels to scan) as well as the scan results that will
+ * trigger a wake (i.e. the matchsets).
+ * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
+ * containing an array with information about what triggered the
+ * wake up. If no elements are present in the array, it means
+ * that the information is not available. If more than one
+ * element is present, it means that more than one match
+ * occurred.
+ * Each element in the array is a nested attribute that contains
+ * one optional %NL80211_ATTR_SSID attribute and one optional
+ * %NL80211_ATTR_SCAN_FREQUENCIES attribute. At least one of
+ * these attributes must be present. If
+ * %NL80211_ATTR_SCAN_FREQUENCIES contains more than one
+ * frequency, it means that the match occurred in more than one
+ * channel.
* @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
* @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
*
@@ -3570,6 +3662,8 @@
NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
+ NL80211_WOWLAN_TRIG_NET_DETECT,
+ NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS,
/* keep last */
NUM_NL80211_WOWLAN_TRIG,
@@ -4042,6 +4136,27 @@
* multiplexing powersave, ie. can turn off all but one chain
* and then wake the rest up as required after, for example,
* rts/cts handshake.
+ * @NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
+ * TSPEC sessions (TID aka TSID 0-7) with the %NL80211_CMD_ADD_TX_TS
+ * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
+ * needs to be able to handle Block-Ack agreements and other things.
+ * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring
+ * the vif's MAC address upon creation.
+ * See 'macaddr' field in the vif_params (cfg80211.h).
+ * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when
+ * operating as a TDLS peer.
+ * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a
+ * random MAC address during scan (if the device is unassociated); the
+ * %NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC
+ * address mask/value will be used.
+ * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports
+ * using a random MAC address for every scan iteration during scheduled
+ * scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ * be set for scheduled scan and the MAC address mask/value will be used.
+ * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a
+ * random MAC address for every scan iteration during "net detect", i.e.
+ * scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ * be set for scheduled scan and the MAC address mask/value will be used.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -4070,6 +4185,12 @@
NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23,
NL80211_FEATURE_STATIC_SMPS = 1 << 24,
NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25,
+ NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26,
+ NL80211_FEATURE_MAC_ON_CREATE = 1 << 27,
+ NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
};
/**
@@ -4118,11 +4239,21 @@
* dangerous because will destroy stations performance as a lot of frames
* will be lost while scanning off-channel, therefore it must be used only
* when really needed
+ * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or
+ * for scheduled scan: a different one for every scan iteration). When the
+ * flag is set, depending on device capabilities the @NL80211_ATTR_MAC and
+ * @NL80211_ATTR_MAC_MASK attributes may also be given in which case only
+ * the masked bits will be preserved from the MAC address and the remainder
+ * randomised. If the attributes are not given full randomisation (46 bits,
+ * locally administered 1, multicast 0) is assumed.
+ * This flag must not be requested when the feature isn't supported, check
+ * the nl80211 feature flags for the device.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
NL80211_SCAN_FLAG_FLUSH = 1<<1,
NL80211_SCAN_FLAG_AP = 1<<2,
+ NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
};
/**
diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h
index 6232088..d3f091c 100644
--- a/src/drivers/priv_netlink.h
+++ b/src/drivers/priv_netlink.h
@@ -68,6 +68,7 @@
((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0))