diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2014-01-10 10:45:54 -0800 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2014-01-14 10:56:46 -0800 |
| commit | fb79edc9df1f20461e90e478363d207348213d35 (patch) | |
| tree | 8d01b8fd9c6957e5f3cbc858bb49dc42209765e1 | |
| parent | 3cf6f79011d16f23e60cbf2846aab0fd440511da (diff) | |
| download | android_external_wpa_supplicant_8-fb79edc9df1f20461e90e478363d207348213d35.tar.gz android_external_wpa_supplicant_8-fb79edc9df1f20461e90e478363d207348213d35.tar.bz2 android_external_wpa_supplicant_8-fb79edc9df1f20461e90e478363d207348213d35.zip | |
Cumulative patch from commit 95fb2db2420d8fa291fd6423cc6dbcd042f4eb46
95fb2db P2P: Reject group formation on WPS provisioning failure
6fc61e1 Fix TX status processing during AP mode shutdown in wpa_supplicant
90a545c nl80211: Clean up netlink parsing and debug prints
b6a9590 Interworking: Keep up to two pending GAS_REQUEST responses
090b8e3 Update copyright notices for the new year 2014
991aa9c nl80211: Move CS supported flag to wpa_driver_capa
f0cbb98 Add DRIVER-STATUS command for hostapd
188ebcd EAP-IKEv2 peer: Fix a memory leak in notify round
a190189 Remove PEAPv2 support
16a19dd EAP-pwd peer: Allow fragmentation limit to be configured
60bf585 EAP-IKEv2 peer: Allow fragmentation limit to be configured
ea6fc58 WPS: Convert printf() debug print to use wpa_printf()
c4b8c71 EAP-GPSK: Report CSuite negotiation failure properly
5a0f596 EAP-GPSK: Allow forced algorithm selection to be configured
5f01c3c EAP peer: Improve failure reporting from METHOD with no eapRespData
7271ee8 Fix EAP-GPSK server compilation for SHA256 cipher suite
356d148 Interworking: Add optional freq argument to INTERWORKING_SELECT
a09ffd5 Fix req_scan-deplete-timeout and update eloop API for this
083916c P2P: Clear p2p_disabled and p2p_per_sta_psk on FLUSH command
3f45fc4 P2P: Clear services on FLUSH command
1f965e6 Allow external programs to request wpa_radio work items
6428d0a Do not start wpa_radio work during externally triggered scan
6470f47 Remove unneeded scan delay on connection-in-progress
4bb2321 Remove unneeded GAS query delay on connection-in-progress
6ac4b15 Use wpa_radio work for connection
b9e6d70 Use radio work for GAS requests
e05e130 P2P: Use radio work to protect offchannel Action frame exchanges
e1d1c8e Use radio work for P2P Listen requests
1b5d471 Use radio work for P2P scan requests
d12a51b Use radio work for scan requests
b1ae396 Add framework for exclusive radio operations
dd43aaa Add helper functions for cloning and freeing scan parameters
06f9acc Ignore externally triggered scan results with scan_res_handler
c9b5559 Clean up ctrl_iface debug prints for monitor events
d31b5ac Use cleaner debug print for ctrl_iface commands with private info
9595151 Remove duplicated RX ctrl_iface hexdump
9b85079 Fix scan-cache-clearing operation to avoid unnecessary cases
2f30cac Avoid unnecessary key clearing operations
466bcf9 Remove some unnecessary EAPOL port (un)authorized callbacks
949938a Ask driver to report only new scan results if requested
a1a31b6 Remove hostapd dump_file functionality
ea23df6 Make EAPOL dump data available through ctrl_iface STA command
96ea74b Convert EAPOL authenticator dump into easier to parse format
ca3b71c Remove hostapd dump_file data that is available through ctrl_iface
4c03a2b Make RADIUS server MIB available through control interface
f538be3 Add more STA information into the ctrl_iface STA command
101bdc2 Remove forgotten notes about already removed driver wrappers
7006753 Update EAP-FAST note regarding OpenSSL support
17b79e6 nl80211: Initial support for vendor commands and events
5890fa8 WPS: Fix clear-from-timeout handling to avoid race condition
c64e3a0 P2P: Send received Presence Response information to ctrl_iface monitors
f7fb676 ACS: Mark acs_fail() static
3cf06c9 OpenSSL: Include sha1/sha256 header files to verify declarations
5ace51a WNM: Clean up le16 variable use to avoid sparse warnings
c583868 Mark wpas_wps_er_nfc_handover_sel() static
8cf1e68 Move declaration of hostapd_acs_completed() into correct header file
0187c41 Declare wpa_debug_* variables in src/utils/wpa_debug.h
fcc6123 Declare wpa_drivers in src/drivers/driver.h
0d79b50 Clear EAPOL Logoff state on FLUSH command
327b01d nl80211: Add driver param for forcing monitor and connect APIs
6f06766 nl80211: Fix nl_mgmt handling in partial error case
4ea6a47 nl80211: Prefer newer scan result over older during duplicate removal
2eef517 nl80211: Report set_supp_port failures in debug log
a0bdd19 nl80211: Share a helper function for connect and associate commands
e00d546 Remove unnecessary build #ifdef from definitions
4848a38 Get rid of duplicated cipher suite and AKM definitions
de4ed4a nl80211: Use helper functions for cipher suite mapping
a565084 nl80211: Set control port for NL80211_CMD_COMMAND
ef93abd WPS: Clean up UUID debug print
35f3d3e nl80211: Clean up regulatory rule debug prints
880de88 nl80211: Print frame registration match on same debug line
03ed332 Interworking: Allow cred blocks not to be saved to a file
04f7ecc Reset WPA parameters to default values on FLUSH command
152cff6 P2P: Remove WPA_DRIVER_FLAGS_P2P_MGMT option
538d6f4 WPS: Use shorter scan interval during pre-provisioning search
3187fd9 WPS: Replace wpas_wps_in_progress with identical wpas_wps_searching
4414d9e SAE: Fix ECC element y coordinate validation step
069fb47 EAP-EKE: Allow forced algorithm selection to be configured
3a88914 Remove unused information element parsing data
dbfb8e8 Remove unnecessary EVENT_RX_ACTION
1450e1e Define __maybe_unused
912b34f Do not process Action frames twice in hostapd SME/MLME
006309b Fix whitespace style
6780713 WPS: Remove unused send_wpabuf()
e912986 tests: Verify concurrent WPS protocol run with assigned PIN
8aaafce Make local UUID available through ctrl_iface STATUS command
0e22b8d WPS: Make sure reconfiguration timeout is not left behind on deinit
75d1d0f WPS: Allow testing mode to disable 2.0 functionality
f7e2542 Remove unused wps_device_data_dup()
c89d9db Remove unnecessary extra tracking of eloop registration
c86bf16 Replace unnecessary hex_value() with hex2byte()
7b02375 Clear wps_fragment_size on FLUSH command
aa189ac Enable FT with SAE
2d2ecf5 nl80211: Fix protected Action frame reporting for AP mode
db76aa6 Fix PeerKey 4-way handshake
7732729 Fix PeerKey deinit behavior
8d321a7 WNM: Move disassociation imminent sending to wnm_ap.c
b76f4c2 hostapd: Make STA flags available through ctrl_iface STA command
aa03dbd Remove IEEE80211_REQUIRE_AUTH_ACK
121f2ab Remove unused STA flags
3578e66 WNM: Add STA flag to indicate the current WNM-Sleep-Mode state
4776897 WNM: Fix AP processing without wnm_oper driver callback
2025cad WNM: Move ESS Disassoc Imminent sending to a helper function
28ab64a WNM: Minimal processing of BSS Transition Management Query/Response
2cd0f6a WNM: Add Target BSSID into BSS Transition Management Response
a8a6a35 WNM: Use nonzero dialog token in BSS Transition Management Query
629edfe WNM: Fix Sleep Mode AP processing in open network
3c1060f WNM: Add debug logs to get the RSSI from the scan results
dff1e28 Initial handling of GTK-not-used cipher suite
51e3eaf OpenSSL: Do not accept SSL Client certificate for server
6bf61fb OpenSSL: Use certificates from TLS authentication in OCSP stapling
c962947 WPS ER: Fix deinit timeout handling with delayed/failing unsubscribe
7b75c30 WPS: Reschedule AP configuration reload on EAP completion
c511b32 WPS: Remove old duplicate network even if key is different
9d2cb3e Make CONFIG_TESTING_OPTIONS=y enable all testing options
662b40b WPS: Reduce scan wait time during WPS processing
015af91 Do not use results from externally requested scan for network selection
1cd93ff Reschedule own scan request if an externally started one is in progress
dc3906c Show timing information about scan requests in debug log
d81c73b Optional scan id for ctrl_iface SCAN requests
a5f40ef Track whether scan was started by us or an external program
18ae237 Fix comment format
88c2d48 Allow passive scan to be requested with SCAN passive=1
3ae3ec2 nl80211: Add scanned frequencies/SSIDs into debug log
69278f7 Remove unused last_scan_full
1f5d2dd Interworking: Allow EAP-FAST to be used
6ffa168 Add GAS-QUERY-START and GAS-QUERY-DONE event messages
93827f4 hostapd: Allow external management frame processing or testing
fee5234 Allow channel list to be specified for SCAN command
98eda9c Move int_array helpfer functions to utils/common.c
a4cfb48 Add make lcov-html to generate code coverage report
bee25cc nl80211: Fetch cipher capabilities from the driver
4daa011 Clean up cipher capability prints
35c2006 Convert wpa_hexdump functions to use void pointer instead of u8 *
5f9c134 Remove obsolete license notifications
bd1e328 Android: Remove old WEXT extensions
bad5cdf Verify that beacon setup succeeds before proceeding
7d7f7be Verify group key configuration for WPA group
30675c3 Add definitions for new cipher suites from IEEE Std 802.11ac-2013
13b24a7 VHT: Use status code 104 to indicate VHT required
ab41595 wpa_supplicant: Fix crash when terminating all interfaces
76aab03 Add secondary channel IE for CSA
8f4713c Store entire CS freq_params and not only freq
13daed5 Include driver.h in hostapd.h
a12d345 wpa_supplicant: Use monotonic time for last_scan check
51bffab WPS: Use monotonic time for AP connection attempt
6473e5c wpa_supplicant: Use relative time for TKIP Michael MIC failures
4e1eae1 wpa_supplicant: Use monotonic time for temp-disabled networks
151ab80 P2P: Use monotonic time for GO client waiting
3326f19 IBSS RSN: Use monotonic time for reinit detection
196a217 WPS_UPNP: Use monotonic time for event debouncing
864c9af wps_registrar: Use monotonic time for PBC workaround
61e98e9 wps_registrar: Use monotonic time for PBC session timeout
3647e5a wps_registrar: Use monotonic time for PIN timeout
3618618 rsn_supp: Use monotonic time for PMKSA cache expiry
c2be937 wpa_supplicant: Use monotonic time for EAPOL RX workaround
e72a001 bgscan: Use monotonic time
e05f060 rsn_supp: Do not track expiration time
5870717 RADIUS server: Use monotonic time
4012804 RADIUS client: Use monotonic time
acb69ce wpa_supplicant: Use monotonic time for RX/BSS times
46b8d4c wpa_supplicant: Use monotonic time for SA query timeout
f073fde EAP server: Remove SIM-DB pending timestamp
636e19a wpa_ctrl: Use monotonic time for request retry loop
7ffe7d2 AP: Use monotonic time for MMIC failure/TKIP countermeasures
dd4e32b AP: Use monotonic time for PMKSA cache
0fc545a AP: Use monotonic time for STA accounting
3e06180 bgscan_learn: Start scanning from the first freq
f4c73ae bgscan_learn: Fix initial interval
7dab119 bgscan_learn: Avoid redundant frequencies
3727123 bgscan: Stop bgscan only on disassociation
b2838ba Update IBSS documentation to include RSN option
429dd9a Advertise QoS Map support based on driver capability
049105b nl80211: Add support for QoS Map configuration
74ddd64 nl80211: Sync with mac80211-next.git
9fcd300 nl80211: Sync with wireless-testing.git
Change-Id: Iabdd88d9cabd478a41c3cb0a8d061b425cc1beca
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
165 files changed, 4682 insertions, 4469 deletions
@@ -1,7 +1,7 @@ wpa_supplicant and hostapd -------------------------- -Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. These programs are licensed under the BSD license (the one with diff --git a/hostapd/Android.mk b/hostapd/Android.mk index bc0273e0..6e37beb4 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -137,10 +137,10 @@ OBJS += src/eapol_auth/eapol_auth_sm.c ifndef CONFIG_NO_DUMP_STATE -# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -# a file (undefine it, if you want to save in binary size) +# define HOSTAPD_DUMP_STATE to include support for dumping internal state +# through control interface commands (undefine it, if you want to save in +# binary size) L_CFLAGS += -DHOSTAPD_DUMP_STATE -OBJS += dump_state.c OBJS += src/eapol_auth/eapol_auth_dump.c endif @@ -351,7 +351,7 @@ ifdef CONFIG_EAP_GPSK L_CFLAGS += -DEAP_SERVER_GPSK OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c ifdef CONFIG_EAP_GPSK_SHA256 -L_CFLAGS += -DEAP_SERVER_GPSK_SHA256 +L_CFLAGS += -DEAP_GPSK_SHA256 endif NEED_SHA256=y NEED_AES_OMAC1=y diff --git a/hostapd/Makefile b/hostapd/Makefile index ae96d35d..5fd64810 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -6,8 +6,8 @@ ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif -CFLAGS += -I../src -CFLAGS += -I../src/utils +CFLAGS += -I$(abspath ../src) +CFLAGS += -I$(abspath ../src/utils) # Uncomment following line and set the path to your kernel tree include # directory if your C library does not include all header files. @@ -15,6 +15,11 @@ CFLAGS += -I../src/utils -include .config +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +CONFIG_WPS_TESTING=y +endif + ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS CONFIG_OS=win32 @@ -114,10 +119,10 @@ LIBS_n += -lgcov endif ifndef CONFIG_NO_DUMP_STATE -# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -# a file (undefine it, if you want to save in binary size) +# define HOSTAPD_DUMP_STATE to include support for dumping internal state +# through control interface commands (undefine it, if you want to save in +# binary size) CFLAGS += -DHOSTAPD_DUMP_STATE -OBJS += dump_state.o OBJS += ../src/eapol_auth/eapol_auth_dump.o endif @@ -327,7 +332,7 @@ ifdef CONFIG_EAP_GPSK CFLAGS += -DEAP_SERVER_GPSK OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o ifdef CONFIG_EAP_GPSK_SHA256 -CFLAGS += -DEAP_SERVER_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 endif NEED_SHA256=y NEED_AES_OMAC1=y @@ -858,10 +863,6 @@ LIBS += -lsqlite3 LIBS_h += -lsqlite3 endif -ifdef CONFIG_TESTING_OPTIONS -CFLAGS += -DCONFIG_TESTING_OPTIONS -endif - ALL=hostapd hostapd_cli all: verify_config $(ALL) @@ -873,9 +874,15 @@ Q= E=true endif +ifdef CONFIG_CODE_COVERAGE +%.o: %.c + @$(E) " CC " $< + $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<) +else %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $< @$(E) " CC " $< +endif verify_config: @if [ ! -r .config ]; then \ @@ -944,9 +951,15 @@ hlr_auc_gw: $(HOBJS) $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h) @$(E) " LD " $@ +lcov-html: + lcov -c -d .. > lcov.info + genhtml lcov.info --output-directory lcov-html + clean: $(MAKE) -C ../src clean rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw rm -f *.d *.gcno *.gcda *.gcov + rm -f lcov.info + rm -rf lcov-html -include $(OBJS:%.o=%.d) diff --git a/hostapd/README b/hostapd/README index 39b70cab..50868ee1 100644 --- a/hostapd/README +++ b/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/hostapd/android.config b/hostapd/android.config index f51a5bfe..33e96c48 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -157,7 +157,7 @@ CONFIG_NO_RADIUS=y # Remove support for VLANs #CONFIG_NO_VLAN=y -# Remove support for dumping state into a file on SIGUSR1 signal +# Remove support for dumping internal state through control interface commands # This can be used to reduce binary size at the cost of disabling a debugging # option. #CONFIG_NO_DUMP_STATE=y diff --git a/hostapd/config_file.c b/hostapd/config_file.c index ae059176..41988345 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -22,9 +22,6 @@ #include "config_file.h" -extern struct wpa_driver_ops *wpa_drivers[]; - - #ifndef CONFIG_NO_VLAN static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, const char *fname) @@ -1634,7 +1631,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "logger_stdout") == 0) { bss->logger_stdout = atoi(pos); } else if (os_strcmp(buf, "dump_file") == 0) { - bss->dump_log_name = os_strdup(pos); + wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore", + line); } else if (os_strcmp(buf, "ssid") == 0) { bss->ssid.ssid_len = os_strlen(pos); if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 2d0379f3..72faeaea 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1,6 +1,6 @@ /* * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,7 @@ #include "common/ieee802_11_defs.h" #include "drivers/driver.h" #include "radius/radius_client.h" +#include "radius/radius_server.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/ieee802_1x.h" @@ -29,6 +30,7 @@ #include "ap/wps_hostapd.h" #include "ap/ctrl_iface_ap.h" #include "ap/ap_drv_ops.h" +#include "ap/wnm_ap.h" #include "ap/wpa_auth.h" #include "wps/wps_defs.h" #include "wps/wps.h" @@ -665,9 +667,8 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, const char *cmd) { u8 addr[ETH_ALEN]; - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; int disassoc_timer; + struct sta_info *sta; if (hwaddr_aton(cmd, addr)) return -1; @@ -675,31 +676,15 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, return -1; disassoc_timer = atoi(cmd + 17); - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for disassociation imminent message", + MAC2STR(addr)); return -1; } - return 0; + return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); } @@ -708,14 +693,20 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, { u8 addr[ETH_ALEN]; const char *url, *timerstr; - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - size_t url_len; int disassoc_timer; + struct sta_info *sta; if (hwaddr_aton(cmd, addr)) return -1; + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for ESS disassociation imminent message", + MAC2STR(addr)); + return -1; + } + timerstr = cmd + 17; if (*timerstr != ' ') return -1; @@ -728,76 +719,8 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, if (url == NULL) return -1; url++; - url_len = os_strlen(url); - if (url_len > 255) - return -1; - - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT | - WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - /* Session Information URL */ - *pos++ = url_len; - os_memcpy(pos, url, url_len); - pos += url_len; - - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); - return -1; - } - - /* send disassociation frame after time-out */ - if (disassoc_timer) { - struct sta_info *sta; - int timeout, beacon_int; - - /* - * Prevent STA from reconnecting using cached PMKSA to force - * full authentication with the authentication server (which may - * decide to reject the connection), - */ - wpa_auth_pmksa_remove(hapd->wpa_auth, addr); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " - "for ESS disassociation imminent message", - MAC2STR(addr)); - return -1; - } - beacon_int = hapd->iconf->beacon_int; - if (beacon_int < 1) - beacon_int = 100; /* best guess */ - /* Calculate timeout in ms based on beacon_int in TU */ - timeout = disassoc_timer * beacon_int * 128 / 125; - wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR - " set to %d ms", MAC2STR(addr), timeout); - - sta->timeout_next = STA_DISASSOC_FROM_CLI; - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(timeout / 1000, - timeout % 1000 * 1000, - ap_handle_timer, hapd, sta); - } - - return 0; + return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); } #endif /* CONFIG_WNM */ @@ -994,6 +917,10 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) else hapd->gas_frag_limit = val; #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { + hapd->ext_mgmt_frame_handling = atoi(value); +#endif /* CONFIG_TESTING_OPTIONS */ } else { ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); } @@ -1051,6 +978,7 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) #ifdef CONFIG_TESTING_OPTIONS + static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) { union wpa_event_data data; @@ -1108,6 +1036,35 @@ static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) return 0; } + + +static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) +{ + size_t len; + u8 *buf; + int res; + + wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(cmd, buf, len) < 0) { + os_free(buf); + return -1; + } + + res = hostapd_drv_send_mlme(hapd, buf, len, 0); + os_free(buf); + return res; +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -1127,6 +1084,19 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos) } +static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, + int reply_size, const char *param) +{ +#ifdef RADIUS_SERVER + if (os_strcmp(param, "radius_server") == 0) { + return radius_server_get_mib(hapd->radius_srv, reply, + reply_size); + } +#endif /* RADIUS_SERVER */ + return -1; +} + + static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { @@ -1170,6 +1140,8 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strcmp(buf, "STATUS") == 0) { reply_len = hostapd_ctrl_iface_status(hapd, reply, reply_size); + } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) { + reply_len = hostapd_drv_status(hapd, reply, reply_size); } else if (os_strcmp(buf, "MIB") == 0) { reply_len = ieee802_11_get_mib(hapd, reply, reply_size); if (reply_len >= 0) { @@ -1199,6 +1171,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len += res; } #endif /* CONFIG_NO_RADIUS */ + } else if (os_strncmp(buf, "MIB ", 4) == 0) { + reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size, + buf + 4); } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, reply_size); @@ -1312,6 +1287,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "RADAR ", 6) == 0) { if (hostapd_ctrl_iface_radar(hapd, buf + 6)) reply_len = -1; + } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { + if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8)) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12)) diff --git a/hostapd/defconfig b/hostapd/defconfig index 3f2924b9..60f2c04e 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -96,10 +96,9 @@ CONFIG_EAP_TTLS=y #CONFIG_EAP_GPSK_SHA256=y # EAP-FAST for the integrated EAP server -# Note: Default OpenSSL package does not include support for all the -# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch) -# to add the needed functions. +# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed +# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., +# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. #CONFIG_EAP_FAST=y # Wi-Fi Protected Setup (WPS) @@ -180,7 +179,7 @@ CONFIG_IPV6=y # Note: This requires libnl 3.1 or newer. #CONFIG_VLAN_NETLINK=y -# Remove support for dumping state into a file on SIGUSR1 signal +# Remove support for dumping internal state through control interface commands # This can be used to reduce binary size at the cost of disabling a debugging # option. #CONFIG_NO_DUMP_STATE=y diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c deleted file mode 100644 index fcd98905..00000000 --- a/hostapd/dump_state.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * hostapd / State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include <time.h> - -#include "utils/common.h" -#include "radius/radius_client.h" -#include "radius/radius_server.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "eap_server/eap.h" -#include "ap/hostapd.h" -#include "ap/ap_config.h" -#include "ap/sta_info.h" -#include "dump_state.h" -#include "ap/ap_drv_ops.h" - - -static void fprint_char(FILE *f, char c) -{ - if (c >= 32 && c < 127) - fprintf(f, "%c", c); - else - fprintf(f, "<%02x>", c); -} - - -static void ieee802_1x_dump_state(FILE *f, const char *prefix, - struct sta_info *sta) -{ - struct eapol_state_machine *sm = sta->eapol_sm; - if (sm == NULL) - return; - - fprintf(f, "%sIEEE 802.1X:\n", prefix); - - if (sm->identity) { - size_t i; - fprintf(f, "%sidentity=", prefix); - for (i = 0; i < sm->identity_len; i++) - fprint_char(f, sm->identity[i]); - fprintf(f, "\n"); - } - - fprintf(f, "%slast EAP type: Authentication Server: %d (%s) " - "Supplicant: %d (%s)\n", prefix, - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv), - sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp)); - - fprintf(f, "%scached_packets=%s\n", prefix, - sm->last_recv_radius ? "[RX RADIUS]" : ""); - - eapol_auth_dump_state(f, prefix, sm); -} - - -/** - * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file - */ -static void hostapd_dump_state(struct hostapd_data *hapd) -{ - FILE *f; - time_t now; - struct sta_info *sta; - int i; -#ifndef CONFIG_NO_RADIUS - char *buf; -#endif /* CONFIG_NO_RADIUS */ - struct hostap_sta_driver_data data; - - if (!hapd->conf->dump_log_name) { - wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump " - "request"); - return; - } - - wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'", - hapd->conf->dump_log_name); - f = fopen(hapd->conf->dump_log_name, "w"); - if (f == NULL) { - wpa_printf(MSG_WARNING, "Could not open dump file '%s' for " - "writing.", hapd->conf->dump_log_name); - return; - } - - time(&now); - fprintf(f, "hostapd state dump - %s", ctime(&now)); - fprintf(f, "num_sta=%d num_sta_non_erp=%d " - "num_sta_no_short_slot_time=%d\n" - "num_sta_no_short_preamble=%d\n", - hapd->num_sta, hapd->iface->num_sta_non_erp, - hapd->iface->num_sta_no_short_slot_time, - hapd->iface->num_sta_no_short_preamble); - - for (sta = hapd->sta_list; sta != NULL; sta = sta->next) { - fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr)); - - fprintf(f, - " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "\n" - " capability=0x%x listen_interval=%d\n", - sta->aid, - sta->flags, - (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""), - (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), - (sta->flags & WLAN_STA_PS ? "[PS]" : ""), - (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""), - (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""), - (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""), - (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : - ""), - (sta->flags & WLAN_STA_SHORT_PREAMBLE ? - "[SHORT_PREAMBLE]" : ""), - (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), - (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""), - (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""), - (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""), - (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), - (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""), - (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""), - (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), - sta->capability, - sta->listen_interval); - - fprintf(f, " supported_rates="); - for (i = 0; i < sta->supported_rates_len; i++) - fprintf(f, "%02x ", sta->supported_rates[i]); - fprintf(f, "\n"); - - fprintf(f, - " timeout_next=%s\n", - (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" : - (sta->timeout_next == STA_DISASSOC ? "DISASSOC" : - "DEAUTH"))); - - ieee802_1x_dump_state(f, " ", sta); - - if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) == 0) { - fprintf(f, " rx_pkt=%lu tx_pkt=%lu\n" - " rx_byte=%lu tx_byte=%lu\n", - data.rx_packets, data.tx_packets, - data.rx_bytes, data.tx_bytes); - } - } - -#ifndef CONFIG_NO_RADIUS - buf = os_malloc(4096); - if (buf) { - int count = radius_client_get_mib(hapd->radius, buf, 4096); - if (count < 0) - count = 0; - else if (count > 4095) - count = 4095; - buf[count] = '\0'; - fprintf(f, "%s", buf); - -#ifdef RADIUS_SERVER - count = radius_server_get_mib(hapd->radius_srv, buf, 4096); - if (count < 0) - count = 0; - else if (count > 4095) - count = 4095; - buf[count] = '\0'; - fprintf(f, "%s", buf); -#endif /* RADIUS_SERVER */ - - os_free(buf); - } -#endif /* CONFIG_NO_RADIUS */ - fclose(f); -} - - -int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx) -{ - size_t i; - - for (i = 0; i < iface->num_bss; i++) - hostapd_dump_state(iface->bss[i]); - - return 0; -} diff --git a/hostapd/dump_state.h b/hostapd/dump_state.h deleted file mode 100644 index a209d653..00000000 --- a/hostapd/dump_state.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * hostapd / State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DUMP_STATE_H -#define DUMP_STATE_H - -int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx); - -#endif /* DUMP_STATE_H */ diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 9b70d0fb..da7817f4 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -51,9 +51,6 @@ logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 -# Dump file for state information (on SIGUSR1) -dump_file=/tmp/hostapd.dump - # Interface for separate control program. If this is specified, hostapd # will create this directory and a UNIX domain socket for listening to requests # from external programs (CLI/GUI, etc.) for status information and diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index b2d3e5ba..eee85041 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1,6 +1,6 @@ /* * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,7 +18,7 @@ static const char *hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; static const char *hostapd_cli_license = @@ -218,12 +218,19 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) { + if (argc > 0 && os_strcmp(argv[0], "driver") == 0) + return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); return wpa_ctrl_command(ctrl, "STATUS"); } static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) { + if (argc > 0) { + char buf[100]; + os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]); + return wpa_ctrl_command(ctrl, buf); + } return wpa_ctrl_command(ctrl, "MIB"); } @@ -276,12 +283,15 @@ static void hostapd_cli_action_process(char *msg, size_t len) static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char buf[64]; - if (argc != 1) { - printf("Invalid 'sta' command - exactly one argument, STA " + if (argc < 1) { + printf("Invalid 'sta' command - at least one argument, STA " "address, is required.\n"); return -1; } - snprintf(buf, sizeof(buf), "STA %s", argv[0]); + if (argc > 1) + snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]); + else + snprintf(buf, sizeof(buf), "STA %s", argv[0]); return wpa_ctrl_command(ctrl, buf); } diff --git a/hostapd/main.c b/hostapd/main.c index 4e9fe404..5a1b0a9e 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -25,17 +25,9 @@ #include "ap/ap_drv_ops.h" #include "config_file.h" #include "eap_register.h" -#include "dump_state.h" #include "ctrl_iface.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -extern struct wpa_driver_ops *wpa_drivers[]; - - struct hapd_global { void **drv_priv; size_t drv_count; @@ -302,10 +294,7 @@ static void handle_reload(int sig, void *signal_ctx) static void handle_dump_state(int sig, void *signal_ctx) { -#ifdef HOSTAPD_DUMP_STATE - struct hapd_interfaces *interfaces = signal_ctx; - hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); -#endif /* HOSTAPD_DUMP_STATE */ + /* Not used anymore - ignore signal */ } #endif /* CONFIG_NATIVE_WINDOWS */ @@ -424,7 +413,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> " "and contributors\n"); } diff --git a/src/ap/accounting.c b/src/ap/accounting.c index a1f67f0c..6290d3f3 100644 --- a/src/ap/accounting.c +++ b/src/ap/accounting.c @@ -10,7 +10,6 @@ #include "utils/common.h" #include "utils/eloop.h" -#include "drivers/driver.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "hostapd.h" @@ -202,7 +201,6 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) { struct radius_msg *msg; - struct os_time t; int interval; if (sta->acct_session_started) @@ -213,8 +211,7 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) "starting accounting session %08X-%08X", sta->acct_session_id_hi, sta->acct_session_id_lo); - os_get_time(&t); - sta->acct_session_start = t.sec; + os_get_reltime(&sta->acct_session_start); sta->last_rx_bytes = sta->last_tx_bytes = 0; sta->acct_input_gigawords = sta->acct_output_gigawords = 0; hostapd_drv_sta_clear_stats(hapd, sta->addr); @@ -244,6 +241,7 @@ static void accounting_sta_report(struct hostapd_data *hapd, struct radius_msg *msg; int cause = sta->acct_terminate_cause; struct hostap_sta_driver_data data; + struct os_reltime now_r, diff; struct os_time now; u32 gigawords; @@ -258,9 +256,11 @@ static void accounting_sta_report(struct hostapd_data *hapd, return; } + os_get_reltime(&now_r); os_get_time(&now); + os_reltime_sub(&now_r, &sta->acct_session_start, &diff); if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME, - now.sec - sta->acct_session_start)) { + diff.sec)) { wpa_printf(MSG_INFO, "Could not add Acct-Session-Time"); goto fail; } diff --git a/src/ap/acs.c b/src/ap/acs.c index 9ef221ed..f58b091e 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -280,7 +280,7 @@ static void acs_cleanup(struct hostapd_iface *iface) } -void acs_fail(struct hostapd_iface *iface) +static void acs_fail(struct hostapd_iface *iface) { wpa_printf(MSG_ERROR, "ACS: Failed to start"); acs_cleanup(iface); diff --git a/src/ap/acs.h b/src/ap/acs.h index a41f17f3..fc85259e 100644 --- a/src/ap/acs.h +++ b/src/ap/acs.h @@ -13,7 +13,6 @@ #ifdef CONFIG_ACS enum hostapd_chan_status acs_init(struct hostapd_iface *iface); -int hostapd_acs_completed(struct hostapd_iface *iface, int err); #else /* CONFIG_ACS */ diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 65a6f12a..a29f4d0e 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -433,7 +433,6 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) } os_free(conf->eap_user_sqlite); - os_free(conf->dump_log_name); os_free(conf->eap_req_id_text); os_free(conf->accept_mac); os_free(conf->deny_mac); @@ -759,7 +758,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, if (conf->ieee80211n && bss->wpa && !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) { + !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) + { bss->disable_11n = 1; wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " "requires CCMP/GCMP to be enabled, disabling HT " @@ -792,7 +793,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, #ifdef CONFIG_HS20 if (bss->hs20 && (!(bss->wpa & 2) || - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) { + !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_CCMP_256 | + WPA_CIPHER_GCMP_256)))) { wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP " "configuration is required for Hotspot 2.0 " "functionality"); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 09b2778e..af30ac49 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -189,8 +189,6 @@ struct hostapd_bss_config { unsigned int logger_syslog; /* module bitfield */ unsigned int logger_stdout; /* module bitfield */ - char *dump_log_name; /* file name for state dump (SIGUSR1) */ - int max_num_sta; /* maximum number of STAs in station table */ int dtim_period; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 09b5f68b..893e6d9e 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -9,7 +9,6 @@ #include "utils/includes.h" #include "utils/common.h" -#include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "wps/wps.h" #include "p2p/p2p.h" @@ -715,7 +714,7 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper, const u8 *peer, u8 *buf, u16 *buf_len) { if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL) - return 0; + return -1; return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf, buf_len); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index b5f6a020..15a4b267 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -1,6 +1,6 @@ /* * hostapd - Driver operations - * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -272,4 +272,12 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, return hapd->driver->switch_channel(hapd->drv_priv, settings); } +static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, + size_t buflen) +{ + if (hapd->driver == NULL || hapd->driver->status == NULL) + return -1; + return hapd->driver->status(hapd->drv_priv, buf, buflen); +} + #endif /* AP_DRV_OPS */ diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c index 0dab39fa..f9b15401 100644 --- a/src/ap/ap_list.c +++ b/src/ap/ap_list.c @@ -14,7 +14,6 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "ieee802_11.h" diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 0e0dae46..5318ecb7 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -4,14 +4,8 @@ * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -21,7 +15,6 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" -#include "drivers/driver.h" #include "wps/wps_defs.h" #include "p2p/p2p.h" #include "hostapd.h" @@ -207,10 +200,10 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) { u8 chan; - if (!hapd->iface->cs_freq) + if (!hapd->iface->cs_freq_params.freq) return eid; - if (ieee80211_freq_to_chan(hapd->iface->cs_freq, &chan) == + if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) == NUM_HOSTAPD_MODES) return eid; @@ -224,13 +217,56 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) } +static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) +{ + u8 sec_ch; + + if (!hapd->iface->cs_freq_params.sec_channel_offset) + return eid; + + if (hapd->iface->cs_freq_params.sec_channel_offset == -1) + sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; + else if (hapd->iface->cs_freq_params.sec_channel_offset == 1) + sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; + else + return eid; + + *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; + *eid++ = 1; + *eid++ = sec_ch; + + return eid; +} + + +static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, + u8 *start, unsigned int *csa_counter_off) +{ + u8 *old_pos = pos; + + if (!csa_counter_off) + return pos; + + *csa_counter_off = 0; + pos = hostapd_eid_csa(hapd, pos); + + if (pos != old_pos) { + /* save an offset to the counter - should be last byte */ + *csa_counter_off = pos - start - 1; + pos = hostapd_eid_secondary_channel(hapd, pos); + } + + return pos; +} + + static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *req, int is_p2p, size_t *resp_len) { struct ieee80211_mgmt *resp; - u8 *pos, *epos, *old_pos; + u8 *pos, *epos; size_t buflen; #define MAX_PROBERESP_LEN 768 @@ -304,13 +340,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_adv_proto(hapd, pos); pos = hostapd_eid_roaming_consortium(hapd, pos); - old_pos = pos; - pos = hostapd_eid_csa(hapd, pos); - - /* save an offset to the counter - should be last byte */ - hapd->iface->cs_c_off_proberesp = (pos != old_pos) ? - pos - (u8 *) resp - 1 : 0; - + pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, + &hapd->iface->cs_c_off_proberesp); #ifdef CONFIG_IEEE80211AC pos = hostapd_eid_vht_capabilities(hapd, pos); pos = hostapd_eid_vht_operation(hapd, pos); @@ -626,7 +657,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, size_t resp_len = 0; #ifdef NEED_AP_MLME u16 capab_info; - u8 *pos, *tailpos, *old_pos; + u8 *pos, *tailpos; #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 @@ -721,11 +752,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_interworking(hapd, tailpos); tailpos = hostapd_eid_adv_proto(hapd, tailpos); tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); - old_pos = tailpos; - tailpos = hostapd_eid_csa(hapd, tailpos); - hapd->iface->cs_c_off_beacon = (old_pos != tailpos) ? - tailpos - tail - 1 : 0; - + tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, + &hapd->iface->cs_c_off_beacon); #ifdef CONFIG_IEEE80211AC tailpos = hostapd_eid_vht_capabilities(hapd, tailpos); tailpos = hostapd_eid_vht_operation(hapd, tailpos); @@ -844,20 +872,21 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) } -void ieee802_11_set_beacon(struct hostapd_data *hapd) +int ieee802_11_set_beacon(struct hostapd_data *hapd) { struct wpa_driver_ap_params params; struct wpabuf *beacon, *proberesp, *assocresp; + int res, ret = -1; if (hapd->iface->csa_in_progress) { wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); - return; + return -1; } hapd->beacon_set_done = 1; if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) - return; + return -1; if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < 0) @@ -867,31 +896,46 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) params.proberesp_ies = proberesp; params.assocresp_ies = assocresp; - if (hostapd_drv_set_ap(hapd, ¶ms)) - wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + res = hostapd_drv_set_ap(hapd, ¶ms); hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); + if (res) + wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + else + ret = 0; fail: ieee802_11_free_ap_params(¶ms); + return ret; } -void ieee802_11_set_beacons(struct hostapd_iface *iface) +int ieee802_11_set_beacons(struct hostapd_iface *iface) { size_t i; + int ret = 0; + for (i = 0; i < iface->num_bss; i++) { - if (iface->bss[i]->started) - ieee802_11_set_beacon(iface->bss[i]); + if (iface->bss[i]->started && + ieee802_11_set_beacon(iface->bss[i]) < 0) + ret = -1; } + + return ret; } /* only update beacons if started */ -void ieee802_11_update_beacons(struct hostapd_iface *iface) +int ieee802_11_update_beacons(struct hostapd_iface *iface) { size_t i; - for (i = 0; i < iface->num_bss; i++) - if (iface->bss[i]->beacon_set_done && iface->bss[i]->started) - ieee802_11_set_beacon(iface->bss[i]); + int ret = 0; + + for (i = 0; i < iface->num_bss; i++) { + if (iface->bss[i]->beacon_set_done && iface->bss[i]->started && + ieee802_11_set_beacon(iface->bss[i]) < 0) + ret = -1; + } + + return ret; } #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/src/ap/beacon.h b/src/ap/beacon.h index a04a829c..722159a7 100644 --- a/src/ap/beacon.h +++ b/src/ap/beacon.h @@ -3,14 +3,8 @@ * Copyright (c) 2002-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef BEACON_H @@ -21,9 +15,9 @@ struct ieee80211_mgmt; void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal); -void ieee802_11_set_beacon(struct hostapd_data *hapd); -void ieee802_11_set_beacons(struct hostapd_iface *iface); -void ieee802_11_update_beacons(struct hostapd_iface *iface); +int ieee802_11_set_beacon(struct hostapd_data *hapd); +int ieee802_11_set_beacons(struct hostapd_iface *iface); +int ieee802_11_update_beacons(struct hostapd_iface *iface); int ieee802_11_build_ap_params(struct hostapd_data *hapd, struct wpa_driver_ap_params *params); void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params); diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 4125fd56..3fb9e04b 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "eapol_auth/eapol_auth_sm.h" #include "hostapd.h" #include "ieee802_1x.h" #include "wpa_auth.h" @@ -21,24 +22,61 @@ #include "ap_drv_ops.h" +static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd, + struct sta_info *sta, + char *buf, size_t buflen) +{ + struct hostap_sta_driver_data data; + int ret; + + if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) + return 0; + + ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n" + "rx_bytes=%lu\ntx_bytes=%lu\n", + data.rx_packets, data.tx_packets, + data.rx_bytes, data.tx_bytes); + if (ret < 0 || (size_t) ret >= buflen) + return 0; + return ret; +} + + static int hostapd_get_sta_conn_time(struct sta_info *sta, char *buf, size_t buflen) { struct os_reltime age; - int len = 0, ret; + int ret; if (!sta->connected_time.sec) return 0; os_reltime_age(&sta->connected_time, &age); - ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n", + ret = os_snprintf(buf, buflen, "connected_time=%u\n", (unsigned int) age.sec); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; + if (ret < 0 || (size_t) ret >= buflen) + return 0; + return ret; +} - return len; + +static const char * timeout_next_str(int val) +{ + switch (val) { + case STA_NULLFUNC: + return "NULLFUNC POLL"; + case STA_DISASSOC: + return "DISASSOC"; + case STA_DEAUTH: + return "DEAUTH"; + case STA_REMOVE: + return "REMOVE"; + case STA_DISASSOC_FROM_CLI: + return "DISASSOC_FROM_CLI"; + } + + return "?"; } @@ -46,22 +84,42 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, struct sta_info *sta, char *buf, size_t buflen) { - int len, res, ret; - - if (sta == NULL) { - ret = os_snprintf(buf, buflen, "FAIL\n"); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - return ret; - } + int len, res, ret, i; len = 0; - ret = os_snprintf(buf + len, buflen - len, MACSTR "\n", + ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=", MAC2STR(sta->addr)); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; + ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len); + if (ret < 0) + return len; + len += ret; + + ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n" + "listen_interval=%d\nsupported_rates=", + sta->aid, sta->capability, sta->listen_interval); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + + for (i = 0; i < sta->supported_rates_len; i++) { + ret = os_snprintf(buf + len, buflen - len, "%02x%s", + sta->supported_rates[i], + i + 1 < sta->supported_rates_len ? " " : ""); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + } + + ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n", + timeout_next_str(sta->timeout_next)); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); if (res >= 0) len += res; @@ -79,9 +137,8 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, if (res >= 0) len += res; - res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len); - if (res >= 0) - len += res; + len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len); + len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len); return len; } @@ -99,6 +156,8 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, { u8 addr[ETH_ALEN]; int ret; + const char *pos; + struct sta_info *sta; if (hwaddr_aton(txtaddr, addr)) { ret = os_snprintf(buf, buflen, "FAIL\n"); @@ -106,8 +165,28 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, return 0; return ret; } - return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr), - buf, buflen); + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) + return -1; + + pos = os_strchr(txtaddr, ' '); + if (pos) { + pos++; + +#ifdef HOSTAPD_DUMP_STATE + if (os_strcmp(pos, "eapol") == 0) { + if (sta->eapol_sm == NULL) + return -1; + return eapol_auth_dump_state(sta->eapol_sm, buf, + buflen); + } +#endif /* HOSTAPD_DUMP_STATE */ + + return -1; + } + + return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); } diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index b066bffd..9af96468 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -299,6 +299,7 @@ skip_wpa_check: new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); @@ -439,7 +440,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; - if (hapd->iface->csa_in_progress && freq == hapd->iface->cs_freq) { + if (hapd->iface->csa_in_progress && + freq == hapd->iface->cs_freq_params.freq) { hostapd_cleanup_cs_params(hapd); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d", @@ -556,39 +558,48 @@ fail: static void hostapd_action_rx(struct hostapd_data *hapd, - struct rx_action *action) + struct rx_mgmt *drv_mgmt) { + struct ieee80211_mgmt *mgmt; struct sta_info *sta; + size_t plen __maybe_unused; + u16 fc; + + if (drv_mgmt->frame_len < 24 + 1) + return; + + plen = drv_mgmt->frame_len - 24 - 1; + + mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; + fc = le_to_host16(mgmt->frame_control); + if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) + return; /* handled by the driver */ wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", - action->category, (int) action->len); + mgmt->u.action.category, (int) plen); - sta = ap_get_sta(hapd, action->sa); + sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { wpa_printf(MSG_DEBUG, "%s: station not found", __func__); return; } #ifdef CONFIG_IEEE80211R - if (action->category == WLAN_ACTION_FT) { - wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d", - __func__, (int) action->len); - wpa_ft_action_rx(sta->wpa_sm, action->data, action->len); + if (mgmt->u.action.category == WLAN_ACTION_FT) { + const u8 *payload = drv_mgmt->frame + 24 + 1; + wpa_ft_action_rx(sta->wpa_sm, payload, plen); } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W - if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) { - wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d", - __func__, (int) action->len); - ieee802_11_sa_query_action(hapd, action->sa, - *(action->data + 1), - action->data + 2); + if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) { + ieee802_11_sa_query_action( + hapd, mgmt->sa, + mgmt->u.action.u.sa_query_resp.action, + mgmt->u.action.u.sa_query_resp.trans_id); } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WNM - if (action->category == WLAN_ACTION_WNM) { - wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d", - __func__, (int) action->len); - ieee802_11_rx_wnm_action_ap(hapd, action); + if (mgmt->u.action.category == WLAN_ACTION_WNM) { + ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); } #endif /* CONFIG_WNM */ } @@ -630,17 +641,18 @@ static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, } -static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) +static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) { struct hostapd_iface *iface = hapd->iface; const struct ieee80211_hdr *hdr; const u8 *bssid; struct hostapd_frame_info fi; + int ret; hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); if (bssid == NULL) - return; + return 0; hapd = get_hapd_bssid(iface, bssid); if (hapd == NULL) { @@ -655,7 +667,7 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) hapd = iface->bss[0]; else - return; + return 0; } os_memset(&fi, 0, sizeof(fi)); @@ -664,53 +676,19 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) if (hapd == HAPD_BROADCAST) { size_t i; - for (i = 0; i < iface->num_bss; i++) - ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, - rx_mgmt->frame_len, &fi); + ret = 0; + for (i = 0; i < iface->num_bss; i++) { + if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, + rx_mgmt->frame_len, &fi) > 0) + ret = 1; + } } else - ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi); + ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, + &fi); random_add_randomness(&fi, sizeof(fi)); -} - -static void hostapd_rx_action(struct hostapd_data *hapd, - struct rx_action *rx_action) -{ - struct rx_mgmt rx_mgmt; - u8 *buf; - struct ieee80211_hdr *hdr; - - wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR - " BSSID=" MACSTR " category=%u", - MAC2STR(rx_action->da), MAC2STR(rx_action->sa), - MAC2STR(rx_action->bssid), rx_action->category); - wpa_hexdump(MSG_MSGDUMP, "Received action frame contents", - rx_action->data, rx_action->len); - - buf = os_zalloc(24 + 1 + rx_action->len); - if (buf == NULL) - return; - hdr = (struct ieee80211_hdr *) buf; - hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - if (rx_action->category == WLAN_ACTION_SA_QUERY) { - /* - * Assume frame was protected; it would have been dropped if - * not. - */ - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); - } - os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN); - os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN); - os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN); - buf[24] = rx_action->category; - os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len); - os_memset(&rx_mgmt, 0, sizeof(rx_mgmt)); - rx_mgmt.frame = buf; - rx_mgmt.frame_len = 24 + 1 + rx_action->len; - hostapd_mgmt_rx(hapd, &rx_mgmt); - os_free(buf); + return ret; } @@ -952,10 +930,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.addr, data->rx_from_unknown.wds); break; +#endif /* NEED_AP_MLME */ case EVENT_RX_MGMT: - hostapd_mgmt_rx(hapd, &data->rx_mgmt); - break; +#ifdef NEED_AP_MLME + if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0) + break; #endif /* NEED_AP_MLME */ + hostapd_action_rx(hapd, &data->rx_mgmt); + break; case EVENT_RX_PROBE_REQ: if (data->rx_probe_req.sa == NULL || data->rx_probe_req.ie == NULL) @@ -994,15 +976,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; hostapd_event_sta_low_ack(hapd, data->low_ack.addr); break; - case EVENT_RX_ACTION: - if (data->rx_action.da == NULL || data->rx_action.sa == NULL || - data->rx_action.bssid == NULL) - break; -#ifdef NEED_AP_MLME - hostapd_rx_action(hapd, &data->rx_action); -#endif /* NEED_AP_MLME */ - hostapd_action_rx(hapd, &data->rx_action); - break; case EVENT_AUTH: hostapd_notif_auth(hapd, &data->auth); break; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a436c2ae..44d05c5d 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -14,7 +14,6 @@ #include "common/wpa_ctrl.h" #include "radius/radius_client.h" #include "radius/radius_das.h" -#include "drivers/driver.h" #include "hostapd.h" #include "authsrv.h" #include "sta_info.h" @@ -42,9 +41,6 @@ static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); static int setup_interface2(struct hostapd_iface *iface); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); -extern int wpa_debug_level; -extern struct wpa_driver_ops *wpa_drivers[]; - int hostapd_for_each_interface(struct hapd_interfaces *interfaces, int (*cb)(struct hostapd_iface *iface, @@ -811,8 +807,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (!hapd->conf->start_disabled) - ieee802_11_set_beacon(hapd); + if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) + return -1; if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) return -1; @@ -2200,7 +2196,7 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, return ret; /* set channel switch parameters for csa ie */ - iface->cs_freq = settings->freq_params.freq; + iface->cs_freq_params = settings->freq_params; iface->cs_count = settings->cs_count; iface->cs_block_tx = settings->block_tx; @@ -2219,7 +2215,8 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, void hostapd_cleanup_cs_params(struct hostapd_data *hapd) { - hapd->iface->cs_freq = 0; + os_memset(&hapd->iface->cs_freq_params, 0, + sizeof(hapd->iface->cs_freq_params)); hapd->iface->cs_count = 0; hapd->iface->cs_block_tx = 0; hapd->iface->cs_c_off_beacon = 0; diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 84468de0..489ab165 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -11,14 +11,13 @@ #include "common/defs.h" #include "ap_config.h" +#include "drivers/driver.h" -struct wpa_driver_ops; struct wpa_ctrl_dst; struct radius_server_data; struct upnp_wps_device_sm; struct hostapd_data; struct sta_info; -struct hostap_sta_driver_data; struct ieee80211_ht_capabilities; struct full_dynamic_vlan; enum wps_event; @@ -27,8 +26,6 @@ union wps_event_data; struct hostapd_iface; struct hostapd_dynamic_iface; -struct csa_settings; - struct hapd_interfaces { int (*reload_config)(struct hostapd_iface *iface); struct hostapd_config * (*config_read_cb)(const char *config_fname); @@ -146,7 +143,7 @@ struct hostapd_data { struct eapol_authenticator *eapol_auth; struct rsn_preauth_interface *preauth_iface; - time_t michael_mic_failure; + struct os_reltime michael_mic_failure; int michael_mic_failures; int tkip_countermeasures; @@ -243,6 +240,10 @@ struct hostapd_data { u8 sae_token_key[8]; struct os_reltime last_sae_token_key_update; #endif /* CONFIG_SAE */ + +#ifdef CONFIG_TESTING_OPTIONS + int ext_mgmt_frame_handling; +#endif /* CONFIG_TESTING_OPTIONS */ }; @@ -337,7 +338,7 @@ struct hostapd_iface { s8 lowest_nf; /* channel switch parameters */ - int cs_freq; + struct hostapd_freq_params cs_freq_params; u8 cs_count; int cs_block_tx; unsigned int cs_c_off_beacon; diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index e95e0e1a..4e663795 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -21,7 +15,6 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "ap_drv_ops.h" diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index abadcd13..783ae5e1 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef HW_FEATURES_H @@ -21,6 +15,7 @@ void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, size_t num_hw_features); int hostapd_get_hw_features(struct hostapd_iface *iface); +int hostapd_acs_completed(struct hostapd_iface *iface, int err); int hostapd_select_hw_mode(struct hostapd_iface *iface); const char * hostapd_hw_mode_txt(int mode); int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index e55f843c..1e3693d1 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -15,7 +15,6 @@ #include "crypto/crypto.h" #include "crypto/sha256.h" #include "crypto/random.h" -#include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" @@ -239,13 +238,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (shared key)"); -#ifdef IEEE80211_REQUIRE_AUTH_ACK - /* Station will be marked authenticated if it ACKs the - * authentication reply. */ -#else sta->flags |= WLAN_STA_AUTH; wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); -#endif os_free(sta->challenge); sta->challenge = NULL; @@ -691,15 +685,10 @@ static void handle_auth(struct hostapd_data *hapd, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (open system)"); -#ifdef IEEE80211_REQUIRE_AUTH_ACK - /* Station will be marked authenticated if it ACKs the - * authentication reply. */ -#else sta->flags |= WLAN_STA_AUTH; wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); sta->auth_alg = WLAN_AUTH_OPEN; mlme_authenticate_indication(hapd, sta); -#endif break; case WLAN_AUTH_SHARED_KEY: resp = auth_shared_key(hapd, sta, auth_transaction, challenge, @@ -926,7 +915,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "Station does not support " "mandatory VHT PHY - reject association"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + return WLAN_STATUS_ASSOC_DENIED_NO_VHT; } #endif /* CONFIG_IEEE80211AC */ @@ -1068,7 +1057,9 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_SAE if (wpa_auth_uses_sae(sta->wpa_sm) && - sta->auth_alg != WLAN_AUTH_SAE) { + sta->auth_alg != WLAN_AUTH_SAE && + !(sta->auth_alg == WLAN_AUTH_FT && + wpa_auth_uses_ft_sae(sta->wpa_sm))) { wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " "SAE AKM after non-SAE auth_alg %u", MAC2STR(sta->addr), sta->auth_alg); @@ -1544,9 +1535,9 @@ static void handle_beacon(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W -static void hostapd_sa_query_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - size_t len) +static int hostapd_sa_query_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len) { const u8 *end; @@ -1555,12 +1546,13 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, if (((u8 *) mgmt) + len < end) { wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action " "frame (len=%lu)", (unsigned long) len); - return; + return 0; } ieee802_11_sa_query_action(hapd, mgmt->sa, mgmt->u.action.u.sa_query_resp.action, mgmt->u.action.u.sa_query_resp.trans_id); + return 1; } @@ -1572,29 +1564,8 @@ static int robust_action_frame(u8 category) #endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WNM -static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta, - const struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct rx_action action; - if (len < IEEE80211_HDRLEN + 2) - return; - os_memset(&action, 0, sizeof(action)); - action.da = mgmt->da; - action.sa = mgmt->sa; - action.bssid = mgmt->bssid; - action.category = mgmt->u.action.category; - action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action; - action.len = len - IEEE80211_HDRLEN - 1; - action.freq = hapd->iface->freq; - ieee802_11_rx_wnm_action_ap(hapd, &action); -} -#endif /* CONFIG_WNM */ - - -static void handle_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) +static int handle_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; sta = ap_get_sta(hapd, mgmt->sa); @@ -1604,7 +1575,7 @@ static void handle_action(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "handle_action - too short payload (len=%lu)", (unsigned long) len); - return; + return 0; } if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && @@ -1612,7 +1583,7 @@ static void handle_action(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " "frame (category=%u) from unassociated STA " MACSTR, MAC2STR(mgmt->sa), mgmt->u.action.category); - return; + return 0; } #ifdef CONFIG_IEEE80211W @@ -1623,7 +1594,7 @@ static void handle_action(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "Dropped unprotected Robust Action frame from " "an MFP STA"); - return; + return 0; } #endif /* CONFIG_IEEE80211W */ @@ -1633,20 +1604,19 @@ static void handle_action(struct hostapd_data *hapd, if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, len - IEEE80211_HDRLEN)) break; - return; + return 1; #endif /* CONFIG_IEEE80211R */ case WLAN_ACTION_WMM: hostapd_wmm_action(hapd, mgmt, len); - return; + return 1; #ifdef CONFIG_IEEE80211W case WLAN_ACTION_SA_QUERY: - hostapd_sa_query_action(hapd, mgmt, len); - return; + return hostapd_sa_query_action(hapd, mgmt, len); #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WNM case WLAN_ACTION_WNM: - hostapd_wnm_action(hapd, sta, mgmt, len); - return; + ieee802_11_rx_wnm_action_ap(hapd, mgmt, len); + return 1; #endif /* CONFIG_WNM */ case WLAN_ACTION_PUBLIC: if (hapd->public_action_cb) { @@ -1660,14 +1630,14 @@ static void handle_action(struct hostapd_data *hapd, hapd->iface->freq); } if (hapd->public_action_cb || hapd->public_action_cb2) - return; + return 1; break; case WLAN_ACTION_VENDOR_SPECIFIC: if (hapd->vendor_action_cb) { if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, (u8 *) mgmt, len, hapd->iface->freq) == 0) - return; + return 1; } break; } @@ -1690,7 +1660,7 @@ static void handle_action(struct hostapd_data *hapd, "frame back to sender"); resp = os_malloc(len); if (resp == NULL) - return; + return 0; os_memcpy(resp, mgmt, len); os_memcpy(resp->da, resp->sa, ETH_ALEN); os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); @@ -1703,6 +1673,8 @@ static void handle_action(struct hostapd_data *hapd, } os_free(resp); } + + return 1; } @@ -1719,15 +1691,29 @@ static void handle_action(struct hostapd_data *hapd, * addition, it can be called to re-inserted pending frames (e.g., when using * external RADIUS server as an MAC ACL). */ -void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, - struct hostapd_frame_info *fi) +int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, + struct hostapd_frame_info *fi) { struct ieee80211_mgmt *mgmt; int broadcast; u16 fc, stype; + int ret = 0; + +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_mgmt_frame_handling) { + size_t hex_len = 2 * len + 1; + char *hex = os_malloc(hex_len); + if (hex) { + wpa_snprintf_hex(hex, hex_len, buf, len); + wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); + os_free(hex); + } + return 1; + } +#endif /* CONFIG_TESTING_OPTIONS */ if (len < 24) - return; + return 0; mgmt = (struct ieee80211_mgmt *) buf; fc = le_to_host16(mgmt->frame_control); @@ -1735,7 +1721,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, if (stype == WLAN_FC_STYPE_BEACON) { handle_beacon(hapd, mgmt, len, fi); - return; + return 1; } broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff && @@ -1751,13 +1737,13 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address", MAC2STR(mgmt->bssid)); - return; + return 0; } if (stype == WLAN_FC_STYPE_PROBE_REQ) { handle_probe_req(hapd, mgmt, len, fi->ssi_signal); - return; + return 1; } if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { @@ -1765,33 +1751,38 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, HOSTAPD_LEVEL_DEBUG, "MGMT: DA=" MACSTR " not our address", MAC2STR(mgmt->da)); - return; + return 0; } switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth"); handle_auth(hapd, mgmt, len); + ret = 1; break; case WLAN_FC_STYPE_ASSOC_REQ: wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); handle_assoc(hapd, mgmt, len, 0); + ret = 1; break; case WLAN_FC_STYPE_REASSOC_REQ: wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); handle_assoc(hapd, mgmt, len, 1); + ret = 1; break; case WLAN_FC_STYPE_DISASSOC: wpa_printf(MSG_DEBUG, "mgmt::disassoc"); handle_disassoc(hapd, mgmt, len); + ret = 1; break; case WLAN_FC_STYPE_DEAUTH: wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); handle_deauth(hapd, mgmt, len); + ret = 1; break; case WLAN_FC_STYPE_ACTION: wpa_printf(MSG_DEBUG, "mgmt::action"); - handle_action(hapd, mgmt, len); + ret = handle_action(hapd, mgmt, len); break; default: hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1799,6 +1790,8 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, "unknown mgmt frame subtype %d", stype); break; } + + return ret; } @@ -1919,6 +1912,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, if (sta->flags & WLAN_STA_ASSOC) new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || sta->auth_alg == WLAN_AUTH_FT) { /* @@ -2075,6 +2069,14 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, const struct ieee80211_mgmt *mgmt; mgmt = (const struct ieee80211_mgmt *) buf; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_mgmt_frame_handling) { + wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d", + stype, ok); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth cb"); diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 61f13167..5edeb71c 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -15,8 +15,8 @@ struct sta_info; struct hostapd_frame_info; struct ieee80211_ht_capabilities; -void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, - struct hostapd_frame_info *fi); +int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, + struct hostapd_frame_info *fi); void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, u16 stype, int ok); void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len); diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 2d53648c..31dc47ed 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -3,21 +3,14 @@ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2007-2008, Intel Corporation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" #include "utils/common.h" #include "common/ieee802_11_defs.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "sta_info.h" diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c index 60e6b572..f2ab182d 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -12,7 +12,6 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "sta_info.h" diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 4465d12e..49b30e41 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -29,6 +29,7 @@ #include "pmksa_cache_auth.h" #include "ap_config.h" #include "ap_drv_ops.h" +#include "wps_hostapd.h" #include "ieee802_1x.h" @@ -1951,7 +1952,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, { int len = 0, ret; struct eapol_state_machine *sm = sta->eapol_sm; - struct os_time t; + struct os_reltime diff; if (sm == NULL) return 0; @@ -2066,7 +2067,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, len += ret; /* dot1xAuthSessionStatsTable */ - os_get_time(&t); + os_reltime_age(&sta->acct_session_start, &diff); ret = os_snprintf(buf + len, buflen - len, /* TODO: dot1xAuthSessionOctetsRx */ /* TODO: dot1xAuthSessionOctetsTx */ @@ -2081,12 +2082,23 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, (wpa_key_mgmt_wpa_ieee8021x( wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 1 : 2, - (unsigned int) (t.sec - sta->acct_session_start), + (unsigned int) diff.sec, sm->identity); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; + ret = os_snprintf(buf + len, buflen - len, + "last_eap_type_as=%d (%s)\n" + "last_eap_type_sta=%d (%s)\n", + sm->eap_type_authsrv, + eap_server_get_name(0, sm->eap_type_authsrv), + sm->eap_type_supp, + eap_server_get_name(0, sm->eap_type_supp)); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + return len; } @@ -2128,5 +2140,6 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, os_sleep(0, 10000); ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_IEEE_802_1X_AUTH_FAILED); + hostapd_wps_eap_completed(hapd); } } diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index 40972e9a..4720b59c 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -91,9 +91,9 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " MACSTR, MAC2STR(pmksa->pmksa->spa)); @@ -107,12 +107,12 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { int sec; - struct os_time now; + struct os_reltime now; eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); if (pmksa->pmksa == NULL) return; - os_get_time(&now); + os_get_reltime(&now); sec = pmksa->pmksa->expiration - now.sec; if (sec < 0) sec = 0; @@ -241,7 +241,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, struct eapol_state_machine *eapol, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos; - struct os_time now; + struct os_reltime now; if (pmk_len > PMK_LEN) return NULL; @@ -253,7 +253,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, entry->pmk_len = pmk_len; rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, wpa_key_mgmt_sha256(akmp)); - os_get_time(&now); + os_get_reltime(&now); entry->expiration = now.sec; if (session_timeout > 0) entry->expiration += session_timeout; diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index d1d86571..670b8344 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -15,7 +15,6 @@ #include "common/sae.h" #include "radius/radius.h" #include "radius/radius_client.h" -#include "drivers/driver.h" #include "p2p/p2p.h" #include "hostapd.h" #include "accounting.h" @@ -495,7 +494,7 @@ void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, u32 session_timeout) { if (eloop_replenish_timeout(session_timeout, 0, - ap_handle_session_timer, hapd, sta)) { + ap_handle_session_timer, hapd, sta) == 1) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "setting session timeout " "to %d seconds", session_timeout); @@ -1012,3 +1011,33 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); ap_sta_disassoc_cb_timeout(hapd, sta); } + + +int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) +{ + int res; + + buf[0] = '\0'; + res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), + (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), + (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), + (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : + ""), + (flags & WLAN_STA_SHORT_PREAMBLE ? + "[SHORT_PREAMBLE]" : ""), + (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), + (flags & WLAN_STA_WMM ? "[WMM]" : ""), + (flags & WLAN_STA_MFP ? "[MFP]" : ""), + (flags & WLAN_STA_WPS ? "[WPS]" : ""), + (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), + (flags & WLAN_STA_WDS ? "[WDS]" : ""), + (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), + (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), + (flags & WLAN_STA_GAS ? "[GAS]" : ""), + (flags & WLAN_STA_VHT ? "[VHT]" : ""), + (flags & WLAN_STA_WNM_SLEEP_MODE ? + "[WNM_SLEEP_MODE]" : "")); + + return res; +} diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index ea3fe407..9b77e060 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -12,9 +12,6 @@ /* STA flags */ #define WLAN_STA_AUTH BIT(0) #define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) -#define WLAN_STA_PERM BIT(4) #define WLAN_STA_AUTHORIZED BIT(5) #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ #define WLAN_STA_SHORT_PREAMBLE BIT(7) @@ -29,6 +26,7 @@ #define WLAN_STA_WPS2 BIT(16) #define WLAN_STA_GAS BIT(17) #define WLAN_STA_VHT BIT(18) +#define WLAN_STA_WNM_SLEEP_MODE BIT(19) #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) @@ -78,7 +76,7 @@ struct sta_info { u32 acct_session_id_hi; u32 acct_session_id_lo; - time_t acct_session_start; + struct os_reltime acct_session_start; int acct_session_started; int acct_terminate_cause; /* Acct-Terminate-Cause */ int acct_interim_interval; /* Acct-Interim-Interval */ @@ -195,4 +193,6 @@ static inline int ap_sta_is_authorized(struct sta_info *sta) void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); +int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); + #endif /* STA_INFO_H */ diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c index 4a2ea066..4725e2b3 100644 --- a/src/ap/tkip_countermeasures.c +++ b/src/ap/tkip_countermeasures.c @@ -68,7 +68,7 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd) int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) { - struct os_time now; + struct os_reltime now; int ret = 0; if (addr && local) { @@ -89,8 +89,8 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) } } - os_get_time(&now); - if (now.sec > hapd->michael_mic_failure + 60) { + os_get_reltime(&now); + if (os_reltime_expired(&now, &hapd->michael_mic_failure, 60)) { hapd->michael_mic_failures = 1; } else { hapd->michael_mic_failures++; @@ -99,7 +99,7 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) ret = 1; } } - hapd->michael_mic_failure = now.sec; + hapd->michael_mic_failure = now; return ret; } diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c index 1afbb8ec..509e557c 100644 --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h index 382d5dee..781eaac4 100644 --- a/src/ap/vlan_init.h +++ b/src/ap/vlan_init.h @@ -3,14 +3,8 @@ * Copyright 2003, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef VLAN_INIT_H diff --git a/src/ap/wmm.c b/src/ap/wmm.c index 28516726..6d4177c2 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" diff --git a/src/ap/wmm.h b/src/ap/wmm.h index 96b04e89..b70b8636 100644 --- a/src/ap/wmm.h +++ b/src/ap/wmm.h @@ -3,14 +3,8 @@ * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef WME_H diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 54a6b857..8e5bdcb0 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -1,6 +1,6 @@ /* * hostapd - WNM - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "ap/hostapd.h" #include "ap/sta_info.h" @@ -72,7 +73,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, wnmsleep_ie.len = wnmsleep_ie_len - 2; wnmsleep_ie.action_type = action_type; wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT; - wnmsleep_ie.intval = intval; + wnmsleep_ie.intval = host_to_le16(intval); /* TFS IE(s) */ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); @@ -154,6 +155,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, */ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { + sta->flags |= WLAN_STA_WNM_SLEEP_MODE; hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM, addr, NULL, NULL); wpa_set_wnmsleep(sta->wpa_sm, 1); @@ -167,6 +169,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, wnmsleep_ie.status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) && wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) { + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; wpa_set_wnmsleep(sta->wpa_sm, 0); hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM, addr, NULL, NULL); @@ -233,7 +236,7 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token, wnmsleep_ie->action_type, - wnmsleep_ie->intval); + le_to_host16(wnmsleep_ie->intval)); if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { /* clear the tfs after sending the resp frame */ @@ -243,29 +246,263 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, } +static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, + const u8 *addr, + u8 dialog_token, + const char *url) +{ + struct ieee80211_mgmt *mgmt; + size_t url_len, len; + u8 *pos; + int res; + + if (url) + url_len = os_strlen(url); + else + url_len = 0; + + mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0)); + if (mgmt == NULL) + return -1; + os_memcpy(mgmt->da, addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; + mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; + mgmt->u.action.u.bss_tm_req.req_mode = 0; + mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); + mgmt->u.action.u.bss_tm_req.validity_interval = 1; + pos = mgmt->u.action.u.bss_tm_req.variable; + if (url) { + *pos++ += url_len; + os_memcpy(pos, url, url_len); + pos += url_len; + } + + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " + MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " + "validity_interval=%u", + MAC2STR(addr), dialog_token, + mgmt->u.action.u.bss_tm_req.req_mode, + le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer), + mgmt->u.action.u.bss_tm_req.validity_interval); + + len = pos - &mgmt->u.action.category; + res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, + mgmt->da, &mgmt->u.action.category, len); + os_free(mgmt); + return res; +} + + +static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, + const u8 *addr, const u8 *frm, + size_t len) +{ + u8 dialog_token, reason; + const u8 *pos, *end; + + if (len < 2) { + wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from " + MACSTR, MAC2STR(addr)); + return; + } + + pos = frm; + end = pos + len; + dialog_token = *pos++; + reason = *pos++; + + wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from " + MACSTR " dialog_token=%u reason=%u", + MAC2STR(addr), dialog_token, reason); + + wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", + pos, end - pos); + + ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL); +} + + +static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd, + const u8 *addr, const u8 *frm, + size_t len) +{ + u8 dialog_token, status_code, bss_termination_delay; + const u8 *pos, *end; + + if (len < 3) { + wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from " + MACSTR, MAC2STR(addr)); + return; + } + + pos = frm; + end = pos + len; + dialog_token = *pos++; + status_code = *pos++; + bss_termination_delay = *pos++; + + wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from " + MACSTR " dialog_token=%u status_code=%u " + "bss_termination_delay=%u", MAC2STR(addr), dialog_token, + status_code, bss_termination_delay); + + if (status_code == WNM_BSS_TM_ACCEPT) { + if (end - pos < ETH_ALEN) { + wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); + return; + } + wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR, + MAC2STR(pos)); + pos += ETH_ALEN; + } + + wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", + pos, end - pos); +} + + int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, - struct rx_action *action) + const struct ieee80211_mgmt *mgmt, size_t len) { - if (action->len < 1 || action->data == NULL) + u8 action; + const u8 *payload; + size_t plen; + + if (len < IEEE80211_HDRLEN + 2) return -1; - switch (action->data[0]) { + payload = &mgmt->u.action.category; + payload++; + action = *payload++; + plen = (((const u8 *) mgmt) + len) - payload; + + switch (action) { case WNM_BSS_TRANS_MGMT_QUERY: - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query"); - /* TODO */ - return -1; + ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, + plen); + return 0; case WNM_BSS_TRANS_MGMT_RESP: - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management " - "Response"); - /* TODO */ - return -1; + ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload, + plen); + return 0; case WNM_SLEEP_MODE_REQ: - ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1, - action->len - 1); + ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen); return 0; } wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR, - action->data[0], MAC2STR(action->sa)); + action, MAC2STR(mgmt->sa)); return -1; } + + +int wnm_send_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, int disassoc_timer) +{ + u8 buf[1000], *pos; + struct ieee80211_mgmt *mgmt; + + os_memset(buf, 0, sizeof(buf)); + mgmt = (struct ieee80211_mgmt *) buf; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt->da, sta->addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; + mgmt->u.action.u.bss_tm_req.dialog_token = 1; + mgmt->u.action.u.bss_tm_req.req_mode = + WNM_BSS_TM_REQ_DISASSOC_IMMINENT; + mgmt->u.action.u.bss_tm_req.disassoc_timer = + host_to_le16(disassoc_timer); + mgmt->u.action.u.bss_tm_req.validity_interval = 0; + + pos = mgmt->u.action.u.bss_tm_req.variable; + + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " + MACSTR, disassoc_timer, MAC2STR(sta->addr)); + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " + "Management Request frame"); + return -1; + } + + return 0; +} + + +int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, const char *url, + int disassoc_timer) +{ + u8 buf[1000], *pos; + struct ieee80211_mgmt *mgmt; + size_t url_len; + + os_memset(buf, 0, sizeof(buf)); + mgmt = (struct ieee80211_mgmt *) buf; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt->da, sta->addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; + mgmt->u.action.u.bss_tm_req.dialog_token = 1; + mgmt->u.action.u.bss_tm_req.req_mode = + WNM_BSS_TM_REQ_DISASSOC_IMMINENT | + WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; + mgmt->u.action.u.bss_tm_req.disassoc_timer = + host_to_le16(disassoc_timer); + mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; + + pos = mgmt->u.action.u.bss_tm_req.variable; + + /* Session Information URL */ + url_len = os_strlen(url); + if (url_len > 255) + return -1; + *pos++ = url_len; + os_memcpy(pos, url, url_len); + pos += url_len; + + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " + "Management Request frame"); + return -1; + } + + /* send disassociation frame after time-out */ + if (disassoc_timer) { + int timeout, beacon_int; + + /* + * Prevent STA from reconnecting using cached PMKSA to force + * full authentication with the authentication server (which may + * decide to reject the connection), + */ + wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); + + beacon_int = hapd->iconf->beacon_int; + if (beacon_int < 1) + beacon_int = 100; /* best guess */ + /* Calculate timeout in ms based on beacon_int in TU */ + timeout = disassoc_timer * beacon_int * 128 / 125; + wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR + " set to %d ms", MAC2STR(sta->addr), timeout); + + sta->timeout_next = STA_DISASSOC_FROM_CLI; + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(timeout / 1000, + timeout % 1000 * 1000, + ap_handle_timer, hapd, sta); + } + + return 0; +} diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h index f05726ee..eeaf5eca 100644 --- a/src/ap/wnm_ap.h +++ b/src/ap/wnm_ap.h @@ -1,6 +1,6 @@ /* * IEEE 802.11v WNM related functions and structures - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,9 +9,14 @@ #ifndef WNM_AP_H #define WNM_AP_H -struct rx_action; +struct sta_info; int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, - struct rx_action *action); + const struct ieee80211_mgmt *mgmt, size_t len); +int wnm_send_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, int disassoc_timer); +int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, const char *url, + int disassoc_timer); #endif /* WNM_AP_H */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 03b15c24..5993edf7 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -437,6 +437,8 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth) wpa_group_sm_step(wpa_auth, group); group->GInit = FALSE; wpa_group_sm_step(wpa_auth, group); + if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return -1; return 0; } @@ -516,6 +518,9 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, { struct wpa_state_machine *sm; + if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return NULL; + sm = os_zalloc(sizeof(struct wpa_state_machine)); if (sm == NULL) return NULL; @@ -2452,7 +2457,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) /* update GTK when exiting WNM-Sleep Mode */ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) { - if (sm->is_wnmsleep) + if (sm == NULL || sm->is_wnmsleep) return; wpa_group_update_sta(sm, NULL); @@ -2461,7 +2466,8 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag) { - sm->is_wnmsleep = !!flag; + if (sm) + sm->is_wnmsleep = !!flag; } @@ -2587,6 +2593,29 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, } +static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx) +{ + if (sm->group == ctx) { + wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR + " for discconnection due to fatal failure", + MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + } + + return 0; +} + + +static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE"); + group->changed = TRUE; + group->wpa_group_state = WPA_GROUP_FATAL_FAILURE; + wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group); +} + + static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { @@ -2595,8 +2624,10 @@ static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, group->changed = TRUE; group->wpa_group_state = WPA_GROUP_SETKEYSDONE; - if (wpa_group_config_group_keys(wpa_auth, group) < 0) + if (wpa_group_config_group_keys(wpa_auth, group) < 0) { + wpa_group_fatal_failure(wpa_auth, group); return -1; + } return 0; } @@ -2607,6 +2638,8 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, { if (group->GInit) { wpa_group_gtk_init(wpa_auth, group); + } else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) { + /* Do not allow group operations */ } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT && group->GTKAuthenticator) { wpa_group_setkeysdone(wpa_auth, group); @@ -3015,6 +3048,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) if (sm->group == group) return 0; + if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return -1; + wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state " "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id); @@ -3059,3 +3095,11 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm) return 0; return wpa_key_mgmt_sae(sm->wpa_key_mgmt); } + + +int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm) +{ + if (sm == NULL) + return 0; + return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE; +} diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 47503d00..da45ae40 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -203,7 +203,7 @@ struct wpa_auth_callbacks { int (*send_ft_action)(void *ctx, const u8 *dst, const u8 *data, size_t data_len); int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie, - size_t tspec_ielen); + size_t tspec_ielen); #endif /* CONFIG_IEEE80211R */ }; @@ -295,5 +295,6 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos); int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos); int wpa_auth_uses_sae(struct wpa_state_machine *sm); +int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm); #endif /* WPA_AUTH_H */ diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 29d9d29e..c22c4cca 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -57,7 +57,7 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth, u8 *tspec_ie, size_t tspec_ielen) { if (wpa_auth->cb.add_tspec == NULL) { - wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized"); + wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized"); return -1; } return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie, @@ -570,8 +570,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, else { /* TSPEC accepted; include updated TSPEC in * response */ - rdie->descr_count = 1; - pos += sizeof(*tspec); + rdie->descr_count = 1; + pos += sizeof(*tspec); } return pos; } @@ -633,8 +633,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, conf = &sm->wpa_auth->conf; - if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK) + if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt)) return pos; end = pos + max_len; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index cbaab9f0..4c1d6257 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -15,7 +15,6 @@ #include "eapol_auth/eapol_auth_sm_i.h" #include "eap_server/eap.h" #include "l2_packet/l2_packet.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ieee802_1x.h" #include "preauth_auth.h" diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 12e59bc4..9736874f 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -139,7 +139,8 @@ struct wpa_group { enum { WPA_GROUP_GTK_INIT = 0, - WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE + WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE, + WPA_GROUP_FATAL_FAILURE } wpa_group_state; u8 GMK[WPA_GMK_LEN]; diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 294a39d6..4c94210e 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -287,6 +287,20 @@ static void wps_reload_config(void *eloop_data, void *user_ctx) } +void hostapd_wps_eap_completed(struct hostapd_data *hapd) +{ + /* + * Reduce race condition of the station trying to reconnect immediately + * after AP reconfiguration through WPS by rescheduling the reload + * timeout to happen after EAP completion rather than the originally + * scheduled 100 ms after new configuration became known. + */ + if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) == + 1) + wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload"); +} + + static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, size_t attr_len) { @@ -1227,6 +1241,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd) { eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL); if (hapd->wps == NULL) return; #ifdef CONFIG_WPS_UPNP diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h index a2c2cf02..a292598b 100644 --- a/src/ap/wps_hostapd.h +++ b/src/ap/wps_hostapd.h @@ -16,6 +16,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, int hostapd_init_wps_complete(struct hostapd_data *hapd); void hostapd_deinit_wps(struct hostapd_data *hapd); void hostapd_update_wps(struct hostapd_data *hapd); +void hostapd_wps_eap_completed(struct hostapd_data *hapd); int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, const char *uuid, const char *pin, int timeout); int hostapd_wps_button_pushed(struct hostapd_data *hapd, @@ -61,6 +62,10 @@ static inline void hostapd_update_wps(struct hostapd_data *hapd) { } +static inline void hostapd_wps_eap_completed(struct hostapd_data *hapd) +{ +} + static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, char *buf, size_t buflen) diff --git a/src/common/defs.h b/src/common/defs.h index 0c90c249..4811e8e9 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -23,11 +23,15 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_CIPHER_WEP104 BIT(2) #define WPA_CIPHER_TKIP BIT(3) #define WPA_CIPHER_CCMP BIT(4) -#ifdef CONFIG_IEEE80211W #define WPA_CIPHER_AES_128_CMAC BIT(5) -#endif /* CONFIG_IEEE80211W */ #define WPA_CIPHER_GCMP BIT(6) #define WPA_CIPHER_SMS4 BIT(7) +#define WPA_CIPHER_GCMP_256 BIT(8) +#define WPA_CIPHER_CCMP_256 BIT(9) +#define WPA_CIPHER_BIP_GMAC_128 BIT(11) +#define WPA_CIPHER_BIP_GMAC_256 BIT(12) +#define WPA_CIPHER_BIP_CMAC_256 BIT(13) +#define WPA_CIPHER_GTK_NOT_USED BIT(14) #define WPA_KEY_MGMT_IEEE8021X BIT(0) #define WPA_KEY_MGMT_PSK BIT(1) @@ -58,7 +62,8 @@ static inline int wpa_key_mgmt_wpa_psk(int akm) return !!(akm & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256 | - WPA_KEY_MGMT_SAE)); + WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_FT_SAE)); } static inline int wpa_key_mgmt_ft(int akm) @@ -83,7 +88,8 @@ static inline int wpa_key_mgmt_sha256(int akm) static inline int wpa_key_mgmt_wpa(int akm) { return wpa_key_mgmt_wpa_ieee8021x(akm) || - wpa_key_mgmt_wpa_psk(akm); + wpa_key_mgmt_wpa_psk(akm) || + wpa_key_mgmt_sae(akm); } static inline int wpa_key_mgmt_wpa_any(int akm) @@ -117,41 +123,12 @@ enum wpa_alg { WPA_ALG_PMK, WPA_ALG_GCMP, WPA_ALG_SMS4, - WPA_ALG_KRK -}; - -/** - * enum wpa_cipher - Cipher suites - */ -enum wpa_cipher { - CIPHER_NONE, - CIPHER_WEP40, - CIPHER_TKIP, - CIPHER_CCMP, - CIPHER_WEP104, - CIPHER_GCMP, - CIPHER_SMS4 -}; - -/** - * enum wpa_key_mgmt - Key management suites - */ -enum wpa_key_mgmt { - KEY_MGMT_802_1X, - KEY_MGMT_PSK, - KEY_MGMT_NONE, - KEY_MGMT_802_1X_NO_WPA, - KEY_MGMT_WPA_NONE, - KEY_MGMT_FT_802_1X, - KEY_MGMT_FT_PSK, - KEY_MGMT_802_1X_SHA256, - KEY_MGMT_PSK_SHA256, - KEY_MGMT_WPS, - KEY_MGMT_SAE, - KEY_MGMT_FT_SAE, - KEY_MGMT_WAPI_PSK, - KEY_MGMT_WAPI_CERT, - KEY_MGMT_CCKM + WPA_ALG_KRK, + WPA_ALG_GCMP_256, + WPA_ALG_CCMP_256, + WPA_ALG_BIP_GMAC_128, + WPA_ALG_BIP_GMAC_256, + WPA_ALG_BIP_CMAC_256 }; /** diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 304dfc69..809089fa 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -189,25 +189,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->supp_rates = pos; elems->supp_rates_len = elen; break; - case WLAN_EID_FH_PARAMS: - elems->fh_params = pos; - elems->fh_params_len = elen; - break; case WLAN_EID_DS_PARAMS: elems->ds_params = pos; elems->ds_params_len = elen; break; case WLAN_EID_CF_PARAMS: - elems->cf_params = pos; - elems->cf_params_len = elen; - break; case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; - break; - case WLAN_EID_IBSS_PARAMS: - elems->ibss_params = pos; - elems->ibss_params_len = elen; break; case WLAN_EID_CHALLENGE: elems->challenge = pos; @@ -232,8 +219,6 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->rsn_ie_len = elen; break; case WLAN_EID_PWR_CAPABILITY: - elems->power_cap = pos; - elems->power_cap_len = elen; break; case WLAN_EID_SUPPORTED_CHANNELS: elems->supp_channels = pos; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index c4618b2d..b84dd9e7 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -13,11 +13,7 @@ struct ieee802_11_elems { const u8 *ssid; const u8 *supp_rates; - const u8 *fh_params; const u8 *ds_params; - const u8 *cf_params; - const u8 *tim; - const u8 *ibss_params; const u8 *challenge; const u8 *erp_info; const u8 *ext_supp_rates; @@ -26,7 +22,6 @@ struct ieee802_11_elems { const u8 *wmm; /* WMM Information or Parameter Element */ const u8 *wmm_tspec; const u8 *wps_ie; - const u8 *power_cap; const u8 *supp_channels; const u8 *mdie; const u8 *ftie; @@ -48,11 +43,7 @@ struct ieee802_11_elems { u8 ssid_len; u8 supp_rates_len; - u8 fh_params_len; u8 ds_params_len; - u8 cf_params_len; - u8 tim_len; - u8 ibss_params_len; u8 challenge_len; u8 erp_info_len; u8 ext_supp_rates_len; @@ -61,7 +52,6 @@ struct ieee802_11_elems { u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ u8 wmm_tspec_len; u8 wps_ie_len; - u8 power_cap_len; u8 supp_channels_len; u8 mdie_len; u8 ftie_len; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 9b2d54f4..7d786483 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -161,6 +161,7 @@ #define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76 #define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77 #define WLAN_STATUS_TRANSMISSION_FAILURE 79 +#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 @@ -1024,6 +1025,11 @@ enum wifi_display_subelem { #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 #define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07 #define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 +#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09 +#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A +#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B +#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C +#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D #define WLAN_CIPHER_SUITE_SMS4 0x00147201 diff --git a/src/common/sae.c b/src/common/sae.c index 4e9e4610..08bf054c 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -701,6 +701,11 @@ static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; } + if (sae->tmp == NULL) { + wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + if (sae->tmp->dh && !allowed_groups) { wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without " "explicit configuration enabling it", group); @@ -797,7 +802,7 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, /* element x and y coordinates < p */ if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 || - os_memcmp(pos + sae->tmp->prime_len + sae->tmp->prime_len, prime, + os_memcmp(pos + sae->tmp->prime_len, prime, sae->tmp->prime_len) >= 0) { wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer " "element"); diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index c3afbfd3..37b265d0 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -353,6 +353,16 @@ static int rsn_selector_to_bitfield(const u8 *s) #endif /* CONFIG_IEEE80211W */ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) return WPA_CIPHER_GCMP; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256) + return WPA_CIPHER_GCMP_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128) + return WPA_CIPHER_BIP_GMAC_128; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256) + return WPA_CIPHER_BIP_GMAC_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) + return WPA_CIPHER_BIP_CMAC_256; return 0; } @@ -912,6 +922,12 @@ const char * wpa_cipher_txt(int cipher) return "CCMP+TKIP"; case WPA_CIPHER_GCMP: return "GCMP"; + case WPA_CIPHER_GCMP_256: + return "GCMP-256"; + case WPA_CIPHER_CCMP_256: + return "CCMP-256"; + case WPA_CIPHER_GTK_NOT_USED: + return "GTK_NOT_USED"; default: return "UNKNOWN"; } @@ -1078,6 +1094,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) int wpa_cipher_key_len(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + case WPA_CIPHER_GCMP_256: + return 32; case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: return 16; @@ -1096,6 +1115,8 @@ int wpa_cipher_key_len(int cipher) int wpa_cipher_rsc_len(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + case WPA_CIPHER_GCMP_256: case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: case WPA_CIPHER_TKIP: @@ -1112,6 +1133,10 @@ int wpa_cipher_rsc_len(int cipher) int wpa_cipher_to_alg(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + return WPA_ALG_CCMP_256; + case WPA_CIPHER_GCMP_256: + return WPA_ALG_GCMP_256; case WPA_CIPHER_CCMP: return WPA_ALG_CCMP; case WPA_CIPHER_GCMP: @@ -1126,29 +1151,11 @@ int wpa_cipher_to_alg(int cipher) } -enum wpa_cipher wpa_cipher_to_suite_driver(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_NONE: - return CIPHER_NONE; - case WPA_CIPHER_WEP40: - return CIPHER_WEP40; - case WPA_CIPHER_WEP104: - return CIPHER_WEP104; - case WPA_CIPHER_CCMP: - return CIPHER_CCMP; - case WPA_CIPHER_GCMP: - return CIPHER_GCMP; - case WPA_CIPHER_TKIP: - default: - return CIPHER_TKIP; - } -} - - int wpa_cipher_valid_pairwise(int cipher) { - return cipher == WPA_CIPHER_CCMP || + return cipher == WPA_CIPHER_CCMP_256 || + cipher == WPA_CIPHER_GCMP_256 || + cipher == WPA_CIPHER_CCMP || cipher == WPA_CIPHER_GCMP || cipher == WPA_CIPHER_TKIP; } @@ -1156,6 +1163,10 @@ int wpa_cipher_valid_pairwise(int cipher) u32 wpa_cipher_to_suite(int proto, int cipher) { + if (cipher & WPA_CIPHER_CCMP_256) + return RSN_CIPHER_SUITE_CCMP_256; + if (cipher & WPA_CIPHER_GCMP_256) + return RSN_CIPHER_SUITE_GCMP_256; if (cipher & WPA_CIPHER_CCMP) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); @@ -1173,6 +1184,8 @@ u32 wpa_cipher_to_suite(int proto, int cipher) if (cipher & WPA_CIPHER_NONE) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); + if (cipher & WPA_CIPHER_GTK_NOT_USED) + return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; return 0; } @@ -1181,6 +1194,16 @@ int rsn_cipher_put_suites(u8 *pos, int ciphers) { int num_suites = 0; + if (ciphers & WPA_CIPHER_CCMP_256) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_GCMP_256) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); + pos += RSN_SELECTOR_LEN; + num_suites++; + } if (ciphers & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; @@ -1232,6 +1255,10 @@ int wpa_cipher_put_suites(u8 *pos, int ciphers) int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) { + if (ciphers & WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (ciphers & WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; if (ciphers & WPA_CIPHER_CCMP) return WPA_CIPHER_CCMP; if (ciphers & WPA_CIPHER_GCMP) @@ -1246,10 +1273,16 @@ int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) int wpa_pick_group_cipher(int ciphers) { + if (ciphers & WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (ciphers & WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; if (ciphers & WPA_CIPHER_CCMP) return WPA_CIPHER_CCMP; if (ciphers & WPA_CIPHER_GCMP) return WPA_CIPHER_GCMP; + if (ciphers & WPA_CIPHER_GTK_NOT_USED) + return WPA_CIPHER_GTK_NOT_USED; if (ciphers & WPA_CIPHER_TKIP) return WPA_CIPHER_TKIP; if (ciphers & WPA_CIPHER_WEP104) @@ -1280,7 +1313,11 @@ int wpa_parse_cipher(const char *value) end++; last = *end == '\0'; *end = '\0'; - if (os_strcmp(start, "CCMP") == 0) + if (os_strcmp(start, "CCMP-256") == 0) + val |= WPA_CIPHER_CCMP_256; + else if (os_strcmp(start, "GCMP-256") == 0) + val |= WPA_CIPHER_GCMP_256; + else if (os_strcmp(start, "CCMP") == 0) val |= WPA_CIPHER_CCMP; else if (os_strcmp(start, "GCMP") == 0) val |= WPA_CIPHER_GCMP; @@ -1292,6 +1329,8 @@ int wpa_parse_cipher(const char *value) val |= WPA_CIPHER_WEP40; else if (os_strcmp(start, "NONE") == 0) val |= WPA_CIPHER_NONE; + else if (os_strcmp(start, "GTK_NOT_USED") == 0) + val |= WPA_CIPHER_GTK_NOT_USED; else { os_free(buf); return -1; @@ -1312,6 +1351,20 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) char *pos = start; int ret; + if (ciphers & WPA_CIPHER_CCMP_256) { + ret = os_snprintf(pos, end - pos, "%sCCMP-256", + pos == start ? "" : delim); + if (ret < 0 || ret >= end - pos) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_GCMP_256) { + ret = os_snprintf(pos, end - pos, "%sGCMP-256", + pos == start ? "" : delim); + if (ret < 0 || ret >= end - pos) + return -1; + pos += ret; + } if (ciphers & WPA_CIPHER_CCMP) { ret = os_snprintf(pos, end - pos, "%sCCMP", pos == start ? "" : delim); @@ -1373,5 +1426,11 @@ int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) return WPA_CIPHER_TKIP; if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) return WPA_CIPHER_GCMP; + if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | + WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; + if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | + WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; return WPA_CIPHER_CCMP; } diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 2d636623..62505f1b 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -21,10 +21,12 @@ #define WPA_GTK_MAX_LEN 32 #define WPA_ALLOWED_PAIRWISE_CIPHERS \ -(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE) +(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \ +WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256) #define WPA_ALLOWED_GROUP_CIPHERS \ (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \ -WPA_CIPHER_WEP40) +WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \ +WPA_CIPHER_GTK_NOT_USED) #define WPA_SELECTOR_LEN 4 #define WPA_VERSION 1 @@ -60,6 +62,10 @@ WPA_CIPHER_WEP40) #define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8) #define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9) +#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11) +#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) +#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \ +RSN_SELECTOR(0x00, 0x0f, 0xac, 13) #define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00) #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) @@ -75,6 +81,11 @@ WPA_CIPHER_WEP40) #endif /* CONFIG_IEEE80211W */ #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) +#define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9) +#define RSN_CIPHER_SUITE_CCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 10) +#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11) +#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) +#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13) /* EAPOL-Key Key Data Encapsulation * GroupKey and PeerKey require encryption, otherwise, encryption is optional. @@ -392,7 +403,6 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse); int wpa_cipher_key_len(int cipher); int wpa_cipher_rsc_len(int cipher); int wpa_cipher_to_alg(int cipher); -enum wpa_cipher wpa_cipher_to_suite_driver(int cipher); int wpa_cipher_valid_pairwise(int cipher); u32 wpa_cipher_to_suite(int proto, int cipher); int rsn_cipher_put_suites(u8 *pos, int ciphers); diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 83788d7d..f4af94aa 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -391,7 +391,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; - struct os_time started_at; + struct os_reltime started_at; int res; fd_set rfds; const char *_cmd; @@ -430,12 +430,12 @@ retry_send: * longer before giving up. */ if (started_at.sec == 0) - os_get_time(&started_at); + os_get_reltime(&started_at); else { - struct os_time n; - os_get_time(&n); + struct os_reltime n; + os_get_reltime(&n); /* Try for a few seconds. */ - if (n.sec > started_at.sec + 5) + if (os_reltime_expired(&n, &started_at, 5)) goto send_err; } os_sleep(1, 0); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 88bfb4d9..9bd59a9c 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -54,6 +54,8 @@ extern "C" { #define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED " /** Temporarily disabled network block re-enabled */ #define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED " +/** New scan started */ +#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED " /** New scan results available */ #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " /** wpa_supplicant state change */ @@ -145,6 +147,7 @@ extern "C" { #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED " #define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id=" +#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE " /* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */ #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " @@ -154,6 +157,13 @@ extern "C" { #define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED " #define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO " +/* parameters: <addr> <dialog_token> <freq> */ +#define GAS_QUERY_START "GAS-QUERY-START " +/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */ +#define GAS_QUERY_DONE "GAS-QUERY-DONE " + +#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START " +#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT " /* hostapd control interface - fixed message prefixes */ #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 5215c00f..1da2b9f4 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -26,6 +26,8 @@ #include "common.h" #include "wpabuf.h" #include "dh_group5.h" +#include "sha1.h" +#include "sha256.h" #include "crypto.h" #if OPENSSL_VERSION_NUMBER < 0x00907000 diff --git a/src/crypto/tls.h b/src/crypto/tls.h index feba13ff..287fd333 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -41,7 +41,8 @@ enum tls_fail_reason { TLS_FAIL_ALTSUBJECT_MISMATCH = 6, TLS_FAIL_BAD_CERTIFICATE = 7, TLS_FAIL_SERVER_CHAIN_PROBE = 8, - TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9 + TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9, + TLS_FAIL_SERVER_USED_CLIENT_CERT = 10 }; union tls_event_data { diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index a5d72f40..cb23eb9c 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -125,8 +125,6 @@ static void tls_log_func(int level, const char *msg) } -extern int wpa_debug_show_keys; - void * tls_init(const struct tls_config *conf) { struct tls_global *global; diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index eeaf859f..4cfa5f43 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -105,6 +105,7 @@ struct tls_connection { unsigned int ca_cert_verify:1; unsigned int cert_probe:1; unsigned int server_cert_only:1; + unsigned int server:1; u8 srv_cert_hash[32]; @@ -112,6 +113,7 @@ struct tls_connection { X509 *peer_cert; X509 *peer_issuer; + X509 *peer_issuer_issuer; }; @@ -1385,6 +1387,8 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) conn->peer_cert = err_cert; else if (depth == 1) conn->peer_issuer = err_cert; + else if (depth == 2) + conn->peer_issuer_issuer = err_cert; context = conn->context; match = conn->subject_match; @@ -1478,6 +1482,16 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) TLS_FAIL_SERVER_CHAIN_PROBE); } + if (!conn->server && err_cert && preverify_ok && depth == 0 && + (err_cert->ex_flags & EXFLAG_XKUSAGE) && + (err_cert->ex_xkusage & XKU_SSL_CLIENT)) { + wpa_printf(MSG_WARNING, "TLS: Server used client certificate"); + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Server used client certificate", + TLS_FAIL_SERVER_USED_CLIENT_CERT); + preverify_ok = 0; + } + if (preverify_ok && context->event_cb != NULL) context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_SUCCESS, NULL); @@ -2529,6 +2543,8 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, int res; struct wpabuf *out_data; + conn->server = !!server; + /* * Give TLS handshake data from the server (if available) to OpenSSL * for processing. @@ -2890,7 +2906,6 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) { #ifndef CONFIG_NO_STDOUT_DEBUG - extern int wpa_debug_level; BIO *out; size_t rlen; char *txt; @@ -2931,6 +2946,8 @@ static int ocsp_resp_cb(SSL *s, void *arg) OCSP_BASICRESP *basic; OCSP_CERTID *id; ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; + X509_STORE *store; + STACK_OF(X509) *certs = NULL; len = SSL_get_tlsext_status_ocsp_resp(s, &p); if (!p) { @@ -2961,8 +2978,41 @@ static int ocsp_resp_cb(SSL *s, void *arg) return 0; } - status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx), - 0); + store = SSL_CTX_get_cert_store(s->ctx); + if (conn->peer_issuer) { + wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); + X509_print_fp(stdout, conn->peer_issuer); + + if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { + tls_show_errors(MSG_INFO, __func__, + "OpenSSL: Could not add issuer to certificate store\n"); + } + certs = sk_X509_new_null(); + if (certs) { + X509 *cert; + cert = X509_dup(conn->peer_issuer); + if (cert && !sk_X509_push(certs, cert)) { + tls_show_errors( + MSG_INFO, __func__, + "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + X509_free(cert); + sk_X509_free(certs); + certs = NULL; + } + if (conn->peer_issuer_issuer) { + cert = X509_dup(conn->peer_issuer_issuer); + if (cert && !sk_X509_push(certs, cert)) { + tls_show_errors( + MSG_INFO, __func__, + "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + X509_free(cert); + } + } + } + } + + status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); + sk_X509_pop_free(certs, X509_free); if (status <= 0) { tls_show_errors(MSG_INFO, __func__, "OpenSSL: OCSP response failed verification"); diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h index 5906527a..31d94408 100644 --- a/src/drivers/android_drv.h +++ b/src/drivers/android_drv.h @@ -1,12 +1,8 @@ /* * Android driver interface * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef ANDROID_DRV_H diff --git a/src/drivers/driver.h b/src/drivers/driver.h index a3602ed7..db34ed13 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1,6 +1,6 @@ /* * Driver interface definition - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -233,7 +233,7 @@ struct wpa_scan_res { struct wpa_scan_results { struct wpa_scan_res **res; size_t num; - struct os_time fetch_time; + struct os_reltime fetch_time; }; /** @@ -340,6 +340,21 @@ struct wpa_driver_scan_params { * and not to transmit the frames at any of those rates. */ u8 p2p_probe; + + /** + * only_new_results - Request driver to report only new results + * + * This is used to request the driver to report only BSSes that have + * been detected after this scan request has been started, i.e., to + * flush old cached BSS entries. + */ + int only_new_results; + + /* + * NOTE: Whenever adding new parameters here, please make sure + * wpa_scan_clone_params() and wpa_scan_free_params() get updated with + * matching changes. + */ }; /** @@ -442,25 +457,25 @@ struct wpa_driver_associate_params { unsigned int wpa_proto; /** - * pairwise_suite - Selected pairwise cipher suite + * pairwise_suite - Selected pairwise cipher suite (WPA_CIPHER_*) * * This is usually ignored if @wpa_ie is used. */ - enum wpa_cipher pairwise_suite; + unsigned int pairwise_suite; /** - * group_suite - Selected group cipher suite + * group_suite - Selected group cipher suite (WPA_CIPHER_*) * * This is usually ignored if @wpa_ie is used. */ - enum wpa_cipher group_suite; + unsigned int group_suite; /** - * key_mgmt_suite - Selected key management suite + * key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*) * * This is usually ignored if @wpa_ie is used. */ - enum wpa_key_mgmt key_mgmt_suite; + unsigned int key_mgmt_suite; /** * auth_alg - Allowed authentication algorithms @@ -833,6 +848,12 @@ struct wpa_driver_capa { #define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008 #define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010 #define WPA_DRIVER_CAPA_ENC_GCMP 0x00000020 +#define WPA_DRIVER_CAPA_ENC_GCMP_256 0x00000040 +#define WPA_DRIVER_CAPA_ENC_CCMP_256 0x00000080 +#define WPA_DRIVER_CAPA_ENC_BIP 0x00000100 +#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_128 0x00000200 +#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256 0x00000400 +#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256 0x00000800 unsigned int enc; #define WPA_DRIVER_AUTH_OPEN 0x00000001 @@ -856,8 +877,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_AP 0x00000040 /* Driver needs static WEP key setup after association has been completed */ #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080 -/* Driver takes care of P2P management operations */ -#define WPA_DRIVER_FLAGS_P2P_MGMT 0x00000100 +/* unused: 0x00000100 */ /* Driver supports concurrent P2P operations */ #define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200 /* @@ -910,6 +930,10 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_RADAR 0x10000000 /* Driver supports a dedicated interface for P2P Device */ #define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE 0x20000000 +/* Driver supports QoS Mapping */ +#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000 +/* Driver supports CSA in AP mode */ +#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000 unsigned int flags; int max_scan_ssids; @@ -1099,17 +1123,6 @@ struct wpa_bss_params { #define WPA_STA_MFP BIT(3) #define WPA_STA_TDLS_PEER BIT(4) -/** - * struct p2p_params - P2P parameters for driver-based P2P management - */ -struct p2p_params { - const char *dev_name; - u8 pri_dev_type[8]; -#define DRV_MAX_SEC_DEV_TYPES 5 - u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8]; - size_t num_sec_dev_types; -}; - enum tdls_oper { TDLS_DISCOVERY_REQ, TDLS_SETUP, @@ -1265,7 +1278,9 @@ struct wpa_driver_ops { * @priv: private driver interface data * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK, - * %WPA_ALG_GCMP); + * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256, + * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, + * %WPA_ALG_BIP_CMAC_256); * %WPA_ALG_NONE clears the key. * @addr: Address of the peer STA (BSSID of the current AP when setting * pairwise key in station mode), ff:ff:ff:ff:ff:ff for @@ -2206,7 +2221,7 @@ struct wpa_driver_ops { * * This command is used to request the driver to remain awake on the * specified channel for the specified duration and report received - * Action frames with EVENT_RX_ACTION events. Optionally, received + * Action frames with EVENT_RX_MGMT events. Optionally, received * Probe Request frames may also be requested to be reported by calling * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ. * @@ -2388,222 +2403,6 @@ struct wpa_driver_ops { const char * (*get_radio_name)(void *priv); /** - * p2p_find - Start P2P Device Discovery - * @priv: Private driver interface data - * @timeout: Timeout for find operation in seconds or 0 for no timeout - * @type: Device Discovery type (enum p2p_discovery_type) - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_find)(void *priv, unsigned int timeout, int type); - - /** - * p2p_stop_find - Stop P2P Device Discovery - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_stop_find)(void *priv); - - /** - * p2p_listen - Start P2P Listen state for specified duration - * @priv: Private driver interface data - * @timeout: Listen state duration in milliseconds - * Returns: 0 on success, -1 on failure - * - * This function can be used to request the P2P module to keep the - * device discoverable on the listen channel for an extended set of - * time. At least in its current form, this is mainly used for testing - * purposes and may not be of much use for normal P2P operations. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_listen)(void *priv, unsigned int timeout); - - /** - * p2p_connect - Start P2P group formation (GO negotiation) - * @priv: Private driver interface data - * @peer_addr: MAC address of the peer P2P client - * @wps_method: enum p2p_wps_method value indicating config method - * @go_intent: Local GO intent value (1..15) - * @own_interface_addr: Intended interface address to use with the - * group - * @force_freq: The only allowed channel frequency in MHz or 0 - * @persistent_group: Whether to create persistent group - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method, - int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group); - - /** - * wps_success_cb - Report successfully completed WPS provisioning - * @priv: Private driver interface data - * @peer_addr: Peer address - * Returns: 0 on success, -1 on failure - * - * This function is used to report successfully completed WPS - * provisioning during group formation in both GO/Registrar and - * client/Enrollee roles. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*wps_success_cb)(void *priv, const u8 *peer_addr); - - /** - * p2p_group_formation_failed - Report failed WPS provisioning - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function is used to report failed group formation. This can - * happen either due to failed WPS provisioning or due to 15 second - * timeout during the provisioning phase. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_group_formation_failed)(void *priv); - - /** - * p2p_set_params - Set P2P parameters - * @priv: Private driver interface data - * @params: P2P parameters - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_set_params)(void *priv, const struct p2p_params *params); - - /** - * p2p_prov_disc_req - Send Provision Discovery Request - * @priv: Private driver interface data - * @peer_addr: MAC address of the peer P2P client - * @config_methods: WPS Config Methods value (only one bit set) - * Returns: 0 on success, -1 on failure - * - * This function can be used to request a discovered P2P peer to - * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared - * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The - * Provision Discovery Request frame is transmitted once immediately - * and if no response is received, the frame will be sent again - * whenever the target device is discovered during device dsicovery - * (start with a p2p_find() call). Response from the peer is indicated - * with the EVENT_P2P_PROV_DISC_RESPONSE event. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr, - u16 config_methods, int join); - - /** - * p2p_sd_request - Schedule a service discovery query - * @priv: Private driver interface data - * @dst: Destination peer or %NULL to apply for all peers - * @tlvs: P2P Service Query TLV(s) - * Returns: Reference to the query or 0 on failure - * - * Response to the query is indicated with the - * EVENT_P2P_SD_RESPONSE driver event. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - u64 (*p2p_sd_request)(void *priv, const u8 *dst, - const struct wpabuf *tlvs); - - /** - * p2p_sd_cancel_request - Cancel a pending service discovery query - * @priv: Private driver interface data - * @req: Query reference from p2p_sd_request() - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_sd_cancel_request)(void *priv, u64 req); - - /** - * p2p_sd_response - Send response to a service discovery query - * @priv: Private driver interface data - * @freq: Frequency from EVENT_P2P_SD_REQUEST event - * @dst: Destination address from EVENT_P2P_SD_REQUEST event - * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event - * @resp_tlvs: P2P Service Response TLV(s) - * Returns: 0 on success, -1 on failure - * - * This function is called as a response to the request indicated with - * the EVENT_P2P_SD_REQUEST driver event. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_sd_response)(void *priv, int freq, const u8 *dst, - u8 dialog_token, - const struct wpabuf *resp_tlvs); - - /** - * p2p_service_update - Indicate a change in local services - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function needs to be called whenever there is a change in - * availability of the local services. This will increment the - * Service Update Indicator value which will be used in SD Request and - * Response frames. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_service_update)(void *priv); - - /** - * p2p_reject - Reject peer device (explicitly block connections) - * @priv: Private driver interface data - * @addr: MAC address of the peer - * Returns: 0 on success, -1 on failure - */ - int (*p2p_reject)(void *priv, const u8 *addr); - - /** - * p2p_invite - Invite a P2P Device into a group - * @priv: Private driver interface data - * @peer: Device Address of the peer P2P Device - * @role: Local role in the group - * @bssid: Group BSSID or %NULL if not known - * @ssid: Group SSID - * @ssid_len: Length of ssid in octets - * @go_dev_addr: Forced GO Device Address or %NULL if none - * @persistent_group: Whether this is to reinvoke a persistent group - * Returns: 0 on success, -1 on failure - */ - int (*p2p_invite)(void *priv, const u8 *peer, int role, - const u8 *bssid, const u8 *ssid, size_t ssid_len, - const u8 *go_dev_addr, int persistent_group); - - /** * send_tdls_mgmt - for sending TDLS management packets * @priv: private driver interface data * @dst: Destination (peer) MAC address @@ -3092,15 +2891,6 @@ enum wpa_event_type { EVENT_RX_MGMT, /** - * EVENT_RX_ACTION - Action frame received - * - * This event is used to indicate when an Action frame has been - * received. Information about the received frame is included in - * union wpa_event_data::rx_action. - */ - EVENT_RX_ACTION, - - /** * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started * * This event is used to indicate when the driver has started the @@ -3247,38 +3037,6 @@ enum wpa_event_type { EVENT_STATION_LOW_ACK, /** - * EVENT_P2P_DEV_FOUND - Report a discovered P2P device - * - * This event is used only if the driver implements P2P management - * internally. Event data is stored in - * union wpa_event_data::p2p_dev_found. - */ - EVENT_P2P_DEV_FOUND, - - /** - * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request - * - * This event is used only if the driver implements P2P management - * internally. Event data is stored in - * union wpa_event_data::p2p_go_neg_req_rx. - */ - EVENT_P2P_GO_NEG_REQ_RX, - - /** - * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation - * - * This event is used only if the driver implements P2P management - * internally. Event data is stored in - * union wpa_event_data::p2p_go_neg_completed. - */ - EVENT_P2P_GO_NEG_COMPLETED, - - EVENT_P2P_PROV_DISC_REQUEST, - EVENT_P2P_PROV_DISC_RESPONSE, - EVENT_P2P_SD_REQUEST, - EVENT_P2P_SD_RESPONSE, - - /** * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore */ EVENT_IBSS_PEER_LOST, @@ -3365,17 +3123,27 @@ enum wpa_event_type { */ EVENT_DFS_NOP_FINISHED, - /* - * EVENT_SURVEY - Received survey data - * - * This event gets triggered when a driver query is issued for survey - * data and the requested data becomes available. The returned data is - * stored in struct survey_results. The results provide at most one - * survey entry for each frequency and at minimum will provide one survey - * entry for one frequency. The survey data can be os_malloc()'d and - * then os_free()'d, so the event callback must only copy data. - */ - EVENT_SURVEY + /** + * EVENT_SURVEY - Received survey data + * + * This event gets triggered when a driver query is issued for survey + * data and the requested data becomes available. The returned data is + * stored in struct survey_results. The results provide at most one + * survey entry for each frequency and at minimum will provide one + * survey entry for one frequency. The survey data can be os_malloc()'d + * and then os_free()'d, so the event callback must only copy data. + */ + EVENT_SURVEY, + + /** + * EVENT_SCAN_STARTED - Scan started + * + * This indicates that driver has started a scan operation either based + * on a request from wpa_supplicant/hostapd or from another application. + * EVENT_SCAN_RESULTS is used to indicate when the scan has been + * completed (either successfully or by getting cancelled). + */ + EVENT_SCAN_STARTED }; @@ -3743,48 +3511,17 @@ union wpa_event_data { const u8 *frame; size_t frame_len; u32 datarate; - int ssi_signal; /* dBm */ - } rx_mgmt; - /** - * struct rx_action - Data for EVENT_RX_ACTION events - */ - struct rx_action { /** - * da - Destination address of the received Action frame - */ - const u8 *da; - - /** - * sa - Source address of the received Action frame - */ - const u8 *sa; - - /** - * bssid - Address 3 of the received Action frame - */ - const u8 *bssid; - - /** - * category - Action frame category - */ - u8 category; - - /** - * data - Action frame body after category field - */ - const u8 *data; - - /** - * len - Length of data in octets + * freq - Frequency (in MHz) on which the frame was received */ - size_t len; + int freq; /** - * freq - Frequency (in MHz) on which the frame was received + * ssi_signal - Signal strength in dBm (or 0 if not available) */ - int freq; - } rx_action; + int ssi_signal; + } rx_mgmt; /** * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events @@ -3924,66 +3661,6 @@ union wpa_event_data { } low_ack; /** - * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND - */ - struct p2p_dev_found { - const u8 *addr; - const u8 *dev_addr; - const u8 *pri_dev_type; - const char *dev_name; - u16 config_methods; - u8 dev_capab; - u8 group_capab; - } p2p_dev_found; - - /** - * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX - */ - struct p2p_go_neg_req_rx { - const u8 *src; - u16 dev_passwd_id; - } p2p_go_neg_req_rx; - - /** - * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED - */ - struct p2p_go_neg_completed { - struct p2p_go_neg_results *res; - } p2p_go_neg_completed; - - struct p2p_prov_disc_req { - const u8 *peer; - u16 config_methods; - const u8 *dev_addr; - const u8 *pri_dev_type; - const char *dev_name; - u16 supp_config_methods; - u8 dev_capab; - u8 group_capab; - } p2p_prov_disc_req; - - struct p2p_prov_disc_resp { - const u8 *peer; - u16 config_methods; - } p2p_prov_disc_resp; - - struct p2p_sd_req { - int freq; - const u8 *sa; - u8 dialog_token; - u16 update_indic; - const u8 *tlvs; - size_t tlvs_len; - } p2p_sd_req; - - struct p2p_sd_resp { - const u8 *sa; - u16 update_indic; - const u8 *tlvs; - size_t tlvs_len; - } p2p_sd_resp; - - /** * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST */ struct ibss_peer_lost { @@ -4143,4 +3820,7 @@ void wpa_scan_results_free(struct wpa_scan_results *res); /* Convert wpa_event_type to a string for logging */ const char * event_to_string(enum wpa_event_type event); +/* NULL terminated array of linked in driver wrappers */ +extern struct wpa_driver_ops *wpa_drivers[]; + #endif /* DRIVER_H */ diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 7d301f79..23a4e2b9 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -806,16 +806,10 @@ static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf, drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); break; case WLAN_FC_STYPE_ACTION: - if (&mgmt->u.action.category > buf + len) - break; os_memset(&event, 0, sizeof(event)); - event.rx_action.da = mgmt->da; - event.rx_action.sa = mgmt->sa; - event.rx_action.bssid = mgmt->bssid; - event.rx_action.category = mgmt->u.action.category; - event.rx_action.data = &mgmt->u.action.category; - event.rx_action.len = buf + len - event.rx_action.data; - wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &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)) @@ -954,16 +948,10 @@ static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf, switch (stype) { case WLAN_FC_STYPE_ACTION: - if (&mgmt->u.action.category > buf + len) - break; os_memset(&event, 0, sizeof(event)); - event.rx_action.da = mgmt->da; - event.rx_action.sa = mgmt->sa; - event.rx_action.bssid = mgmt->bssid; - event.rx_action.category = mgmt->u.action.category; - event.rx_action.data = &mgmt->u.action.category; - event.rx_action.len = buf + len - event.rx_action.data; - wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); break; default: break; diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index fb6402da..7f5e2314 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -1110,9 +1110,9 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) return -1; - privacy = !(params->pairwise_suite == CIPHER_NONE && - params->group_suite == CIPHER_NONE && - params->key_mgmt_suite == KEY_MGMT_NONE && + privacy = !(params->pairwise_suite == WPA_CIPHER_NONE && + params->group_suite == WPA_CIPHER_NONE && + params->key_mgmt_suite == WPA_KEY_MGMT_NONE && params->wpa_ie_len == 0); wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 8d1d22eb..64bdddb2 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -49,7 +49,6 @@ const char * event_to_string(enum wpa_event_type event) E2S(TX_STATUS); E2S(RX_FROM_UNKNOWN); E2S(RX_MGMT); - E2S(RX_ACTION); E2S(REMAIN_ON_CHANNEL); E2S(CANCEL_REMAIN_ON_CHANNEL); E2S(MLME_RX); @@ -65,13 +64,6 @@ const char * event_to_string(enum wpa_event_type event) E2S(UNPROT_DEAUTH); E2S(UNPROT_DISASSOC); E2S(STATION_LOW_ACK); - E2S(P2P_DEV_FOUND); - E2S(P2P_GO_NEG_REQ_RX); - E2S(P2P_GO_NEG_COMPLETED); - E2S(P2P_PROV_DISC_REQUEST); - E2S(P2P_PROV_DISC_RESPONSE); - E2S(P2P_SD_REQUEST); - E2S(P2P_SD_RESPONSE); E2S(IBSS_PEER_LOST); E2S(DRIVER_GTK_REKEY); E2S(SCHED_SCAN_STOPPED); @@ -85,6 +77,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(DFS_CAC_ABORTED); E2S(DFS_NOP_FINISHED); E2S(SURVEY); + E2S(SCAN_STARTED); } return "UNKNOWN"; diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c index 09308347..1635c1fb 100644 --- a/src/drivers/driver_madwifi.c +++ b/src/drivers/driver_madwifi.c @@ -1,5 +1,5 @@ /* - * WPA Supplicant - driver interaction with MADWIFI 802.11 driver + * 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> @@ -7,10 +7,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. * - * While this driver wrapper supports both AP (hostapd) and station - * (wpa_supplicant) operations, the station side is deprecated and - * driver_wext.c should be used instead. This driver wrapper should only be - * used with hostapd for AP mode functionality. + * 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" diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 4656c1b7..4953af6a 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -1074,8 +1074,8 @@ wpa_driver_ndis_associate(void *priv, /* Try to continue anyway */ } - if (params->key_mgmt_suite == KEY_MGMT_NONE || - params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { + if (params->key_mgmt_suite == WPA_KEY_MGMT_NONE || + params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { /* Re-set WEP keys if static WEP configuration is used. */ int i; for (i = 0; i < 4; i++) { @@ -1102,12 +1102,12 @@ wpa_driver_ndis_associate(void *priv, priv_mode = Ndis802_11PrivFilterAcceptAll; } else if (params->wpa_ie[0] == WLAN_EID_RSN) { priv_mode = Ndis802_11PrivFilter8021xWEP; - if (params->key_mgmt_suite == KEY_MGMT_PSK) + if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK) auth_mode = Ndis802_11AuthModeWPA2PSK; else auth_mode = Ndis802_11AuthModeWPA2; #ifdef CONFIG_WPS - } else if (params->key_mgmt_suite == KEY_MGMT_WPS) { + } else if (params->key_mgmt_suite == WPA_KEY_MGMT_WPS) { auth_mode = Ndis802_11AuthModeOpen; priv_mode = Ndis802_11PrivFilterAcceptAll; if (params->wps == WPS_MODE_PRIVACY) { @@ -1129,35 +1129,35 @@ wpa_driver_ndis_associate(void *priv, #endif /* CONFIG_WPS */ } else { priv_mode = Ndis802_11PrivFilter8021xWEP; - if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) + if (params->key_mgmt_suite == WPA_KEY_MGMT_WPA_NONE) auth_mode = Ndis802_11AuthModeWPANone; - else if (params->key_mgmt_suite == KEY_MGMT_PSK) + else if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK) auth_mode = Ndis802_11AuthModeWPAPSK; else auth_mode = Ndis802_11AuthModeWPA; } switch (params->pairwise_suite) { - case CIPHER_CCMP: + case WPA_CIPHER_CCMP: encr = Ndis802_11Encryption3Enabled; break; - case CIPHER_TKIP: + case WPA_CIPHER_TKIP: encr = Ndis802_11Encryption2Enabled; break; - case CIPHER_WEP40: - case CIPHER_WEP104: + case WPA_CIPHER_WEP40: + case WPA_CIPHER_WEP104: encr = Ndis802_11Encryption1Enabled; break; - case CIPHER_NONE: + case WPA_CIPHER_NONE: #ifdef CONFIG_WPS if (params->wps == WPS_MODE_PRIVACY) { encr = Ndis802_11Encryption1Enabled; break; } #endif /* CONFIG_WPS */ - if (params->group_suite == CIPHER_CCMP) + if (params->group_suite == WPA_CIPHER_CCMP) encr = Ndis802_11Encryption3Enabled; - else if (params->group_suite == CIPHER_TKIP) + else if (params->group_suite == WPA_CIPHER_TKIP) encr = Ndis802_11Encryption2Enabled; else encr = Ndis802_11EncryptionDisabled; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 42dddf04..fce6efde 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1,6 +1,6 @@ /* * Driver interaction with Linux nl80211/cfg80211 - * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> + * 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> @@ -300,7 +300,6 @@ struct wpa_driver_nl80211_data { unsigned int hostapd:1; unsigned int start_mode_ap:1; unsigned int start_iface_up:1; - unsigned int channel_switch_supported:1; u64 remain_on_chan_cookie; u64 send_action_cookie; @@ -497,6 +496,11 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) 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"; } @@ -1045,49 +1049,55 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) } -static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, - char *buf, size_t len, int del) +static void wpa_driver_nl80211_event_newlink( + struct wpa_driver_nl80211_data *drv, char *ifname) { union wpa_event_data event; + if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { + if (if_nametoindex(drv->first_bss->ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK", + drv->first_bss->ifname); + return; + } + if (!drv->if_removed) + return; + wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event", + drv->first_bss->ifname); + drv->if_removed = 0; + } + os_memset(&event, 0, sizeof(event)); - if (len > sizeof(event.interface_status.ifname)) - len = sizeof(event.interface_status.ifname) - 1; - os_memcpy(event.interface_status.ifname, buf, len); - event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : - EVENT_INTERFACE_ADDED; - - wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", - del ? "DEL" : "NEW", - event.interface_status.ifname, - del ? "removed" : "added"); - - if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) == - 0) { - if (del) { - if (drv->if_removed) { - wpa_printf(MSG_DEBUG, "nl80211: if_removed " - "already set - ignore event"); - return; - } - drv->if_removed = 1; - } else { - if (if_nametoindex(drv->first_bss->ifname) == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Interface %s " - "does not exist - ignore " - "RTM_NEWLINK", - drv->first_bss->ifname); - return; - } - if (!drv->if_removed) { - wpa_printf(MSG_DEBUG, "nl80211: if_removed " - "already cleared - ignore event"); - return; - } - drv->if_removed = 0; + os_strlcpy(event.interface_status.ifname, ifname, + sizeof(event.interface_status.ifname)); + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); +} + + +static void wpa_driver_nl80211_event_dellink( + struct wpa_driver_nl80211_data *drv, char *ifname) +{ + union wpa_event_data event; + + if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { + if (drv->if_removed) { + wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s", + ifname); + return; } + wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1", + ifname); + drv->if_removed = 1; + } else { + wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed", + ifname); } + os_memset(&event, 0, sizeof(event)); + os_strlcpy(event.interface_status.ifname, ifname, + sizeof(event.interface_status.ifname)); + event.interface_status.ievent = EVENT_INTERFACE_REMOVED; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } @@ -1154,21 +1164,57 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, { struct nl80211_global *global = ctx; struct wpa_driver_nl80211_data *drv; - int attrlen, rta_len; + int attrlen; struct rtattr *attr; u32 brid = 0; char namebuf[IFNAMSIZ]; + char ifname[IFNAMSIZ + 1]; + char extra[100], *pos, *end; drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign " - "ifindex %d", ifi->ifi_index); + wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d", + ifi->ifi_index); return; } - wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " - "(%s%s%s%s)", - drv->operstate, ifi->ifi_flags, + extra[0] = '\0'; + pos = extra; + end = pos + sizeof(extra); + ifname[0] = '\0'; + + attrlen = len; + attr = (struct rtattr *) buf; + while (RTA_OK(attr, attrlen)) { + switch (attr->rta_type) { + case IFLA_IFNAME: + if (RTA_PAYLOAD(attr) >= IFNAMSIZ) + break; + os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); + ifname[RTA_PAYLOAD(attr)] = '\0'; + break; + case IFLA_MASTER: + brid = nla_get_u32((struct nlattr *) attr); + pos += os_snprintf(pos, end - pos, " master=%u", brid); + break; + case IFLA_WIRELESS: + pos += os_snprintf(pos, end - pos, " wext"); + break; + case IFLA_OPERSTATE: + pos += os_snprintf(pos, end - pos, " operstate=%u", + nla_get_u32((struct nlattr *) attr)); + break; + case IFLA_LINKMODE: + pos += os_snprintf(pos, end - pos, " linkmode=%u", + nla_get_u32((struct nlattr *) attr)); + break; + } + attr = RTA_NEXT(attr, attrlen); + } + extra[sizeof(extra) - 1] = '\0'; + + wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)", + ifi->ifi_index, ifname, extra, ifi->ifi_flags, (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", @@ -1225,24 +1271,15 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, */ if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && - !(ifi->ifi_flags & IFF_RUNNING)) + !(ifi->ifi_flags & IFF_RUNNING)) { + wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate"); netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, IF_OPER_UP); - - attrlen = len; - attr = (struct rtattr *) buf; - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_nl80211_event_link( - drv, - ((char *) attr) + rta_len, - attr->rta_len - rta_len, 0); - } else if (attr->rta_type == IFLA_MASTER) - brid = nla_get_u32((struct nlattr *) attr); - attr = RTA_NEXT(attr, attrlen); } + if (ifname[0]) + wpa_driver_nl80211_event_newlink(drv, ifname); + if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been added to bridge */ if_indextoname(brid, namebuf); @@ -1259,32 +1296,40 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, { struct nl80211_global *global = ctx; struct wpa_driver_nl80211_data *drv; - int attrlen, rta_len; + int attrlen; struct rtattr *attr; u32 brid = 0; + char ifname[IFNAMSIZ + 1]; drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for " - "foreign ifindex %d", ifi->ifi_index); + wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d", + ifi->ifi_index); return; } + ifname[0] = '\0'; + attrlen = len; attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_nl80211_event_link( - drv, - ((char *) attr) + rta_len, - attr->rta_len - rta_len, 1); - } else if (attr->rta_type == IFLA_MASTER) + switch (attr->rta_type) { + case IFLA_IFNAME: + if (RTA_PAYLOAD(attr) >= IFNAMSIZ) + break; + os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); + ifname[RTA_PAYLOAD(attr)] = '\0'; + break; + case IFLA_MASTER: brid = nla_get_u32((struct nlattr *) attr); + break; + } attr = RTA_NEXT(attr, attrlen); } + if (ifname[0]) + wpa_driver_nl80211_event_dellink(drv, ifname); + if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; @@ -1602,7 +1647,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_MSGDUMP, "nl80211: Frame event"); mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24) { - wpa_printf(MSG_DEBUG, "nl80211: Too short action frame"); + wpa_printf(MSG_DEBUG, "nl80211: Too short management frame"); return; } @@ -1614,26 +1659,16 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, os_memset(&event, 0, sizeof(event)); if (freq) { - event.rx_action.freq = nla_get_u32(freq); - rx_freq = drv->last_mgmt_freq = event.rx_action.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 freq=%d ssi_signal=%d stype=%u len=%u", rx_freq, ssi_signal, stype, (unsigned int) len); - if (stype == WLAN_FC_STYPE_ACTION) { - event.rx_action.da = mgmt->da; - event.rx_action.sa = mgmt->sa; - event.rx_action.bssid = mgmt->bssid; - event.rx_action.category = mgmt->u.action.category; - event.rx_action.data = &mgmt->u.action.category + 1; - event.rx_action.len = frame + len - event.rx_action.data; - wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); - } else { - event.rx_mgmt.frame = frame; - event.rx_mgmt.frame_len = len; - event.rx_mgmt.ssi_signal = ssi_signal; - wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); - } + event.rx_mgmt.frame = frame; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.ssi_signal = ssi_signal; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } @@ -2037,21 +2072,36 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, &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); } @@ -2666,6 +2716,48 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, } +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) { + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); + break; + } +} + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -2687,6 +2779,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_TRIGGER_SCAN: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); drv->scan_state = SCAN_STARTED; + 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"); @@ -2838,6 +2931,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, 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); @@ -3105,6 +3201,7 @@ struct wiphy_info_data { unsigned int p2p_client_supported:1; unsigned int p2p_concurrent:1; unsigned int channel_switch_supported:1; + unsigned int set_qos_map_supported:1; }; @@ -3265,6 +3362,65 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info, 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; } } } @@ -3369,6 +3525,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) 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 " @@ -3421,6 +3578,38 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) } } + 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); + 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); + } + } + return NL_SKIP; } @@ -3479,6 +3668,9 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, 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); @@ -3496,15 +3688,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) return -1; drv->has_capability = 1; - /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104 | - WPA_DRIVER_CAPA_ENC_TKIP | - WPA_DRIVER_CAPA_ENC_CCMP; drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; @@ -3526,7 +3713,8 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->device_ap_sme = info.device_ap_sme; drv->poll_command_supported = info.poll_command_supported; drv->data_tx_status = info.data_tx_status; - drv->channel_switch_supported = info.channel_switch_supported; + if (info.set_qos_map_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING; /* * If poll command and tx status are supported, mac80211 is new enough @@ -3652,6 +3840,16 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) /* Continue without regulatory events */ } + ret = nl_get_multicast_id(global, "nl80211", "vendor"); + if (ret >= 0) + ret = nl_socket_add_membership(global->nl_event, ret); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " + "membership for vendor events: %d (%s)", + ret, strerror(-ret)); + /* Continue without vendor events */ + } + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, @@ -3912,15 +4110,16 @@ static int nl80211_register_frame(struct i802_bss *bss, struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; int ret = -1; + char buf[30]; msg = nlmsg_alloc(); if (!msg) return -1; - wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p", - type, nl_handle); - wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match", - match, match_len); + buf[0] = '\0'; + wpa_snprintf_hex(buf, sizeof(buf), match, match_len); + wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p match=%s", + type, nl_handle, buf); nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); @@ -3985,6 +4184,7 @@ static int nl80211_register_action_frame(struct i802_bss *bss, static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) { struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = 0; if (nl80211_alloc_mgmt_handle(bss)) return -1; @@ -4001,65 +4201,65 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) #ifdef CONFIG_INTERWORKING /* QoS Map Configure */ if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_INTERWORKING */ #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) /* GAS Initial Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0) - return -1; + ret = -1; /* GAS Initial Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0) - return -1; + ret = -1; /* GAS Comeback Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0) - return -1; + ret = -1; /* GAS Comeback Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_P2P || CONFIG_INTERWORKING */ #ifdef CONFIG_P2P /* P2P Public Action */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x09\x50\x6f\x9a\x09", 6) < 0) - return -1; + ret = -1; /* P2P Action */ if (nl80211_register_action_frame(bss, (u8 *) "\x7f\x50\x6f\x9a\x09", 5) < 0) - return -1; + ret = -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211W /* SA Query Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_TDLS if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) { /* TDLS Discovery Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) < 0) - return -1; + ret = -1; } #endif /* CONFIG_TDLS */ /* FT Action frames */ if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) - return -1; + ret = -1; else drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; /* WNM - BSS Transition Management Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0) - return -1; + ret = -1; /* WNM-Sleep Mode Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0) - return -1; + ret = -1; nl80211_mgmt_handle_register_eloop(bss); - return 0; + return ret; } @@ -4521,6 +4721,12 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd, 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"); + NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, + NL80211_SCAN_FLAG_FLUSH); + } + return msg; fail: @@ -4931,7 +5137,8 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) * 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. + * 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; @@ -4949,8 +5156,9 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) 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)) { + 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 @@ -5116,6 +5324,95 @@ static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) } +static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len) +{ + switch (alg) { + case WPA_ALG_WEP: + if (key_len == 5) + return WLAN_CIPHER_SUITE_WEP40; + return WLAN_CIPHER_SUITE_WEP104; + case WPA_ALG_TKIP: + return WLAN_CIPHER_SUITE_TKIP; + case WPA_ALG_CCMP: + return WLAN_CIPHER_SUITE_CCMP; + case WPA_ALG_GCMP: + return WLAN_CIPHER_SUITE_GCMP; + case WPA_ALG_CCMP_256: + return WLAN_CIPHER_SUITE_CCMP_256; + case WPA_ALG_GCMP_256: + return WLAN_CIPHER_SUITE_GCMP_256; + case WPA_ALG_IGTK: + return WLAN_CIPHER_SUITE_AES_CMAC; + case WPA_ALG_BIP_GMAC_128: + return WLAN_CIPHER_SUITE_BIP_GMAC_128; + case WPA_ALG_BIP_GMAC_256: + return WLAN_CIPHER_SUITE_BIP_GMAC_256; + case WPA_ALG_BIP_CMAC_256: + return WLAN_CIPHER_SUITE_BIP_CMAC_256; + case WPA_ALG_SMS4: + return WLAN_CIPHER_SUITE_SMS4; + case WPA_ALG_KRK: + return WLAN_CIPHER_SUITE_KRK; + case WPA_ALG_NONE: + case WPA_ALG_PMK: + wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d", + alg); + return 0; + } + + wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d", + alg); + return 0; +} + + +static u32 wpa_cipher_to_cipher_suite(unsigned int cipher) +{ + switch (cipher) { + case WPA_CIPHER_CCMP_256: + return WLAN_CIPHER_SUITE_CCMP_256; + case WPA_CIPHER_GCMP_256: + return WLAN_CIPHER_SUITE_GCMP_256; + case WPA_CIPHER_CCMP: + return WLAN_CIPHER_SUITE_CCMP; + case WPA_CIPHER_GCMP: + return WLAN_CIPHER_SUITE_GCMP; + case WPA_CIPHER_TKIP: + return WLAN_CIPHER_SUITE_TKIP; + case WPA_CIPHER_WEP104: + return WLAN_CIPHER_SUITE_WEP104; + case WPA_CIPHER_WEP40: + return WLAN_CIPHER_SUITE_WEP40; + } + + return 0; +} + + +static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[], + int max_suites) +{ + int num_suites = 0; + + if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256; + if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256) + suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256; + if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; + if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP; + if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP) + suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; + if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; + if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + + return num_suites; +} + + 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, @@ -5153,45 +5450,8 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, } else { nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); - switch (alg) { - case WPA_ALG_WEP: - if (key_len == 5) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP40); - else - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP104); - break; - case WPA_ALG_TKIP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_TKIP); - break; - case WPA_ALG_CCMP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_CCMP); - break; - case WPA_ALG_GCMP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_GCMP); - break; - case WPA_ALG_IGTK: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_AES_CMAC); - break; - case WPA_ALG_SMS4: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_SMS4); - break; - case WPA_ALG_KRK: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_KRK); - break; - default: - wpa_printf(MSG_ERROR, "%s: Unsupported encryption " - "algorithm %d", __func__, alg); - nlmsg_free(msg); - return -1; - } + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + wpa_alg_to_cipher_suite(alg, key_len)); } if (seq && seq_len) @@ -5296,33 +5556,8 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); - switch (alg) { - case WPA_ALG_WEP: - if (key_len == 5) - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP40); - else - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP104); - break; - case WPA_ALG_TKIP: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); - break; - case WPA_ALG_CCMP: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); - break; - case WPA_ALG_GCMP: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP); - break; - case WPA_ALG_IGTK: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_AES_CMAC); - break; - default: - wpa_printf(MSG_ERROR, "%s: Unsupported encryption " - "algorithm %d", __func__, alg); - return -1; - } + 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); @@ -5784,10 +6019,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) chan->flag |= HOSTAPD_CHAN_DISABLED; - if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) - chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) - chan->flag |= HOSTAPD_CHAN_NO_IBSS; + 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; @@ -5816,8 +6049,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info, static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_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 }, @@ -6113,24 +6345,11 @@ static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, } -static void nl80211_reg_rule_max_eirp(struct nlattr *tb[], +static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp, struct phy_info_arg *results) { - u32 start, end, max_eirp; u16 m; - if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || - tb[NL80211_ATTR_POWER_RULE_MAX_EIRP] == 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_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100; - - wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u mBm", - start, end, max_eirp); - for (m = 0; m < *results->num_modes; m++) { int c; struct hostapd_hw_modes *mode = &results->modes[m]; @@ -6145,26 +6364,11 @@ static void nl80211_reg_rule_max_eirp(struct nlattr *tb[], } -static void nl80211_reg_rule_ht40(struct nlattr *tb[], +static void nl80211_reg_rule_ht40(u32 start, u32 end, 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; - - wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz", - start, end, max_bw); - if (max_bw < 40) - return; - for (m = 0; m < *results->num_modes; m++) { if (!(results->modes[m].ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) @@ -6285,10 +6489,26 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg) nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) { + u32 start, end, max_eirp = 0, max_bw = 0; nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_rule), nla_len(nl_rule), reg_policy); - nl80211_reg_rule_ht40(tb_rule, results); - nl80211_reg_rule_max_eirp(tb_rule, results); + 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; + + wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm", + start, end, max_bw, max_eirp); + 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) @@ -6648,7 +6868,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, int beacon_set; int ifindex = if_nametoindex(bss->ifname); int num_suites; - u32 suites[10]; + u32 suites[10], suite; u32 ver; beacon_set = bss->beacon_set; @@ -6743,17 +6963,8 @@ static int wpa_driver_nl80211_set_ap(void *priv, wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x", params->pairwise_ciphers); - num_suites = 0; - if (params->pairwise_ciphers & WPA_CIPHER_CCMP) - suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; - if (params->pairwise_ciphers & WPA_CIPHER_GCMP) - suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP; - if (params->pairwise_ciphers & WPA_CIPHER_TKIP) - suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; - if (params->pairwise_ciphers & WPA_CIPHER_WEP104) - suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; - if (params->pairwise_ciphers & WPA_CIPHER_WEP40) - suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + 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); @@ -6761,28 +6972,9 @@ static int wpa_driver_nl80211_set_ap(void *priv, wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x", params->group_cipher); - switch (params->group_cipher) { - case WPA_CIPHER_CCMP: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_CCMP); - break; - case WPA_CIPHER_GCMP: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_GCMP); - break; - case WPA_CIPHER_TKIP: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_TKIP); - break; - case WPA_CIPHER_WEP104: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_WEP104); - break; - case WPA_CIPHER_WEP40: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_WEP40); - break; - } + suite = wpa_cipher_to_cipher_suite(params->group_cipher); + if (suite) + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite); if (params->beacon_ies) { wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies", @@ -7977,10 +8169,10 @@ retry: NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK || - params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 || - params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) { + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK || + 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); } @@ -8018,40 +8210,32 @@ nla_put_failure: } -static int wpa_driver_nl80211_try_connect( - struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) +static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params, + struct nl_msg *msg) { - struct nl_msg *msg; - enum nl80211_auth_type type; - int ret = 0; - int algs; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); - nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } + if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); drv->assoc_freq = params->freq; } else drv->assoc_freq = 0; + if (params->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 (params->ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", params->ssid, params->ssid_len); @@ -8062,39 +8246,12 @@ static int wpa_driver_nl80211_try_connect( 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); - algs = 0; - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - algs++; - if (params->auth_alg & WPA_AUTH_ALG_SHARED) - algs++; - if (params->auth_alg & WPA_AUTH_ALG_LEAP) - algs++; - if (algs > 1) { - wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " - "selection"); - goto skip_auth_type; - } - - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - type = NL80211_AUTHTYPE_OPEN_SYSTEM; - else if (params->auth_alg & WPA_AUTH_ALG_SHARED) - type = NL80211_AUTHTYPE_SHARED_KEY; - else if (params->auth_alg & WPA_AUTH_ALG_LEAP) - type = NL80211_AUTHTYPE_NETWORK_EAP; - else if (params->auth_alg & WPA_AUTH_ALG_FT) - type = NL80211_AUTHTYPE_FT; - else - goto nla_put_failure; - - wpa_printf(MSG_DEBUG, " * Auth Type %d", type); - NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); - -skip_auth_type: if (params->wpa_proto) { enum nl80211_wpa_versions ver = 0; @@ -8107,81 +8264,39 @@ skip_auth_type: NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); } - if (params->pairwise_suite != CIPHER_NONE) { - int cipher; - - switch (params->pairwise_suite) { - case CIPHER_SMS4: - cipher = WLAN_CIPHER_SUITE_SMS4; - break; - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } + 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 (params->group_suite != CIPHER_NONE) { - int cipher; - - switch (params->group_suite) { - case CIPHER_SMS4: - cipher = WLAN_CIPHER_SUITE_SMS4; - break; - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } + 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 (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK || - params->key_mgmt_suite == KEY_MGMT_FT_802_1X || - params->key_mgmt_suite == KEY_MGMT_FT_PSK || - params->key_mgmt_suite == KEY_MGMT_CCKM) { + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK || + params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK || + params->key_mgmt_suite == WPA_KEY_MGMT_CCKM) { int mgmt = WLAN_AKM_SUITE_PSK; switch (params->key_mgmt_suite) { - case KEY_MGMT_CCKM: + case WPA_KEY_MGMT_CCKM: mgmt = WLAN_AKM_SUITE_CCKM; break; - case KEY_MGMT_802_1X: + case WPA_KEY_MGMT_IEEE8021X: mgmt = WLAN_AKM_SUITE_8021X; break; - case KEY_MGMT_FT_802_1X: + case WPA_KEY_MGMT_FT_IEEE8021X: mgmt = WLAN_AKM_SUITE_FT_8021X; break; - case KEY_MGMT_FT_PSK: + case WPA_KEY_MGMT_FT_PSK: mgmt = WLAN_AKM_SUITE_FT_PSK; break; - case KEY_MGMT_PSK: + case WPA_KEY_MGMT_PSK: default: mgmt = WLAN_AKM_SUITE_PSK; break; @@ -8189,10 +8304,10 @@ skip_auth_type: NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); } -#ifdef CONFIG_IEEE80211W + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); -#endif /* CONFIG_IEEE80211W */ if (params->disable_ht) NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); @@ -8218,6 +8333,63 @@ skip_auth_type: } #endif /* CONFIG_VHT_OVERRIDES */ + if (params->p2p) + wpa_printf(MSG_DEBUG, " * P2P group"); + + return 0; +nla_put_failure: + return -1; +} + + +static int wpa_driver_nl80211_try_connect( + struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + enum nl80211_auth_type type; + int ret; + int algs; + + msg = nlmsg_alloc(); + 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; + + algs = 0; + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + algs++; + if (params->auth_alg & WPA_AUTH_ALG_SHARED) + algs++; + if (params->auth_alg & WPA_AUTH_ALG_LEAP) + algs++; + if (algs > 1) { + wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " + "selection"); + goto skip_auth_type; + } + + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (params->auth_alg & WPA_AUTH_ALG_SHARED) + type = NL80211_AUTHTYPE_SHARED_KEY; + else if (params->auth_alg & WPA_AUTH_ALG_LEAP) + type = NL80211_AUTHTYPE_NETWORK_EAP; + else if (params->auth_alg & WPA_AUTH_ALG_FT) + type = NL80211_AUTHTYPE_FT; + else + goto nla_put_failure; + + wpa_printf(MSG_DEBUG, " * Auth Type %d", type); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); + +skip_auth_type: ret = nl80211_set_conn_keys(params, msg); if (ret) goto nla_put_failure; @@ -8267,7 +8439,7 @@ static int wpa_driver_nl80211_associate( { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - int ret = -1; + int ret; struct nl_msg *msg; if (params->mode == IEEE80211_MODE_AP) @@ -8295,95 +8467,9 @@ static int wpa_driver_nl80211_associate( drv->ifindex); nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - if (params->bssid) { - wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, - MAC2STR(params->bssid)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); - } - if (params->freq) { - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); - drv->assoc_freq = params->freq; - } else - drv->assoc_freq = 0; - if (params->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 (params->ssid) { - wpa_hexdump_ascii(MSG_DEBUG, " * SSID", - params->ssid, params->ssid_len); - NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, - params->ssid); - if (params->ssid_len > sizeof(drv->ssid)) - goto nla_put_failure; - os_memcpy(drv->ssid, params->ssid, params->ssid_len); - drv->ssid_len = params->ssid_len; - } - wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); - if (params->wpa_ie) - NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, - params->wpa_ie); - - if (params->pairwise_suite != CIPHER_NONE) { - int cipher; - - switch (params->pairwise_suite) { - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } - wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); - } - - if (params->group_suite != CIPHER_NONE) { - int cipher; - - switch (params->group_suite) { - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } - wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); - } - -#ifdef CONFIG_IEEE80211W - if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) - NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); -#endif /* CONFIG_IEEE80211W */ - - NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + ret = nl80211_connect_common(drv, params, msg); + if (ret) + goto nla_put_failure; if (params->prev_bssid) { wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, @@ -8392,33 +8478,6 @@ static int wpa_driver_nl80211_associate( params->prev_bssid); } - if (params->disable_ht) - NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); - - if (params->htcaps && params->htcaps_mask) { - int sz = sizeof(struct ieee80211_ht_capabilities); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz, - params->htcaps_mask); - } - -#ifdef CONFIG_VHT_OVERRIDES - if (params->disable_vht) { - wpa_printf(MSG_DEBUG, " * VHT disabled"); - NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT); - } - - if (params->vhtcaps && params->vhtcaps_mask) { - int sz = sizeof(struct ieee80211_vht_capabilities); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz, - params->vhtcaps_mask); - } -#endif /* CONFIG_VHT_OVERRIDES */ - - if (params->p2p) - wpa_printf(MSG_DEBUG, " * P2P group"); - ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { @@ -8593,8 +8652,9 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", - __func__, drv->operstate, state, state ? "UP" : "DORMANT"); + wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)", + bss->ifname, drv->operstate, state, + state ? "UP" : "DORMANT"); drv->operstate = state; return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); @@ -8607,6 +8667,12 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; struct nl80211_sta_flag_update upd; + int ret = -ENOBUFS; + + if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) { + wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated"); + return 0; + } wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for " MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid)); @@ -8627,10 +8693,15 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); - return send_and_recv_msgs(drv, msg, NULL, NULL); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (!ret) + return 0; nla_put_failure: nlmsg_free(msg); - return -ENOBUFS; + wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)", + ret, strerror(-ret)); + return ret; } @@ -10209,6 +10280,18 @@ static int nl80211_set_param(void *priv, const char *param) } #endif /* CONFIG_P2P */ + if (os_strstr(param, "use_monitor=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + drv->use_monitor = 1; + } + + if (os_strstr(param, "force_connect_cmd=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME; + } + return 0; } @@ -11321,7 +11404,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) settings->freq_params.center_freq1, settings->freq_params.center_freq2); - if (!drv->channel_switch_supported) { + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) { wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command"); return -EOPNOTSUPP; } @@ -11397,6 +11480,37 @@ error: } +static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set, + u8 qos_map_set_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + 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); + + 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; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -11485,4 +11599,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #ifdef ANDROID .driver_cmd = wpa_driver_nl80211_driver_cmd, #endif /* ANDROID */ + .set_qos_map = nl80211_set_qos_map, }; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 5742b988..7d306553 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -28,7 +28,6 @@ #include "common/ieee802_11_defs.h" #include "crypto/sha1.h" #include "l2_packet/l2_packet.h" -#include "p2p/p2p.h" #include "wps/wps.h" #include "driver.h" @@ -102,20 +101,6 @@ struct wpa_driver_test_data { unsigned int remain_on_channel_duration; int current_freq; - - struct p2p_data *p2p; - unsigned int off_channel_freq; - struct wpabuf *pending_action_tx; - u8 pending_action_src[ETH_ALEN]; - u8 pending_action_dst[ETH_ALEN]; - u8 pending_action_bssid[ETH_ALEN]; - unsigned int pending_action_freq; - unsigned int pending_action_no_cck; - unsigned int pending_listen_freq; - unsigned int pending_listen_duration; - int pending_p2p_scan; - struct sockaddr *probe_from; - socklen_t probe_from_len; }; @@ -125,7 +110,6 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, 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 int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv); static void test_driver_free_bss(struct test_driver_bss *bss) @@ -479,34 +463,6 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data, event.tx_status.ack = ret >= 0; wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); -#ifdef CONFIG_P2P - if (drv->p2p && - WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { - if (drv->pending_action_tx == NULL) { - wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " - "no pending operation"); - return ret; - } - - if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) != - 0) { - wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " - "unknown destination address"); - return ret; - } - - wpabuf_free(drv->pending_action_tx); - drv->pending_action_tx = NULL; - - p2p_send_action_cb(drv->p2p, drv->pending_action_freq, - drv->pending_action_dst, - drv->pending_action_src, - drv->pending_action_bssid, - ret >= 0); - } -#endif /* CONFIG_P2P */ - return ret; } @@ -553,10 +509,6 @@ static void test_driver_scan(struct wpa_driver_test_data *drv, event.rx_probe_req.ie = ie; event.rx_probe_req.ie_len = ielen; wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); -#ifdef CONFIG_P2P - if (drv->p2p) - p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); -#endif /* CONFIG_P2P */ } dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { @@ -1313,25 +1265,7 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) { - struct wpa_driver_test_data *drv = eloop_ctx; wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); - if (drv->pending_p2p_scan && drv->p2p) { -#ifdef CONFIG_P2P - size_t i; - struct os_time now; - os_get_time(&now); - for (i = 0; i < drv->num_scanres; i++) { - struct wpa_scan_res *bss = drv->scanres[i]; - if (p2p_scan_res_handler(drv->p2p, bss->bssid, - bss->freq, &now, bss->level, - (const u8 *) (bss + 1), - bss->ie_len) > 0) - return; - } - p2p_scan_res_handled(drv->p2p); -#endif /* CONFIG_P2P */ - return; - } wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } @@ -1949,30 +1883,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, data_len - (mgmt->u.probe_req.variable - data); wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); -#ifdef CONFIG_P2P - if (drv->p2p) - p2p_probe_req_rx(drv->p2p, mgmt->sa, - mgmt->da, mgmt->bssid, - event.rx_probe_req.ie, - event.rx_probe_req.ie_len); -#endif /* CONFIG_P2P */ } } - -#ifdef CONFIG_P2P - if (drv->p2p && - WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { - size_t hdr_len; - hdr_len = (const u8 *) - &mgmt->u.action.u.vs_public_action.action - data; - p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid, - mgmt->u.action.category, - &mgmt->u.action.u.vs_public_action.action, - data_len - hdr_len, freq); - } -#endif /* CONFIG_P2P */ - } @@ -1988,29 +1900,6 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, bss = dl_list_first(&drv->bss, struct test_driver_bss, list); /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ -#ifdef CONFIG_P2P - if (drv->probe_req_report && drv->p2p && data_len) { - const char *d = (const char *) data; - u8 sa[ETH_ALEN]; - u8 ie[512]; - size_t ielen; - - if (hwaddr_aton(d, sa)) - return; - d += 18; - while (*d == ' ') - d++; - ielen = os_strlen(d) / 2; - if (ielen > sizeof(ie)) - ielen = sizeof(ie); - if (hexstr2bin(d, ie, ielen) < 0) - ielen = 0; - drv->probe_from = from; - drv->probe_from_len = fromlen; - p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); - drv->probe_from = NULL; - } -#endif /* CONFIG_P2P */ if (!drv->ibss) return; @@ -2167,12 +2056,6 @@ static void wpa_driver_test_deinit(void *priv) struct test_client_socket *cli, *prev; int i; -#ifdef CONFIG_P2P - if (drv->p2p) - p2p_deinit(drv->p2p); - wpabuf_free(drv->pending_action_tx); -#endif /* CONFIG_P2P */ - cli = drv->cli; while (cli) { prev = cli; @@ -2369,13 +2252,6 @@ static int wpa_driver_test_set_param(void *priv, const char *param) drv->use_associnfo = 1; } - if (os_strstr(param, "p2p_mgmt=1")) { - wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P " - "management"); - if (wpa_driver_test_init_p2p(drv) < 0) - return -1; - } - return 0; } @@ -2465,8 +2341,6 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) { - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; os_memset(capa, 0, sizeof(*capa)); capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | @@ -2482,8 +2356,6 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; - if (drv->p2p) - capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT; capa->flags |= WPA_DRIVER_FLAGS_AP; capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE; @@ -2691,33 +2563,6 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, } -#ifdef CONFIG_P2P -static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_test_data *drv = eloop_ctx; - - if (drv->pending_action_tx == NULL) - return; - - if (drv->off_channel_freq != drv->pending_action_freq) { - wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX " - "waiting for another freq=%u", - drv->pending_action_freq); - return; - } - wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to " - MACSTR, MAC2STR(drv->pending_action_dst)); - wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, - drv->pending_action_dst, - drv->pending_action_src, - drv->pending_action_bssid, - wpabuf_head(drv->pending_action_tx), - wpabuf_len(drv->pending_action_tx), - drv->pending_action_no_cck); -} -#endif /* CONFIG_P2P */ - - static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_test_data *drv = eloop_ctx; @@ -2729,9 +2574,6 @@ static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) data.remain_on_channel.freq = drv->remain_on_channel_freq; data.remain_on_channel.duration = drv->remain_on_channel_duration; - if (drv->p2p) - drv->off_channel_freq = 0; - drv->remain_on_channel_freq = 0; wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); @@ -2765,18 +2607,6 @@ static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq, data.remain_on_channel.duration = duration; wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data); -#ifdef CONFIG_P2P - if (drv->p2p) { - drv->off_channel_freq = drv->remain_on_channel_freq; - test_send_action_cb(drv, NULL); - if (drv->off_channel_freq == drv->pending_listen_freq) { - p2p_listen_cb(drv->p2p, drv->pending_listen_freq, - drv->pending_listen_duration); - drv->pending_listen_freq = 0; - } - } -#endif /* CONFIG_P2P */ - return 0; } @@ -2804,470 +2634,6 @@ static int wpa_driver_test_probe_req_report(void *priv, int report) } -#ifdef CONFIG_P2P - -static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); - if (!drv->p2p) - return -1; - return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0); -} - - -static int wpa_driver_test_p2p_stop_find(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->p2p) - return -1; - p2p_stop_find(drv->p2p); - return 0; -} - - -static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); - if (!drv->p2p) - return -1; - return p2p_listen(drv->p2p, timeout); -} - - -static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr, - int wps_method, int go_intent, - const u8 *own_interface_addr, - unsigned int force_freq, - int persistent_group) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d " - "go_intent=%d " - "own_interface_addr=" MACSTR " force_freq=%u " - "persistent_group=%d)", - __func__, MAC2STR(peer_addr), wps_method, go_intent, - MAC2STR(own_interface_addr), force_freq, persistent_group); - if (!drv->p2p) - return -1; - return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent, - own_interface_addr, force_freq, persistent_group, - NULL, 0, 0, 0); -} - - -static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")", - __func__, MAC2STR(peer_addr)); - if (!drv->p2p) - return -1; - p2p_wps_success_cb(drv->p2p, peer_addr); - return 0; -} - - -static int wpa_driver_test_p2p_group_formation_failed(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->p2p) - return -1; - p2p_group_formation_failed(drv->p2p); - return 0; -} - - -static int wpa_driver_test_p2p_set_params(void *priv, - const struct p2p_params *params) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->p2p) - return -1; - if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 || - p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 || - p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type, - params->num_sec_dev_types) < 0) - return -1; - return 0; -} - - -static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, - unsigned int num_req_dev_types, - const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) -{ - struct wpa_driver_test_data *drv = ctx; - struct wpa_driver_scan_params params; - int ret; - struct wpabuf *wps_ie, *ies; - int social_channels[] = { 2412, 2437, 2462, 0, 0 }; - size_t ielen; - - wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)", - __func__, type, freq); - - os_memset(¶ms, 0, sizeof(params)); - - /* P2P Wildcard SSID */ - params.num_ssids = 1; - params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; - params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; - -#if 0 /* TODO: WPS IE */ - wpa_s->wps->dev.p2p = 1; - wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, - wpa_s->wps->uuid, WPS_REQ_ENROLLEE); -#else - wps_ie = wpabuf_alloc(1); -#endif - if (wps_ie == NULL) - return -1; - - ielen = p2p_scan_ie_buf_len(drv->p2p); - ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); - if (ies == NULL) { - wpabuf_free(wps_ie); - return -1; - } - wpabuf_put_buf(ies, wps_ie); - wpabuf_free(wps_ie); - - p2p_scan_ie(drv->p2p, ies, dev_id); - - params.extra_ies = wpabuf_head(ies); - params.extra_ies_len = wpabuf_len(ies); - - switch (type) { - case P2P_SCAN_SOCIAL: - params.freqs = social_channels; - break; - case P2P_SCAN_FULL: - break; - case P2P_SCAN_SOCIAL_PLUS_ONE: - social_channels[3] = freq; - params.freqs = social_channels; - break; - } - - drv->pending_p2p_scan = 1; - ret = wpa_driver_test_scan(drv, ¶ms); - - wpabuf_free(ies); - - return ret; -} - - -static int test_send_action(void *ctx, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time) -{ - struct wpa_driver_test_data *drv = ctx; - - wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR - " bssid=" MACSTR " len=%d", - __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), - (int) len); - if (freq <= 0) { - wpa_printf(MSG_WARNING, "P2P: No frequency specified for " - "action frame TX"); - return -1; - } - - if (drv->pending_action_tx) { - wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX " - "to " MACSTR, MAC2STR(drv->pending_action_dst)); - wpabuf_free(drv->pending_action_tx); - } - drv->pending_action_tx = wpabuf_alloc(len); - if (drv->pending_action_tx == NULL) - return -1; - wpabuf_put_data(drv->pending_action_tx, buf, len); - os_memcpy(drv->pending_action_src, src, ETH_ALEN); - os_memcpy(drv->pending_action_dst, dst, ETH_ALEN); - os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN); - drv->pending_action_freq = freq; - drv->pending_action_no_cck = 1; - - if (drv->off_channel_freq == freq) { - /* Already on requested channel; send immediately */ - /* TODO: Would there ever be need to extend the current - * duration on the channel? */ - eloop_cancel_timeout(test_send_action_cb, drv, NULL); - eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL); - return 0; - } - - wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted " - "once the driver gets to the requested channel"); - if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) { - wpa_printf(MSG_DEBUG, "P2P: Failed to request driver " - "to remain on channel (%u MHz) for Action " - "Frame TX", freq); - return -1; - } - - return 0; -} - - -static void test_send_action_done(void *ctx) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) -{ - struct wpa_driver_test_data *drv = ctx; - union wpa_event_data event; - wpa_printf(MSG_DEBUG, "%s", __func__); - os_memset(&event, 0, sizeof(event)); - event.p2p_go_neg_completed.res = res; - wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event); -} - - -static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) -{ - struct wpa_driver_test_data *drv = ctx; - union wpa_event_data event; - wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src)); - os_memset(&event, 0, sizeof(event)); - event.p2p_go_neg_req_rx.src = src; - event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id; - wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event); -} - - -static void test_dev_found(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, int new_device) -{ - struct wpa_driver_test_data *drv = ctx; - union wpa_event_data event; - char devtype[WPS_DEV_TYPE_BUFSIZE]; - wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR - " pri_dev_type=%s name='%s' config_methods=0x%x " - "dev_capab=0x%x group_capab=0x%x)", - __func__, MAC2STR(addr), MAC2STR(info->p2p_device_addr), - wps_dev_type_bin2str(info->pri_dev_type, devtype, - sizeof(devtype)), - info->device_name, info->config_methods, info->dev_capab, - info->group_capab); - - os_memset(&event, 0, sizeof(event)); - event.p2p_dev_found.addr = addr; - event.p2p_dev_found.dev_addr = info->p2p_device_addr; - event.p2p_dev_found.pri_dev_type = info->pri_dev_type; - event.p2p_dev_found.dev_name = info->device_name; - event.p2p_dev_found.config_methods = info->config_methods; - event.p2p_dev_found.dev_capab = info->dev_capab; - event.p2p_dev_found.group_capab = info->group_capab; - wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event); -} - - -static int test_start_listen(void *ctx, unsigned int freq, - unsigned int duration, - const struct wpabuf *probe_resp_ie) -{ - struct wpa_driver_test_data *drv = ctx; - - wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)", - __func__, freq, duration); - - if (wpa_driver_test_probe_req_report(drv, 1) < 0) - return -1; - - drv->pending_listen_freq = freq; - drv->pending_listen_duration = duration; - - if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) { - drv->pending_listen_freq = 0; - return -1; - } - - return 0; -} - - -static void test_stop_listen(void *ctx) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static int test_send_probe_resp(void *ctx, const struct wpabuf *buf) -{ - struct wpa_driver_test_data *drv = ctx; - char resp[512], *pos, *end; - int ret; - const struct ieee80211_mgmt *mgmt; - const u8 *ie, *ie_end; - - wpa_printf(MSG_DEBUG, "%s", __func__); - wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf); - if (wpabuf_len(buf) < 24) - return -1; - if (!drv->probe_from) { - wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__); - return -1; - } - - pos = resp; - end = resp + sizeof(resp); - - mgmt = wpabuf_head(buf); - - /* reply: SCANRESP BSSID SSID IEs */ - ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ", - MAC2STR(mgmt->bssid)); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - - ie = mgmt->u.probe_resp.variable; - ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf); - if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID || - ie + 2 + ie[1] > ie_end) - return -1; - pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]); - - ret = os_snprintf(pos, end - pos, " "); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie); - - sendto(drv->test_socket, resp, pos - resp, 0, - drv->probe_from, drv->probe_from_len); - - return 0; -} - - -static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, - const u8 *dev_addr, const u8 *pri_dev_type, - const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab, - const u8 *group_id, size_t group_id_len) -{ - wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", - __func__, MAC2STR(peer), config_methods); - /* TODO */ -} - - -static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) -{ - wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", - __func__, MAC2STR(peer), config_methods); - /* TODO */ -} - - -static void test_p2p_debug_print(void *ctx, int level, const char *msg) -{ - wpa_printf(level, "P2P: %s", msg); -} - -#endif /* CONFIG_P2P */ - - -static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv) -{ -#ifdef CONFIG_P2P - struct p2p_config p2p; - unsigned int r; - int i; - - os_memset(&p2p, 0, sizeof(p2p)); - p2p.cb_ctx = drv; - p2p.debug_print = test_p2p_debug_print; - p2p.p2p_scan = test_p2p_scan; - p2p.send_action = test_send_action; - p2p.send_action_done = test_send_action_done; - p2p.go_neg_completed = test_go_neg_completed; - p2p.go_neg_req_rx = test_go_neg_req_rx; - p2p.dev_found = test_dev_found; - p2p.start_listen = test_start_listen; - p2p.stop_listen = test_stop_listen; - p2p.send_probe_resp = test_send_probe_resp; - p2p.sd_request = test_sd_request; - p2p.sd_response = test_sd_response; - p2p.prov_disc_req = test_prov_disc_req; - p2p.prov_disc_resp = test_prov_disc_resp; - - os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN); - - p2p.reg_class = 12; /* TODO: change depending on location */ - /* - * Pick one of the social channels randomly as the listen - * channel. - */ - os_get_random((u8 *) &r, sizeof(r)); - p2p.channel = 1 + (r % 3) * 5; - - /* TODO: change depending on location */ - p2p.op_reg_class = 12; - /* - * For initial tests, pick the operation channel randomly. - * TODO: Use scan results (etc.) to select the best channel. - */ - p2p.op_channel = 1 + r % 11; - - os_memcpy(p2p.country, "US ", 3); - - /* FIX: fetch available channels from the driver */ - p2p.channels.reg_classes = 1; - p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */ - p2p.channels.reg_class[0].channels = 11; - for (i = 0; i < 11; i++) - p2p.channels.reg_class[0].channel[i] = i + 1; - - p2p.max_peers = 100; - - drv->p2p = p2p_init(&p2p); - if (drv->p2p == NULL) - return -1; - return 0; -#else /* CONFIG_P2P */ - wpa_printf(MSG_INFO, "driver_test: P2P support not included"); - return -1; -#endif /* CONFIG_P2P */ -} - - const struct wpa_driver_ops wpa_driver_test_ops = { "test", "wpa_supplicant test driver", @@ -3309,14 +2675,4 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .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, -#ifdef CONFIG_P2P - .p2p_find = wpa_driver_test_p2p_find, - .p2p_stop_find = wpa_driver_test_p2p_stop_find, - .p2p_listen = wpa_driver_test_p2p_listen, - .p2p_connect = wpa_driver_test_p2p_connect, - .wps_success_cb = wpa_driver_test_wps_success_cb, - .p2p_group_formation_failed = - wpa_driver_test_p2p_group_formation_failed, - .p2p_set_params = wpa_driver_test_p2p_set_params, -#endif /* CONFIG_P2P */ }; diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 6e2e771b..e5734bdd 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -31,10 +31,6 @@ #include "driver.h" #include "driver_wext.h" -#ifdef ANDROID -#include "android_drv.h" -#endif /* ANDROID */ - static int wpa_driver_wext_flush_pmkid(void *priv); static int wpa_driver_wext_get_range(void *priv); static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); @@ -299,14 +295,6 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) } wpa_supplicant_event(ctx, EVENT_STKSTART, &data); #endif /* CONFIG_PEERKEY */ -#ifdef ANDROID - } else if (os_strncmp(custom, "STOP", 4) == 0) { - wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); - } else if (os_strncmp(custom, "START", 5) == 0) { - wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); - } else if (os_strncmp(custom, "HANG", 4) == 0) { - wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); -#endif /* ANDROID */ } } @@ -858,12 +846,6 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) drv->mlme_sock = -1; -#ifdef ANDROID - drv->errors = 0; - drv->driver_is_started = TRUE; - drv->bgscan_enabled = 0; -#endif /* ANDROID */ - if (wpa_driver_wext_finish_drv_init(drv) < 0) goto err3; @@ -1869,10 +1851,8 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) { struct iwreq iwr; const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; -#ifndef ANDROID u8 ssid[32]; int i; -#endif /* ANDROID */ /* * Only force-disconnect when the card is in infrastructure mode, @@ -1893,7 +1873,6 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) "selection on disconnect"); } -#ifndef ANDROID if (drv->cfg80211) { /* * cfg80211 supports SIOCSIWMLME commands, so there is @@ -1919,7 +1898,6 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " "SSID to disconnect"); } -#endif /* ANDROID */ } } @@ -1960,15 +1938,15 @@ static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, int wpa_driver_wext_cipher2wext(int cipher) { switch (cipher) { - case CIPHER_NONE: + case WPA_CIPHER_NONE: return IW_AUTH_CIPHER_NONE; - case CIPHER_WEP40: + case WPA_CIPHER_WEP40: return IW_AUTH_CIPHER_WEP40; - case CIPHER_TKIP: + case WPA_CIPHER_TKIP: return IW_AUTH_CIPHER_TKIP; - case CIPHER_CCMP: + case WPA_CIPHER_CCMP: return IW_AUTH_CIPHER_CCMP; - case CIPHER_WEP104: + case WPA_CIPHER_WEP104: return IW_AUTH_CIPHER_WEP104; default: return 0; @@ -1979,10 +1957,10 @@ int wpa_driver_wext_cipher2wext(int cipher) int wpa_driver_wext_keymgmt2wext(int keymgmt) { switch (keymgmt) { - case KEY_MGMT_802_1X: - case KEY_MGMT_802_1X_NO_WPA: + case WPA_KEY_MGMT_IEEE8021X: + case WPA_KEY_MGMT_IEEE8021X_NO_WPA: return IW_AUTH_KEY_MGMT_802_1X; - case KEY_MGMT_PSK: + case WPA_KEY_MGMT_PSK: return IW_AUTH_KEY_MGMT_PSK; default: return 0; @@ -2099,9 +2077,9 @@ int wpa_driver_wext_associate(void *priv, if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0) ret = -1; - value = params->key_mgmt_suite != KEY_MGMT_NONE || - params->pairwise_suite != CIPHER_NONE || - params->group_suite != CIPHER_NONE || + 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; if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_PRIVACY_INVOKED, value) < 0) @@ -2110,8 +2088,8 @@ int wpa_driver_wext_associate(void *priv, /* Allow unencrypted EAPOL messages even if pairwise keys are set when * not using WPA. IEEE 802.1X specifies that these frames are not * encrypted, but WPA encrypts them when pairwise keys are in use. */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK) + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK) allow_unencrypted_eapol = 0; else allow_unencrypted_eapol = 1; @@ -2338,129 +2316,6 @@ static const char * wext_get_radio_name(void *priv) } -#ifdef ANDROID - -static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd) -{ - struct iwreq iwr; - char buf[MAX_DRV_CMD_SIZE]; - int ret; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - os_memset(buf, 0, sizeof(buf)); - os_strlcpy(buf, cmd, sizeof(buf)); - - iwr.u.data.pointer = buf; - iwr.u.data.length = sizeof(buf); - - ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); - - if (ret < 0) { - wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, - cmd); - drv->errors++; - if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { - drv->errors = 0; - wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE - "HANGED"); - } - return ret; - } - - drv->errors = 0; - return 0; -} - - -static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params, - u32 interval) -{ - struct wpa_driver_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0, i = 0, bp; - char buf[WEXT_PNO_MAX_COMMAND_SIZE]; - - bp = WEXT_PNOSETUP_HEADER_SIZE; - os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); - buf[bp++] = WEXT_PNO_TLV_PREFIX; - buf[bp++] = WEXT_PNO_TLV_VERSION; - buf[bp++] = WEXT_PNO_TLV_SUBVERSION; - buf[bp++] = WEXT_PNO_TLV_RESERVED; - - while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { - /* - * Check that there is enough space needed for 1 more SSID, the - * other sections and null termination. - */ - if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + - WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) - break; - - wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", - params->ssids[i].ssid, - params->ssids[i].ssid_len); - buf[bp++] = WEXT_PNO_SSID_SECTION; - buf[bp++] = params->ssids[i].ssid_len; - os_memcpy(&buf[bp], params->ssids[i].ssid, - params->ssids[i].ssid_len); - bp += params->ssids[i].ssid_len; - i++; - } - - buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; - /* TODO: consider using interval parameter (interval in msec) instead - * of hardcoded value here */ - os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", - WEXT_PNO_SCAN_INTERVAL); - bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; - - buf[bp++] = WEXT_PNO_REPEAT_SECTION; - os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", - WEXT_PNO_REPEAT); - bp += WEXT_PNO_REPEAT_LENGTH; - - buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; - os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", - WEXT_PNO_MAX_REPEAT); - bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = buf; - iwr.u.data.length = bp; - - ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); - if (ret < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", - ret); - drv->errors++; - if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { - drv->errors = 0; - wpa_msg(drv->ctx, MSG_INFO, - WPA_EVENT_DRIVER_STATE "HANGED"); - } - return ret; - } - - drv->errors = 0; - drv->bgscan_enabled = 1; - - return android_wext_cmd(drv, "PNOFORCE 1"); -} - - -static int wext_stop_sched_scan(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - drv->bgscan_enabled = 0; - return android_wext_cmd(drv, "PNOFORCE 0"); -} - -#endif /* ANDROID */ - - const struct wpa_driver_ops wpa_driver_wext_ops = { .name = "wext", .desc = "Linux wireless extensions (generic)", @@ -2480,8 +2335,4 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .get_capa = wpa_driver_wext_get_capa, .set_operstate = wpa_driver_wext_set_operstate, .get_radio_name = wext_get_radio_name, -#ifdef ANDROID - .sched_scan = wext_sched_scan, - .stop_sched_scan = wext_stop_sched_scan, -#endif /* ANDROID */ }; diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index c4a5bc99..b4b5960a 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -44,12 +44,6 @@ struct wpa_driver_wext_data { int cfg80211; /* whether driver is using cfg80211 */ u8 max_level; - -#ifdef ANDROID - int errors; - int driver_is_started; - int bgscan_enabled; -#endif /* ANDROID */ }; int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index 04eb4fd1..446ab639 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -6,8 +6,9 @@ * See README for more details. */ -#include "includes.h" - +#include "utils/includes.h" +#include "utils/common.h" +#include "driver.h" #ifdef CONFIG_DRIVER_WEXT extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c index 6c60550f..2fa20b1e 100644 --- a/src/drivers/netlink.c +++ b/src/drivers/netlink.c @@ -1,6 +1,6 @@ /* * Netlink helper functions for driver wrappers - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -137,6 +137,35 @@ void netlink_deinit(struct netlink_data *netlink) os_free(netlink); } + +static const char * linkmode_str(int mode) +{ + switch (mode) { + case -1: + return "no change"; + case 0: + return "kernel-control"; + case 1: + return "userspace-control"; + } + return "?"; +} + + +static const char * operstate_str(int state) +{ + switch (state) { + case -1: + return "no change"; + case IF_OPER_DORMANT: + return "IF_OPER_DORMANT"; + case IF_OPER_UP: + return "IF_OPER_UP"; + } + return "?"; +} + + int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, int linkmode, int operstate) { @@ -184,8 +213,9 @@ int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, RTA_LENGTH(sizeof(char)); } - wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d", - linkmode, operstate); + wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)", + ifindex, linkmode, linkmode_str(linkmode), + operstate, operstate_str(operstate)); ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0); if (ret < 0) { diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index f752e982..91054fd6 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -581,7 +581,14 @@ * operation, %NL80211_ATTR_MAC contains the peer MAC address, and * %NL80211_ATTR_REASON_CODE the reason code to be used (only with * %NL80211_TDLS_TEARDOWN). - * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The + * %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be + * sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as + * 802.11 management frames, while TDLS action codes (802.11-2012 + * 8.5.13.1) will be encapsulated and sent as data frames. The currently + * supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES + * and the currently supported TDLS actions codes are given in + * &enum ieee80211_tdls_actioncode. * * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP * (or GO) interface (i.e. hostapd) to ask for unexpected frames to @@ -686,6 +693,21 @@ * other station that transmission must be blocked until the channel * switch is complete. * + * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified + * by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in + * %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in + * %NL80211_ATTR_VENDOR_DATA. + * For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is + * used in the wiphy data as a nested attribute containing descriptions + * (&struct nl80211_vendor_cmd_info) of the supported vendor commands. + * This may also be sent as an event with the same attributes. + * + * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values. + * The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If + * that attribute is not included, QoS mapping is disabled. Since this + * QoS mapping is relevant for IP packets, it is only valid during an + * association. This is cleared on disassociation and AP restart. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -853,6 +875,10 @@ enum nl80211_commands { NL80211_CMD_CHANNEL_SWITCH, + NL80211_CMD_VENDOR, + + NL80211_CMD_SET_QOS_MAP, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1508,6 +1534,27 @@ enum nl80211_commands { * to react to radar events, e.g. initiate a channel switch or leave the * IBSS network. * + * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports + * 5 MHz channel bandwidth. + * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports + * 10 MHz channel bandwidth. + * + * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode + * Notification Element based on association request when used with + * %NL80211_CMD_NEW_STATION; u8 attribute. + * + * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if + * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) + * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command + * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this + * attribute is also used for vendor command feature advertisement + * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy + * info, containing a nested array of possible events + * + * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This + * data is in the format defined for the payload of the QoS Map Set element + * in IEEE Std 802.11-2012, 8.4.2.97. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1824,6 +1871,18 @@ enum nl80211_attrs { NL80211_ATTR_HANDLE_DFS, + NL80211_ATTR_SUPPORT_5_MHZ, + NL80211_ATTR_SUPPORT_10_MHZ, + + NL80211_ATTR_OPMODE_NOTIF, + + NL80211_ATTR_VENDOR_ID, + NL80211_ATTR_VENDOR_SUBCMD, + NL80211_ATTR_VENDOR_DATA, + NL80211_ATTR_VENDOR_EVENTS, + + NL80211_ATTR_QOS_MAP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2224,10 +2283,9 @@ enum nl80211_band_attr { * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current * regulatory domain. - * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is - * permitted on this channel in current regulatory domain. - * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted - * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation + * are permitted on this channel, this includes sending probe + * requests, or modes of operation that require beaconing. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm @@ -2254,8 +2312,8 @@ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, NL80211_FREQUENCY_ATTR_FREQ, NL80211_FREQUENCY_ATTR_DISABLED, - NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, - NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_NO_IR, + __NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, NL80211_FREQUENCY_ATTR_DFS_STATE, @@ -2271,6 +2329,9 @@ enum nl80211_frequency_attr { }; #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER +#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR /** * enum nl80211_bitrate_attr - bitrate attributes @@ -2413,8 +2474,9 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_DFS: DFS support is required to be used * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links - * @NL80211_RRF_PASSIVE_SCAN: passive scan is required - * @NL80211_RRF_NO_IBSS: no IBSS is allowed + * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, + * this includes probe requests or modes of operation that require + * beaconing. */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2424,10 +2486,17 @@ enum nl80211_reg_rule_flags { NL80211_RRF_DFS = 1<<4, NL80211_RRF_PTP_ONLY = 1<<5, NL80211_RRF_PTMP_ONLY = 1<<6, - NL80211_RRF_PASSIVE_SCAN = 1<<7, - NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_NO_IR = 1<<7, + __NL80211_RRF_NO_IBSS = 1<<8, }; +#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 + +/* For backport compatibility with older userspace */ +#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) + /** * enum nl80211_dfs_regions - regulatory DFS regions * @@ -3058,21 +3127,35 @@ enum nl80211_key_attributes { * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with * 1 = 500 kbps) but without the IE length restriction (at most * %NL80211_MAX_SUPP_RATES in a single array). - * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection * in an array of MCS numbers. + * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, + * see &struct nl80211_txrate_vht * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ enum nl80211_tx_rate_attributes { __NL80211_TXRATE_INVALID, NL80211_TXRATE_LEGACY, - NL80211_TXRATE_MCS, + NL80211_TXRATE_HT, + NL80211_TXRATE_VHT, /* keep last */ __NL80211_TXRATE_AFTER_LAST, NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 }; +#define NL80211_TXRATE_MCS NL80211_TXRATE_HT +#define NL80211_VHT_NSS_MAX 8 + +/** + * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) + */ +struct nl80211_txrate_vht { + __u16 mcs[NL80211_VHT_NSS_MAX]; +}; + /** * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band @@ -3934,4 +4017,24 @@ enum nl80211_rxmgmt_flags { NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, }; +/* + * If this flag is unset, the lower 24 bits are an OUI, if set + * a Linux nl80211 vendor ID is used (no such IDs are allocated + * yet, so that's not valid so far) + */ +#define NL80211_VENDOR_ID_IS_LINUX 0x80000000 + +/** + * struct nl80211_vendor_cmd_info - vendor command data + * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the + * value is a 24-bit OUI; if it is set then a separately allocated ID + * may be used, but no such IDs are allocated yet. New IDs should be + * added to this file when needed. + * @subcmd: sub-command ID for the command + */ +struct nl80211_vendor_cmd_info { + __u32 vendor_id; + __u32 subcmd; +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h index 74d6ce58..62320880 100644 --- a/src/drivers/priv_netlink.h +++ b/src/drivers/priv_netlink.h @@ -69,6 +69,7 @@ (struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len))) #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) #define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0))) +#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0)) struct sockaddr_nl diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 3439c2df..98abd4ef 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1,6 +1,6 @@ /* * EAP peer state machines (RFC 4137) - * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -388,10 +388,11 @@ SM_STATE(EAP, METHOD) sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret, eapReqData); wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s " - "methodState=%s decision=%s", + "methodState=%s decision=%s eapRespData=%p", ret.ignore ? "TRUE" : "FALSE", eap_sm_method_state_txt(ret.methodState), - eap_sm_decision_txt(ret.decision)); + eap_sm_decision_txt(ret.decision), + sm->eapRespData); sm->ignore = ret.ignore; if (sm->ignore) @@ -432,8 +433,10 @@ SM_STATE(EAP, SEND_RESPONSE) sm->lastId = sm->reqId; sm->lastRespData = wpabuf_dup(sm->eapRespData); eapol_set_bool(sm, EAPOL_eapResp, TRUE); - } else + } else { + wpa_printf(MSG_DEBUG, "EAP: No eapRespData available"); sm->lastRespData = NULL; + } eapol_set_bool(sm, EAPOL_eapReq, FALSE); eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); } @@ -724,8 +727,19 @@ static void eap_peer_sm_step_local(struct eap_sm *sm) SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_METHOD: + /* + * Note: RFC 4137 uses methodState == DONE && decision == FAIL + * as the condition. eapRespData == NULL here is used to allow + * final EAP method response to be sent without having to change + * all methods to either use methodState MAY_CONT or leaving + * decision to something else than FAIL in cases where the only + * expected response is EAP-Failure. + */ if (sm->ignore) SM_ENTER(EAP, DISCARD); + else if (sm->methodState == METHOD_DONE && + sm->decision == DECISION_FAIL && !sm->eapRespData) + SM_ENTER(EAP, FAILURE); else SM_ENTER(EAP, SEND_RESPONSE); break; diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c index c71db5fd..864ea1d9 100644 --- a/src/eap_peer/eap_eke.c +++ b/src/eap_peer/eap_eke.c @@ -28,6 +28,10 @@ struct eap_eke_data { u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; struct wpabuf *msgs; + u8 dhgroup; /* forced DH group or 0 to allow all supported */ + u8 encr; /* forced encryption algorithm or 0 to allow all supported */ + u8 prf; /* forced PRF or 0 to allow all supported */ + u8 mac; /* forced MAC or 0 to allow all supported */ }; @@ -66,6 +70,7 @@ static void * eap_eke_init(struct eap_sm *sm) struct eap_eke_data *data; const u8 *identity, *password; size_t identity_len, password_len; + const char *phase1; password = eap_get_config_password(sm, &password_len); if (!password) { @@ -89,6 +94,39 @@ static void * eap_eke_init(struct eap_sm *sm) data->peerid_len = identity_len; } + phase1 = eap_get_config_phase1(sm); + if (phase1) { + const char *pos; + + pos = os_strstr(phase1, "dhgroup="); + if (pos) { + data->dhgroup = atoi(pos + 8); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u", + data->dhgroup); + } + + pos = os_strstr(phase1, "encr="); + if (pos) { + data->encr = atoi(pos + 5); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u", + data->encr); + } + + pos = os_strstr(phase1, "prf="); + if (pos) { + data->prf = atoi(pos + 4); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u", + data->prf); + } + + pos = os_strstr(phase1, "mac="); + if (pos) { + data->mac = atoi(pos + 4); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u", + data->mac); + } + } + return data; } @@ -226,16 +264,20 @@ static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data, i, pos[0], pos[1], pos[2], pos[3]); pos += 4; - if (!eap_eke_supp_dhgroup(*tmp)) + if ((data->dhgroup && data->dhgroup != *tmp) || + !eap_eke_supp_dhgroup(*tmp)) continue; tmp++; - if (!eap_eke_supp_encr(*tmp)) + if ((data->encr && data->encr != *tmp) || + !eap_eke_supp_encr(*tmp)) continue; tmp++; - if (!eap_eke_supp_prf(*tmp)) + if ((data->prf && data->prf != *tmp) || + !eap_eke_supp_prf(*tmp)) continue; tmp++; - if (!eap_eke_supp_mac(*tmp)) + if ((data->mac && data->mac != *tmp) || + !eap_eke_supp_mac(*tmp)) continue; prop = tmp - 3; diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c index 8a0644d0..5b023c79 100644 --- a/src/eap_peer/eap_gpsk.c +++ b/src/eap_peer/eap_gpsk.c @@ -1,6 +1,6 @@ /* * EAP peer method: EAP-GPSK (RFC 5433) - * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -33,6 +33,7 @@ struct eap_gpsk_data { int specifier; /* CSuite/Specifier */ u8 *psk; size_t psk_len; + u16 forced_cipher; /* force cipher or 0 to allow all supported */ }; @@ -80,6 +81,7 @@ static void * eap_gpsk_init(struct eap_sm *sm) struct eap_gpsk_data *data; const u8 *identity, *password; size_t identity_len, password_len; + const char *phase1; password = eap_get_config_password(sm, &password_len); if (password == NULL) { @@ -103,6 +105,18 @@ static void * eap_gpsk_init(struct eap_sm *sm) data->id_peer_len = identity_len; } + phase1 = eap_get_config_phase1(sm); + if (phase1) { + const char *pos; + + pos = os_strstr(phase1, "cipher="); + if (pos) { + data->forced_cipher = atoi(pos + 7); + wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u", + data->forced_cipher); + } + } + data->psk = os_malloc(password_len); if (data->psk == NULL) { eap_gpsk_deinit(sm, data); @@ -195,7 +209,9 @@ static int eap_gpsk_select_csuite(struct eap_sm *sm, i, vendor, specifier); if (data->vendor == EAP_GPSK_VENDOR_IETF && data->specifier == EAP_GPSK_CIPHER_RESERVED && - eap_gpsk_supported_ciphersuite(vendor, specifier)) { + eap_gpsk_supported_ciphersuite(vendor, specifier) && + (!data->forced_cipher || data->forced_cipher == specifier)) + { data->vendor = vendor; data->specifier = specifier; } @@ -273,6 +289,7 @@ static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm, pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list, &csuite_list_len, pos, end); if (pos == NULL) { + ret->methodState = METHOD_DONE; eap_gpsk_state(data, FAILURE); return NULL; } diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c index 09a655ec..2d7841dd 100644 --- a/src/eap_peer/eap_ikev2.c +++ b/src/eap_peer/eap_ikev2.c @@ -1,6 +1,6 @@ /* * EAP-IKEv2 peer (RFC 5106) - * Copyright (c) 2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2007-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -60,6 +60,7 @@ static void * eap_ikev2_init(struct eap_sm *sm) struct eap_ikev2_data *data; const u8 *identity, *password; size_t identity_len, password_len; + int fragment_size; identity = eap_get_config_identity(sm, &identity_len); if (identity == NULL) { @@ -71,7 +72,11 @@ static void * eap_ikev2_init(struct eap_sm *sm) if (data == NULL) return NULL; data->state = WAIT_START; - data->fragment_size = IKEV2_FRAGMENT_SIZE; + fragment_size = eap_get_config_fragment_size(sm); + if (fragment_size <= 0) + data->fragment_size = IKEV2_FRAGMENT_SIZE; + else + data->fragment_size = fragment_size; data->ikev2.state = SA_INIT; data->ikev2.peer_auth = PEER_AUTH_SECRET; data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 3b932090..8634f754 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -22,7 +22,6 @@ /* Maximum supported PEAP version * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt */ #define EAP_PEAP_VERSION 1 @@ -315,8 +314,6 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm, len[1] = 1; tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - if (data->peap_version >= 2) - tlv_type |= EAP_TLV_TYPE_MANDATORY; wpabuf_put_be16(buf, tlv_type); wpabuf_put_be16(buf, 56); @@ -580,33 +577,6 @@ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, } -static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) -{ - struct wpabuf *e; - struct eap_tlv_hdr *tlv; - - if (buf == NULL) - return NULL; - - /* Encapsulate EAP packet in EAP-Payload TLV */ - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); - e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); - if (e == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " - "for TLV encapsulation"); - wpabuf_free(buf); - return NULL; - } - tlv = wpabuf_put(e, sizeof(*tlv)); - tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_EAP_PAYLOAD_TLV); - tlv->length = host_to_be16(wpabuf_len(buf)); - wpabuf_put_buf(e, buf); - wpabuf_free(buf); - return e; -} - - static int eap_peap_phase2_request(struct eap_sm *sm, struct eap_peap_data *data, struct eap_method_ret *ret, @@ -837,49 +807,6 @@ continue_req: in_decrypted = nmsg; } - if (data->peap_version >= 2) { - struct eap_tlv_hdr *tlv; - struct wpabuf *nmsg; - - if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " - "EAP TLV"); - wpabuf_free(in_decrypted); - return 0; - } - tlv = wpabuf_mhead(in_decrypted); - if ((be_to_host16(tlv->tlv_type) & 0x3fff) != - EAP_TLV_EAP_PAYLOAD_TLV) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); - wpabuf_free(in_decrypted); - return 0; - } - if (sizeof(*tlv) + be_to_host16(tlv->length) > - wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " - "length"); - wpabuf_free(in_decrypted); - return 0; - } - hdr = (struct eap_hdr *) (tlv + 1); - if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " - "EAP packet in EAP TLV"); - wpabuf_free(in_decrypted); - return 0; - } - - nmsg = wpabuf_alloc(be_to_host16(hdr->length)); - if (nmsg == NULL) { - wpabuf_free(in_decrypted); - return 0; - } - - wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); - wpabuf_free(in_decrypted); - in_decrypted = nmsg; - } - hdr = wpabuf_mhead(in_decrypted); if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " @@ -996,11 +923,6 @@ continue_req: wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", resp); /* PEAP version changes */ - if (data->peap_version >= 2) { - resp = eap_peapv2_tlv_eap_payload(resp); - if (resp == NULL) - return -1; - } if (wpabuf_len(resp) >= 5 && wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && eap_get_type(resp) == EAP_TYPE_TLV) @@ -1091,7 +1013,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, * label, "client EAP encryption", instead. Use the old * label by default, but allow it to be configured with * phase1 parameter peaplabel=1. */ - if (data->peap_version > 1 || data->force_new_label) + if (data->force_new_label) label = "client PEAP encryption"; else label = "client EAP encryption"; diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index 267d0a5c..fef47837 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -81,6 +81,7 @@ static void * eap_pwd_init(struct eap_sm *sm) struct eap_pwd_data *data; const u8 *identity, *password; size_t identity_len, password_len; + int fragment_size; password = eap_get_config_password(sm, &password_len); if (password == NULL) { @@ -127,7 +128,11 @@ static void * eap_pwd_init(struct eap_sm *sm) data->out_frag_pos = data->in_frag_pos = 0; data->inbuf = data->outbuf = NULL; - data->mtu = 1020; /* default from RFC 5931, make it configurable! */ + fragment_size = eap_get_config_fragment_size(sm); + if (fragment_size <= 0) + data->mtu = 1020; /* default from RFC 5931 */ + else + data->mtu = fragment_size; data->state = PWD_ID_Req; diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c index fcf4712a..1ccc3523 100644 --- a/src/eap_peer/ikev2.c +++ b/src/eap_peer/ikev2.c @@ -1257,6 +1257,7 @@ static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) wpabuf_free(msg); return NULL; } + wpabuf_free(plain); data->state = IKEV2_FAILED; } else { /* HDR, N */ diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index 68253c43..defcb3c0 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -22,7 +22,6 @@ /* Maximum supported PEAP version * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt */ #define EAP_PEAP_VERSION 1 @@ -99,33 +98,6 @@ static void eap_peap_state(struct eap_peap_data *data, int state) } -static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) -{ - struct wpabuf *e; - struct eap_tlv_hdr *tlv; - - if (buf == NULL) - return NULL; - - /* Encapsulate EAP packet in EAP-Payload TLV */ - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); - e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); - if (e == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " - "for TLV encapsulation"); - wpabuf_free(buf); - return NULL; - } - tlv = wpabuf_put(e, sizeof(*tlv)); - tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_EAP_PAYLOAD_TLV); - tlv->length = host_to_be16(wpabuf_len(buf)); - wpabuf_put_buf(e, buf); - wpabuf_free(buf); - return e; -} - - static void eap_peap_req_success(struct eap_sm *sm, struct eap_peap_data *data) { @@ -239,8 +211,6 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, return NULL; } buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); - if (data->peap_version >= 2 && buf) - buf = eap_peapv2_tlv_eap_payload(buf); if (buf == NULL) return NULL; @@ -425,8 +395,6 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, len[1] = 1; tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - if (data->peap_version >= 2) - tlv_type |= EAP_TLV_TYPE_MANDATORY; wpabuf_put_be16(buf, tlv_type); wpabuf_put_be16(buf, 56); @@ -505,8 +473,7 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) return eap_peap_build_start(sm, data, id); case PHASE1: case PHASE1_ID2: - if (data->peap_version < 2 && - tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " "starting Phase2"); eap_peap_state(data, PHASE2_START); @@ -1079,47 +1046,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm, wpabuf_free(in_decrypted); in_decrypted = nbuf; - } else if (data->peap_version >= 2) { - struct eap_tlv_hdr *tlv; - struct wpabuf *nmsg; - - if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " - "EAP TLV"); - wpabuf_free(in_decrypted); - return; - } - tlv = wpabuf_mhead(in_decrypted); - if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) != - EAP_TLV_EAP_PAYLOAD_TLV) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); - wpabuf_free(in_decrypted); - return; - } - if (sizeof(*tlv) + be_to_host16(tlv->length) > - wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " - "length"); - wpabuf_free(in_decrypted); - return; - } - hdr = (struct eap_hdr *) (tlv + 1); - if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " - "EAP packet in EAP TLV"); - wpabuf_free(in_decrypted); - return; - } - - nmsg = wpabuf_alloc(be_to_host16(hdr->length)); - if (nmsg == NULL) { - wpabuf_free(in_decrypted); - return; - } - - wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); - wpabuf_free(in_decrypted); - in_decrypted = nmsg; } hdr = wpabuf_head(in_decrypted); @@ -1168,53 +1094,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm, } -static int eap_peapv2_start_phase2(struct eap_sm *sm, - struct eap_peap_data *data) -{ - struct wpabuf *buf, *buf2; - - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " - "payload in the same message"); - eap_peap_state(data, PHASE1_ID2); - if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY)) - return -1; - - /* TODO: which Id to use here? */ - buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6); - if (buf == NULL) - return -1; - - buf2 = eap_peapv2_tlv_eap_payload(buf); - if (buf2 == NULL) - return -1; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); - - buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, - buf2); - wpabuf_free(buf2); - - if (buf == NULL) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " - "data"); - return -1; - } - - wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", - buf); - - /* Append TLS data into the pending buffer after the Server Finished */ - if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) { - wpabuf_free(buf); - return -1; - } - wpabuf_put_buf(data->ssl.tls_out, buf); - wpabuf_free(buf); - - return 0; -} - - static int eap_peap_process_version(struct eap_sm *sm, void *priv, int peer_version) { @@ -1249,14 +1128,6 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv, eap_peap_state(data, FAILURE); break; } - - if (data->peap_version >= 2 && - tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - if (eap_peapv2_start_phase2(sm, data)) { - eap_peap_state(data, FAILURE); - break; - } - } break; case PHASE2_START: eap_peap_state(data, PHASE2_ID); diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c index 345c7887..45660ed7 100644 --- a/src/eap_server/eap_sim_db.c +++ b/src/eap_server/eap_sim_db.c @@ -38,7 +38,6 @@ struct eap_sim_db_pending { char imsi[20]; enum { PENDING, SUCCESS, FAILURE } state; void *cb_session_ctx; - struct os_time timestamp; int aka; union { struct { @@ -935,7 +934,6 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, if (entry == NULL) return EAP_SIM_DB_FAILURE; - os_get_time(&entry->timestamp); os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); entry->cb_session_ctx = cb_session_ctx; entry->state = PENDING; @@ -1395,7 +1393,6 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, if (entry == NULL) return EAP_SIM_DB_FAILURE; - os_get_time(&entry->timestamp); entry->aka = 1; os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); entry->cb_session_ctx = cb_session_ctx; diff --git a/src/eapol_auth/eapol_auth_dump.c b/src/eapol_auth/eapol_auth_dump.c index b6e0b137..6c6969b5 100644 --- a/src/eapol_auth/eapol_auth_dump.c +++ b/src/eapol_auth/eapol_auth_dump.c @@ -1,6 +1,6 @@ /* * IEEE 802.1X-2004 Authenticator - State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -118,108 +118,172 @@ static inline const char * ctrl_dir_state_txt(int s) } -void eapol_auth_dump_state(FILE *f, const char *prefix, - struct eapol_state_machine *sm) +int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf, + size_t buflen) { - fprintf(f, "%sEAPOL state machine:\n", prefix); - fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix, - sm->aWhile, sm->quietWhile, sm->reAuthWhen); + char *pos, *end; + int ret; + + pos = buf; + end = pos + buflen; + + ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n" + "reAuthWhen=%d\n", + sm->aWhile, sm->quietWhile, sm->reAuthWhen); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + #define _SB(b) ((b) ? "TRUE" : "FALSE") - fprintf(f, - "%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n" - "%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n" - "%s eapSuccess=%s eapTimeout=%s initialize=%s " - "keyAvailable=%s\n" - "%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n" - "%s portEnabled=%s portValid=%s reAuthenticate=%s\n", - prefix, _SB(sm->authAbort), _SB(sm->authFail), - port_state_txt(sm->authPortStatus), _SB(sm->authStart), - prefix, _SB(sm->authTimeout), _SB(sm->authSuccess), - _SB(sm->eap_if->eapFail), _SB(sm->eapolEap), - prefix, _SB(sm->eap_if->eapSuccess), - _SB(sm->eap_if->eapTimeout), - _SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable), - prefix, _SB(sm->keyDone), _SB(sm->keyRun), - _SB(sm->keyTxEnabled), port_type_txt(sm->portControl), - prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid), - _SB(sm->reAuthenticate)); - - fprintf(f, "%s Authenticator PAE:\n" - "%s state=%s\n" - "%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n" - "%s portMode=%s reAuthCount=%d\n" - "%s quietPeriod=%d reAuthMax=%d\n" - "%s authEntersConnecting=%d\n" - "%s authEapLogoffsWhileConnecting=%d\n" - "%s authEntersAuthenticating=%d\n" - "%s authAuthSuccessesWhileAuthenticating=%d\n" - "%s authAuthTimeoutsWhileAuthenticating=%d\n" - "%s authAuthFailWhileAuthenticating=%d\n" - "%s authAuthEapStartsWhileAuthenticating=%d\n" - "%s authAuthEapLogoffWhileAuthenticating=%d\n" - "%s authAuthReauthsWhileAuthenticated=%d\n" - "%s authAuthEapStartsWhileAuthenticated=%d\n" - "%s authAuthEapLogoffWhileAuthenticated=%d\n", - prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix, - _SB(sm->eapolLogoff), _SB(sm->eapolStart), - _SB(sm->eap_if->eapRestart), - prefix, port_type_txt(sm->portMode), sm->reAuthCount, - prefix, sm->quietPeriod, sm->reAuthMax, - prefix, sm->authEntersConnecting, - prefix, sm->authEapLogoffsWhileConnecting, - prefix, sm->authEntersAuthenticating, - prefix, sm->authAuthSuccessesWhileAuthenticating, - prefix, sm->authAuthTimeoutsWhileAuthenticating, - prefix, sm->authAuthFailWhileAuthenticating, - prefix, sm->authAuthEapStartsWhileAuthenticating, - prefix, sm->authAuthEapLogoffWhileAuthenticating, - prefix, sm->authAuthReauthsWhileAuthenticated, - prefix, sm->authAuthEapStartsWhileAuthenticated, - prefix, sm->authAuthEapLogoffWhileAuthenticated); - - fprintf(f, "%s Backend Authentication:\n" - "%s state=%s\n" - "%s eapNoReq=%s eapReq=%s eapResp=%s\n" - "%s serverTimeout=%d\n" - "%s backendResponses=%d\n" - "%s backendAccessChallenges=%d\n" - "%s backendOtherRequestsToSupplicant=%d\n" - "%s backendAuthSuccesses=%d\n" - "%s backendAuthFails=%d\n", - prefix, prefix, - be_auth_state_txt(sm->be_auth_state), - prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq), - _SB(sm->eap_if->eapResp), - prefix, sm->serverTimeout, - prefix, sm->backendResponses, - prefix, sm->backendAccessChallenges, - prefix, sm->backendOtherRequestsToSupplicant, - prefix, sm->backendAuthSuccesses, - prefix, sm->backendAuthFails); - - fprintf(f, "%s Reauthentication Timer:\n" - "%s state=%s\n" - "%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix, - reauth_timer_state_txt(sm->reauth_timer_state), prefix, - sm->reAuthPeriod, _SB(sm->reAuthEnabled)); - - fprintf(f, "%s Authenticator Key Transmit:\n" - "%s state=%s\n", prefix, prefix, - auth_key_tx_state_txt(sm->auth_key_tx_state)); - - fprintf(f, "%s Key Receive:\n" - "%s state=%s\n" - "%s rxKey=%s\n", prefix, prefix, - key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey)); - - fprintf(f, "%s Controlled Directions:\n" - "%s state=%s\n" - "%s adminControlledDirections=%s " - "operControlledDirections=%s\n" - "%s operEdge=%s\n", prefix, prefix, - ctrl_dir_state_txt(sm->ctrl_dir_state), - prefix, ctrl_dir_txt(sm->adminControlledDirections), - ctrl_dir_txt(sm->operControlledDirections), - prefix, _SB(sm->operEdge)); + ret = os_snprintf(pos, end - pos, + "authAbort=%s\n" + "authFail=%s\n" + "authPortStatus=%s\n" + "authStart=%s\n" + "authTimeout=%s\n" + "authSuccess=%s\n" + "eapFail=%s\n" + "eapolEap=%s\n" + "eapSuccess=%s\n" + "eapTimeout=%s\n" + "initialize=%s\n" + "keyAvailable=%s\n" + "keyDone=%s\n" + "keyRun=%s\n" + "keyTxEnabled=%s\n" + "portControl=%s\n" + "portEnabled=%s\n" + "portValid=%s\n" + "reAuthenticate=%s\n", + _SB(sm->authAbort), + _SB(sm->authFail), + port_state_txt(sm->authPortStatus), + _SB(sm->authStart), + _SB(sm->authTimeout), + _SB(sm->authSuccess), + _SB(sm->eap_if->eapFail), + _SB(sm->eapolEap), + _SB(sm->eap_if->eapSuccess), + _SB(sm->eap_if->eapTimeout), + _SB(sm->initialize), + _SB(sm->eap_if->eapKeyAvailable), + _SB(sm->keyDone), _SB(sm->keyRun), + _SB(sm->keyTxEnabled), + port_type_txt(sm->portControl), + _SB(sm->eap_if->portEnabled), + _SB(sm->portValid), + _SB(sm->reAuthenticate)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "auth_pae_state=%s\n" + "eapolLogoff=%s\n" + "eapolStart=%s\n" + "eapRestart=%s\n" + "portMode=%s\n" + "reAuthCount=%d\n" + "quietPeriod=%d\n" + "reAuthMax=%d\n" + "authEntersConnecting=%d\n" + "authEapLogoffsWhileConnecting=%d\n" + "authEntersAuthenticating=%d\n" + "authAuthSuccessesWhileAuthenticating=%d\n" + "authAuthTimeoutsWhileAuthenticating=%d\n" + "authAuthFailWhileAuthenticating=%d\n" + "authAuthEapStartsWhileAuthenticating=%d\n" + "authAuthEapLogoffWhileAuthenticating=%d\n" + "authAuthReauthsWhileAuthenticated=%d\n" + "authAuthEapStartsWhileAuthenticated=%d\n" + "authAuthEapLogoffWhileAuthenticated=%d\n", + auth_pae_state_txt(sm->auth_pae_state), + _SB(sm->eapolLogoff), + _SB(sm->eapolStart), + _SB(sm->eap_if->eapRestart), + port_type_txt(sm->portMode), + sm->reAuthCount, + sm->quietPeriod, sm->reAuthMax, + sm->authEntersConnecting, + sm->authEapLogoffsWhileConnecting, + sm->authEntersAuthenticating, + sm->authAuthSuccessesWhileAuthenticating, + sm->authAuthTimeoutsWhileAuthenticating, + sm->authAuthFailWhileAuthenticating, + sm->authAuthEapStartsWhileAuthenticating, + sm->authAuthEapLogoffWhileAuthenticating, + sm->authAuthReauthsWhileAuthenticated, + sm->authAuthEapStartsWhileAuthenticated, + sm->authAuthEapLogoffWhileAuthenticated); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "be_auth_state=%s\n" + "eapNoReq=%s\n" + "eapReq=%s\n" + "eapResp=%s\n" + "serverTimeout=%d\n" + "backendResponses=%d\n" + "backendAccessChallenges=%d\n" + "backendOtherRequestsToSupplicant=%d\n" + "backendAuthSuccesses=%d\n" + "backendAuthFails=%d\n", + be_auth_state_txt(sm->be_auth_state), + _SB(sm->eap_if->eapNoReq), + _SB(sm->eap_if->eapReq), + _SB(sm->eap_if->eapResp), + sm->serverTimeout, + sm->backendResponses, + sm->backendAccessChallenges, + sm->backendOtherRequestsToSupplicant, + sm->backendAuthSuccesses, + sm->backendAuthFails); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "reauth_timer_state=%s\n" + "reAuthPeriod=%d\n" + "reAuthEnabled=%s\n", + reauth_timer_state_txt(sm->reauth_timer_state), + sm->reAuthPeriod, + _SB(sm->reAuthEnabled)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "auth_key_tx_state=%s\n", + auth_key_tx_state_txt(sm->auth_key_tx_state)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "key_rx_state=%s\n" + "rxKey=%s\n", + key_rx_state_txt(sm->key_rx_state), + _SB(sm->rxKey)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "ctrl_dir_state=%s\n" + "adminControlledDirections=%s\n" + "operControlledDirections=%s\n" + "operEdge=%s\n", + ctrl_dir_state_txt(sm->ctrl_dir_state), + ctrl_dir_txt(sm->adminControlledDirections), + ctrl_dir_txt(sm->operControlledDirections), + _SB(sm->operEdge)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; #undef _SB + + return pos - buf; } diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h index 3a0f4509..f0ff4644 100644 --- a/src/eapol_auth/eapol_auth_sm.h +++ b/src/eapol_auth/eapol_auth_sm.h @@ -83,8 +83,8 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, const char *identity, const char *radius_cui); void eapol_auth_free(struct eapol_state_machine *sm); void eapol_auth_step(struct eapol_state_machine *sm); -void eapol_auth_dump_state(FILE *f, const char *prefix, - struct eapol_state_machine *sm); +int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf, + size_t buflen); int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx); #endif /* EAPOL_AUTH_SM_H */ diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index 9d7aef04..05b9851f 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -137,6 +137,9 @@ struct eapol_sm { Boolean cached_pmk; Boolean unicast_key_received, broadcast_key_received; + + Boolean force_authorized_update; + #ifdef CONFIG_EAP_PROXY Boolean use_eap_proxy; struct eap_proxy_sm *eap_proxy; @@ -210,7 +213,6 @@ SM_STATE(SUPP_PAE, LOGOFF) SM_ENTRY(SUPP_PAE, LOGOFF); eapol_sm_txLogoff(sm); sm->logoffSent = TRUE; - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); } @@ -221,7 +223,6 @@ SM_STATE(SUPP_PAE, DISCONNECTED) sm->sPortMode = Auto; sm->startCount = 0; sm->logoffSent = FALSE; - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); sm->suppAbort = TRUE; @@ -286,7 +287,6 @@ SM_STATE(SUPP_PAE, HELD) SM_ENTRY(SUPP_PAE, HELD); sm->heldWhile = sm->heldPeriod; eapol_enable_timer_tick(sm); - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); sm->cb_status = EAPOL_CB_FAILURE; } @@ -295,7 +295,6 @@ SM_STATE(SUPP_PAE, HELD) SM_STATE(SUPP_PAE, AUTHENTICATED) { SM_ENTRY(SUPP_PAE, AUTHENTICATED); - sm->suppPortStatus = Authorized; eapol_sm_set_port_authorized(sm); sm->cb_status = EAPOL_CB_SUCCESS; } @@ -311,7 +310,6 @@ SM_STATE(SUPP_PAE, RESTART) SM_STATE(SUPP_PAE, S_FORCE_AUTH) { SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); - sm->suppPortStatus = Authorized; eapol_sm_set_port_authorized(sm); sm->sPortMode = ForceAuthorized; } @@ -320,7 +318,6 @@ SM_STATE(SUPP_PAE, S_FORCE_AUTH) SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) { SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); sm->sPortMode = ForceUnauthorized; eapol_sm_txLogoff(sm); @@ -879,14 +876,24 @@ static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) static void eapol_sm_set_port_authorized(struct eapol_sm *sm) { - if (sm->ctx->port_cb) + int cb; + + cb = sm->suppPortStatus != Authorized || sm->force_authorized_update; + sm->force_authorized_update = FALSE; + sm->suppPortStatus = Authorized; + if (cb && sm->ctx->port_cb) sm->ctx->port_cb(sm->ctx->ctx, 1); } static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm) { - if (sm->ctx->port_cb) + int cb; + + cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update; + sm->force_authorized_update = FALSE; + sm->suppPortStatus = Unauthorized; + if (cb && sm->ctx->port_cb) sm->ctx->port_cb(sm->ctx->ctx, 0); } @@ -1370,6 +1377,8 @@ void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) return; wpa_printf(MSG_DEBUG, "EAPOL: External notification - " "portEnabled=%d", enabled); + if (sm->portEnabled != enabled) + sm->force_authorized_update = TRUE; sm->portEnabled = enabled; eapol_sm_step(sm); } @@ -1608,7 +1617,6 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm) return; sm->cached_pmk = FALSE; sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); /* Make sure we do not start sending EAPOL-Start frames first, but @@ -2002,6 +2010,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) #endif /* CONFIG_EAP_PROXY */ /* Initialize EAPOL state machines */ + sm->force_authorized_update = TRUE; sm->initialize = TRUE; eapol_sm_step(sm); sm->initialize = FALSE; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index e77563bb..61cafe43 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -78,10 +78,10 @@ int p2p_connection_in_progress(struct p2p_data *p2p) static void p2p_expire_peers(struct p2p_data *p2p) { struct p2p_device *dev, *n; - struct os_time now; + struct os_reltime now; size_t i; - os_get_time(&now); + os_get_reltime(&now); dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) { if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec) continue; @@ -93,7 +93,7 @@ static void p2p_expire_peers(struct p2p_data *p2p) * We are connected as a client to a group in which the * peer is the GO, so do not expire the peer entry. */ - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); continue; } @@ -107,7 +107,7 @@ static void p2p_expire_peers(struct p2p_data *p2p) * The peer is connected as a client in a group where * we are the GO, so do not expire the peer entry. */ - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); continue; } @@ -170,10 +170,6 @@ static const char * p2p_state_txt(int state) return "INVITE"; case P2P_INVITE_LISTEN: return "INVITE_LISTEN"; - case P2P_SEARCH_WHEN_READY: - return "SEARCH_WHEN_READY"; - case P2P_CONTINUE_SEARCH_WHEN_READY: - return "CONTINUE_SEARCH_WHEN_READY"; default: return "?"; } @@ -420,7 +416,7 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p, dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { count++; if (oldest == NULL || - os_time_before(&dev->last_seen, &oldest->last_seen)) + os_reltime_before(&dev->last_seen, &oldest->last_seen)) oldest = dev; } if (count + 1 > p2p->cfg->max_peers && oldest) { @@ -528,7 +524,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, os_memcpy(dev->interface_addr, cli->p2p_interface_addr, ETH_ALEN); - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN); os_memcpy(dev->member_in_go_iface, go_interface_addr, ETH_ALEN); @@ -644,14 +640,14 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, * Info attributes. */ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len, int scan_res) { struct p2p_device *dev; struct p2p_message msg; const u8 *p2p_dev_addr; int i; - struct os_time time_now; + struct os_reltime time_now; os_memset(&msg, 0, sizeof(msg)); if (p2p_parse_ies(ies, ies_len, &msg)) { @@ -685,7 +681,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, } if (rx_time == NULL) { - os_get_time(&time_now); + os_get_reltime(&time_now); rx_time = &time_now; } @@ -694,7 +690,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, * entry is newer than the one previously stored. */ if (dev->last_seen.sec > 0 && - os_time_before(rx_time, &dev->last_seen)) { + os_reltime_before(rx_time, &dev->last_seen)) { p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)", (unsigned int) rx_time->sec, (unsigned int) rx_time->usec, @@ -704,7 +700,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, return -1; } - os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_time)); + os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime)); dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY); @@ -932,9 +928,6 @@ static void p2p_search(struct p2p_data *p2p) if (res < 0) { p2p_dbg(p2p, "Scan request failed"); p2p_continue_find(p2p); - } else if (res == 1) { - p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes"); - p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY); } else { p2p_dbg(p2p, "Running p2p_scan"); p2p->p2p_scan_running = 1; @@ -1038,7 +1031,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, int res; p2p_dbg(p2p, "Starting find (type=%d)", type); - os_get_time(&p2p->find_start); + os_get_reltime(&p2p->find_start); if (p2p->p2p_scan_running) { p2p_dbg(p2p, "p2p_scan is already running"); } @@ -1097,11 +1090,9 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, p2p, NULL); - } else if (res == 1) { - p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes"); - res = 0; - p2p_set_state(p2p, P2P_SEARCH_WHEN_READY); - eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); + } else if (p2p->p2p_scan_running) { + p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running"); + /* wait for the previous p2p_scan to complete */ } else { p2p_dbg(p2p, "Failed to start p2p_scan"); p2p_set_state(p2p, P2P_IDLE); @@ -1112,34 +1103,12 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, } -int p2p_other_scan_completed(struct p2p_data *p2p) -{ - if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) { - p2p_set_state(p2p, P2P_SEARCH); - p2p_search(p2p); - return 1; - } - if (p2p->state != P2P_SEARCH_WHEN_READY) - return 0; - p2p_dbg(p2p, "Starting pending P2P find now that previous scan was completed"); - if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type, - p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, p2p->search_delay) < 0) { - p2p->cfg->find_stopped(p2p->cfg->cb_ctx); - return 0; - } - return 1; -} - - void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) { p2p_dbg(p2p, "Stopping find"); eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); p2p_clear_timeout(p2p); - if (p2p->state == P2P_SEARCH || - p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY || - p2p->state == P2P_SEARCH_WHEN_READY) + if (p2p->state == P2P_SEARCH) p2p->cfg->find_stopped(p2p->cfg->cb_ctx); p2p_set_state(p2p, P2P_IDLE); p2p_free_req_dev_types(p2p); @@ -1527,7 +1496,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, struct p2p_device *dev, struct p2p_message *msg) { - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); p2p_copy_wps_info(p2p, dev, 0, msg); @@ -1866,7 +1835,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, if (dev) { if (dev->country[0] == 0 && msg.listen_channel) os_memcpy(dev->country, msg.listen_channel, 3); - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); p2p_parse_free(&msg); return; /* already known */ } @@ -1877,7 +1846,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, return; } - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); dev->flags |= P2P_DEV_PROBE_REQ_ONLY; if (msg.listen_channel) { @@ -1911,7 +1880,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, dev = p2p_get_device(p2p, addr); if (dev) { - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); return dev; /* already known */ } @@ -2868,10 +2837,10 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success) int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len) { - if (os_time_before(rx_time, &p2p->find_start)) { + if (os_reltime_before(rx_time, &p2p->find_start)) { /* * The driver may have cached (e.g., in cfg80211 BSS table) the * scan results for relatively long time. To avoid reporting @@ -3467,10 +3436,6 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) case P2P_INVITE_LISTEN: p2p_timeout_invite_listen(p2p); break; - case P2P_SEARCH_WHEN_READY: - break; - case P2P_CONTINUE_SEARCH_WHEN_READY: - break; } } @@ -3553,7 +3518,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info, struct p2p_device *dev; int res; char *pos, *end; - struct os_time now; + struct os_reltime now; if (info == NULL) return -1; @@ -3564,7 +3529,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info, pos = buf; end = buf + buflen; - os_get_time(&now); + os_get_reltime(&now); res = os_snprintf(pos, end - pos, "age=%d\n" "listen_freq=%d\n" @@ -3868,6 +3833,11 @@ static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da, return; } + if (p2p->cfg->presence_resp) { + p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status, + msg.noa, msg.noa_len); + } + if (*msg.status) { p2p_dbg(p2p, "P2P Presence Request was rejected: status %u", *msg.status); @@ -4276,8 +4246,7 @@ int p2p_in_progress(struct p2p_data *p2p) { if (p2p == NULL) return 0; - if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY || - p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) + if (p2p->state == P2P_SEARCH) return 2; return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING; } @@ -4293,13 +4262,6 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, } -void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay) -{ - if (p2p && p2p->search_delay < delay) - p2p->search_delay = delay; -} - - #ifdef CONFIG_WIFI_DISPLAY static void p2p_update_wfd_ie_groups(struct p2p_data *p2p) diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 22d0c580..25a91e77 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -778,6 +778,17 @@ struct p2p_config { * or 0 if not. */ int (*go_connected)(void *ctx, const u8 *dev_addr); + + /** + * presence_resp - Callback on Presence Response + * @ctx: Callback context from cb_ctx + * @src: Source address (GO's P2P Interface Address) + * @status: Result of the request (P2P_SC_*) + * @noa: Returned NoA value + * @noa_len: Length of the NoA buffer in octets + */ + void (*presence_resp)(void *ctx, const u8 *src, u8 status, + const u8 *noa, size_t noa_len); }; @@ -1245,7 +1256,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, * start of a pending operation, e.g., to start a pending GO negotiation. */ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len); /** @@ -1815,13 +1826,6 @@ int p2p_set_no_go_freq(struct p2p_data *p2p, */ int p2p_in_progress(struct p2p_data *p2p); -/** - * p2p_other_scan_completed - Notify completion of non-P2P scan - * @p2p: P2P module context from p2p_init() - * Returns: 0 if P2P module is idle or 1 if an operation was started - */ -int p2p_other_scan_completed(struct p2p_data *p2p); - const char * p2p_wps_method_text(enum p2p_wps_method method); /** @@ -1833,8 +1837,6 @@ const char * p2p_wps_method_text(enum p2p_wps_method method); void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, u8 client_timeout); -void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay); - int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie); int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie); int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 008651e4..0e688a96 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -1040,6 +1040,7 @@ fail: wpabuf_head(conf), wpabuf_len(conf), 0) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); p2p_go_neg_failed(p2p, dev, -1); + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); } wpabuf_free(conf); if (status != P2P_SC_SUCCESS) { diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index e980be68..fef223f7 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -23,7 +23,7 @@ enum p2p_go_state { */ struct p2p_device { struct dl_list list; - struct os_time last_seen; + struct os_reltime last_seen; int listen_freq; enum p2p_wps_method wps_method; @@ -205,16 +205,6 @@ struct p2p_data { * P2P_INVITE_LISTEN - Listen during Invite */ P2P_INVITE_LISTEN, - - /** - * P2P_SEARCH_WHEN_READY - Waiting to start Search - */ - P2P_SEARCH_WHEN_READY, - - /** - * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search - */ - P2P_CONTINUE_SEARCH_WHEN_READY, } state; /** @@ -403,7 +393,7 @@ struct p2p_data { u8 *find_dev_id; u8 find_dev_id_buf[ETH_ALEN]; - struct os_time find_start; /* time of last p2p_find start */ + struct os_reltime find_start; /* time of last p2p_find start */ struct p2p_group **groups; size_t num_groups; @@ -726,7 +716,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, struct p2p_device *dev, struct p2p_message *msg); int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len, int scan_res); struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr); struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 290c7c81..76259966 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -122,7 +122,7 @@ struct radius_msg_list { /** * last_attempt - Time of the last transmission attempt */ - struct os_time last_attempt; + struct os_reltime last_attempt; /** * shared_secret - Shared secret with the target RADIUS server @@ -351,7 +351,7 @@ static int radius_client_retransmit(struct radius_client_data *radius, HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", radius_msg_get_hdr(entry->msg)->identifier); - os_get_time(&entry->last_attempt); + os_get_reltime(&entry->last_attempt); buf = radius_msg_get_buf(entry->msg); if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) radius_client_handle_send_error(radius, s, entry->msg_type); @@ -373,7 +373,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) { struct radius_client_data *radius = eloop_ctx; struct hostapd_radius_servers *conf = radius->conf; - struct os_time now; + struct os_reltime now; os_time_t first; struct radius_msg_list *entry, *prev, *tmp; int auth_failover = 0, acct_failover = 0; @@ -383,7 +383,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) if (!entry) return; - os_get_time(&now); + os_get_reltime(&now); first = 0; prev = NULL; @@ -481,7 +481,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) static void radius_client_update_timeout(struct radius_client_data *radius) { - struct os_time now; + struct os_reltime now; os_time_t first; struct radius_msg_list *entry; @@ -497,7 +497,7 @@ static void radius_client_update_timeout(struct radius_client_data *radius) first = entry->next_try; } - os_get_time(&now); + os_get_reltime(&now); if (first < now.sec) first = now.sec; eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, @@ -536,7 +536,7 @@ static void radius_client_list_add(struct radius_client_data *radius, entry->msg_type = msg_type; entry->shared_secret = shared_secret; entry->shared_secret_len = shared_secret_len; - os_get_time(&entry->last_attempt); + os_get_reltime(&entry->last_attempt); entry->first_try = entry->last_attempt.sec; entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 1; @@ -692,7 +692,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) struct radius_rx_handler *handlers; size_t num_handlers, i; struct radius_msg_list *req, *prev_req; - struct os_time now; + struct os_reltime now; struct hostapd_radius_server *rconf; int invalid_authenticator = 0; @@ -772,7 +772,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) goto fail; } - os_get_time(&now); + os_get_reltime(&now); roundtrip = (now.sec - req->last_attempt.sec) * 100 + (now.usec - req->last_attempt.usec) / 10000; hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c index 418b1605..b2a27735 100644 --- a/src/radius/radius_das.c +++ b/src/radius/radius_das.c @@ -16,9 +16,6 @@ #include "radius_das.h" -extern int wpa_debug_level; - - struct radius_das_data { int sock; u8 *shared_secret; diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index fe197704..1063d65a 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -244,7 +244,7 @@ struct radius_server_data { /** * start_time - Timestamp of server start */ - struct os_time start_time; + struct os_reltime start_time; /** * counters - Statistics counters for server operations @@ -298,8 +298,6 @@ struct radius_server_data { }; -extern int wpa_debug_level; - #define RADIUS_DEBUG(args...) \ wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) #define RADIUS_ERROR(args...) \ @@ -1261,7 +1259,7 @@ radius_server_init(struct radius_server_conf *conf) if (data == NULL) return NULL; - os_get_time(&data->start_time); + os_get_reltime(&data->start_time); data->conf_ctx = conf->conf_ctx; data->eap_sim_db_priv = conf->eap_sim_db_priv; data->ssl_ctx = conf->ssl_ctx; @@ -1375,7 +1373,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, int ret, uptime; unsigned int idx; char *end, *pos; - struct os_time now; + struct os_reltime now; struct radius_client *cli; /* RFC 2619 - RADIUS Authentication Server MIB */ @@ -1386,7 +1384,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, pos = buf; end = buf + buflen; - os_get_time(&now); + os_get_reltime(&now); uptime = (now.sec - data->start_time.sec) * 100 + ((now.usec - data->start_time.usec) / 10000) % 100; ret = os_snprintf(pos, end - pos, diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c index 789ac255..cb86dfbc 100644 --- a/src/rsn_supp/peerkey.c +++ b/src/rsn_supp/peerkey.c @@ -516,7 +516,6 @@ static int wpa_supplicant_process_smk_m45( struct wpa_peerkey *peerkey; struct wpa_eapol_ie_parse kde; u32 lifetime; - struct os_time now; if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " @@ -568,10 +567,8 @@ static int wpa_supplicant_process_smk_m45( lifetime = WPA_GET_BE32(kde.lifetime); wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime); if (lifetime > 1000000000) - lifetime = 1000000000; /* avoid overflowing expiration time */ + lifetime = 1000000000; /* avoid overflowing eloop time */ peerkey->lifetime = lifetime; - os_get_time(&now); - peerkey->expiration = now.sec + lifetime; eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, sm, peerkey); @@ -736,7 +733,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, struct wpa_eapol_ie_parse *kde) { u32 lifetime; - struct os_time now; if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime)) return; @@ -755,8 +751,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, lifetime, peerkey->lifetime); peerkey->lifetime = lifetime; - os_get_time(&now); - peerkey->expiration = now.sec + lifetime; eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, sm, peerkey); @@ -1116,7 +1110,7 @@ void peerkey_deinit(struct wpa_sm *sm) while (peerkey) { prev = peerkey; peerkey = peerkey->next; - os_free(prev); + wpa_supplicant_peerkey_free(sm, prev); } sm->peerkey = NULL; } diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h index b8845f71..f420691a 100644 --- a/src/rsn_supp/peerkey.h +++ b/src/rsn_supp/peerkey.h @@ -24,7 +24,6 @@ struct wpa_peerkey { int smk_complete; u8 smkid[PMKID_LEN]; u32 lifetime; - os_time_t expiration; int cipher; /* Selected cipher (WPA_CIPHER_*) */ u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; int replay_counter_set; diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index 33fa1a29..09608153 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -53,9 +53,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; pmksa->pmksa = entry->next; @@ -80,13 +80,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { int sec; struct rsn_pmksa_cache_entry *entry; - struct os_time now; + struct os_reltime now; eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); if (pmksa->pmksa == NULL) return; - os_get_time(&now); + os_get_reltime(&now); sec = pmksa->pmksa->expiration - now.sec; if (sec < 0) sec = 0; @@ -125,7 +125,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos, *prev; - struct os_time now; + struct os_reltime now; if (pmk_len > PMK_LEN) return NULL; @@ -137,7 +137,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, entry->pmk_len = pmk_len; rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, wpa_key_mgmt_sha256(akmp)); - os_get_time(&now); + os_get_reltime(&now); entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; @@ -466,9 +466,9 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) int i, ret; char *pos = buf; struct rsn_pmksa_cache_entry *entry; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); ret = os_snprintf(pos, buf + len - pos, "Index / AA / PMKID / expiration (in seconds) / " "opportunistic\n"); diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index d4f86e6f..a294730d 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -688,10 +688,11 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, os_memcpy(gd.gtk, gtk, gtk_len); gd.gtk_len = gtk_len; - if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, - gtk_len, gtk_len, - &gd.key_rsc_len, &gd.alg) || - wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) { + if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED && + (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, + gtk_len, gtk_len, + &gd.key_rsc_len, &gd.alg) || + wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Failed to install GTK"); return -1; @@ -1112,7 +1113,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, } wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); - if (ie.gtk && + if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) { + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info & WPA_KEY_INFO_SECURE); + } else if (ie.gtk && wpa_supplicant_pairwise_gtk(sm, key, ie.gtk, ie.gtk_len, key_info) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, @@ -2094,6 +2098,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) */ void wpa_sm_notify_disassoc(struct wpa_sm *sm) { + peerkey_deinit(sm); rsn_preauth_deinit(sm); pmksa_cache_clear_current(sm); if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE) @@ -2705,3 +2710,24 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) return 0; } #endif /* CONFIG_WNM */ + + +#ifdef CONFIG_PEERKEY +int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, + const u8 *buf, size_t len) +{ + struct wpa_peerkey *peerkey; + + for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { + if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0) + break; + } + + if (!peerkey) + return 0; + + wpa_sm_rx_eapol(sm, src_addr, buf, len); + + return 1; +} +#endif /* CONFIG_PEERKEY */ diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index db7f0db8..e189a585 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -306,11 +306,19 @@ static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, #ifdef CONFIG_PEERKEY int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer); +int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, + const u8 *buf, size_t len); #else /* CONFIG_PEERKEY */ static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) { return -1; } + +static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, + const u8 *buf, size_t len) +{ + return 0; +} #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211R diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 3a40c96f..c8d8cfc8 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -207,6 +207,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); + else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE) + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); else { wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", sm->key_mgmt); @@ -400,8 +402,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, } } - if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { + if (!wpa_key_mgmt_ft(sm->key_mgmt)) { wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " "enabled for this connection"); return -1; @@ -526,8 +527,7 @@ int wpa_ft_is_completed(struct wpa_sm *sm) if (sm == NULL) return 0; - if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) + if (!wpa_key_mgmt_ft(sm->key_mgmt)) return 0; return sm->ft_completed; @@ -678,8 +678,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); - if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { + if (!wpa_key_mgmt_ft(sm->key_mgmt)) { wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " "enabled for this connection"); return -1; diff --git a/src/utils/common.c b/src/utils/common.c index 257bb6d4..39751d40 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -735,3 +735,95 @@ char * freq_range_list_str(const struct wpa_freq_range_list *list) return buf; } + + +int int_array_len(const int *a) +{ + int i; + for (i = 0; a && a[i]; i++) + ; + return i; +} + + +void int_array_concat(int **res, const int *a) +{ + int reslen, alen, i; + int *n; + + reslen = int_array_len(*res); + alen = int_array_len(a); + + n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + return; + } + for (i = 0; i <= alen; i++) + n[reslen + i] = a[i]; + *res = n; +} + + +static int freq_cmp(const void *a, const void *b) +{ + int _a = *(int *) a; + int _b = *(int *) b; + + if (_a == 0) + return 1; + if (_b == 0) + return -1; + return _a - _b; +} + + +void int_array_sort_unique(int *a) +{ + int alen; + int i, j; + + if (a == NULL) + return; + + alen = int_array_len(a); + qsort(a, alen, sizeof(int), freq_cmp); + + i = 0; + j = 1; + while (a[i] && a[j]) { + if (a[i] == a[j]) { + j++; + continue; + } + a[++i] = a[j++]; + } + if (a[i]) + i++; + a[i] = 0; +} + + +void int_array_add_unique(int **res, int a) +{ + int reslen; + int *n; + + for (reslen = 0; *res && (*res)[reslen]; reslen++) { + if ((*res)[reslen] == a) + return; /* already in the list */ + } + + n = os_realloc_array(*res, reslen + 2, sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + return; + } + + n[reslen] = a; + n[reslen + 1] = 0; + + *res = n; +} diff --git a/src/utils/common.h b/src/utils/common.h index 028a5eff..a85cc159 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -459,6 +459,14 @@ typedef u64 __bitwise le64; #endif /* __GNUC__ */ #endif /* __must_check */ +#ifndef __maybe_unused +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __maybe_unused __attribute__((unused)) +#else +#define __maybe_unused +#endif /* __GNUC__ */ +#endif /* __must_check */ + int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_compact_aton(const char *txt, u8 *addr); int hwaddr_aton2(const char *txt, u8 *addr); @@ -519,6 +527,11 @@ int freq_range_list_includes(const struct wpa_freq_range_list *list, unsigned int freq); char * freq_range_list_str(const struct wpa_freq_range_list *list); +int int_array_len(const int *a); +void int_array_concat(int **res, const int *a); +void int_array_sort_unique(int *a); +void int_array_add_unique(int **res, int a); + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) diff --git a/src/utils/eloop.c b/src/utils/eloop.c index e983edcf..f83a2327 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -623,10 +623,11 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } @@ -654,10 +655,11 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } diff --git a/src/utils/eloop.h b/src/utils/eloop.h index d3980fa4..07b8c0dc 100644 --- a/src/utils/eloop.h +++ b/src/utils/eloop.h @@ -229,7 +229,8 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler, * @handler: Matching callback function * @eloop_data: Matching eloop_data * @user_data: Matching user_data - * Returns: 1 if the timeout is depleted, 0 if no change is made + * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no + * timeout matched * * Find a registered matching <handler,eloop_data,user_data> timeout. If found, * deplete the timeout if remaining time is more than the requested time. @@ -245,7 +246,8 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, * @handler: Matching callback function * @eloop_data: Matching eloop_data * @user_data: Matching user_data - * Returns: 1 if the timeout is replenished, 0 if no change is made + * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no + * timeout matched * * Find a registered matching <handler,eloop_data,user_data> timeout. If found, * replenish the timeout if remaining time is less than the requested time. diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c index a1f99964..de47fb21 100644 --- a/src/utils/eloop_win.c +++ b/src/utils/eloop_win.c @@ -378,10 +378,11 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } @@ -409,10 +410,11 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 38ea8aa3..7846c1e5 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -375,19 +375,19 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, #endif /* CONFIG_ANDROID_LOG */ } -void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) +void wpa_hexdump(int level, const char *title, const void *buf, size_t len) { _wpa_hexdump(level, title, buf, len, 1); } -void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len) { _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); } -static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, +static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len, int show) { size_t i, llen; @@ -407,7 +407,7 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, /* can do ascii processing in userspace */ for (i = 0; i < len; i++) fprintf(wpa_debug_tracing_file, - " %02x", buf[i]); + " %02x", pos[i]); } fflush(wpa_debug_tracing_file); } @@ -495,13 +495,14 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, } -void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) +void wpa_hexdump_ascii(int level, const char *title, const void *buf, + size_t len) { _wpa_hexdump_ascii(level, title, buf, len, 1); } -void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len) { _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index 2ed1bd8e..50e8ae9d 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -11,6 +11,10 @@ #include "wpabuf.h" +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + /* Debugging function - conditional printf and hex dump. Driver wrappers can * use these for debugging purposes. */ @@ -77,7 +81,7 @@ PRINTF_FORMAT(2, 3); * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump. */ -void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); +void wpa_hexdump(int level, const char *title, const void *buf, size_t len); static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) @@ -99,7 +103,7 @@ static inline void wpa_hexdump_buf(int level, const char *title, * like wpa_hexdump(), but by default, does not include secret keys (passwords, * etc.) in debug output. */ -void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len); static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) @@ -121,7 +125,7 @@ static inline void wpa_hexdump_buf_key(int level, const char *title, * the hex numbers and ASCII characters (for printable range) are shown. 16 * bytes per line will be shown. */ -void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, +void wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len); /** @@ -138,7 +142,7 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by * default, does not include secret keys (passwords, etc.) in debug output. */ -void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len); /* diff --git a/src/wps/httpread.c b/src/wps/httpread.c index ad4f4a1d..b51d9757 100644 --- a/src/wps/httpread.c +++ b/src/wps/httpread.c @@ -67,8 +67,6 @@ struct httpread { int timeout_seconds; /* 0 or total duration timeout period */ /* dynamically used information follows */ - int sd_registered; /* nonzero if we need to unregister socket */ - int to_registered; /* nonzero if we need to unregister timeout */ int got_hdr; /* nonzero when header is finalized */ char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */ @@ -129,19 +127,6 @@ static int word_eq(char *s1, char *s2) } -/* convert hex to binary - * Requires that c have been previously tested true with isxdigit(). - */ -static int hex_value(int c) -{ - if (isdigit(c)) - return c - '0'; - if (islower(c)) - return 10 + c - 'a'; - return 10 + c - 'A'; -} - - static void httpread_timeout_handler(void *eloop_data, void *user_ctx); /* httpread_destroy -- if h is non-NULL, clean up @@ -156,12 +141,8 @@ void httpread_destroy(struct httpread *h) if (!h) return; - if (h->to_registered) - eloop_cancel_timeout(httpread_timeout_handler, NULL, h); - h->to_registered = 0; - if (h->sd_registered) - eloop_unregister_sock(h->sd, EVENT_TYPE_READ); - h->sd_registered = 0; + eloop_cancel_timeout(httpread_timeout_handler, NULL, h); + eloop_unregister_sock(h->sd, EVENT_TYPE_READ); os_free(h->body); os_free(h->uri); os_memset(h, 0, sizeof(*h)); /* aid debugging */ @@ -176,7 +157,6 @@ static void httpread_timeout_handler(void *eloop_data, void *user_ctx) { struct httpread *h = user_ctx; wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h); - h->to_registered = 0; /* is self-cancelling */ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT); } @@ -295,8 +275,7 @@ static int httpread_hdr_analyze(struct httpread *h) int c = *rawuri; if (c == '%' && isxdigit(rawuri[1]) && isxdigit(rawuri[2])) { - *uri++ = (hex_value(rawuri[1]) << 4) | - hex_value(rawuri[2]); + *uri++ = hex2byte(rawuri + 1); rawuri += 3; } else { *uri++ = c; @@ -703,15 +682,11 @@ got_file: * and just in case somehow we don't get destroyed right away, * unregister now. */ - if (h->sd_registered) - eloop_unregister_sock(h->sd, EVENT_TYPE_READ); - h->sd_registered = 0; + eloop_unregister_sock(h->sd, EVENT_TYPE_READ); /* The application can destroy us whenever they feel like... * cancel timeout. */ - if (h->to_registered) - eloop_cancel_timeout(httpread_timeout_handler, NULL, h); - h->to_registered = 0; + eloop_cancel_timeout(httpread_timeout_handler, NULL, h); (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); } @@ -749,21 +724,17 @@ struct httpread * httpread_create( h->max_bytes = max_bytes; h->timeout_seconds = timeout_seconds; - if (timeout_seconds > 0) { - if (eloop_register_timeout(timeout_seconds, 0, - httpread_timeout_handler, - NULL, h)) { - /* No way to recover (from malloc failure) */ - goto fail; - } - h->to_registered = 1; + if (timeout_seconds > 0 && + eloop_register_timeout(timeout_seconds, 0, + httpread_timeout_handler, NULL, h)) { + /* No way to recover (from malloc failure) */ + goto fail; } if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler, NULL, h)) { /* No way to recover (from malloc failure) */ goto fail; } - h->sd_registered = 1; return h; fail: diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index b2327544..336246ea 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -201,6 +201,11 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, #ifdef CONFIG_WPS2 u8 *len; +#ifdef CONFIG_WPS_TESTING + if (WPS_VERSION == 0x10) + return 0; +#endif /* CONFIG_WPS_TESTING */ + if (wpabuf_tailroom(msg) < 7 + 3 + (req_to_enroll ? 3 : 0) + (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0)) diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c index 1b12b5a1..fe736f32 100644 --- a/src/wps/wps_dev_attr.c +++ b/src/wps/wps_dev_attr.c @@ -409,25 +409,6 @@ int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands) } -void wps_device_data_dup(struct wps_device_data *dst, - const struct wps_device_data *src) -{ - if (src->device_name) - dst->device_name = os_strdup(src->device_name); - if (src->manufacturer) - dst->manufacturer = os_strdup(src->manufacturer); - if (src->model_name) - dst->model_name = os_strdup(src->model_name); - if (src->model_number) - dst->model_number = os_strdup(src->model_number); - if (src->serial_number) - dst->serial_number = os_strdup(src->serial_number); - os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN); - dst->os_version = src->os_version; - dst->rf_bands = src->rf_bands; -} - - void wps_device_data_free(struct wps_device_data *dev) { os_free(dev->device_name); diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h index 0158cdc3..f0169a79 100644 --- a/src/wps/wps_dev_attr.h +++ b/src/wps/wps_dev_attr.h @@ -29,8 +29,6 @@ int wps_process_device_attrs(struct wps_device_data *dev, struct wps_parse_attr *attr); int wps_process_os_version(struct wps_device_data *dev, const u8 *ver); int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands); -void wps_device_data_dup(struct wps_device_data *dst, - const struct wps_device_data *src); void wps_device_data_free(struct wps_device_data *dev); int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg, diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 56949970..e729617c 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -185,10 +185,8 @@ static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap) dl_list_del(&ap->list); wps_er_ap_free(ap); - if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) { - eloop_cancel_timeout(wps_er_deinit_finish, er, NULL); + if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) wps_er_deinit_finish(er, NULL); - } } @@ -1347,9 +1345,19 @@ static void wps_er_deinit_finish(void *eloop_data, void *user_ctx) struct wps_er *er = eloop_data; void (*deinit_done_cb)(void *ctx); void *deinit_done_ctx; + struct wps_er_ap *ap, *tmp; wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit"); + dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap, + list) { + wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it", + inet_ntoa(ap->addr), ap->location); + dl_list_del(&ap->list); + wps_er_ap_free(ap); + } + + eloop_cancel_timeout(wps_er_deinit_finish, er, NULL); deinit_done_cb = er->deinit_done_cb; deinit_done_ctx = er->deinit_done_ctx; os_free(er->ip_addr_text); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index ef176170..19490a15 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -82,7 +82,7 @@ struct wps_uuid_pin { #define PIN_LOCKED BIT(0) #define PIN_EXPIRES BIT(1) int flags; - struct os_time expiration; + struct os_reltime expiration; u8 enrollee_addr[ETH_ALEN]; }; @@ -113,7 +113,7 @@ struct wps_pbc_session { struct wps_pbc_session *next; u8 addr[ETH_ALEN]; u8 uuid_e[WPS_UUID_LEN]; - struct os_time timestamp; + struct os_reltime timestamp; }; @@ -183,7 +183,9 @@ struct wps_registrar { u8 p2p_dev_addr[ETH_ALEN]; u8 pbc_ignore_uuid[WPS_UUID_LEN]; - struct os_time pbc_ignore_start; +#ifdef WPS_WORKAROUNDS + struct os_reltime pbc_ignore_start; +#endif /* WPS_WORKAROUNDS */ }; @@ -311,9 +313,9 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e) { struct wps_pbc_session *pbc, *prev = NULL; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); pbc = reg->pbc_sessions; while (pbc) { @@ -347,7 +349,8 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg, pbc = pbc->next; while (pbc) { - if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { + if (os_reltime_expired(&now, &pbc->timestamp, + WPS_PBC_WALK_TIME)) { prev->next = NULL; wps_free_pbc_sessions(pbc); break; @@ -395,9 +398,9 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg, int count = 0; struct wps_pbc_session *pbc; struct wps_pbc_session *first = NULL; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap"); @@ -413,9 +416,9 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg, MAC2STR(pbc->addr)); wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", pbc->uuid_e, WPS_UUID_LEN); - if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { - wpa_printf(MSG_DEBUG, "WPS: PBC walk time has " - "expired"); + if (os_reltime_expired(&now, &pbc->timestamp, + WPS_PBC_WALK_TIME)) { + wpa_printf(MSG_DEBUG, "WPS: PBC walk time has expired"); break; } if (first && @@ -748,7 +751,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr, if (timeout) { p->flags |= PIN_EXPIRES; - os_get_time(&p->expiration); + os_get_reltime(&p->expiration); p->expiration.sec += timeout; } @@ -797,13 +800,13 @@ static void wps_registrar_remove_pin(struct wps_registrar *reg, static void wps_registrar_expire_pins(struct wps_registrar *reg) { struct wps_uuid_pin *pin, *prev; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) { if ((pin->flags & PIN_EXPIRES) && - os_time_before(&pin->expiration, &now)) { + os_reltime_before(&pin->expiration, &now)) { wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID", pin->uuid, WPS_UUID_LEN); wps_registrar_remove_pin(reg, pin); @@ -1037,7 +1040,9 @@ void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e, wps_registrar_remove_pbc_session(registrar, uuid_e, NULL); wps_registrar_pbc_completed(registrar); - os_get_time(®istrar->pbc_ignore_start); +#ifdef WPS_WORKAROUNDS + os_get_reltime(®istrar->pbc_ignore_start); +#endif /* WPS_WORKAROUNDS */ os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN); } else { wps_registrar_pin_completed(registrar); @@ -1140,9 +1145,9 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, #ifdef WPS_WORKAROUNDS if (reg->pbc_ignore_start.sec && os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) { - struct os_time now, dur; - os_get_time(&now); - os_time_sub(&now, ®->pbc_ignore_start, &dur); + struct os_reltime now, dur; + os_get_reltime(&now); + os_reltime_sub(&now, ®->pbc_ignore_start, &dur); if (dur.sec >= 0 && dur.sec < 5) { wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation " "based on Probe Request from the Enrollee " @@ -3189,7 +3194,9 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, wps->uuid_e, wps->p2p_dev_addr); wps_registrar_pbc_completed(wps->wps->registrar); - os_get_time(&wps->wps->registrar->pbc_ignore_start); +#ifdef WPS_WORKAROUNDS + os_get_reltime(&wps->wps->registrar->pbc_ignore_start); +#endif /* WPS_WORKAROUNDS */ os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e, WPS_UUID_LEN); } else { @@ -3446,7 +3453,7 @@ int wps_registrar_config_ap(struct wps_registrar *reg, struct wps_credential *cred) { #ifdef CONFIG_WPS2 - printf("encr_type=0x%x\n", cred->encr_type); + wpa_printf(MSG_DEBUG, "WPS: encr_type=0x%x", cred->encr_type); if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { if (cred->encr_type & WPS_ENCR_WEP) { diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index bea2b331..6fb3d4c5 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -432,23 +432,6 @@ static void subscr_addr_list_create(struct subscription *s, } -int send_wpabuf(int fd, struct wpabuf *buf) -{ - wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message", - (unsigned long) wpabuf_len(buf)); - errno = 0; - if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) != - (int) wpabuf_len(buf)) { - wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: " - "errno=%d (%s)", - errno, strerror(errno)); - return -1; - } - - return 0; -} - - static void wpabuf_put_property(struct wpabuf *buf, const char *name, const char *value) { @@ -480,14 +463,14 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm) "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n"; const char *format_tail = "</e:propertyset>\n"; - struct os_time now; + struct os_reltime now; if (dl_list_empty(&sm->subscriptions)) { /* optimize */ return; } - if (os_get_time(&now) == 0) { + if (os_get_reltime(&now) == 0) { if (now.sec != sm->last_event_sec) { sm->last_event_sec = now.sec; sm->num_events_in_sec = 1; diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h index 5c39f7ef..f289fe68 100644 --- a/src/wps/wps_upnp_i.h +++ b/src/wps/wps_upnp_i.h @@ -158,7 +158,6 @@ void subscription_destroy(struct subscription *s); struct subscription * subscription_find(struct upnp_wps_device_sm *sm, const u8 uuid[UUID_LEN]); void subscr_addr_delete(struct subscr_addr *a); -int send_wpabuf(int fd, struct wpabuf *buf); int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, u8 mac[ETH_ALEN]); diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 260c0ae4..2c709c33 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -10,11 +10,17 @@ export LIBDIR ?= /usr/local/lib/ export BINDIR ?= /usr/local/sbin/ PKG_CONFIG ?= pkg-config -CFLAGS += -I../src -CFLAGS += -I../src/utils +CFLAGS += -I$(abspath ../src) +CFLAGS += -I$(abspath ../src/utils) -include .config +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +CONFIG_WPS_TESTING=y +CONFIG_TDLS_TESTING=y +endif + BINALL=wpa_supplicant wpa_cli ifndef CONFIG_NO_WPA_PASSPHRASE @@ -1622,9 +1628,15 @@ eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \ -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init +ifdef CONFIG_CODE_COVERAGE +%.o: %.c + @$(E) " CC " $< + $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<) +else %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $< @$(E) " CC " $< +endif %.service: %.service.in sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ @@ -1676,6 +1688,10 @@ FIPSLD=$(FIPSDIR)/bin/fipsld fips: $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)" +lcov-html: wpa_supplicant.gcda + lcov -c -d .. > lcov.info + genhtml lcov.info --output-directory lcov-html + clean: $(MAKE) -C ../src clean $(MAKE) -C dbus clean @@ -1683,5 +1699,7 @@ clean: rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test rm -f wpa_priv rm -f nfc_pw_token + rm -f lcov.info + rm -rf lcov-html -include $(OBJS:%.o=%.d) diff --git a/wpa_supplicant/README b/wpa_supplicant/README index 8e9cc45f..7f88cd65 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1,7 +1,7 @@ WPA Supplicant ============== -Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with @@ -983,3 +983,71 @@ directory could be created before starting the wpa_supplicant and set to suitable mode to allow wpa_supplicant to create sockets there. Alternatively, other directory or abstract socket namespace could be used for the control interface. + + +External requests for radio control +----------------------------------- + +External programs can request wpa_supplicant to not start offchannel +operations during other tasks that may need exclusive control of the +radio. The RADIO_WORK control interface command can be used for this. + +"RADIO_WORK add <name> [freq=<MHz>] [timeout=<seconds>]" command can be +used to reserve a slot for radio access. If freq is specified, other +radio work items on the same channel may be completed in +parallel. Otherwise, all other radio work items are blocked during +execution. Timeout is set to 10 seconds by default to avoid blocking +wpa_supplicant operations for excessive time. If a longer (or shorter) +safety timeout is needed, that can be specified with the optional +timeout parameter. This command returns an identifier for the radio work +item. + +Once the radio work item has been started, "EXT-RADIO-WORK-START <id>" +event message is indicated that the external processing can start. Once +the operation has been completed, "RADIO_WORK done <id>" is used to +indicate that to wpa_supplicant. This allows other radio works to be +performed. If this command is forgotten (e.g., due to the external +program terminating), wpa_supplicant will time out the radio owrk item +and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has +happened. "RADIO_WORK done <id>" can also be used to cancel items that +have not yet been started. + +For example, in wpa_cli interactive mode: + +> radio_work add test +1 +<3>EXT-RADIO-WORK-START 1 +> radio_work show +ext:test@wlan0:0:1:2.487797 +> radio_work done 1 +OK +> radio_work show + + +> radio_work done 3 +OK +> radio_work show +ext:test freq=2412 timeout=30@wlan0:2412:1:28.583483 +<3>EXT-RADIO-WORK-TIMEOUT 2 + + +> radio_work add test2 freq=2412 timeout=60 +5 +<3>EXT-RADIO-WORK-START 5 +> radio_work add test3 +6 +> radio_work add test4 +7 +> radio_work show +ext:test2 freq=2412 timeout=60@wlan0:2412:1:9.751844 +ext:test3@wlan0:0:0:5.071812 +ext:test4@wlan0:0:0:3.143870 +> radio_work done 6 +OK +> radio_work show +ext:test2 freq=2412 timeout=60@wlan0:2412:1:16.287869 +ext:test4@wlan0:0:0:9.679895 +> radio_work done 5 +OK +<3>EXT-RADIO-WORK-START 7 +<3>EXT-RADIO-WORK-TIMEOUT 7 diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 61e4a4dc..ad29ef77 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -109,6 +109,8 @@ Credentials can be pre-configured for automatic network selection: # # credential fields: # +# temporary: Whether this credential is temporary and not to be saved +# # priority: Priority group # By default, all networks and credentials get the same priority group # (0). This field can be used to give higher priority for credentials @@ -269,6 +271,8 @@ OK OK > set_cred 0 priority 1 OK +> set_cred 0 temporary 1 +OK Add a SIM credential using a simulated SIM/USIM card for testing: diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index ffc2baf0..08d39e24 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -418,9 +418,11 @@ p2p_presence_req [<duration> <interval>] [<duration> <interval>] Send a P2P Presence Request to the GO (this is only available when acting as a P2P client). If no duration/interval pairs are given, the request indicates that this client has no special needs for GO -presence. the first parameter pair gives the preferred duration and +presence. The first parameter pair gives the preferred duration and interval values in microseconds. If the second pair is included, that -indicates which value would be acceptable. +indicates which value would be acceptable. This command returns OK +immediately and the response from the GO is indicated in a +P2P-PRESENCE-RESPONSE event message. Parameters diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index 501137cf..ec7df03e 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -20,63 +20,6 @@ # used to fix build issues on such systems (krb5.h not found). #CFLAGS += -I/usr/include/kerberos -# Example configuration for various cross-compilation platforms - -#### sveasoft (e.g., for Linksys WRT54G) ###################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS += -I../src/include -I../../src/router/openssl/include -#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl -############################################################################### - -#### openwrt (e.g., for Linksys WRT54G) ####################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \ -# -I../WRT54GS/release/src/include -#LIBS = -lssl -############################################################################### - - -# Driver interface for Host AP driver -#CONFIG_DRIVER_HOSTAP=y - -# Driver interface for Agere driver -#CONFIG_DRIVER_HERMES=y -# Change include directories to match with the local setup -#CFLAGS += -I../../hcf -I../../include -I../../include/hcf -#CFLAGS += -I../../include/wireless - -# Driver interface for madwifi driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_MADWIFI=y -# Set include directory to the madwifi source tree -#CFLAGS += -I../../madwifi - -# Driver interface for ndiswrapper -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_NDISWRAPPER=y - -# Driver interface for Atmel driver -#CONFIG_DRIVER_ATMEL=y - -# Driver interface for old Broadcom driver -# Please note that the newer Broadcom driver ("hybrid Linux driver") supports -# Linux wireless extensions and does not need (or even work) with the old -# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver. -#CONFIG_DRIVER_BROADCOM=y -# Example path for wlioctl.h; change to match your configuration -#CFLAGS += -I/opt/WRT54GS/release/src/include - -# Driver interface for Intel ipw2100/2200 driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_IPW=y - -# Driver interface for Ralink driver -#CONFIG_DRIVER_RALINK=y - # Driver interface for generic Linux wireless extensions # Note: WEXT is deprecated in the current Linux kernel version and no new # functionality is added to it. nl80211-based interface is the new diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 394ab30d..ea4e6bba 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -276,7 +276,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) && (bss->wpa_group == WPA_CIPHER_CCMP || - bss->wpa_group == WPA_CIPHER_GCMP)) { + bss->wpa_group == WPA_CIPHER_GCMP || + bss->wpa_group == WPA_CIPHER_CCMP_256 || + bss->wpa_group == WPA_CIPHER_GCMP_256)) { /* * Strong ciphers do not need frequent rekeying, so increase * the default GTK rekeying period to 24 hours. @@ -511,7 +513,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; else wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; - params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt); + params.key_mgmt_suite = wpa_s->key_mgmt; wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 1); @@ -520,8 +522,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, "cipher."); return -1; } - params.pairwise_suite = - wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher); + params.pairwise_suite = wpa_s->pairwise_cipher; params.group_suite = params.pairwise_suite; #ifdef CONFIG_P2P @@ -679,6 +680,8 @@ void ap_eapol_tx_status(void *ctx, const u8 *dst, { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; + if (!wpa_s->ap_iface) + return; hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack); #endif /* NEED_AP_MLME */ } diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c index 07d31e4c..6a92b735 100644 --- a/wpa_supplicant/bgscan_learn.c +++ b/wpa_supplicant/bgscan_learn.c @@ -34,7 +34,7 @@ struct bgscan_learn_data { int signal_threshold; int short_interval; /* use if signal < threshold */ int long_interval; /* use if signal > threshold */ - struct os_time last_bgscan; + struct os_reltime last_bgscan; char *fname; struct dl_list bss; int *supp_freqs; @@ -240,17 +240,14 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, if (data->supp_freqs == NULL) return freqs; - idx = data->probe_idx + 1; - while (idx != data->probe_idx) { - if (data->supp_freqs[idx] == 0) { - if (data->probe_idx == 0) - break; - idx = 0; - } + idx = data->probe_idx; + do { if (!in_array(freqs, data->supp_freqs[idx])) { wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq " "%u", data->supp_freqs[idx]); - data->probe_idx = idx; + data->probe_idx = idx + 1; + if (data->supp_freqs[data->probe_idx] == 0) + data->probe_idx = 0; n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) return freqs; @@ -262,7 +259,9 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, } idx++; - } + if (data->supp_freqs[idx] == 0) + idx = 0; + } while (idx != data->probe_idx); return freqs; } @@ -311,7 +310,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx) eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); } else - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); os_free(freqs); } @@ -363,6 +362,9 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s) for (j = 0; j < modes[i].num_channels; j++) { if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED) continue; + /* some hw modes (e.g. 11b & 11g) contain same freqs */ + if (in_array(freqs, modes[i].channels[j].freq)) + continue; n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) continue; @@ -419,6 +421,14 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s); data->scan_interval = data->short_interval; + if (data->signal_threshold) { + /* Poll for signal info to set initial scan interval */ + struct wpa_signal_info siginfo; + if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && + siginfo.current_signal >= data->signal_threshold) + data->scan_interval = data->long_interval; + } + eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); @@ -428,7 +438,7 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, * us skip an immediate new scan in cases where the current signal * level is below the bgscan threshold. */ - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); return data; } @@ -555,7 +565,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above, { struct bgscan_learn_data *data = priv; int scan = 0; - struct os_time now; + struct os_reltime now; if (data->short_interval == data->long_interval || data->signal_threshold == 0) @@ -569,7 +579,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above, wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan " "interval"); data->scan_interval = data->short_interval; - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 1) scan = 1; } else if (data->scan_interval == data->short_interval && above) { @@ -584,7 +594,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above, * Signal dropped further 4 dB. Request a new scan if we have * not yet scanned in a while. */ - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 10) scan = 1; } diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c index 479f703b..a467cc5b 100644 --- a/wpa_supplicant/bgscan_simple.c +++ b/wpa_supplicant/bgscan_simple.c @@ -26,7 +26,7 @@ struct bgscan_simple_data { int max_short_scans; /* maximum times we short-scan before back-off */ int short_interval; /* use if signal < threshold */ int long_interval; /* use if signal > threshold */ - struct os_time last_bgscan; + struct os_reltime last_bgscan; }; @@ -75,7 +75,7 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) */ data->short_scan_count--; } - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); } } @@ -159,7 +159,7 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s, * us skip an immediate new scan in cases where the current signal * level is below the bgscan threshold. */ - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); return data; } @@ -211,7 +211,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above, { struct bgscan_simple_data *data = priv; int scan = 0; - struct os_time now; + struct os_reltime now; if (data->short_interval == data->long_interval || data->signal_threshold == 0) @@ -225,7 +225,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above, wpa_printf(MSG_DEBUG, "bgscan simple: Start using short " "bgscan interval"); data->scan_interval = data->short_interval; - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 1 && data->short_scan_count <= data->max_short_scans) /* @@ -259,7 +259,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above, * Signal dropped further 4 dB. Request a new scan if we have * not yet scanned in a while. */ - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 10) scan = 1; } diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index df1a0c88..9ea69033 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -224,9 +224,9 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, } -static void calculate_update_time(const struct os_time *fetch_time, +static void calculate_update_time(const struct os_reltime *fetch_time, unsigned int age_ms, - struct os_time *update_time) + struct os_reltime *update_time) { os_time_t usec; @@ -243,7 +243,7 @@ static void calculate_update_time(const struct os_time *fetch_time, static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, - struct os_time *fetch_time) + struct os_reltime *fetch_time) { dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); @@ -326,7 +326,7 @@ static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len, struct wpa_scan_res *res, - struct os_time *fetch_time) + struct os_reltime *fetch_time) { struct wpa_bss *bss; @@ -492,7 +492,7 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, static struct wpa_bss * wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - struct wpa_scan_res *res, struct os_time *fetch_time) + struct wpa_scan_res *res, struct os_reltime *fetch_time) { u32 changes; @@ -587,17 +587,18 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s) */ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, - struct os_time *fetch_time) + struct os_reltime *fetch_time) { const u8 *ssid, *p2p; struct wpa_bss *bss; if (wpa_s->conf->ignore_old_scan_res) { - struct os_time update; + struct os_reltime update; calculate_update_time(fetch_time, res->age, &update); - if (os_time_before(&update, &wpa_s->scan_trigger_time)) { - struct os_time age; - os_time_sub(&wpa_s->scan_trigger_time, &update, &age); + if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) { + struct os_reltime age; + os_reltime_sub(&wpa_s->scan_trigger_time, &update, + &age); wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS " "table entry that is %u.%06u seconds older " "than our scan trigger", @@ -731,26 +732,10 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, { struct wpa_bss *bss, *n; - wpa_s->last_scan_full = 0; - os_get_time(&wpa_s->last_scan); + os_get_reltime(&wpa_s->last_scan); if (!new_scan) return; /* do not expire entries without new scan */ - if (info && !info->aborted && !info->freqs) { - size_t i; - if (info->num_ssids == 0) { - wpa_s->last_scan_full = 1; - } else { - for (i = 0; i < info->num_ssids; i++) { - if (info->ssids[i].ssid == NULL || - info->ssids[i].ssid_len == 0) { - wpa_s->last_scan_full = 1; - break; - } - } - } - } - dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; @@ -764,10 +749,8 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, } } - wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u " - "last_scan_full=%d", - wpa_s->last_scan_res_used, wpa_s->last_scan_res_size, - wpa_s->last_scan_full); + wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u", + wpa_s->last_scan_res_used, wpa_s->last_scan_res_size); } @@ -781,19 +764,19 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) { struct wpa_bss *bss, *n; - struct os_time t; + struct os_reltime t; if (dl_list_empty(&wpa_s->bss)) return; - os_get_time(&t); + os_get_reltime(&t); t.sec -= age; dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; - if (os_time_before(&bss->last_update, &t)) { + if (os_reltime_before(&bss->last_update, &t)) { wpa_bss_remove(wpa_s, bss, __func__); } else break; @@ -837,6 +820,8 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss, *n; + wpa_s->clear_driver_scan_cache = 1; + if (wpa_s->bss.next == NULL) return; /* BSS table not yet initialized */ @@ -900,7 +885,7 @@ struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s, if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0) continue; if (found == NULL || - os_time_before(&found->last_update, &bss->last_update)) + os_reltime_before(&found->last_update, &bss->last_update)) found = bss; } return found; diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 0d2693fd..4deeb5f5 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -84,7 +84,7 @@ struct wpa_bss { /** Timestamp of last Beacon/Probe Response frame */ u64 tsf; /** Time of the last update (i.e., Beacon or Probe Response RX) */ - struct os_time last_update; + struct os_reltime last_update; /** ANQP data */ struct wpa_bss_anqp *anqp; /** Length of the following IE field in octets (from Probe Response) */ @@ -98,7 +98,7 @@ struct wpa_bss { void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, - struct os_time *fetch_time); + struct os_reltime *fetch_time); void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan); int wpa_bss_init(struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 9ceaaf85..5301ed71 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2393,6 +2393,11 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, char *val; size_t len; + if (os_strcmp(var, "temporary") == 0) { + cred->temporary = atoi(value); + return 0; + } + if (os_strcmp(var, "priority") == 0) { cred->priority = atoi(value); return 0; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 068679e5..e24772d1 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -52,6 +52,11 @@ struct wpa_cred { int id; /** + * temporary - Whether this credential is temporary and not to be saved + */ + int temporary; + + /** * priority - Priority group * * By default, all networks and credentials get the same priority group diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 7d328673..6312a77b 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1110,6 +1110,8 @@ int wpa_config_write(const char *name, struct wpa_config *config) wpa_config_write_global(f, config); for (cred = config->cred; cred; cred = cred->next) { + if (cred->temporary) + continue; fprintf(f, "\ncred={\n"); wpa_config_write_cred(f, cred); fprintf(f, "}\n"); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 0102da94..d515030f 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -315,12 +315,13 @@ struct wpa_ssid { * 4 = P2P Group Formation (used internally; not in configuration * files) * - * Note: IBSS can only be used with key_mgmt NONE (plaintext and - * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In - * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires - * following network block options: proto=WPA, key_mgmt=WPA-NONE, - * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also - * be set (either directly or using ASCII passphrase). + * Note: IBSS can only be used with key_mgmt NONE (plaintext and static + * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE + * (fixed group key TKIP/CCMP) is available for backwards compatibility, + * but its use is deprecated. WPA-None requires following network block + * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or + * CCMP, but not both), and psk must also be set (either directly or + * using ASCII passphrase). */ enum wpas_mode { WPAS_MODE_INFRA = 0, @@ -610,7 +611,7 @@ struct wpa_ssid { /** * disabled_until - Network block disabled until this time if non-zero */ - struct os_time disabled_until; + struct os_reltime disabled_until; /** * parent_cred - Pointer to parent wpa_cred entry diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 4e344b8c..cb299db0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -10,6 +10,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "utils/uuid.h" #include "common/version.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -40,8 +41,6 @@ #include "autoscan.h" #include "wnm_sta.h" -extern struct wpa_driver_ops *wpa_drivers[]; - static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, @@ -361,13 +360,13 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "ampdu") == 0) { if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) ret = -1; +#ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { extern unsigned int tdls_testing; tdls_testing = strtol(value, NULL, 0); wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); #endif /* CONFIG_TDLS_TESTING */ -#ifdef CONFIG_TDLS } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) { int disabled = atoi(value); wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled); @@ -1629,6 +1628,17 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, if (res >= 0) pos += res; +#ifdef CONFIG_WPS + { + char uuid_str[100]; + uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str)); + ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_WPS */ + #ifdef ANDROID wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE "id=%d state=%d BSSID=" MACSTR " SSID=%s", @@ -1740,9 +1750,6 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s, } -extern int wpa_debug_level; -extern int wpa_debug_timestamp; - static const char * debug_level_str(int level) { switch (level) { @@ -2658,6 +2665,24 @@ static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) #endif /* CONFIG_NO_CONFIG_WRITE */ +struct cipher_info { + unsigned int capa; + const char *name; + int group_only; +}; + +static const struct cipher_info ciphers[] = { + { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 }, + { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 }, + { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 }, + { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 }, + { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 }, + { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 }, + { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 }, + { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } +}; + + static int ctrl_iface_get_capability_pairwise(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) @@ -2665,6 +2690,7 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict, int ret, first = 1; char *pos, *end; size_t len; + unsigned int i; pos = buf; end = pos + buflen; @@ -2678,36 +2704,15 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict, return len; } - if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) { - ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) { - ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { - ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { - ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; + for (i = 0; i < ARRAY_SIZE(ciphers); i++) { + if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) { + ret = os_snprintf(pos, end - pos, "%s%s", + first ? "" : " ", ciphers[i].name); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } } return pos - buf; @@ -2721,6 +2726,7 @@ static int ctrl_iface_get_capability_group(int res, char *strict, int ret, first = 1; char *pos, *end; size_t len; + unsigned int i; pos = buf; end = pos + buflen; @@ -2734,45 +2740,15 @@ static int ctrl_iface_get_capability_group(int res, char *strict, return len; } - if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) { - ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) { - ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { - ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) { - ret = os_snprintf(pos, end - pos, "%sWEP104", - first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) { - ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; + for (i = 0; i < ARRAY_SIZE(ciphers); i++) { + if (capa->enc & ciphers[i].capa) { + ret = os_snprintf(pos, end - pos, "%s%s", + first ? "" : " ", ciphers[i].name); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } } return pos - buf; @@ -3248,9 +3224,9 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } if (mask & WPA_BSS_MASK_AGE) { - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); ret = os_snprintf(pos, end - pos, "age=%d\n", (int) (now.sec - bss->last_update.sec)); if (ret < 0 || ret >= end - pos) @@ -4688,7 +4664,68 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) #endif /* CONFIG_P2P */ +static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val) +{ + struct wpa_freq_range_list ranges; + int *freqs = NULL; + struct hostapd_hw_modes *mode; + u16 i; + + if (wpa_s->hw.modes == NULL) + return NULL; + + os_memset(&ranges, 0, sizeof(ranges)); + if (freq_range_list_parse(&ranges, val) < 0) + return NULL; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + int j; + + mode = &wpa_s->hw.modes[i]; + for (j = 0; j < mode->num_channels; j++) { + unsigned int freq; + + if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) + continue; + + freq = mode->channels[j].freq; + if (!freq_range_list_includes(&ranges, freq)) + continue; + + int_array_add_unique(&freqs, freq); + } + } + + os_free(ranges.range); + return freqs; +} + + #ifdef CONFIG_INTERWORKING + +static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param) +{ + int auto_sel = 0; + int *freqs = NULL; + + if (param) { + char *pos; + + auto_sel = os_strstr(param, "auto") != NULL; + + pos = os_strstr(param, "freq="); + if (pos) { + freqs = freq_range_to_channel_list(wpa_s, pos + 5); + if (freqs == NULL) + return -1; + } + + } + + return interworking_select(wpa_s, auto_sel, freqs); +} + + static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst) { u8 bssid[ETH_ALEN]; @@ -4812,9 +4849,8 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, int used; char *pos; size_t resp_len, start, requested_len; - - if (!wpa_s->last_gas_resp) - return -1; + struct wpabuf *resp; + int ret; used = hwaddr_aton2(cmd, addr); if (used < 0) @@ -4825,11 +4861,18 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, pos++; dialog_token = atoi(pos); - if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 || - dialog_token != wpa_s->last_gas_dialog_token) + if (wpa_s->last_gas_resp && + os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && + dialog_token == wpa_s->last_gas_dialog_token) + resp = wpa_s->last_gas_resp; + else if (wpa_s->prev_gas_resp && + os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && + dialog_token == wpa_s->prev_gas_dialog_token) + resp = wpa_s->prev_gas_resp; + else return -1; - resp_len = wpabuf_len(wpa_s->last_gas_resp); + resp_len = wpabuf_len(resp); start = 0; requested_len = resp_len; @@ -4850,9 +4893,24 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, if (requested_len * 2 + 1 > buflen) return os_snprintf(buf, buflen, "FAIL-Too long response"); - return wpa_snprintf_hex(buf, buflen, - wpabuf_head_u8(wpa_s->last_gas_resp) + start, - requested_len); + ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start, + requested_len); + + if (start + requested_len == resp_len) { + /* + * Free memory by dropping the response after it has been + * fetched. + */ + if (resp == wpa_s->prev_gas_resp) { + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = NULL; + } else { + wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = NULL; + } + } + + return ret; } #endif /* CONFIG_INTERWORKING */ @@ -5191,6 +5249,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpas_p2p_stop_find(wpa_s); p2p_ctrl_flush(wpa_s); wpas_p2p_group_remove(wpa_s, "*"); + wpas_p2p_service_flush(wpa_s); + wpa_s->global->p2p_disabled = 0; + wpa_s->global->p2p_per_sta_psk = 0; #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS_TESTING @@ -5198,16 +5259,17 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wps_testing_dummy_cred = 0; #endif /* CONFIG_WPS_TESTING */ #ifdef CONFIG_WPS + wpa_s->wps_fragment_size = 0; wpas_wps_cancel(wpa_s); #endif /* CONFIG_WPS */ wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; +#ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING extern unsigned int tdls_testing; tdls_testing = 0; #endif /* CONFIG_TDLS_TESTING */ -#ifdef CONFIG_TDLS wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); wpa_tdls_enable(wpa_s->wpa, 1); #endif /* CONFIG_TDLS */ @@ -5234,6 +5296,193 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->extra_blacklist_count = 0; wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all"); wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all"); + + wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200); + wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70); + wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60); + eapol_sm_notify_logoff(wpa_s->eapol, FALSE); + + radio_remove_unstarted_work(wpa_s, NULL); +} + + +static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + struct wpa_radio_work *work; + char *pos, *end; + struct os_reltime now, diff; + + pos = buf; + end = buf + buflen; + + os_get_reltime(&now); + + dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) + { + int ret; + + os_reltime_sub(&now, &work->time, &diff); + ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n", + work->type, work->wpa_s->ifname, work->freq, + work->started, diff.sec, diff.usec); + if (ret < 0 || ret >= end - pos) + break; + pos += ret; + } + + return pos - buf; +} + + +static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_radio_work *work = eloop_ctx; + struct wpa_external_work *ework = work->ctx; + + wpa_dbg(work->wpa_s, MSG_DEBUG, + "Timing out external radio work %u (%s)", + ework->id, work->type); + wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id); + os_free(ework); + radio_work_done(work); +} + + +static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_external_work *ework = work->ctx; + + if (deinit) { + os_free(ework); + return; + } + + wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)", + ework->id, ework->type); + wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id); + if (!ework->timeout) + ework->timeout = 10; + eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout, + work, NULL); +} + + +static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + struct wpa_external_work *ework; + char *pos, *pos2; + size_t type_len; + int ret; + unsigned int freq = 0; + + /* format: <name> [freq=<MHz>] [timeout=<seconds>] */ + + ework = os_zalloc(sizeof(*ework)); + if (ework == NULL) + return -1; + + pos = os_strchr(cmd, ' '); + if (pos) { + type_len = pos - cmd; + pos++; + + pos2 = os_strstr(pos, "freq="); + if (pos2) + freq = atoi(pos2 + 5); + + pos2 = os_strstr(pos, "timeout="); + if (pos2) + ework->timeout = atoi(pos2 + 8); + } else { + type_len = os_strlen(cmd); + } + if (4 + type_len >= sizeof(ework->type)) + type_len = sizeof(ework->type) - 4 - 1; + os_strlcpy(ework->type, "ext:", sizeof(ework->type)); + os_memcpy(ework->type + 4, cmd, type_len); + ework->type[4 + type_len] = '\0'; + + wpa_s->ext_work_id++; + if (wpa_s->ext_work_id == 0) + wpa_s->ext_work_id++; + ework->id = wpa_s->ext_work_id; + + if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb, + ework) < 0) { + os_free(ework); + return -1; + } + + ret = os_snprintf(buf, buflen, "%u", ework->id); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; +} + + +static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd) +{ + struct wpa_radio_work *work; + unsigned int id = atoi(cmd); + + dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) + { + struct wpa_external_work *ework; + + if (os_strncmp(work->type, "ext:", 4) != 0) + continue; + ework = work->ctx; + if (id && ework->id != id) + continue; + wpa_dbg(wpa_s, MSG_DEBUG, + "Completed external radio work %u (%s)", + ework->id, ework->type); + eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); + os_free(ework); + radio_work_done(work); + return 3; /* "OK\n" */ + } + + return -1; +} + + +static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + if (os_strcmp(cmd, "show") == 0) + return wpas_ctrl_radio_work_show(wpa_s, buf, buflen); + if (os_strncmp(cmd, "add ", 4) == 0) + return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen); + if (os_strncmp(cmd, "done ", 5) == 0) + return wpas_ctrl_radio_work_done(wpa_s, cmd + 4); + return -1; +} + + +void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) +{ + struct wpa_radio_work *work, *tmp; + + dl_list_for_each_safe(work, tmp, &wpa_s->radio->work, + struct wpa_radio_work, list) { + struct wpa_external_work *ework; + + if (os_strncmp(work->type, "ext:", 4) != 0) + continue; + ework = work->ctx; + wpa_dbg(wpa_s, MSG_DEBUG, + "Flushing %sexternal radio work %u (%s)", + work->started ? " started" : "", ework->id, + ework->type); + if (work->started) + eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, + work, NULL); + os_free(ework); + radio_work_done(work); + } } @@ -5244,6 +5493,97 @@ static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx) } +static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val) +{ + int *freqs = NULL; + + freqs = freq_range_to_channel_list(wpa_s, val); + if (freqs == NULL) + return -1; + + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; + + return 0; +} + + +static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, + char *reply, int reply_size, int *reply_len) +{ + char *pos; + + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + *reply_len = -1; + return; + } + + wpa_s->manual_scan_passive = 0; + wpa_s->manual_scan_use_id = 0; + wpa_s->manual_scan_only_new = 0; + + if (params) { + if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) + wpa_s->scan_res_handler = scan_only_handler; + + pos = os_strstr(params, "freq="); + if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) { + *reply_len = -1; + return; + } + + pos = os_strstr(params, "passive="); + if (pos) + wpa_s->manual_scan_passive = !!atoi(pos + 8); + + pos = os_strstr(params, "use_id="); + if (pos) + wpa_s->manual_scan_use_id = atoi(pos + 7); + + pos = os_strstr(params, "only_new=1"); + if (pos) + wpa_s->manual_scan_only_new = 1; + } else { + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + if (wpa_s->scan_res_handler == scan_only_handler) + wpa_s->scan_res_handler = NULL; + } + + if (!wpa_s->sched_scanning && !wpa_s->scanning && + ((wpa_s->wpa_state <= WPA_SCANNING) || + (wpa_s->wpa_state == WPA_COMPLETED))) { + wpa_s->normal_scans = 0; + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->manual_scan_use_id) { + wpa_s->manual_scan_id++; + wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", + wpa_s->manual_scan_id); + *reply_len = os_snprintf(reply, reply_size, "%u\n", + wpa_s->manual_scan_id); + } + } else if (wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->manual_scan_use_id) { + wpa_s->manual_scan_id++; + *reply_len = os_snprintf(reply, reply_size, "%u\n", + wpa_s->manual_scan_id); + wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", + wpa_s->manual_scan_id); + } + } else { + wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); + *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); + } +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -5252,18 +5592,25 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, int reply_len; if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || - os_strncmp(buf, "SET_NETWORK ", 12) == 0 || - os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || - os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 || - os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) { + os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + if (wpa_debug_show_keys) + wpa_dbg(wpa_s, MSG_DEBUG, + "Control interface command '%s'", buf); + else + wpa_dbg(wpa_s, MSG_DEBUG, + "Control interface command '%s [REMOVED]'", + os_strncmp(buf, WPA_CTRL_RSP, + os_strlen(WPA_CTRL_RSP)) == 0 ? + WPA_CTRL_RSP : "SET_NETWORK"); + } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || + os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 || + os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) { wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", (const u8 *) buf, os_strlen(buf)); } else { int level = MSG_DEBUG; if (os_strcmp(buf, "PING") == 0) level = MSG_EXCESSIVE; - wpa_hexdump_ascii(level, "RX ctrl_iface", - (const u8 *) buf, os_strlen(buf)); wpa_dbg(wpa_s, level, "Control interface command '%s'", buf); } @@ -5557,9 +5904,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) { interworking_stop_fetch_anqp(wpa_s); - } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) { - if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") != - NULL) < 0) + } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) { + if (ctrl_interworking_select(wpa_s, NULL) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) { + if (ctrl_interworking_select(wpa_s, buf + 20) < 0) reply_len = -1; } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { if (ctrl_interworking_connect(wpa_s, buf + 21) < 0) @@ -5622,36 +5971,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); - } else if (os_strcmp(buf, "SCAN") == 0 || - os_strncmp(buf, "SCAN ", 5) == 0) { - if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) - reply_len = -1; - else { - if (os_strlen(buf) > 4 && - os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0) - wpa_s->scan_res_handler = scan_only_handler; - if (!wpa_s->sched_scanning && !wpa_s->scanning && - ((wpa_s->wpa_state <= WPA_SCANNING) || - (wpa_s->wpa_state == WPA_COMPLETED))) { - wpa_s->normal_scans = 0; - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_s->after_wps = 0; - wpa_s->known_wps_freq = 0; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, "Stop ongoing " - "sched_scan to allow requested " - "full scan to proceed"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else { - wpa_printf(MSG_DEBUG, "Ongoing scan action - " - "reject new request"); - reply_len = os_snprintf(reply, reply_size, - "FAIL-BUSY\n"); - } - } + } else if (os_strcmp(buf, "SCAN") == 0) { + wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); + } else if (os_strncmp(buf, "SCAN ", 5) == 0) { + wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); @@ -5792,6 +6115,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); + } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { + reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply, + reply_size); } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h index a329ef32..b0dec53f 100644 --- a/wpa_supplicant/ctrl_iface.h +++ b/wpa_supplicant/ctrl_iface.h @@ -113,6 +113,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global); void wpa_supplicant_global_ctrl_iface_deinit( struct ctrl_iface_global_priv *priv); +void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s); + #else /* CONFIG_CTRL_IFACE */ static inline struct ctrl_iface_priv * @@ -148,6 +150,10 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { } +static inline void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) +{ +} + #endif /* CONFIG_CTRL_IFACE */ #endif /* CTRL_IFACE_H */ diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 7135d068..8fb217da 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / UNIX domain socket -based control interface - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -75,6 +75,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, socklen_t fromlen) { struct wpa_ctrl_dst *dst; + char addr_txt[200]; dst = os_zalloc(sizeof(*dst)); if (dst == NULL) @@ -83,9 +84,10 @@ static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, dst->addrlen = fromlen; dst->debug_level = MSG_INFO; dl_list_add(ctrl_dst, &dst->list); - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) from->sun_path, + fromlen - offsetof(struct sockaddr_un, sun_path)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt); return 0; } @@ -101,10 +103,13 @@ static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); + char addr_txt[200]; + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) from->sun_path, + fromlen - + offsetof(struct sockaddr_un, sun_path)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", + addr_txt); dl_list_del(&dst->list); os_free(dst); return 0; @@ -128,11 +133,13 @@ static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); + char addr_txt[200]; dst->debug_level = atoi(level); + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) from->sun_path, fromlen - + offsetof(struct sockaddr_un, sun_path)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", + dst->debug_level, addr_txt); return 0; } } @@ -676,32 +683,33 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, msg.msg_iov = io; msg.msg_iovlen = idx; - idx = -1; dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { int _errno; + char addr_txt[200]; - idx++; if (level < dst->debug_level) continue; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) dst->addr.sun_path, dst->addrlen - + offsetof(struct sockaddr_un, sun_path)); msg.msg_name = (void *) &dst->addr; msg.msg_namelen = dst->addrlen; if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor sent successfully to %s", + addr_txt); dst->errors = 0; - idx++; continue; } _errno = errno; - wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: %d - %s", - idx, errno, strerror(errno)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", + addr_txt, errno, strerror(errno)); dst->errors++; if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { - wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages"); + wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", + addr_txt); wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, dst->addrlen); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index fdf9a0a6..5380b430 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -28,10 +28,6 @@ #include "dbus_dict_helpers.h" #include "dbus_common_i.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - static const char *debug_strings[] = { "excessive", "msgdump", "debug", "info", "warning", "error", NULL }; @@ -2260,6 +2256,18 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, &iter_array)) goto nomem; + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp-256")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp-256")) + goto nomem; + } + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp")) @@ -2307,6 +2315,18 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, &iter_array)) goto nomem; + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp-256")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp-256")) + goto nomem; + } + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp")) @@ -3601,7 +3621,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, { DBusMessageIter iter_dict, variant_iter; const char *group; - const char *pairwise[3]; /* max 3 pairwise ciphers is supported */ + const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ const char *key_mgmt[7]; /* max 7 key managements may be supported */ int n; @@ -3650,6 +3670,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, case WPA_CIPHER_WEP104: group = "wep104"; break; + case WPA_CIPHER_CCMP_256: + group = "ccmp-256"; + break; + case WPA_CIPHER_GCMP_256: + group = "gcmp-256"; + break; default: group = ""; break; @@ -3666,6 +3692,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, pairwise[n++] = "ccmp"; if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) pairwise[n++] = "gcmp"; + if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256) + pairwise[n++] = "ccmp-256"; + if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256) + pairwise[n++] = "gcmp-256"; if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", pairwise, n)) diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c index 6d178f45..7c4630e4 100644 --- a/wpa_supplicant/dbus/dbus_old_handlers.c +++ b/wpa_supplicant/dbus/dbus_old_handlers.c @@ -25,10 +25,6 @@ #include "dbus_old_handlers.h" #include "dbus_dict_helpers.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - /** * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message * @message: Pointer to incoming dbus message this error refers to diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index ea0db04f..0627661c 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -20,63 +20,6 @@ # used to fix build issues on such systems (krb5.h not found). #CFLAGS += -I/usr/include/kerberos -# Example configuration for various cross-compilation platforms - -#### sveasoft (e.g., for Linksys WRT54G) ###################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS += -I../src/include -I../../src/router/openssl/include -#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl -############################################################################### - -#### openwrt (e.g., for Linksys WRT54G) ####################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \ -# -I../WRT54GS/release/src/include -#LIBS = -lssl -############################################################################### - - -# Driver interface for Host AP driver -CONFIG_DRIVER_HOSTAP=y - -# Driver interface for Agere driver -#CONFIG_DRIVER_HERMES=y -# Change include directories to match with the local setup -#CFLAGS += -I../../hcf -I../../include -I../../include/hcf -#CFLAGS += -I../../include/wireless - -# Driver interface for madwifi driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_MADWIFI=y -# Set include directory to the madwifi source tree -#CFLAGS += -I../../madwifi - -# Driver interface for ndiswrapper -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_NDISWRAPPER=y - -# Driver interface for Atmel driver -CONFIG_DRIVER_ATMEL=y - -# Driver interface for old Broadcom driver -# Please note that the newer Broadcom driver ("hybrid Linux driver") supports -# Linux wireless extensions and does not need (or even work) with the old -# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver. -#CONFIG_DRIVER_BROADCOM=y -# Example path for wlioctl.h; change to match your configuration -#CFLAGS += -I/opt/WRT54GS/release/src/include - -# Driver interface for Intel ipw2100/2200 driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_IPW=y - -# Driver interface for Ralink driver -#CONFIG_DRIVER_RALINK=y - # Driver interface for generic Linux wireless extensions # Note: WEXT is deprecated in the current Linux kernel version and no new # functionality is added to it. nl80211-based interface is the new @@ -147,10 +90,9 @@ CONFIG_EAP_PEAP=y CONFIG_EAP_TTLS=y # EAP-FAST -# Note: Default OpenSSL package does not include support for all the -# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch) -# to add the needed functions. +# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed +# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., +# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. #CONFIG_EAP_FAST=y # EAP-GTC diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 7f196de2..0691b6ca 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -117,11 +117,16 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, 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) -{ + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + if (alg != WPA_ALG_NONE) { + if (key_idx >= 0 && key_idx <= 6) + wpa_s->keys_cleared &= ~BIT(key_idx); + else + wpa_s->keys_cleared = 0; + } if (wpa_s->driver->set_key) { - wpa_s->keys_cleared = 0; return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); @@ -516,134 +521,6 @@ static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu) return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu); } -static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s, - unsigned int timeout, int type) -{ - if (!wpa_s->driver->p2p_find) - return -1; - return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type); -} - -static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->driver->p2p_stop_find) - return -1; - return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv); -} - -static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s, - unsigned int timeout) -{ - if (!wpa_s->driver->p2p_listen) - return -1; - return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout); -} - -static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s, - const u8 *peer_addr, int wps_method, - int go_intent, - const u8 *own_interface_addr, - unsigned int force_freq, - int persistent_group) -{ - if (!wpa_s->driver->p2p_connect) - return -1; - return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr, - wps_method, go_intent, - own_interface_addr, force_freq, - persistent_group); -} - -static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s, - const u8 *peer_addr) -{ - if (!wpa_s->driver->wps_success_cb) - return -1; - return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr); -} - -static inline int -wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->driver->p2p_group_formation_failed) - return -1; - return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv); -} - -static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s, - const struct p2p_params *params) -{ - if (!wpa_s->driver->p2p_set_params) - return -1; - return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params); -} - -static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s, - const u8 *peer_addr, - u16 config_methods, int join) -{ - if (!wpa_s->driver->p2p_prov_disc_req) - return -1; - return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr, - config_methods, join); -} - -static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s, - const u8 *dst, - const struct wpabuf *tlvs) -{ - if (!wpa_s->driver->p2p_sd_request) - return 0; - return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs); -} - -static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, - u64 req) -{ - if (!wpa_s->driver->p2p_sd_cancel_request) - return -1; - return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req); -} - -static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s, - int freq, const u8 *dst, - u8 dialog_token, - const struct wpabuf *resp_tlvs) -{ - if (!wpa_s->driver->p2p_sd_response) - return -1; - return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst, - dialog_token, resp_tlvs); -} - -static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->driver->p2p_service_update) - return -1; - return wpa_s->driver->p2p_service_update(wpa_s->drv_priv); -} - -static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s, - const u8 *addr) -{ - if (!wpa_s->driver->p2p_reject) - return -1; - return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr); -} - -static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s, - const u8 *peer, int role, const u8 *bssid, - const u8 *ssid, size_t ssid_len, - const u8 *go_dev_addr, - int persistent_group) -{ - if (!wpa_s->driver->p2p_invite) - return -1; - return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid, - ssid, ssid_len, go_dev_addr, - persistent_group); -} - static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index 2b25b699..cb714754 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -30,9 +30,6 @@ #include "wpas_glue.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; - struct wpa_driver_ops *wpa_drivers[] = { NULL }; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index c03dcc25..49c4058a 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Driver event processing - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -53,12 +53,12 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { - struct os_time now; + struct os_reltime now; if (ssid == NULL || ssid->disabled_until.sec == 0) return 0; - os_get_time(&now); + os_get_reltime(&now); if (ssid->disabled_until.sec > now.sec) return ssid->disabled_until.sec - now.sec; @@ -978,9 +978,6 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request " "since there are no enabled networks"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); -#ifdef CONFIG_P2P - wpa_s->sta_scan_pending = 0; -#endif /* CONFIG_P2P */ return; } @@ -1181,7 +1178,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, union wpa_event_data *data, int own_request) { - struct wpa_scan_results *scan_res; + struct wpa_scan_results *scan_res = NULL; + int ret = 0; int ap = 0; #ifndef CONFIG_NO_RANDOM_POOL size_t i, num; @@ -1194,24 +1192,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpa_supplicant_notify_scanning(wpa_s, 0); -#ifdef CONFIG_P2P - if (own_request && wpa_s->global->p2p_cb_on_scan_complete && - !wpa_s->global->p2p_disabled && - wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending && - !wpa_s->scan_res_handler) { - wpa_s->global->p2p_cb_on_scan_complete = 0; - if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " - "stopped scan processing"); - wpa_s->scan_req = wpa_s->last_scan_req; - wpa_s->sta_scan_pending = 1; - wpa_supplicant_req_scan(wpa_s, 5, 0); - return -1; - } - } - wpa_s->sta_scan_pending = 0; -#endif /* CONFIG_P2P */ - scan_res = wpa_supplicant_get_scan_results(wpa_s, data ? &data->scan_info : NULL, 1); @@ -1224,7 +1204,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try " "scanning again"); wpa_supplicant_req_new_scan(wpa_s, 1, 0); - return -1; + ret = -1; + goto scan_work_done; } #ifndef CONFIG_NO_RANDOM_POOL @@ -1243,16 +1224,16 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_NO_RANDOM_POOL */ - if (own_request && wpa_s->scan_res_handler) { + if (own_request && wpa_s->scan_res_handler && + (wpa_s->own_scan_running || !wpa_s->external_scan_running)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); scan_res_handler = wpa_s->scan_res_handler; wpa_s->scan_res_handler = NULL; scan_res_handler(wpa_s, scan_res); - - wpa_scan_results_free(scan_res); - return -2; + ret = -2; + goto scan_work_done; } if (ap) { @@ -1261,48 +1242,67 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (wpa_s->ap_iface->scan_cb) wpa_s->ap_iface->scan_cb(wpa_s->ap_iface); #endif /* CONFIG_AP */ - wpa_scan_results_free(scan_res); - return 0; + goto scan_work_done; } - wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available"); - wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", + wpa_s->own_scan_running, wpa_s->external_scan_running); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", + wpa_s->manual_scan_id); + wpa_s->manual_scan_use_id = 0; + } else { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); - if (sme_proc_obss_scan(wpa_s) > 0) { + if (!wpa_s->own_scan_running && wpa_s->external_scan_running) { + wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection"); wpa_scan_results_free(scan_res); return 0; } - if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) { - wpa_scan_results_free(scan_res); - return 0; - } + if (sme_proc_obss_scan(wpa_s) > 0) + goto scan_work_done; - if (autoscan_notify_scan(wpa_s, scan_res)) { - wpa_scan_results_free(scan_res); - return 0; - } + if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) + goto scan_work_done; + + if (autoscan_notify_scan(wpa_s, scan_res)) + goto scan_work_done; if (wpa_s->disconnected) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); - wpa_scan_results_free(scan_res); - return 0; + goto scan_work_done; } if (!wpas_driver_bss_selection(wpa_s) && - bgscan_notify_scan(wpa_s, scan_res) == 1) { - wpa_scan_results_free(scan_res); - return 0; - } + bgscan_notify_scan(wpa_s, scan_res) == 1) + goto scan_work_done; wpas_wps_update_ap_info(wpa_s, scan_res); wpa_scan_results_free(scan_res); + if (wpa_s->scan_work) { + struct wpa_radio_work *work = wpa_s->scan_work; + wpa_s->scan_work = NULL; + radio_work_done(work); + } + return wpas_select_network_from_last_scan(wpa_s, 1, own_request); + +scan_work_done: + wpa_scan_results_free(scan_res); + if (wpa_s->scan_work) { + struct wpa_radio_work *work = wpa_s->scan_work; + wpa_s->scan_work = NULL; + radio_work_done(work); + } + return ret; } @@ -1381,6 +1381,16 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 1; } #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_WPS + if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) { + wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing"); + timeout_sec = 0; + timeout_usec = 500000; + wpa_supplicant_req_new_scan(wpa_s, timeout_sec, + timeout_usec); + return 0; + } +#endif /* CONFIG_WPS */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); @@ -1428,13 +1438,13 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s) #ifdef CONFIG_NO_SCAN_PROCESSING return -1; #else /* CONFIG_NO_SCAN_PROCESSING */ - struct os_time now; + struct os_reltime now; if (wpa_s->last_scan_res_used <= 0) return -1; - os_get_time(&now); - if (now.sec - wpa_s->last_scan.sec > 5) { + os_get_reltime(&now); + if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) { wpa_printf(MSG_DEBUG, "Fast associate: Old scan results"); return -1; } @@ -1955,9 +1965,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s->last_eapol_matches_bssid = 0; if (wpa_s->pending_eapol_rx) { - struct os_time now, age; - os_get_time(&now); - os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age); + struct os_reltime now, age; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age); if (age.sec == 0 && age.usec < 100000 && os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == 0) { @@ -2143,7 +2153,6 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, wpas_notify_disconnect_reason(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys"); - wpa_s->keys_cleared = 0; wpa_clear_keys(wpa_s, wpa_s->bssid); } last_ssid = wpa_s->current_ssid; @@ -2187,13 +2196,13 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { int pairwise; - struct os_time t; + struct os_reltime t; wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected"); pairwise = (data && data->michael_mic_failure.unicast); - os_get_time(&t); - if ((wpa_s->last_michael_mic_error && - t.sec - wpa_s->last_michael_mic_error <= 60) || + os_get_reltime(&t); + if ((wpa_s->last_michael_mic_error.sec && + !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) || wpa_s->pending_mic_error_report) { if (wpa_s->pending_mic_error_report) { /* @@ -2271,7 +2280,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, wpa_sm_key_request(wpa_s->wpa, 1, pairwise); #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ } - wpa_s->last_michael_mic_error = t.sec; + wpa_s->last_michael_mic_error = t; wpa_s->mic_errors_seen++; } @@ -2687,6 +2696,87 @@ static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s) } +static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, + const struct ieee80211_mgmt *mgmt, + size_t len, int freq) +{ + const u8 *payload; + size_t plen; + u8 category; + + if (len < IEEE80211_HDRLEN + 2) + return; + + payload = &mgmt->u.action.category; + category = *payload++; + plen = (((const u8 *) mgmt) + len) - payload; + + wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR + " Category=%u DataLen=%d freq=%d MHz", + MAC2STR(mgmt->sa), category, (int) plen, freq); + +#ifdef CONFIG_IEEE80211R + if (category == WLAN_ACTION_FT) { + ft_rx_action(wpa_s, payload, plen); + return; + } +#endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211W +#ifdef CONFIG_SME + if (category == WLAN_ACTION_SA_QUERY) { + sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen); + return; + } +#endif /* CONFIG_SME */ +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_WNM + if (mgmt->u.action.category == WLAN_ACTION_WNM) { + ieee802_11_rx_wnm_action(wpa_s, mgmt, len); + return; + } +#endif /* CONFIG_WNM */ + +#ifdef CONFIG_GAS + if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && + gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid, + payload, plen, freq) == 0) + return; +#endif /* CONFIG_GAS */ + +#ifdef CONFIG_TDLS + if (category == WLAN_ACTION_PUBLIC && plen >= 4 && + payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) { + wpa_dbg(wpa_s, MSG_DEBUG, + "TDLS: Received Discovery Response from " MACSTR, + MAC2STR(mgmt->sa)); + return; + } +#endif /* CONFIG_TDLS */ + +#ifdef CONFIG_INTERWORKING + if (category == WLAN_ACTION_QOS && plen >= 1 && + payload[0] == QOS_QOS_MAP_CONFIG) { + const u8 *pos = payload + 1; + size_t qlen = plen - 1; + wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " + MACSTR, MAC2STR(mgmt->sa)); + if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 && + qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET && + pos[1] <= qlen - 2 && pos[1] >= 16) + wpas_qos_map_set(wpa_s, pos + 2, pos[1]); + return; + } +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_P2P + wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, + category, payload, plen, freq); +#endif /* CONFIG_P2P */ +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -2740,11 +2830,44 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_supplicant_event_michael_mic_failure(wpa_s, data); break; #ifndef CONFIG_NO_SCAN_PROCESSING + case EVENT_SCAN_STARTED: + os_get_reltime(&wpa_s->scan_start_time); + if (wpa_s->own_scan_requested) { + struct os_reltime diff; + + os_reltime_sub(&wpa_s->scan_start_time, + &wpa_s->scan_trigger_time, &diff); + wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds", + diff.sec, diff.usec); + wpa_s->own_scan_requested = 0; + wpa_s->own_scan_running = 1; + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_use_id) { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED "id=%u", + wpa_s->manual_scan_id); + } else { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); + } + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan"); + wpa_s->external_scan_running = 1; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); + } + break; case EVENT_SCAN_RESULTS: + if (os_reltime_initialized(&wpa_s->scan_start_time)) { + struct os_reltime now, diff; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); + wpa_s->scan_start_time.sec = 0; + wpa_s->scan_start_time.usec = 0; + wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds", + diff.sec, diff.usec); + } wpa_supplicant_event_scan_results(wpa_s, data); - if (wpa_s->wpa_state != WPA_AUTHENTICATING && - wpa_s->wpa_state != WPA_ASSOCIATING) - wpas_p2p_continue_after_scan(wpa_s); + wpa_s->own_scan_running = 0; + wpa_s->external_scan_running = 0; + radio_work_check_next(wpa_s); break; #endif /* CONFIG_NO_SCAN_PROCESSING */ case EVENT_ASSOCINFO: @@ -2901,7 +3024,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.cf2); break; #endif /* CONFIG_AP */ -#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN) case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; @@ -2936,6 +3058,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } #endif /* CONFIG_IBSS_RSN */ + + if (stype == WLAN_FC_STYPE_ACTION) { + wpas_event_rx_mgmt_action( + wpa_s, mgmt, data->rx_mgmt.frame_len, + data->rx_mgmt.freq); + break; + } + wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received " "management frame in non-AP mode"); break; @@ -2958,79 +3088,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ break; } -#endif /* CONFIG_AP || CONFIG_IBSS_RSN */ - case EVENT_RX_ACTION: - wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR - " Category=%u DataLen=%d freq=%d MHz", - MAC2STR(data->rx_action.sa), - data->rx_action.category, (int) data->rx_action.len, - data->rx_action.freq); -#ifdef CONFIG_IEEE80211R - if (data->rx_action.category == WLAN_ACTION_FT) { - ft_rx_action(wpa_s, data->rx_action.data, - data->rx_action.len); - break; - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W -#ifdef CONFIG_SME - if (data->rx_action.category == WLAN_ACTION_SA_QUERY) { - sme_sa_query_rx(wpa_s, data->rx_action.sa, - data->rx_action.data, - data->rx_action.len); - break; - } -#endif /* CONFIG_SME */ -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WNM - if (data->rx_action.category == WLAN_ACTION_WNM) { - ieee802_11_rx_wnm_action(wpa_s, &data->rx_action); - break; - } -#endif /* CONFIG_WNM */ -#ifdef CONFIG_GAS - if (data->rx_action.category == WLAN_ACTION_PUBLIC && - gas_query_rx(wpa_s->gas, data->rx_action.da, - data->rx_action.sa, data->rx_action.bssid, - data->rx_action.data, data->rx_action.len, - data->rx_action.freq) == 0) - break; -#endif /* CONFIG_GAS */ -#ifdef CONFIG_TDLS - if (data->rx_action.category == WLAN_ACTION_PUBLIC && - data->rx_action.len >= 4 && - data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) { - wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery " - "Response from " MACSTR, - MAC2STR(data->rx_action.sa)); - break; - } -#endif /* CONFIG_TDLS */ -#ifdef CONFIG_INTERWORKING - if (data->rx_action.category == WLAN_ACTION_QOS && - data->rx_action.len >= 1 && - data->rx_action.data[0] == QOS_QOS_MAP_CONFIG) { - const u8 *pos = data->rx_action.data + 1; - size_t len = data->rx_action.len - 1; - wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " - MACSTR, MAC2STR(data->rx_action.sa)); - if (os_memcmp(data->rx_action.sa, wpa_s->bssid, - ETH_ALEN) == 0 && - len > 2 && pos[0] == WLAN_EID_QOS_MAP_SET && - pos[1] <= len - 2 && pos[1] >= 16) - wpas_qos_map_set(wpa_s, pos + 2, pos[1]); - break; - } -#endif /* CONFIG_INTERWORKING */ -#ifdef CONFIG_P2P - wpas_p2p_rx_action(wpa_s, data->rx_action.da, - data->rx_action.sa, - data->rx_action.bssid, - data->rx_action.category, - data->rx_action.data, - data->rx_action.len, data->rx_action.freq); -#endif /* CONFIG_P2P */ - break; case EVENT_RX_PROBE_REQ: if (data->rx_probe_req.sa == NULL || data->rx_probe_req.ie == NULL) @@ -3078,71 +3135,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, data->remain_on_channel.freq); #endif /* CONFIG_P2P */ break; -#ifdef CONFIG_P2P - case EVENT_P2P_DEV_FOUND: { - struct p2p_peer_info peer_info; - - os_memset(&peer_info, 0, sizeof(peer_info)); - if (data->p2p_dev_found.dev_addr) - os_memcpy(peer_info.p2p_device_addr, - data->p2p_dev_found.dev_addr, ETH_ALEN); - if (data->p2p_dev_found.pri_dev_type) - os_memcpy(peer_info.pri_dev_type, - data->p2p_dev_found.pri_dev_type, - sizeof(peer_info.pri_dev_type)); - if (data->p2p_dev_found.dev_name) - os_strlcpy(peer_info.device_name, - data->p2p_dev_found.dev_name, - sizeof(peer_info.device_name)); - peer_info.config_methods = data->p2p_dev_found.config_methods; - peer_info.dev_capab = data->p2p_dev_found.dev_capab; - peer_info.group_capab = data->p2p_dev_found.group_capab; - - /* - * FIX: new_device=1 is not necessarily correct. We should - * maintain a P2P peer database in wpa_supplicant and update - * this information based on whether the peer is truly new. - */ - wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1); - break; - } - case EVENT_P2P_GO_NEG_REQ_RX: - wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src, - data->p2p_go_neg_req_rx.dev_passwd_id); - break; - case EVENT_P2P_GO_NEG_COMPLETED: - wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res); - break; - case EVENT_P2P_PROV_DISC_REQUEST: - wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer, - data->p2p_prov_disc_req.config_methods, - data->p2p_prov_disc_req.dev_addr, - data->p2p_prov_disc_req.pri_dev_type, - data->p2p_prov_disc_req.dev_name, - data->p2p_prov_disc_req.supp_config_methods, - data->p2p_prov_disc_req.dev_capab, - data->p2p_prov_disc_req.group_capab, - NULL, 0); - break; - case EVENT_P2P_PROV_DISC_RESPONSE: - wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer, - data->p2p_prov_disc_resp.config_methods); - break; - case EVENT_P2P_SD_REQUEST: - wpas_sd_request(wpa_s, data->p2p_sd_req.freq, - data->p2p_sd_req.sa, - data->p2p_sd_req.dialog_token, - data->p2p_sd_req.update_indic, - data->p2p_sd_req.tlvs, - data->p2p_sd_req.tlvs_len); - break; - case EVENT_P2P_SD_RESPONSE: - wpas_sd_response(wpa_s, data->p2p_sd_resp.sa, - data->p2p_sd_resp.update_indic, - data->p2p_sd_resp.tlvs, - data->p2p_sd_resp.tlvs_len); - break; -#endif /* CONFIG_P2P */ case EVENT_EAPOL_RX: wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src, data->eapol_rx.data, diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index f9885e39..f002fd50 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -2,6 +2,7 @@ * Generic advertisement service (GAS) query * Copyright (c) 2009, Atheros Communications * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -13,6 +14,7 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/gas.h" +#include "common/wpa_ctrl.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "offchannel.h" @@ -21,8 +23,6 @@ /** GAS query timeout in seconds */ #define GAS_QUERY_TIMEOUT_PERIOD 2 -/** Retry period for GAS query requests in milliseconds */ -#define GAS_SERVICE_RETRY_PERIOD_MS 500 /** @@ -30,6 +30,7 @@ */ struct gas_query_pending { struct dl_list list; + struct gas_query *gas; u8 addr[ETH_ALEN]; u8 dialog_token; u8 next_frag_id; @@ -54,12 +55,12 @@ struct gas_query { struct wpa_supplicant *wpa_s; struct dl_list pending; /* struct gas_query_pending */ struct gas_query_pending *current; + struct wpa_radio_work *work; }; static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); static void gas_query_timeout(void *eloop_data, void *user_ctx); -static void gas_service_timeout(void *eloop_data, void *user_ctx); /** @@ -82,24 +83,66 @@ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s) } +static const char * gas_result_txt(enum gas_query_result result) +{ + switch (result) { + case GAS_QUERY_SUCCESS: + return "SUCCESS"; + case GAS_QUERY_FAILURE: + return "FAILURE"; + case GAS_QUERY_TIMEOUT: + return "TIMEOUT"; + case GAS_QUERY_PEER_ERROR: + return "PEER_ERROR"; + case GAS_QUERY_INTERNAL_ERROR: + return "INTERNAL_ERROR"; + case GAS_QUERY_CANCELLED: + return "CANCELLED"; + case GAS_QUERY_DELETED_AT_DEINIT: + return "DELETED_AT_DEINIT"; + } + + return "N/A"; +} + + +static void gas_query_free(struct gas_query_pending *query, int del_list) +{ + struct gas_query *gas = query->gas; + + if (del_list) + dl_list_del(&query->list); + + if (gas->work && gas->work->ctx == query) { + radio_work_done(gas->work); + gas->work = NULL; + } + + wpabuf_free(query->req); + wpabuf_free(query->adv_proto); + wpabuf_free(query->resp); + os_free(query); +} + + static void gas_query_done(struct gas_query *gas, struct gas_query_pending *query, enum gas_query_result result) { + wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR + " dialog_token=%u freq=%d status_code=%u result=%s", + MAC2STR(query->addr), query->dialog_token, query->freq, + query->status_code, gas_result_txt(result)); if (gas->current == query) gas->current = NULL; if (query->offchannel_tx_started) offchannel_send_action_done(gas->wpa_s); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_cancel_timeout(gas_query_timeout, gas, query); - eloop_cancel_timeout(gas_service_timeout, gas, query); dl_list_del(&query->list); query->cb(query->ctx, query->addr, query->dialog_token, result, query->adv_proto, query->resp, query->status_code); - wpabuf_free(query->req); - wpabuf_free(query->adv_proto); - wpabuf_free(query->resp); - os_free(query); + gas_query_free(query, 0); } @@ -480,32 +523,36 @@ static void gas_query_timeout(void *eloop_data, void *user_ctx) } -static void gas_service_timeout(void *eloop_data, void *user_ctx) +static int gas_query_dialog_token_available(struct gas_query *gas, + const u8 *dst, u8 dialog_token) { - struct gas_query *gas = eloop_data; - struct wpa_supplicant *wpa_s = gas->wpa_s; - struct gas_query_pending *query = user_ctx; - int conn; - - conn = wpas_wpa_is_in_progress(wpa_s, 1); - if (conn || wpa_s->scanning || gas->current) { - wpa_printf(MSG_DEBUG, "GAS: Delaying GAS query Tx while another operation is in progress:%s%s%s", - conn ? " connection" : "", - wpa_s->scanning ? " scanning" : "", - gas->current ? " gas_query" : ""); - eloop_register_timeout( - GAS_SERVICE_RETRY_PERIOD_MS / 1000, - (GAS_SERVICE_RETRY_PERIOD_MS % 1000) * 1000, - gas_service_timeout, gas, query); + struct gas_query_pending *q; + dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { + if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && + dialog_token == q->dialog_token) + return 0; + } + + return 1; +} + + +static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) +{ + struct gas_query_pending *query = work->ctx; + struct gas_query *gas = query->gas; + + if (deinit) { + gas_query_free(query, 1); return; } + gas->work = work; + if (gas_query_tx(gas, query, query->req) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); - dl_list_del(&query->list); - wpabuf_free(query->req); - os_free(query); + gas_query_free(query, 1); return; } gas->current = query; @@ -514,20 +561,7 @@ static void gas_service_timeout(void *eloop_data, void *user_ctx) query->dialog_token); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); -} - -static int gas_query_dialog_token_available(struct gas_query *gas, - const u8 *dst, u8 dialog_token) -{ - struct gas_query_pending *q; - dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { - if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && - dialog_token == q->dialog_token) - return 0; - } - - return 1; } @@ -571,6 +605,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, if (query == NULL) return -1; + query->gas = gas; os_memcpy(query->addr, dst, ETH_ALEN); query->dialog_token = dialog_token; query->freq = freq; @@ -581,10 +616,15 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, *(wpabuf_mhead_u8(req) + 2) = dialog_token; - wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR - " dialog_token %u", MAC2STR(dst), dialog_token); + wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR + " dialog_token=%u freq=%d", + MAC2STR(query->addr), query->dialog_token, query->freq); - eloop_register_timeout(0, 0, gas_service_timeout, gas, query); + if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, + query) < 0) { + gas_query_free(query, 1); + return -1; + } return dialog_token; } @@ -605,9 +645,3 @@ void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) gas_query_done(gas, query, GAS_QUERY_CANCELLED); } - - -int gas_query_in_progress(struct gas_query *gas) -{ - return gas->current != NULL; -} diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h index 6b6c77ce..5c3d161a 100644 --- a/wpa_supplicant/gas_query.h +++ b/wpa_supplicant/gas_query.h @@ -18,7 +18,6 @@ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s); void gas_query_deinit(struct gas_query *gas); int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, const u8 *bssid, const u8 *data, size_t len, int freq); -int gas_query_in_progress(struct gas_query *gas); /** * enum gas_query_result - GAS query result diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 47ef35ec..3083dd80 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -590,7 +590,7 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) peer->authentication_status |= IBSS_RSN_AUTH_BY_US; return ibss_rsn_auth_init(ibss_rsn, peer); } else { - os_get_time(&peer->own_auth_tx); + os_get_reltime(&peer->own_auth_tx); eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL); } @@ -834,9 +834,9 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, if (peer && peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { if (peer->own_auth_tx.sec) { - struct os_time now, diff; - os_get_time(&now); - os_time_sub(&now, &peer->own_auth_tx, &diff); + struct os_reltime now, diff; + os_get_reltime(&now); + os_reltime_sub(&now, &peer->own_auth_tx, &diff); if (diff.sec == 0 && diff.usec < 500000) { wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX", (int) diff.usec); diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h index 3089283f..67fae2d1 100644 --- a/wpa_supplicant/ibss_rsn.h +++ b/wpa_supplicant/ibss_rsn.h @@ -40,7 +40,7 @@ struct ibss_rsn_peer { struct wpa_state_machine *auth; int authentication_status; - struct os_time own_auth_tx; + struct os_reltime own_auth_tx; }; struct ibss_rsn { diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 93652d8f..da8971d9 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1,6 +1,7 @@ /* * Interworking (IEEE 802.11u) * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -520,12 +521,13 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap) if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) return 0; /* method not supported */ - if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) { + if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP && + eap->method != EAP_TYPE_FAST) { /* Only tunneled methods with username/password supported */ return 0; } - if (eap->method == EAP_TYPE_PEAP) { + if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) { if (eap->inner_method && eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) return 0; @@ -1416,6 +1418,13 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) } break; case EAP_TYPE_PEAP: + case EAP_TYPE_FAST: + if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"", + 0) < 0) + goto fail; + if (wpa_config_set(ssid, "pac_file", + "\"blob://pac_interworking\"", 0) < 0) + goto fail; os_snprintf(buf, sizeof(buf), "\"auth=%s\"", eap_get_name(EAP_VENDOR_IETF, eap->inner_method ? @@ -2194,7 +2203,8 @@ static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s, } -int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) +int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, + int *freqs) { interworking_stop_fetch_anqp(wpa_s); wpa_s->network_select = 1; @@ -2206,6 +2216,8 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) wpa_s->scan_res_handler = interworking_scan_res_handler; wpa_s->normal_scans = 0; wpa_s->scan_req = MANUAL_SCAN_REQ; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; wpa_supplicant_req_scan(wpa_s, 0, 0); @@ -2220,6 +2232,7 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; + struct wpabuf *n; wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR " dialog_token=%d status_code=%d resp_len=%d", @@ -2228,10 +2241,14 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, if (!resp) return; - wpabuf_free(wpa_s->last_gas_resp); - wpa_s->last_gas_resp = wpabuf_dup(resp); - if (wpa_s->last_gas_resp == NULL) + n = wpabuf_dup(resp); + if (n == NULL) return; + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = wpa_s->last_gas_resp; + os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN); + wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token; + wpa_s->last_gas_resp = n; os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); wpa_s->last_gas_dialog_token = dialog_token; } diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 4a4af827..c8e70938 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -22,7 +22,8 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *query); int interworking_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s); -int interworking_select(struct wpa_supplicant *wpa_s, int auto_select); +int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, + int *freqs); int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c index 39b837e5..37f0c781 100644 --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -16,8 +16,6 @@ #include "driver_i.h" #include "p2p_supplicant.h" -extern struct wpa_driver_ops *wpa_drivers[]; - static void usage(void) { diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e6a88e63..41d5102c 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1,6 +1,7 @@ /* * wpa_supplicant - P2P * Copyright (c) 2009-2010, Atheros Communications + * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -196,6 +197,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, { size_t i; + if (wpa_s->p2p_scan_work) { + struct wpa_radio_work *work = wpa_s->p2p_scan_work; + wpa_s->p2p_scan_work = NULL; + radio_work_done(work); + } + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; @@ -204,13 +211,13 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; - struct os_time time_tmp_age, entry_ts; + struct os_reltime time_tmp_age, entry_ts; const u8 *ies; size_t ies_len; time_tmp_age.sec = bss->age / 1000; time_tmp_age.usec = (bss->age % 1000) * 1000; - os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts); + os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts); ies = (const u8 *) (bss + 1); ies_len = bss->ie_len; @@ -234,94 +241,125 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, } +static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpa_driver_scan_params *params = work->ctx; + int ret; + + if (deinit) { + wpa_scan_free_params(params); + return; + } + + ret = wpa_drv_scan(wpa_s, params); + wpa_scan_free_params(params); + work->ctx = NULL; + if (ret) { + radio_work_done(work); + return; + } + + os_get_reltime(&wpa_s->scan_trigger_time); + wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; + wpa_s->own_scan_requested = 1; + wpa_s->p2p_scan_work = work; +} + + static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) { struct wpa_supplicant *wpa_s = ctx; - struct wpa_supplicant *ifs; - struct wpa_driver_scan_params params; - int ret; + struct wpa_driver_scan_params *params = NULL; struct wpabuf *wps_ie, *ies; - int social_channels[] = { 2412, 2437, 2462, 0, 0 }; size_t ielen; + u8 *n; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; - for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { - if (ifs->sta_scan_pending && - (wpas_scan_scheduled(ifs) || ifs->scanning) && - wpas_p2p_in_progress(wpa_s) == 2) { - wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow " - "pending station mode scan to be " - "completed on interface %s", ifs->ifname); - wpa_s->global->p2p_cb_on_scan_complete = 1; - wpa_supplicant_req_scan(ifs, 0, 0); - return 1; - } + if (wpa_s->p2p_scan_work) { + wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending"); + return -1; } - os_memset(¶ms, 0, sizeof(params)); + params = os_zalloc(sizeof(*params)); + if (params == NULL) + return -1; /* P2P Wildcard SSID */ - params.num_ssids = 1; - params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; - params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; + params->num_ssids = 1; + n = os_malloc(P2P_WILDCARD_SSID_LEN); + if (n == NULL) + goto fail; + os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); + params->ssids[0].ssid = n; + params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, wpa_s->wps->uuid, WPS_REQ_ENROLLEE, num_req_dev_types, req_dev_types); if (wps_ie == NULL) - return -1; + goto fail; ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); if (ies == NULL) { wpabuf_free(wps_ie); - return -1; + goto fail; } wpabuf_put_buf(ies, wps_ie); wpabuf_free(wps_ie); p2p_scan_ie(wpa_s->global->p2p, ies, dev_id); - params.p2p_probe = 1; - params.extra_ies = wpabuf_head(ies); - params.extra_ies_len = wpabuf_len(ies); + params->p2p_probe = 1; + n = os_malloc(wpabuf_len(ies)); + if (n == NULL) { + wpabuf_free(ies); + goto fail; + } + os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies)); + params->extra_ies = n; + params->extra_ies_len = wpabuf_len(ies); + wpabuf_free(ies); switch (type) { case P2P_SCAN_SOCIAL: - params.freqs = social_channels; + params->freqs = os_malloc(4 * sizeof(int)); + if (params->freqs == NULL) + goto fail; + params->freqs[0] = 2412; + params->freqs[1] = 2437; + params->freqs[2] = 2462; + params->freqs[3] = 0; break; case P2P_SCAN_FULL: break; case P2P_SCAN_SOCIAL_PLUS_ONE: - social_channels[3] = freq; - params.freqs = social_channels; + params->freqs = os_malloc(5 * sizeof(int)); + if (params->freqs == NULL) + goto fail; + params->freqs[0] = 2412; + params->freqs[1] = 2437; + params->freqs[2] = 2462; + params->freqs[3] = freq; + params->freqs[4] = 0; break; } - ret = wpa_drv_scan(wpa_s, ¶ms); - - wpabuf_free(ies); - - if (ret) { - for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { - if (ifs->scanning || - ifs->scan_res_handler == wpas_p2p_scan_res_handler) { - wpa_s->global->p2p_cb_on_scan_complete = 1; - ret = 1; - break; - } - } - } else { - os_get_time(&wpa_s->scan_trigger_time); - wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; - } + radio_remove_unstarted_work(wpa_s, "p2p-scan"); + if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb, + params) < 0) + goto fail; + return 0; - return ret; +fail: + wpa_scan_free_params(params); + return -1; } @@ -488,6 +526,8 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, os_free(wpa_s->go_params); wpa_s->go_params = NULL; + wpa_s->waiting_presence_resp = 0; + wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network"); if (ssid && (ssid->p2p_group || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION || @@ -510,7 +550,6 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, wpa_config_remove_network(wpa_s->conf, id); wpa_supplicant_clear_status(wpa_s); wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_s->sta_scan_pending = 0; } else { wpa_printf(MSG_DEBUG, "P2P: Temporary group network not " "found"); @@ -853,11 +892,37 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, network_id = ssid->id; if (!client) { wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); - os_get_time(&wpa_s->global->p2p_go_wait_client); + os_get_reltime(&wpa_s->global->p2p_go_wait_client); } } +struct send_action_work { + unsigned int freq; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + size_t len; + unsigned int wait_time; + u8 buf[0]; +}; + + +static void wpas_p2p_send_action_work_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (!wpa_s->p2p_send_action_work) + return; + + wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out"); + os_free(wpa_s->p2p_send_action_work->ctx); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; +} + + static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, @@ -868,10 +933,31 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, { enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS; + if (wpa_s->p2p_send_action_work) { + struct send_action_work *awork; + awork = wpa_s->p2p_send_action_work->ctx; + if (awork->wait_time == 0) { + os_free(awork); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; + } else { + /* + * In theory, this should not be needed, but number of + * places in the P2P code is still using non-zero wait + * time for the last Action frame in the sequence and + * some of these do not call send_action_done(). + */ + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + eloop_register_timeout( + 0, awork->wait_time * 1000, + wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + } + } + if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return; switch (result) { case OFFCHANNEL_SEND_ACTION_SUCCESS: @@ -901,11 +987,81 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, } +static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct send_action_work *awork = work->ctx; + + if (deinit) { + os_free(awork); + return; + } + + if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src, + awork->bssid, awork->buf, awork->len, + awork->wait_time, + wpas_p2p_send_action_tx_status, 1) < 0) { + os_free(awork); + radio_work_done(work); + return; + } + wpa_s->p2p_send_action_work = work; +} + + +static int wpas_send_action_work(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, const u8 *buf, + size_t len, unsigned int wait_time) +{ + struct send_action_work *awork; + + if (wpa_s->p2p_send_action_work) { + wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending"); + return -1; + } + + awork = os_zalloc(sizeof(*awork) + len); + if (awork == NULL) + return -1; + + awork->freq = freq; + os_memcpy(awork->dst, dst, ETH_ALEN); + os_memcpy(awork->src, src, ETH_ALEN); + os_memcpy(awork->bssid, bssid, ETH_ALEN); + awork->len = len; + awork->wait_time = wait_time; + os_memcpy(awork->buf, buf, len); + + if (radio_add_work(wpa_s, freq, "p2p-send-action", 0, + wpas_send_action_cb, awork) < 0) { + os_free(awork); + return -1; + } + + return 0; +} + + static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time) { struct wpa_supplicant *wpa_s = ctx; + int listen_freq = -1, send_freq = -1; + + if (wpa_s->p2p_listen_work) + listen_freq = wpa_s->p2p_listen_work->freq; + if (wpa_s->p2p_send_action_work) + send_freq = wpa_s->p2p_send_action_work->freq; + if (listen_freq != (int) freq && send_freq != (int) freq) { + wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)", + listen_freq, send_freq); + return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, + len, wait_time); + } + + wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX"); return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len, wait_time, wpas_p2p_send_action_tx_status, 1); @@ -915,6 +1071,15 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, static void wpas_send_action_done(void *ctx) { struct wpa_supplicant *wpa_s = ctx; + + if (wpa_s->p2p_send_action_work) { + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + os_free(wpa_s->p2p_send_action_work->ctx); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; + } + offchannel_send_action_done(wpa_s); } @@ -1030,7 +1195,7 @@ static void p2p_go_configured(void *ctx, void *data) " [PERSISTENT]" : ""); } - os_get_time(&wpa_s->global->p2p_go_wait_client); + os_get_reltime(&wpa_s->global->p2p_go_wait_client); if (params->persistent_group) { network_id = wpas_p2p_store_persistent_group( wpa_s->parent, ssid, @@ -1328,12 +1493,21 @@ void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s) wpa_s->parent, NULL); if (wpa_s->global->p2p) p2p_group_formation_failed(wpa_s->global->p2p); - else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - wpa_drv_p2p_group_formation_failed(wpa_s); wpas_group_formation_completed(wpa_s, 0); } +static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure"); + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + wpa_s->global->p2p_fail_on_wps_complete = 0; +} + + void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) { if (wpa_s->global->p2p_group_formation != wpa_s) @@ -1346,7 +1520,7 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) } -void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) +static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; @@ -1433,7 +1607,7 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) } -void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) +static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) { struct wpa_supplicant *wpa_s = ctx; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR @@ -1443,9 +1617,9 @@ void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) } -void wpas_dev_found(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, - int new_device) +static void wpas_dev_found(void *ctx, const u8 *addr, + const struct p2p_peer_info *info, + int new_device) { #ifndef CONFIG_NO_STDOUT_DEBUG struct wpa_supplicant *wpa_s = ctx; @@ -1494,32 +1668,104 @@ static void wpas_find_stopped(void *ctx) } -static int wpas_start_listen(void *ctx, unsigned int freq, - unsigned int duration, - const struct wpabuf *probe_resp_ie) +struct wpas_p2p_listen_work { + unsigned int freq; + unsigned int duration; + struct wpabuf *probe_resp_ie; +}; + + +static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork) { - struct wpa_supplicant *wpa_s = ctx; + if (lwork == NULL) + return; + wpabuf_free(lwork->probe_resp_ie); + os_free(lwork); +} + + +static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpas_p2p_listen_work *lwork; + + if (!wpa_s->p2p_listen_work) + return; + + lwork = wpa_s->p2p_listen_work->ctx; + wpas_p2p_listen_work_free(lwork); + radio_work_done(wpa_s->p2p_listen_work); + wpa_s->p2p_listen_work = NULL; +} + - wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL); +static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpas_p2p_listen_work *lwork = work->ctx; + + if (deinit) { + wpas_p2p_listen_work_free(lwork); + return; + } + + wpa_s->p2p_listen_work = work; + + wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL); if (wpa_drv_probe_req_report(wpa_s, 1) < 0) { wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to " "report received Probe Request frames"); - return -1; + wpas_p2p_listen_work_done(wpa_s); + return; } - wpa_s->pending_listen_freq = freq; - wpa_s->pending_listen_duration = duration; + wpa_s->pending_listen_freq = lwork->freq; + wpa_s->pending_listen_duration = lwork->duration; - if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) { + if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0) + { wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver " "to remain on channel (%u MHz) for Listen " - "state", freq); + "state", lwork->freq); + wpas_p2p_listen_work_done(wpa_s); wpa_s->pending_listen_freq = 0; - return -1; + return; } wpa_s->off_channel_freq = 0; - wpa_s->roc_waiting_drv_freq = freq; + wpa_s->roc_waiting_drv_freq = lwork->freq; +} + + +static int wpas_start_listen(void *ctx, unsigned int freq, + unsigned int duration, + const struct wpabuf *probe_resp_ie) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpas_p2p_listen_work *lwork; + + if (wpa_s->p2p_listen_work) { + wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists"); + return -1; + } + + lwork = os_zalloc(sizeof(*lwork)); + if (lwork == NULL) + return -1; + lwork->freq = freq; + lwork->duration = duration; + if (probe_resp_ie) { + lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie); + if (lwork->probe_resp_ie == NULL) { + wpas_p2p_listen_work_free(lwork); + return -1; + } + } + + if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb, + lwork) < 0) { + wpas_p2p_listen_work_free(lwork); + return -1; + } return 0; } @@ -1535,6 +1781,7 @@ static void wpas_stop_listen(void *ctx) } wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL); wpa_drv_probe_req_report(wpa_s, 0); + wpas_p2p_listen_work_done(wpa_s); } @@ -2035,8 +2282,8 @@ static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WIFI_DISPLAY */ -void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len) +static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, + u16 update_indic, const u8 *tlvs, size_t tlvs_len) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos = tlvs; @@ -2153,8 +2400,8 @@ done: } -void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len) +static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, + const u8 *tlvs, size_t tlvs_len) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos = tlvs; @@ -2221,8 +2468,6 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs); @@ -2254,8 +2499,6 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs); @@ -2333,8 +2576,6 @@ u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s, int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_sd_cancel_request(wpa_s, req); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; return p2p_sd_cancel_request(wpa_s->global->p2p, @@ -2346,11 +2587,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, const u8 *dst, u8 dialog_token, const struct wpabuf *resp_tlvs) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token, - resp_tlvs); - return; - } if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token, @@ -2360,10 +2596,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - wpa_drv_p2p_service_update(wpa_s); - return; - } if (wpa_s->global->p2p) p2p_sd_service_update(wpa_s->global->p2p); } @@ -2488,11 +2720,11 @@ static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s, } -void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, - const u8 *dev_addr, const u8 *pri_dev_type, - const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab, const u8 *group_id, - size_t group_id_len) +static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, + const u8 *dev_addr, const u8 *pri_dev_type, + const char *dev_name, u16 supp_config_methods, + u8 dev_capab, u8 group_capab, const u8 *group_id, + size_t group_id_len) { struct wpa_supplicant *wpa_s = ctx; char devtype[WPS_DEV_TYPE_BUFSIZE]; @@ -2545,7 +2777,7 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, } -void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) +static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) { struct wpa_supplicant *wpa_s = ctx; unsigned int generated_pin = 0; @@ -3388,6 +3620,28 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s) } +static void wpas_presence_resp(void *ctx, const u8 *src, u8 status, + const u8 *noa, size_t noa_len) +{ + struct wpa_supplicant *wpa_s, *intf = ctx; + char hex[100]; + + for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_s->waiting_presence_resp) + break; + } + if (!wpa_s) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response"); + return; + } + wpa_s->waiting_presence_resp = 0; + + wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len); + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR + " status=%u noa=%s", MAC2STR(src), status, hex); +} + + /** * wpas_p2p_init - Initialize P2P module for %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() @@ -3409,25 +3663,6 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) if (global->p2p) return 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - struct p2p_params params; - - wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management"); - os_memset(¶ms, 0, sizeof(params)); - params.dev_name = wpa_s->conf->device_name; - os_memcpy(params.pri_dev_type, wpa_s->conf->device_type, - WPS_DEV_TYPE_LEN); - params.num_sec_dev_types = wpa_s->conf->num_sec_device_types; - os_memcpy(params.sec_dev_type, - wpa_s->conf->sec_device_type, - params.num_sec_dev_types * WPS_DEV_TYPE_LEN); - - if (wpa_drv_p2p_set_params(wpa_s, ¶ms) < 0) - return -1; - - return 0; - } - os_memset(&p2p, 0, sizeof(p2p)); p2p.cb_ctx = wpa_s; p2p.debug_print = wpas_p2p_debug_print; @@ -3452,6 +3687,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.invitation_result = wpas_invitation_result; p2p.get_noa = wpas_get_noa; p2p.go_connected = wpas_go_connected; + p2p.presence_resp = wpas_presence_resp; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); @@ -3588,6 +3824,13 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); wpas_p2p_remove_pending_group_interface(wpa_s); eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL); + wpas_p2p_listen_work_done(wpa_s); + if (wpa_s->p2p_send_action_work) { + os_free(wpa_s->p2p_send_action_work->ctx); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; + } + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL); /* TODO: remove group interface from the driver if this wpa_s instance * is on top of a P2P group interface */ @@ -3672,12 +3915,6 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method, - go_intent, own_interface_addr, - force_freq, persistent_group); - } - /* * Increase GO config timeout if HT40 is used since it takes some time * to scan channels for coex purposes before the BSS can be started. @@ -3703,9 +3940,6 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; - return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group, ssid ? ssid->ssid : NULL, @@ -3789,7 +4023,8 @@ static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s, return 0; } - updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update); + updated = os_reltime_before(&wpa_s->p2p_auto_started, + &bss->last_update); wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at " "%ld.%06ld (%supdated in last scan)", bss->last_update.sec, bss->last_update.usec, @@ -4044,8 +4279,9 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq) */ ret = wpa_drv_scan(wpa_s, ¶ms); if (!ret) { - os_get_time(&wpa_s->scan_trigger_time); + os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_join; + wpa_s->own_scan_requested = 1; } wpabuf_free(ies); @@ -4287,6 +4523,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; + wpa_s->global->p2p_fail_on_wps_complete = 0; + if (go_intent < 0) go_intent = wpa_s->conf->p2p_go_intent; @@ -4331,7 +4569,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, dev_addr); } if (auto_join) { - os_get_time(&wpa_s->p2p_auto_started); + os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto join started at " "%ld.%06ld", wpa_s->p2p_auto_started.sec, @@ -4417,9 +4655,6 @@ static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, if (timeout > wpa_s->max_remain_on_chan) timeout = wpa_s->max_remain_on_chan; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_listen(wpa_s, timeout); - return p2p_listen(wpa_s->global->p2p, timeout); } @@ -4439,6 +4674,7 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback " "(p2p_long_listen=%d ms pending_action_tx=%p)", wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s)); + wpas_p2p_listen_work_done(wpa_s); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (p2p_listen_end(wpa_s->global->p2p, freq) > 0) @@ -4916,9 +5152,14 @@ static void wpas_p2p_idle_update(void *ctx, int idle) if (!wpa_s->ap_iface) return; wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not "); - if (idle) + if (idle) { + if (wpa_s->global->p2p_fail_on_wps_complete && + wpa_s->p2p_in_provisioning) { + wpas_p2p_grpform_fail_after_wps(wpa_s); + return; + } wpas_p2p_set_group_idle_timeout(wpa_s); - else + } else eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); } @@ -4929,8 +5170,6 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct p2p_group *group; struct p2p_group_config *cfg; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return NULL; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return NULL; @@ -5019,8 +5258,6 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } if (wpa_s->global->p2p) p2p_wps_success_cb(wpa_s->global->p2p, peer_addr); - else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - wpa_drv_wps_success_cb(wpa_s, peer_addr); wpas_group_formation_completed(wpa_s, 1); } @@ -5041,6 +5278,31 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, } wpas_notify_p2p_wps_failed(wpa_s, fail); + + if (wpa_s == wpa_s->global->p2p_group_formation) { + /* + * Allow some time for the failed WPS negotiation exchange to + * complete, but remove the group since group formation cannot + * succeed after provisioning failure. + */ + wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout"); + wpa_s->global->p2p_fail_on_wps_complete = 1; + eloop_deplete_timeout(0, 50000, + wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + } +} + + +int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->global->p2p_fail_on_wps_complete || + !wpa_s->p2p_in_provisioning) + return 0; + + wpas_p2p_grpform_fail_after_wps(wpa_s); + + return 1; } @@ -5073,7 +5335,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->auto_pd_scan_retry = 0; wpas_p2p_stop_find(wpa_s); wpa_s->p2p_join_scan_count = 0; - os_get_time(&wpa_s->p2p_auto_started); + os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld", wpa_s->p2p_auto_started.sec, wpa_s->p2p_auto_started.usec); @@ -5081,12 +5343,6 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return 0; } - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr, - config_methods, - use == WPAS_P2P_PD_FOR_JOIN); - } - if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return -1; @@ -5122,9 +5378,6 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_find(wpa_s, timeout, type); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || wpa_s->p2p_in_provisioning) return -1; @@ -5143,12 +5396,6 @@ static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s) wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); - wpa_s->global->p2p_cb_on_scan_complete = 0; - - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - wpa_drv_p2p_stop_find(wpa_s); - return 1; - } if (wpa_s->global->p2p) p2p_stop_find(wpa_s->global->p2p); @@ -5302,9 +5549,6 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) { wpa_s->p2p_long_listen = 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_reject(wpa_s, addr); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5360,11 +5604,6 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (res) return res; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid, - ssid->ssid, ssid->ssid_len, - go_dev_addr, 1); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5442,11 +5681,6 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, } wpa_s->parent->pending_invite_ssid_id = -1; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid, - ssid->ssid, ssid->ssid_len, - go_dev_addr, persistent); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5477,7 +5711,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) } if (!wpa_s->show_group_started || !ssid) - goto done; + return; wpa_s->show_group_started = 0; @@ -5519,17 +5753,14 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) if (network_id < 0) network_id = ssid->id; wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1); - -done: - wpas_p2p_continue_after_scan(wpa_s); } int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, u32 interval1, u32 duration2, u32 interval2) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; + int ret; + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5538,18 +5769,19 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, wpa_s->current_ssid->mode != WPAS_MODE_INFRA) return -1; - return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid, - wpa_s->own_addr, wpa_s->assoc_freq, - duration1, interval1, duration2, interval2); + ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid, + wpa_s->own_addr, wpa_s->assoc_freq, + duration1, interval1, duration2, interval2); + if (ret == 0) + wpa_s->waiting_presence_resp = 1; + + return ret; } int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period, unsigned int interval) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5651,8 +5883,6 @@ int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return 0; if (!locally_generated) p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, @@ -5680,8 +5910,6 @@ void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return; if (!locally_generated) p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, @@ -5831,8 +6059,6 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; wpa_s->global->cross_connection = enabled; p2p_set_cross_connect(wpa_s->global->p2p, enabled); @@ -6090,7 +6316,7 @@ void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s, int freq_24, int freq_5, int freq_overall) { struct p2p_data *p2p = wpa_s->global->p2p; - if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) + if (p2p == NULL) return; p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall); } @@ -6101,7 +6327,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr) u8 peer[ETH_ALEN]; struct p2p_data *p2p = wpa_s->global->p2p; - if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) + if (p2p == NULL) return -1; if (hwaddr_aton(addr, peer)) @@ -6158,10 +6384,10 @@ int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s) } if (!ret && wpa_s->global->p2p_go_wait_client.sec) { - struct os_time now; - os_get_time(&now); - if (now.sec > wpa_s->global->p2p_go_wait_client.sec + - P2P_MAX_INITIAL_CONN_WAIT_GO) { + struct os_reltime now; + os_get_reltime(&now); + if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client, + P2P_MAX_INITIAL_CONN_WAIT_GO)) { /* Wait for the first client has expired */ wpa_s->global->p2p_go_wait_client.sec = 0; } else { @@ -6324,30 +6550,6 @@ unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s) } -void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s) -{ - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not " - "pending anymore (sta_scan_pending=%d " - "p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending, - wpa_s->global->p2p_cb_on_scan_complete); - wpa_s->sta_scan_pending = 0; - - if (!wpa_s->global->p2p_cb_on_scan_complete) - return; - wpa_s->global->p2p_cb_on_scan_complete = 0; - - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) - return; - - if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " - "continued after successful connection"); - p2p_increase_search_delay(wpa_s->global->p2p, - wpas_p2p_search_delay(wpa_s)); - } -} - - static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s, struct wpa_ssid *s, const u8 *addr, int iface_addr) diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 9630eb5b..7abfb125 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -74,22 +74,7 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, u8 category, const u8 *data, size_t len, int freq); void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies); void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s); -void wpas_dev_found(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, - int new_device); void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s); -void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res); -void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id); -void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, - const u8 *dev_addr, const u8 *pri_dev_type, - const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab, const u8 *group_id, - size_t group_id_len); -void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods); -void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len); -void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len); u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs); u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, @@ -143,6 +128,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr); int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s); void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); +int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s); int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s); void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -164,14 +150,9 @@ void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer, int iface_addr); #ifdef CONFIG_P2P -void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s); int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s); void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ -static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s) -{ -} - static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) { return 0; diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index ff2ae747..ed570858 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -27,9 +27,6 @@ #include "drivers/driver.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; - struct wpa_driver_ops *wpa_drivers[] = { NULL }; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index f38dfbb2..da827bd7 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Scanning - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -21,7 +21,6 @@ #include "hs20_supplicant.h" #include "notify.h" #include "bss.h" -#include "gas_query.h" #include "scan.h" @@ -142,71 +141,37 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, } -static int int_array_len(const int *a) +static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) { - int i; - for (i = 0; a && a[i]; i++) - ; - return i; -} - - -static void int_array_concat(int **res, const int *a) -{ - int reslen, alen, i; - int *n; - - reslen = int_array_len(*res); - alen = int_array_len(a); + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpa_driver_scan_params *params = work->ctx; + int ret; - n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); - if (n == NULL) { - os_free(*res); - *res = NULL; + if (deinit) { + wpa_scan_free_params(params); return; } - for (i = 0; i <= alen; i++) - n[reslen + i] = a[i]; - *res = n; -} - - -static int freq_cmp(const void *a, const void *b) -{ - int _a = *(int *) a; - int _b = *(int *) b; - - if (_a == 0) - return 1; - if (_b == 0) - return -1; - return _a - _b; -} + wpa_supplicant_notify_scanning(wpa_s, 1); -static void int_array_sort_unique(int *a) -{ - int alen; - int i, j; - - if (a == NULL) + if (wpa_s->clear_driver_scan_cache) + params->only_new_results = 1; + ret = wpa_drv_scan(wpa_s, params); + wpa_scan_free_params(params); + work->ctx = NULL; + if (ret) { + wpa_supplicant_notify_scanning(wpa_s, 0); + wpas_notify_scan_done(wpa_s, 0); + radio_work_done(work); return; - - alen = int_array_len(a); - qsort(a, alen, sizeof(int), freq_cmp); - - i = 0; - j = 1; - while (a[i] && a[j]) { - if (a[i] == a[j]) { - j++; - continue; - } - a[++i] = a[j++]; } - if (a[i]) - i++; - a[i] = 0; + + os_get_reltime(&wpa_s->scan_trigger_time); + wpa_s->scan_runs++; + wpa_s->normal_scans++; + wpa_s->own_scan_requested = 1; + wpa_s->clear_driver_scan_cache = 0; + wpa_s->scan_work = work; } @@ -219,21 +184,24 @@ static void int_array_sort_unique(int *a) int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { - int ret; + struct wpa_driver_scan_params *ctx; - wpa_supplicant_notify_scanning(wpa_s, 1); + if (wpa_s->scan_work) { + wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending"); + return -1; + } - ret = wpa_drv_scan(wpa_s, params); - if (ret) { - wpa_supplicant_notify_scanning(wpa_s, 0); - wpas_notify_scan_done(wpa_s, 0); - } else { - os_get_time(&wpa_s->scan_trigger_time); - wpa_s->scan_runs++; - wpa_s->normal_scans++; + ctx = wpa_scan_clone_params(params); + if (ctx == NULL) + return -1; + + if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) + { + wpa_scan_free_params(ctx); + return -1; } - return ret; + return 0; } @@ -366,7 +334,8 @@ static void wpa_supplicant_optimize_freqs( if (params->freqs) params->freqs[0] = wpa_s->wps_freq; wpa_s->after_wps--; - } + } else if (wpa_s->after_wps) + wpa_s->after_wps--; if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq) { @@ -554,14 +523,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); - wpas_p2p_continue_after_scan(wpa_s); return; } if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); - wpas_p2p_continue_after_scan(wpa_s); return; } @@ -579,7 +546,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); - wpas_p2p_continue_after_scan(wpa_s); return; } @@ -597,29 +563,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } #ifdef CONFIG_P2P - if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) { - if (wpa_s->sta_scan_pending && - wpas_p2p_in_progress(wpa_s) == 2 && - wpa_s->global->p2p_cb_on_scan_complete) { - wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " - "mode scan during P2P search"); - } else { - wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " - "while P2P operation is in progress"); - wpa_s->sta_scan_pending = 1; - wpa_supplicant_req_scan(wpa_s, 5, 0); - return; - } - } -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_GAS - if (gas_query_in_progress(wpa_s->gas)) { - wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress"); - wpa_supplicant_req_scan(wpa_s, 1, 0); + if (wpas_p2p_in_progress(wpa_s)) { + wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress"); + wpa_supplicant_req_scan(wpa_s, 5, 0); return; } -#endif /* CONFIG_GAS */ +#endif /* CONFIG_P2P */ if (wpa_s->conf->ap_scan == 2) max_ssids = 1; @@ -766,6 +715,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; + } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_passive && params.num_ssids == 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; @@ -779,6 +731,17 @@ ssid_list_set: wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_only_new) + params.only_new_results = 1; + + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && + wpa_s->manual_scan_freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); + params.freqs = wpa_s->manual_scan_freqs; + wpa_s->manual_scan_freqs = NULL; + } + if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); @@ -867,6 +830,13 @@ scan: ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); + if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && + !wpa_s->manual_scan_freqs) { + /* Restore manual_scan_freqs for the next attempt */ + wpa_s->manual_scan_freqs = params.freqs; + params.freqs = NULL; + } + wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); @@ -918,17 +888,19 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec) */ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { - if (eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL)) - { - wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d sec %d usec", + int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, + NULL); + if (res == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec", sec, usec); - return; + } else if (res == 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner", + sec, usec); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec", + sec, usec); + eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); } - - wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", - sec, usec); - eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); - eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); } @@ -1200,7 +1172,6 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request"); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); - wpas_p2p_continue_after_scan(wpa_s); } @@ -1663,12 +1634,12 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, * Make sure we have a valid timestamp if the driver wrapper * does not set this. */ - os_get_time(&scan_res->fetch_time); + os_get_reltime(&scan_res->fetch_time); } filter_scan_res(wpa_s, scan_res); #ifdef CONFIG_WPS - if (wpas_wps_in_progress(wpa_s)) { + if (wpas_wps_searching(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS " "provisioning rules"); compar = wpa_scan_result_wps_compar; @@ -1720,9 +1691,21 @@ void scan_only_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received"); - wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", + wpa_s->manual_scan_id); + wpa_s->manual_scan_use_id = 0; + } else { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); + if (wpa_s->scan_work) { + struct wpa_radio_work *work = wpa_s->scan_work; + wpa_s->scan_work = NULL; + radio_work_done(work); + } } @@ -1730,3 +1713,82 @@ int wpas_scan_scheduled(struct wpa_supplicant *wpa_s) { return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL); } + + +struct wpa_driver_scan_params * +wpa_scan_clone_params(const struct wpa_driver_scan_params *src) +{ + struct wpa_driver_scan_params *params; + size_t i; + u8 *n; + + params = os_zalloc(sizeof(*params)); + if (params == NULL) + return NULL; + + for (i = 0; i < src->num_ssids; i++) { + if (src->ssids[i].ssid) { + n = os_malloc(src->ssids[i].ssid_len); + if (n == NULL) + goto failed; + os_memcpy(n, src->ssids[i].ssid, + src->ssids[i].ssid_len); + params->ssids[i].ssid = n; + params->ssids[i].ssid_len = src->ssids[i].ssid_len; + } + } + params->num_ssids = src->num_ssids; + + if (src->extra_ies) { + n = os_malloc(src->extra_ies_len); + if (n == NULL) + goto failed; + os_memcpy(n, src->extra_ies, src->extra_ies_len); + params->extra_ies = n; + params->extra_ies_len = src->extra_ies_len; + } + + if (src->freqs) { + int len = int_array_len(src->freqs); + params->freqs = os_malloc((len + 1) * sizeof(int)); + if (params->freqs == NULL) + goto failed; + os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int)); + } + + if (src->filter_ssids) { + params->filter_ssids = os_malloc(sizeof(params->filter_ssids) * + src->num_filter_ssids); + if (params->filter_ssids == NULL) + goto failed; + os_memcpy(params->filter_ssids, src->filter_ssids, + sizeof(params->filter_ssids) * src->num_filter_ssids); + params->num_filter_ssids = src->num_filter_ssids; + } + + params->filter_rssi = src->filter_rssi; + params->p2p_probe = src->p2p_probe; + params->only_new_results = src->only_new_results; + + return params; + +failed: + wpa_scan_free_params(params); + return NULL; +} + + +void wpa_scan_free_params(struct wpa_driver_scan_params *params) +{ + size_t i; + + if (params == NULL) + return; + + for (i = 0; i < params->num_ssids; i++) + os_free((u8 *) params->ssids[i].ssid); + os_free((u8 *) params->extra_ies); + os_free(params->freqs); + os_free(params->filter_ssids); + os_free(params); +} diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index b6fe070e..e4c89895 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -1,6 +1,6 @@ /* * WPA Supplicant - Scanning - * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -43,5 +43,8 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params, int interval); int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s); +struct wpa_driver_scan_params * +wpa_scan_clone_params(const struct wpa_driver_scan_params *src); +void wpa_scan_free_params(struct wpa_driver_scan_params *params); #endif /* SCAN_H */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 87c14ae3..43f40cd1 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1,6 +1,6 @@ /* * wpa_supplicant - SME - * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -157,6 +157,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (bss == NULL) { wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for " "the network"); + wpas_connect_work_done(wpa_s); return; } @@ -244,6 +245,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, &wpa_s->sme.assoc_req_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites"); + wpas_connect_work_done(wpa_s); return; } } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && @@ -263,6 +265,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites (no " "scan results)"); + wpas_connect_work_done(wpa_s); return; } #ifdef CONFIG_WPS @@ -386,8 +389,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, bss->bssid); else resp = sme_auth_build_sae_confirm(wpa_s); - if (resp == NULL) + if (resp == NULL) { + wpas_connect_work_done(wpa_s); return; + } params.sae_data = wpabuf_head(resp); params.sae_data_len = wpabuf_len(resp); wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED; @@ -417,6 +422,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpas_connection_failed(wpa_s, bss->bssid); wpa_supplicant_mark_disassoc(wpa_s); wpabuf_free(resp); + wpas_connect_work_done(wpa_s); return; } @@ -432,15 +438,56 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } +static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_connect_work *cwork = work->ctx; + struct wpa_supplicant *wpa_s = work->wpa_s; + + if (deinit) { + wpas_connect_work_free(cwork); + return; + } + + wpa_s->connect_work = work; + + if (!wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt"); + wpas_connect_work_done(wpa_s); + return; + } + + sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1); +} + + void sme_authenticate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { + struct wpa_connect_work *cwork; + + if (bss == NULL || ssid == NULL) + return; + if (wpa_s->connect_work) { + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist"); + return; + } + + cwork = os_zalloc(sizeof(*cwork)); + if (cwork == NULL) + return; + cwork->bss = bss; + cwork->ssid = ssid; + cwork->sme = 1; + #ifdef CONFIG_SAE wpa_s->sme.sae.state = SAE_NOTHING; wpa_s->sme.sae.send_confirm = 0; wpa_s->sme.sae_group_index = 0; #endif /* CONFIG_SAE */ - sme_send_authentication(wpa_s, bss, ssid, 1); + + if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1, + sme_auth_start_cb, cwork) < 0) + wpas_connect_work_free(cwork); } @@ -651,9 +698,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; - params.pairwise_suite = - wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher); - params.group_suite = wpa_cipher_to_suite_driver(wpa_s->group_cipher); + params.pairwise_suite = wpa_s->pairwise_cipher; + params.group_suite = wpa_s->group_cipher; #ifdef CONFIG_HT_OVERRIDES os_memset(&htcaps, 0, sizeof(htcaps)); os_memset(&htcaps_mask, 0, sizeof(htcaps_mask)); @@ -1151,9 +1197,9 @@ static const unsigned int sa_query_retry_timeout = 201; static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s) { u32 tu; - struct os_time now, passed; - os_get_time(&now); - os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed); + struct os_reltime now, passed; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->sme.sa_query_start, &passed); tu = (passed.sec * 1000000 + passed.usec) / 1024; if (sa_query_max_timeout < tu) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out"); @@ -1203,7 +1249,7 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx) return; if (wpa_s->sme.sa_query_count == 0) { /* Starting a new SA Query procedure */ - os_get_time(&wpa_s->sme.sa_query_start); + os_get_reltime(&wpa_s->sme.sa_query_start); } trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; wpa_s->sme.sa_query_trans_id = nbuf; diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c index 484a4068..39971f28 100644 --- a/wpa_supplicant/tests/test_wpa.c +++ b/wpa_supplicant/tests/test_wpa.c @@ -17,10 +17,6 @@ #include "ap/wpa_auth.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; - - struct wpa { u8 auth_addr[ETH_ALEN]; u8 supp_addr[ETH_ALEN]; diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 4f8d895a..65b27838 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -181,7 +181,7 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, /* Install GTK/IGTK */ /* point to key data field */ - ptr = (u8 *) frm + 1 + 1 + 2; + ptr = (u8 *) frm + 1 + 2; end = ptr + key_len_total; wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); @@ -237,16 +237,16 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data | * WNM-Sleep Mode IE | TFS Response IE */ - u8 *pos = (u8 *) frm; /* point to action field */ + u8 *pos = (u8 *) frm; /* point to payload after the action field */ u16 key_len_total = le_to_host16(*((u16 *)(frm+2))); struct wnm_sleep_element *wnmsleep_ie = NULL; /* multiple TFS Resp IE (assuming consecutive) */ u8 *tfsresp_ie_start = NULL; u8 *tfsresp_ie_end = NULL; - wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d", - frm[0], frm[1], key_len_total); - pos += 4 + key_len_total; + wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", + frm[0], key_len_total); + pos += 3 + key_len_total; if (pos > frm + len) { wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); return; @@ -473,6 +473,10 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, if (scan_res == NULL || num_neigh_rep == 0) return 0; + wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", + MAC2STR(wpa_s->bssid), + wpa_s->current_bss ? wpa_s->current_bss->level : 0); + for (i = 0; i < num_neigh_rep; i++) { for (j = 0; j < scan_res->num; j++) { /* Check for a better RSSI AP */ @@ -483,8 +487,16 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, /* Got a BSSID with better RSSI value */ os_memcpy(bssid_to_connect, neigh_rep[i].bssid, ETH_ALEN); + wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR + " with better scan RSSI %d", + MAC2STR(scan_res->res[j]->bssid), + scan_res->res[j]->level); return 1; } + wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR + " RSSI %d", j, + MAC2STR(scan_res->res[j]->bssid), + scan_res->res[j]->level); } } @@ -521,6 +533,14 @@ static void wnm_send_bss_transition_mgmt_resp( if (target_bssid) { os_memcpy(pos, target_bssid, ETH_ALEN); pos += ETH_ALEN; + } else if (status == WNM_BSS_TM_ACCEPT) { + /* + * P802.11-REVmc clarifies that the Target BSSID field is always + * present when status code is zero, so use a fake value here if + * no BSSID is yet known. + */ + os_memset(pos, 0, ETH_ALEN); + pos += ETH_ALEN; } len = pos - (u8 *) &mgmt->u.action.category; @@ -562,7 +582,7 @@ void wnm_scan_response(struct wpa_supplicant *wpa_s, wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, - 0, NULL); + 0, bssid); } wpa_s->reassociate = 1; @@ -717,7 +737,7 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; - mgmt->u.action.u.bss_tm_query.dialog_token = 0; + mgmt->u.action.u.bss_tm_query.dialog_token = 1; mgmt->u.action.u.bss_tm_query.query_reason = query_reason; pos = mgmt->u.action.u.bss_tm_query.variable; @@ -732,22 +752,23 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, - struct rx_action *action) + const struct ieee80211_mgmt *mgmt, size_t len) { const u8 *pos, *end; u8 act; - if (action->data == NULL || action->len == 0) + if (len < IEEE80211_HDRLEN + 2) return; - pos = action->data; - end = pos + action->len; + pos = &mgmt->u.action.category; + pos++; act = *pos++; + end = ((const u8 *) mgmt) + len; wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, - act, MAC2STR(action->sa)); + act, MAC2STR(mgmt->sa)); if (wpa_s->wpa_state < WPA_ASSOCIATED || - os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) { + os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " "frame"); return; @@ -756,10 +777,10 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, switch (act) { case WNM_BSS_TRANS_MGMT_REQ: ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, - !(action->da[0] & 0x01)); + !(mgmt->da[0] & 0x01)); break; case WNM_SLEEP_MODE_RESP: - ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len); + ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); break; default: wpa_printf(MSG_ERROR, "WNM: Unknown request"); diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index 2933926c..de873015 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -9,9 +9,6 @@ #ifndef WNM_STA_H #define WNM_STA_H -struct rx_action; -struct wpa_supplicant; - struct tsf_info { u8 present; u8 tsf_offset[2]; @@ -78,7 +75,7 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 intval, struct wpabuf *tfs_req); void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, - struct rx_action *action); + const struct ieee80211_mgmt *mgmt, size_t len); void wnm_scan_response(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index aabaa3cc..358c2feb 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -28,7 +28,7 @@ static const char *wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; static const char *wpa_cli_license = @@ -2426,6 +2426,12 @@ static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv); +} + + enum wpa_cli_cmd_flags { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 @@ -2893,6 +2899,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none, "<command> = driver private commands" }, #endif /* ANDROID */ + { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none, + "= radio_work <show/add/done>" }, { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c index 4afaae90..5426177a 100644 --- a/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant/wpa_priv.c @@ -552,8 +552,6 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) } -extern struct wpa_driver_ops *wpa_drivers[]; - static struct wpa_priv_interface * wpa_priv_interface_init(const char *dir, const char *params) { @@ -946,8 +944,6 @@ static void usage(void) } -extern int wpa_debug_level; - int main(int argc, char *argv[]) { int c, i; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 2d6272b1..187e5d9b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -54,7 +54,7 @@ const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors"; const char *wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -104,11 +104,6 @@ const char *wpa_supplicant_full_license5 = "\n"; #endif /* CONFIG_NO_STDOUT_DEBUG */ -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; -extern struct wpa_driver_ops *wpa_drivers[]; - /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -200,8 +195,6 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) * So, wait a second until scanning again. */ wpa_supplicant_req_scan(wpa_s, 1, 0); - - wpas_p2p_continue_after_scan(wpa_s); } @@ -459,6 +452,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + gas_query_deinit(wpa_s->gas); wpa_s->gas = NULL; @@ -481,6 +477,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->ext_pw = NULL; wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = NULL; + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = NULL; os_free(wpa_s->last_scan_res); wpa_s->last_scan_res = NULL; @@ -497,29 +496,23 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) */ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) { - if (wpa_s->keys_cleared) { - /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have - * timing issues with keys being cleared just before new keys - * are set or just after association or something similar. This - * shows up in group key handshake failing often because of the - * client not receiving the first encrypted packets correctly. - * Skipping some of the extra key clearing steps seems to help - * in completing group key handshake more reliably. */ - wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - " - "skip key clearing"); - return; - } + int i, max; - /* MLME-DELETEKEYS.request */ - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); #ifdef CONFIG_IEEE80211W - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); + max = 6; +#else /* CONFIG_IEEE80211W */ + max = 4; #endif /* CONFIG_IEEE80211W */ - if (addr) { + + /* MLME-DELETEKEYS.request */ + for (i = 0; i < max; i++) { + if (wpa_s->keys_cleared & BIT(i)) + continue; + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0, + NULL, 0); + } + if (!(wpa_s->keys_cleared & BIT(0)) && addr && + !is_zero_ether_addr(addr)) { wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0); /* MLME-SETPROTECTION.request(None) */ @@ -528,7 +521,7 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) MLME_SETPROTECTION_PROTECT_TYPE_NONE, MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); } - wpa_s->keys_cleared = 1; + wpa_s->keys_cleared = (u32) -1; } @@ -659,6 +652,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_supplicant_state_txt(state)); + if (state == WPA_COMPLETED) + wpas_connect_work_done(wpa_s); + if (state != WPA_SCANNING) wpa_supplicant_notify_scanning(wpa_s, 0); @@ -699,7 +695,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, #ifdef CONFIG_BGSCAN if (state == WPA_COMPLETED) wpa_supplicant_start_bgscan(wpa_s); - else + else if (state < WPA_ASSOCIATED) wpa_supplicant_stop_bgscan(wpa_s); #endif /* CONFIG_BGSCAN */ @@ -725,6 +721,7 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global) #ifdef CONFIG_WPS struct wpa_supplicant *wpa_s = global->ifaces; while (wpa_s) { + struct wpa_supplicant *next = wpa_s->next; #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE || (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)) @@ -732,7 +729,7 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global) #endif /* CONFIG_P2P */ if (wpas_wps_terminate_pending(wpa_s) == 1) pending = 1; - wpa_s = wpa_s->next; + wpa_s = next; } #endif /* CONFIG_WPS */ if (pending) @@ -861,34 +858,6 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx) } -enum wpa_key_mgmt key_mgmt2driver(int key_mgmt) -{ - switch (key_mgmt) { - case WPA_KEY_MGMT_NONE: - return KEY_MGMT_NONE; - case WPA_KEY_MGMT_IEEE8021X_NO_WPA: - return KEY_MGMT_802_1X_NO_WPA; - case WPA_KEY_MGMT_IEEE8021X: - return KEY_MGMT_802_1X; - case WPA_KEY_MGMT_WPA_NONE: - return KEY_MGMT_WPA_NONE; - case WPA_KEY_MGMT_FT_IEEE8021X: - return KEY_MGMT_FT_802_1X; - case WPA_KEY_MGMT_FT_PSK: - return KEY_MGMT_FT_PSK; - case WPA_KEY_MGMT_IEEE8021X_SHA256: - return KEY_MGMT_802_1X_SHA256; - case WPA_KEY_MGMT_PSK_SHA256: - return KEY_MGMT_PSK_SHA256; - case WPA_KEY_MGMT_WPS: - return KEY_MGMT_WPS; - case WPA_KEY_MGMT_PSK: - default: - return KEY_MGMT_PSK; - } -} - - static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_ie_data *ie) @@ -1229,7 +1198,8 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) break; case 4: /* Bits 32-39 */ #ifdef CONFIG_INTERWORKING - *pos |= 0x01; /* Bit 32 - QoS Map */ + if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING) + *pos |= 0x01; /* Bit 32 - QoS Map */ #endif /* CONFIG_INTERWORKING */ break; case 5: /* Bits 40-47 */ @@ -1270,6 +1240,70 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf) } +static int wpas_valid_bss(struct wpa_supplicant *wpa_s, + struct wpa_bss *test_bss) +{ + struct wpa_bss *bss; + + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + if (bss == test_bss) + return 1; + } + + return 0; +} + + +static int wpas_valid_ssid(struct wpa_supplicant *wpa_s, + struct wpa_ssid *test_ssid) +{ + struct wpa_ssid *ssid; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (ssid == test_ssid) + return 1; + } + + return 0; +} + + +int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss, + struct wpa_ssid *test_ssid) +{ + if (test_bss && !wpas_valid_bss(wpa_s, test_bss)) + return 0; + + return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid); +} + + +void wpas_connect_work_free(struct wpa_connect_work *cwork) +{ + if (cwork == NULL) + return; + os_free(cwork); +} + + +void wpas_connect_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpa_connect_work *cwork; + struct wpa_radio_work *work = wpa_s->connect_work; + + if (!work) + return; + + wpa_s->connect_work = NULL; + cwork = work->ctx; + work->ctx = NULL; + wpas_connect_work_free(cwork); + radio_work_done(work); +} + + +static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit); + /** * wpa_supplicant_associate - Request association * @wpa_s: Pointer to wpa_supplicant data @@ -1281,19 +1315,7 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf) void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { - u8 wpa_ie[200]; - size_t wpa_ie_len; - int use_crypt, ret, i, bssid_changed; - int algs = WPA_AUTH_ALG_OPEN; - enum wpa_cipher cipher_pairwise, cipher_group; - struct wpa_driver_associate_params params; - int wep_keys_set = 0; - int assoc_failed = 0; - struct wpa_ssid *old_ssid; -#ifdef CONFIG_HT_OVERRIDES - struct ieee80211_ht_capabilities htcaps; - struct ieee80211_ht_capabilities htcaps_mask; -#endif /* CONFIG_HT_OVERRIDES */ + struct wpa_connect_work *cwork; #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); @@ -1334,6 +1356,58 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + if (wpa_s->connect_work) { + wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist"); + return; + } + + cwork = os_zalloc(sizeof(*cwork)); + if (cwork == NULL) + return; + + cwork->bss = bss; + cwork->ssid = ssid; + + if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1, + wpas_start_assoc_cb, cwork) < 0) { + os_free(cwork); + } +} + + +static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_connect_work *cwork = work->ctx; + struct wpa_bss *bss = cwork->bss; + struct wpa_ssid *ssid = cwork->ssid; + struct wpa_supplicant *wpa_s = work->wpa_s; + u8 wpa_ie[200]; + size_t wpa_ie_len; + int use_crypt, ret, i, bssid_changed; + int algs = WPA_AUTH_ALG_OPEN; + unsigned int cipher_pairwise, cipher_group; + struct wpa_driver_associate_params params; + int wep_keys_set = 0; + int assoc_failed = 0; + struct wpa_ssid *old_ssid; +#ifdef CONFIG_HT_OVERRIDES + struct ieee80211_ht_capabilities htcaps; + struct ieee80211_ht_capabilities htcaps_mask; +#endif /* CONFIG_HT_OVERRIDES */ + + if (deinit) { + wpas_connect_work_free(cwork); + return; + } + + wpa_s->connect_work = work; + + if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt"); + wpas_connect_work_done(wpa_s); + return; + } + os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; if (bss && !wpas_driver_bss_selection(wpa_s)) { @@ -1526,8 +1600,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); use_crypt = 1; - cipher_pairwise = wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher); - cipher_group = wpa_cipher_to_suite_driver(wpa_s->group_cipher); + cipher_pairwise = wpa_s->pairwise_cipher; + cipher_group = wpa_s->group_cipher; if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) @@ -1551,7 +1625,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, /* Assume that dynamic WEP-104 keys will be used and * set cipher suites in order for drivers to expect * encryption. */ - cipher_pairwise = cipher_group = CIPHER_WEP104; + cipher_pairwise = cipher_group = WPA_CIPHER_WEP104; } } #endif /* IEEE8021X_EAPOL */ @@ -1592,7 +1666,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, params.wpa_ie_len = wpa_ie_len; params.pairwise_suite = cipher_pairwise; params.group_suite = cipher_group; - params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt); + params.key_mgmt_suite = wpa_s->key_mgmt; params.wpa_proto = wpa_s->wpa_proto; params.auth_alg = algs; params.mode = ssid->mode; @@ -1605,8 +1679,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, params.wep_tx_keyidx = ssid->wep_tx_keyidx; if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && - (params.key_mgmt_suite == KEY_MGMT_PSK || - params.key_mgmt_suite == KEY_MGMT_FT_PSK)) { + (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || + params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { params.passphrase = ssid->passphrase; if (ssid->psk_set) params.psk = ssid->psk; @@ -2323,6 +2397,16 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); +#ifdef CONFIG_PEERKEY + if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid && + wpa_s->current_ssid->peerkey && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && + wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key"); + return; + } +#endif /* CONFIG_PEERKEY */ + if (wpa_s->wpa_state < WPA_ASSOCIATED || (wpa_s->last_eapol_matches_bssid && #ifdef CONFIG_AP @@ -2348,7 +2432,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len); if (wpa_s->pending_eapol_rx) { - os_get_time(&wpa_s->pending_eapol_rx_time); + os_get_reltime(&wpa_s->pending_eapol_rx_time); os_memcpy(wpa_s->pending_eapol_rx_src, src_addr, ETH_ALEN); } @@ -2918,12 +3002,89 @@ static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s, if (rn) os_strlcpy(radio->name, rn, sizeof(radio->name)); dl_list_init(&radio->ifaces); + dl_list_init(&radio->work); dl_list_add(&radio->ifaces, &wpa_s->radio_list); return radio; } +static void radio_work_free(struct wpa_radio_work *work) +{ + if (work->wpa_s->scan_work == work) { + /* This should not really happen. */ + wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work", + work->type, work, work->started); + work->wpa_s->scan_work = NULL; + } + +#ifdef CONFIG_P2P + if (work->wpa_s->p2p_scan_work == work) { + /* This should not really happen. */ + wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work", + work->type, work, work->started); + work->wpa_s->p2p_scan_work = NULL; + } +#endif /* CONFIG_P2P */ + + dl_list_del(&work->list); + os_free(work); +} + + +static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_radio *radio = eloop_ctx; + struct wpa_radio_work *work; + struct os_reltime now, diff; + struct wpa_supplicant *wpa_s; + + work = dl_list_first(&radio->work, struct wpa_radio_work, list); + if (work == NULL) + return; + + if (work->started) + return; /* already started and still in progress */ + + wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant, + radio_list); + if (wpa_s && wpa_s->external_scan_running) { + wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); + return; + } + + os_get_reltime(&now); + os_reltime_sub(&now, &work->time, &diff); + wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait", + work->type, work, diff.sec, diff.usec); + work->started = 1; + work->time = now; + work->cb(work, 0); +} + + +void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s, const char *type) +{ + struct wpa_radio_work *work, *tmp; + struct wpa_radio *radio = wpa_s->radio; + + dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work, + list) { + if (type && (work->started || os_strcmp(type, work->type) != 0)) + continue; + if (work->started) { + wpa_dbg(wpa_s, MSG_DEBUG, "Leaving started radio work '%s'@%p in the list", + work->type, work); + continue; + } + wpa_dbg(wpa_s, MSG_DEBUG, "Remove unstarted radio work '%s'@%p", + work->type, work); + work->cb(work, 1); + radio_work_free(work); + } +} + + static void radio_remove_interface(struct wpa_supplicant *wpa_s) { struct wpa_radio *radio = wpa_s->radio; @@ -2934,16 +3095,112 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s", wpa_s->ifname, radio->name); dl_list_del(&wpa_s->radio_list); - wpa_s->radio = NULL; - - if (!dl_list_empty(&radio->ifaces)) + if (!dl_list_empty(&radio->ifaces)) { + wpa_s->radio = NULL; return; /* Interfaces remain for this radio */ + } wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name); + radio_remove_unstarted_work(wpa_s, NULL); + eloop_cancel_timeout(radio_start_next_work, radio, NULL); + wpa_s->radio = NULL; os_free(radio); } +void radio_work_check_next(struct wpa_supplicant *wpa_s) +{ + struct wpa_radio *radio = wpa_s->radio; + + if (dl_list_empty(&radio->work)) + return; + eloop_cancel_timeout(radio_start_next_work, radio, NULL); + eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL); +} + + +/** + * radio_add_work - Add a radio work item + * @wpa_s: Pointer to wpa_supplicant data + * @freq: Frequency of the offchannel operation in MHz or 0 + * @type: Unique identifier for each type of work + * @next: Force as the next work to be executed + * @cb: Callback function for indicating when radio is available + * @ctx: Context pointer for the work (work->ctx in cb()) + * Returns: 0 on success, -1 on failure + * + * This function is used to request time for an operation that requires + * exclusive radio control. Once the radio is available, the registered callback + * function will be called. radio_work_done() must be called once the exclusive + * radio operation has been completed, so that the radio is freed for other + * operations. The special case of deinit=1 is used to free the context data + * during interface removal. That does not allow the callback function to start + * the radio operation, i.e., it must free any resources allocated for the radio + * work and return. + * + * The @freq parameter can be used to indicate a single channel on which the + * offchannel operation will occur. This may allow multiple radio work + * operations to be performed in parallel if they apply for the same channel. + * Setting this to 0 indicates that the work item may use multiple channels or + * requires exclusive control of the radio. + */ +int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, + const char *type, int next, + void (*cb)(struct wpa_radio_work *work, int deinit), + void *ctx) +{ + struct wpa_radio_work *work; + int was_empty; + + work = os_zalloc(sizeof(*work)); + if (work == NULL) + return -1; + wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work); + os_get_reltime(&work->time); + work->freq = freq; + work->type = type; + work->wpa_s = wpa_s; + work->cb = cb; + work->ctx = ctx; + + was_empty = dl_list_empty(&wpa_s->radio->work); + if (next) + dl_list_add(&wpa_s->radio->work, &work->list); + else + dl_list_add_tail(&wpa_s->radio->work, &work->list); + if (was_empty) { + wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately"); + radio_work_check_next(wpa_s); + } + + return 0; +} + + +/** + * radio_work_done - Indicate that a radio work item has been completed + * @work: Completed work + * + * This function is called once the callback function registered with + * radio_add_work() has completed its work. + */ +void radio_work_done(struct wpa_radio_work *work) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct os_reltime now, diff; + unsigned int started = work->started; + + os_get_reltime(&now); + os_reltime_sub(&now, &work->time, &diff); + wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds", + work->type, work, started ? "done" : "canceled", + diff.sec, diff.usec); + radio_work_free(work); + if (started) + radio_work_check_next(wpa_s); +} + + static int wpas_init_driver(struct wpa_supplicant *wpa_s, struct wpa_interface *iface) { @@ -3263,6 +3520,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ + wpas_ctrl_radio_work_flush(wpa_s); radio_remove_interface(wpa_s); if (wpa_s->drv_priv) @@ -3751,6 +4009,8 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) int count; int *freqs = NULL; + wpas_connect_work_done(wpa_s); + /* * Remove possible authentication timeout since the connection failed. */ @@ -3837,8 +4097,6 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) */ wpa_supplicant_req_scan(wpa_s, timeout / 1000, 1000 * (timeout % 1000)); - - wpas_p2p_continue_after_scan(wpa_s); } @@ -3978,7 +4236,7 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; int dur; - struct os_time now; + struct os_reltime now; if (ssid == NULL) { wpa_printf(MSG_DEBUG, "Authentication failure but no known " @@ -4015,7 +4273,7 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s) else dur = 10; - os_get_time(&now); + os_get_reltime(&now); if (now.sec + dur <= ssid->disabled_until.sec) return; @@ -4103,42 +4361,6 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s) } -static int wpas_conn_in_progress(struct wpa_supplicant *wpa_s) -{ - return wpa_s->wpa_state >= WPA_AUTHENTICATING && - wpa_s->wpa_state != WPA_COMPLETED; -} - - -/** - * wpas_wpa_is_in_progress - Check whether a connection is in progress - * @wpa_s: Pointer to wpa_supplicant data - * @include_current: Whether to consider specified interface - * - * This function is to check if the wpa state is in beginning of the connection - * during 4-way handshake or group key handshake with WPA on any shared - * interface. - */ -int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current) -{ - struct wpa_supplicant *ifs; - - dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, - radio_list) { - if (!include_current && ifs == wpa_s) - continue; - - if (wpas_conn_in_progress(ifs)) { - wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress " - "on interface %s - defer", ifs->ifname); - return 1; - } - } - - return 0; -} - - void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title, int *freq_array, unsigned int len) { diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 0ecfaa68..9d3bf6d5 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -342,6 +342,8 @@ fast_reauth=1 # # credential fields: # +# temporary: Whether this credential is temporary and not to be saved +# # priority: Priority group # By default, all networks and credentials get the same priority group # (0). This field can be used to give higher priority for credentials @@ -506,9 +508,10 @@ fast_reauth=1 # 0 = infrastructure (Managed) mode, i.e., associate with an AP (default) # 1 = IBSS (ad-hoc, peer-to-peer) # 2 = AP (access point) -# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) -# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires -# following network block options: +# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) and +# WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE (fixed group key +# TKIP/CCMP) is available for backwards compatibility, but its use is +# deprecated. WPA-None requires following network block options: # proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not # both), and psk must also be set. # @@ -1163,7 +1166,19 @@ network={ } -# IBSS/ad-hoc network with WPA-None/TKIP. +# IBSS/ad-hoc network with RSN +network={ + ssid="ibss-rsn" + key_mgmt=WPA-PSK + proto=RSN + psk="12345678" + mode=1 + frequency=2412 + pairwise=CCMP + group=CCMP +} + +# IBSS/ad-hoc network with WPA-None/TKIP (deprecated) network={ ssid="test adhoc" mode=1 diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 8cc813c8..d1ea77bb 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal definitions - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -246,7 +246,7 @@ struct wpa_global { struct wpa_supplicant *p2p_group_formation; struct wpa_supplicant *p2p_invite_group; u8 p2p_dev_addr[ETH_ALEN]; - struct os_time p2p_go_wait_client; + struct os_reltime p2p_go_wait_client; struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */ struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; @@ -257,8 +257,8 @@ struct wpa_global { WPA_CONC_PREF_STA, WPA_CONC_PREF_P2P } conc_pref; - unsigned int p2p_cb_on_scan_complete:1; unsigned int p2p_per_sta_psk:1; + unsigned int p2p_fail_on_wps_complete:1; #ifdef CONFIG_WIFI_DISPLAY int wifi_display; @@ -281,6 +281,47 @@ struct wpa_radio { char name[16]; /* from driver_ops get_radio_name() or empty if not * available */ struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */ + struct dl_list work; /* struct wpa_radio_work::list entries */ +}; + +/** + * struct wpa_radio_work - Radio work item + */ +struct wpa_radio_work { + struct dl_list list; + unsigned int freq; /* known frequency (MHz) or 0 for multiple/unknown */ + const char *type; + struct wpa_supplicant *wpa_s; + void (*cb)(struct wpa_radio_work *work, int deinit); + void *ctx; + unsigned int started:1; + struct os_reltime time; +}; + +int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, + const char *type, int next, + void (*cb)(struct wpa_radio_work *work, int deinit), + void *ctx); +void radio_work_done(struct wpa_radio_work *work); +void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s, + const char *type); +void radio_work_check_next(struct wpa_supplicant *wpa_s); + +struct wpa_connect_work { + unsigned int sme:1; + struct wpa_bss *bss; + struct wpa_ssid *ssid; +}; + +int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss, + struct wpa_ssid *test_ssid); +void wpas_connect_work_free(struct wpa_connect_work *cwork); +void wpas_connect_work_done(struct wpa_supplicant *wpa_s); + +struct wpa_external_work { + unsigned int id; + char type[100]; + unsigned int timeout; }; /** @@ -302,7 +343,7 @@ struct wps_ap_info { WPS_AP_SEL_REG_OUR } type; unsigned int tries; - struct os_time last_attempt; + struct os_reltime last_attempt; }; struct wpa_ssid_value { @@ -344,7 +385,7 @@ struct wpa_supplicant { char *confanother; struct wpa_config *conf; int countermeasures; - os_time_t last_michael_mic_error; + struct os_reltime last_michael_mic_error; u8 bssid[ETH_ALEN]; u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this * field contains the target BSSID. */ @@ -408,8 +449,7 @@ struct wpa_supplicant { struct wpa_bss **last_scan_res; unsigned int last_scan_res_used; unsigned int last_scan_res_size; - int last_scan_full; - struct os_time last_scan; + struct os_reltime last_scan; struct wpa_driver_ops *driver; int interface_removed; /* whether the network interface has been @@ -420,6 +460,7 @@ struct wpa_supplicant { struct ctrl_iface_priv *ctrl_iface; enum wpa_states wpa_state; + struct wpa_radio_work *scan_work; int scanning; int sched_scanning; int new_connection; @@ -433,7 +474,8 @@ struct wpa_supplicant { unsigned char last_eapol_src[ETH_ALEN]; - int keys_cleared; + unsigned int keys_cleared; /* bitfield of key indexes that the driver is + * known not to be configured with a key */ struct wpa_blacklist *blacklist; @@ -479,9 +521,18 @@ struct wpa_supplicant { */ MANUAL_SCAN_REQ } scan_req, last_scan_req; - struct os_time scan_trigger_time; + struct os_reltime scan_trigger_time, scan_start_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; + int *manual_scan_freqs; + unsigned int manual_scan_passive:1; + unsigned int manual_scan_use_id:1; + unsigned int manual_scan_only_new:1; + unsigned int own_scan_requested:1; + unsigned int own_scan_running:1; + unsigned int external_scan_running:1; + unsigned int clear_driver_scan_cache:1; + unsigned int manual_scan_id; int scan_interval; /* time in sec between scans to find suitable AP */ int normal_scans; /* normal scans run before sched_scan */ int scan_for_connection; /* whether the scan request was triggered for @@ -517,7 +568,7 @@ struct wpa_supplicant { int blacklist_cleared; struct wpabuf *pending_eapol_rx; - struct os_time pending_eapol_rx_time; + struct os_reltime pending_eapol_rx_time; u8 pending_eapol_rx_src[ETH_ALEN]; unsigned int last_eapol_matches_bssid:1; @@ -551,7 +602,7 @@ struct wpa_supplicant { u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * * sa_query_count octets of pending * SA Query transaction identifiers */ - struct os_time sa_query_start; + struct os_reltime sa_query_start; u8 sched_obss_scan; u16 obss_scan_int; u16 bss_max_idle_period; @@ -647,7 +698,6 @@ struct wpa_supplicant { */ char cross_connect_uplink[100]; - unsigned int sta_scan_pending:1; unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1; @@ -657,13 +707,17 @@ struct wpa_supplicant { unsigned int p2p_go_vht:1; unsigned int user_initiated_pd:1; unsigned int p2p_go_group_formation_completed:1; + unsigned int waiting_presence_resp; int p2p_first_connection_timeout; int p2p_persistent_go_freq; int p2p_persistent_id; int p2p_go_intent; int p2p_connect_freq; - struct os_time p2p_auto_started; + struct os_reltime p2p_auto_started; struct wpa_ssid *p2p_last_4way_hs_fail; + struct wpa_radio_work *p2p_scan_work; + struct wpa_radio_work *p2p_listen_work; + struct wpa_radio_work *p2p_send_action_work; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid; @@ -717,9 +771,9 @@ struct wpa_supplicant { struct ext_password_data *ext_pw; - struct wpabuf *last_gas_resp; - u8 last_gas_addr[ETH_ALEN]; - u8 last_gas_dialog_token; + struct wpabuf *last_gas_resp, *prev_gas_resp; + u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN]; + u8 last_gas_dialog_token, prev_gas_dialog_token; unsigned int no_keep_alive:1; @@ -740,6 +794,9 @@ struct wpa_supplicant { #endif /* CONFIG_TESTING_GET_GTK */ unsigned int num_multichan_concurrent; + struct wpa_radio_work *connect_work; + + unsigned int ext_work_id; }; @@ -821,7 +878,6 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, void wpa_supplicant_terminate_proc(struct wpa_global *global); void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, const u8 *buf, size_t len); -enum wpa_key_mgmt key_mgmt2driver(int key_mgmt); void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); @@ -835,7 +891,6 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf); -int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current); /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 0b3c8922..038c7fae 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1,6 +1,6 @@ /* * wpa_supplicant / WPS integration - * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -54,6 +54,11 @@ static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s) int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { +#ifdef CONFIG_P2P + if (wpas_p2p_wps_eapol_cb(wpa_s) > 0) + return 1; +#endif /* CONFIG_P2P */ + if (!wpa_s->wps_success && wpa_s->current_ssid && eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) { @@ -260,31 +265,6 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, ssid->group_cipher != new_ssid->group_cipher) continue; - if (ssid->passphrase && new_ssid->passphrase) { - if (os_strlen(ssid->passphrase) != - os_strlen(new_ssid->passphrase)) - continue; - if (os_strcmp(ssid->passphrase, new_ssid->passphrase) != - 0) - continue; - } else if (ssid->passphrase || new_ssid->passphrase) - continue; - - if ((ssid->psk_set || new_ssid->psk_set) && - os_memcmp(ssid->psk, new_ssid->psk, sizeof(ssid->psk)) != 0) - continue; - - if (ssid->auth_alg == WPA_ALG_WEP) { - if (ssid->wep_tx_keyidx != new_ssid->wep_tx_keyidx) - continue; - if (os_memcmp(ssid->wep_key, new_ssid->wep_key, - sizeof(ssid->wep_key))) - continue; - if (os_memcmp(ssid->wep_key_len, new_ssid->wep_key_len, - sizeof(ssid->wep_key_len))) - continue; - } - /* Remove the duplicated older network entry. */ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpas_notify_network_removed(wpa_s, ssid); @@ -891,6 +871,7 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s) wpas_wps_reenable_networks(wpa_s); eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL); /* Remove any existing WPS network from configuration */ ssid = wpa_s->conf->ssid; @@ -1160,6 +1141,9 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) } else { wpas_wps_reenable_networks(wpa_s); wpas_wps_clear_ap_info(wpa_s); + if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) > + 0) + wpas_clear_wps(wpa_s); } wpa_s->after_wps = 0; @@ -1298,7 +1282,9 @@ static u16 wps_fix_config_methods(u16 config_methods) static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, struct wps_context *wps) { - wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname); + char buf[50]; + const char *src; + if (is_nil_uuid(wpa_s->conf->uuid)) { struct wpa_supplicant *first; first = wpa_s->global->ifaces; @@ -1309,18 +1295,18 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid, WPS_UUID_LEN); - wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first " - "interface", wps->uuid, WPS_UUID_LEN); + src = "from the first interface"; } else { uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); - wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " - "address", wps->uuid, WPS_UUID_LEN); + src = "based on MAC address"; } } else { os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); - wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration", - wps->uuid, WPS_UUID_LEN); + src = "based on configuration"; } + + uuid_bin2str(wps->uuid, buf, sizeof(buf)); + wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf); } @@ -1959,19 +1945,6 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s) } -int wpas_wps_in_progress(struct wpa_supplicant *wpa_s) -{ - struct wpa_ssid *ssid; - - for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { - if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS) - return 1; - } - - return 0; -} - - void wpas_wps_update_config(struct wpa_supplicant *wpa_s) { struct wps_context *wps = wpa_s->wps; @@ -2260,8 +2233,9 @@ struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr) #ifdef CONFIG_WPS_NFC -struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, - int ndef, const char *uuid) +static struct wpabuf * +wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, + const char *uuid) { #ifdef CONFIG_WPS_ER struct wpabuf *ret; @@ -2355,12 +2329,10 @@ int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WPS_NFC */ -extern int wpa_debug_level; - static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) { size_t i; - struct os_time now; + struct os_reltime now; if (wpa_debug_level > MSG_DEBUG) return; @@ -2368,7 +2340,7 @@ static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) if (wpa_s->wps_ap == NULL) return; - os_get_time(&now); + os_get_reltime(&now); for (i = 0; i < wpa_s->num_wps_ap; i++) { struct wps_ap_info *ap = &wpa_s->wps_ap[i]; @@ -2481,5 +2453,5 @@ void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) if (ap == NULL) return; ap->tries++; - os_get_time(&ap->last_attempt); + os_get_reltime(&ap->last_attempt); } diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 2a212cab..3fcfbbe1 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -60,7 +60,6 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *uuid); int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s); -int wpas_wps_in_progress(struct wpa_supplicant *wpa_s); void wpas_wps_update_config(struct wpa_supplicant *wpa_s); struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *id_str); |
