Accumulative patch from commit f5f37d3a4fc2df2a24676b4f95afca15ed793cba

Author: Jouni Malinen <j@w1.fi>
Date:   Sun Nov 25 22:05:32 2012 +0200

   Fix REAUTHENTICATE command after PMKSA caching

   The current PMKSA cache entry needs to be clear to allow EAPOL
   reauthentication to be started in case this association used PMKSA
   caching.

 - Remove old WPS_OOB NCF
 - WPS: Add preliminary NFC connection handover support for Enrollee
 - WPS: Reenable the networks disabled during wpa_wpas_reassoc
 - P2P: Avoid multi-channel scans when they are not needed
 - P2P: Allow discoverable interval for p2p_find to be configured
 - P2P: Allow all channels with multi-channel concurrency
 - Bonjour changes
 - Remove disassociate
 - HS 2.0 changes
 - Add preliminary support for using SQLite for eap_user database
 - Add SAE support
 - Add disallow_aps parameter to disallow BSSIDs/SSIDs

Change-Id: I85358a05b39d46b8db49acdad667e771c580b05c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 33e4579..da86a49 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -31,6 +31,7 @@
 
 ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
 L_CFLAGS += -DANDROID_P2P
+L_CFLAGS += -DP2P_CONCURRENT_SEARCH_DELAY=0
 endif
 
 ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
@@ -193,6 +194,10 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 L_CFLAGS += -DCONFIG_IEEE80211V
 OBJS += wnm_sta.c
@@ -333,6 +338,17 @@
 CONFIG_IEEE8021X_EAPOL=y
 endif
 
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+L_CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += src/eap_peer/eap_tls.c
+OBJS_h += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
 ifdef CONFIG_EAP_PEAP
 # EAP-PEAP
 ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -599,25 +615,10 @@
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 L_CFLAGS += -DCONFIG_WPS_NFC
 OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -743,6 +744,7 @@
 OBJS += src/ap/drv_callbacks.c
 OBJS += src/ap/ap_drv_ops.c
 OBJS += src/ap/beacon.c
+OBJS += src/ap/eap_user_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 endif
@@ -910,6 +912,10 @@
 endif
 LIBS += -lcrypto
 LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
 endif
 
 ifeq ($(CONFIG_TLS), gnutls)
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 650b8a0..6a5ab17 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,229 @@
 ChangeLog for wpa_supplicant
 
+????-??-?? - v2.0
+	* removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
+	* removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
+	  hostap, madwifi (hostap and madwifi remain available for hostapd;
+	  their wpa_supplicant functionality is obsoleted by wext)
+	* improved debug logging (human readable event names, interface name
+	  included in more entries)
+	* changed AP mode behavior to enable WPS only for open and
+	  WPA/WPA2-Personal configuration
+	* improved P2P concurrency operations
+	  - better coordination of concurrent scan and P2P search operations
+	  - avoid concurrent remain-on-channel operation requests by canceling
+	    previous operations prior to starting a new one
+	  - reject operations that would require multi-channel concurrency if
+	    the driver does not support it
+	  - add parameter to select whether STA or P2P connection is preferred
+	    if the driver cannot support both at the same time
+	  - allow driver to indicate channel changes
+	  - added optional delay=<search delay in milliseconds> parameter for
+	    p2p_find to avoid taking all radio resources
+	  - use 500 ms p2p_find search delay by default during concurrent
+	    operations
+	  - allow all channels in GO Negotiation if the driver supports
+	    multi-channel concurrency
+	* added number of small changes to make it easier for static analyzers
+	  to understand the implementation
+	* fixed number of small bugs (see git logs for more details)
+	* nl80211: number of updates to use new cfg80211/nl80211 functionality
+	  - replace monitor interface with nl80211 commands for AP mode
+	  - additional information for driver-based AP SME
+	  - STA entry authorization in RSN IBSS
+	* EAP-pwd:
+	  - fixed KDF for group 21 and zero-padding
+	  - added support for fragmentation
+	  - increased maximum number of hunting-and-pecking iterations
+	* avoid excessive Probe Response retries for broadcast Probe Request
+	  frames (only with drivers using wpa_supplicant AP mode SME/MLME)
+	* added "GET country" ctrl_iface command
+	* do not save an invalid network block in wpa_supplicant.conf to avoid
+	  problems reading the file on next start
+	* send STA connected/disconnected ctrl_iface events to both the P2P
+	  group and parent interfaces
+	* added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+	* added "SET pno <1/0>" ctrl_iface command to start/stop preferred
+	  network offload with sched_scan driver command
+	* merged in number of changes from Android repository for P2P, nl80211,
+	  and build parameters
+	* changed P2P GO mode configuration to use driver capabilities to
+	  automatically enable HT operations when supported
+	* added "wpa_cli status wps" command to fetch WPA2-Personal passhrase
+	  for WPS use cases in AP mode
+	* EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM
+	  behavior
+	* improved reassociation behavior in cases where association is rejected
+	  or when an AP disconnects us to handle common load balancing
+	  mechanisms
+	  - try to avoid extra scans when the needed information is available
+	* added optional "join" argument for p2p_prov_disc ctrl_iface command
+	* added group ifname to P2P-PROV-DISC-* events
+	* added P2P Device Address to AP-STA-DISCONNECTED event and use
+	  p2p_dev_addr parameter name with AP-STA-CONNECTED
+	* added workarounds for WPS PBC overlap detection for some P2P use cases
+	  where deployed stations work incorrectly
+	* optimize WPS connection speed by disconnecting prior to WPS scan and
+	  by using single channel scans when AP channel is known
+	* PCSC and SIM/USIM improvements:
+	  - accept 0x67 (Wrong length) as a response to READ RECORD to fix
+	    issues with some USIM cards
+	  - try to read MNC length from SIM/USIM
+	  - build realm according to 3GPP TS 23.003 with identity from the SIM
+	  - allow T1 protocol to be enabled
+	* added more WPS and P2P information available through D-Bus
+	* improve P2P negotiation robustness
+	  - extra waits to get ACK frames through
+	  - longer timeouts for cases where deployed devices have been
+	    identified have issues meeting the specification requirements
+	  - more retries for some P2P frames
+	  - handle race conditions in GO Negotiation start by both devices
+	  - ignore unexpected GO Negotiation Response frame
+	* added support for libnl 3.2 and newer
+	* added P2P persistent group info to P2P_PEER data
+	* maintain a list of P2P Clients for persistent group on GO
+	* AP: increased initial group key handshake retransmit timeout to 500 ms
+	* added optional dev_id parameter for p2p_find
+	* added P2P-FIND-STOPPED ctrl_iface event
+	* fixed issues in WPA/RSN element validation when roaming with ap_scan=1
+	  and driver-based BSS selection
+	* do not expire P2P peer entries while connected with the peer in a
+	  group
+	* fixed WSC element inclusion in cases where P2P is disabled
+	* AP: added a WPS workaround for mixed mode AP Settings with Windows 7
+	* EAP-SIM: fixed AT_COUNTER_TOO_SMALL use
+	* EAP-SIM/AKA: append realm to pseudonym identity
+	* EAP-SIM/AKA: store pseudonym identity in network configuration to
+	  allow it to persist over multiple EAP sessions and wpa_supplicant
+	  restarts
+	* EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+	  breaks interoperability with older versions
+	* added support for WFA Hotspot 2.0
+	  - GAS/ANQP to fetch network information
+	  - credential configuration and automatic network selections based on
+	    credential match with ANQP information
+	* limited PMKSA cache entries to be used only with the network context
+	  that was used to create them
+	* adjusted bgscan_simple fast-scan backoff to avoid too frequent
+	  background scans
+	* removed ctrl_iface event on P2P PD Response in join-group case
+	* added option to fetch BSS table entry based on P2P Device Address
+	  ("BSS p2p_dev_addr=<P2P Device Address>")
+	* added BSS entry age to ctrl_iface BSS command output
+	* added optional MASK=0xH option for ctrl_iface BSS command to select
+	  which fields are included in the response
+	* added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to
+	  fetch information about several BSSes in one call
+	* simplified licensing terms by selecting the BSD license as the only
+	  alternative
+	* added "P2P_SET disallow_freq <freq list>" ctrl_iface command to
+	  disable channels from P2P use
+	* added p2p_pref_chan configuration parameter to allow preferred P2P
+	  channels to be specified
+	* added support for advertising immediate availability of a WPS
+	  credential for P2P use cases
+	* optimized scan operations for P2P use cases (use single channel scan
+	  for a specific SSID when possible)
+	* EAP-TTLS: fixed peer challenge generation for MSCHAPv2
+	* SME: do not use reassociation after explicit disconnection request
+	  (local or a notification from an AP)
+	* added support for sending debug info to Linux tracing (-T on command
+	  line)
+	* added support for using Deauthentication reason code 3 as an
+	  indication of P2P group termination
+	* added wps_vendor_ext_m1 configuration parameter to allow vendor
+	  specific attributes to be added to WPS M1
+	* started using separate TLS library context for tunneled TLS
+	  (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA
+	  certificate configuration between Phase 1 and Phase 2
+	* added optional "auto" parameter for p2p_connect to request automatic
+	  GO Negotiation vs. join-a-group selection
+	* added disabled_scan_offload parameter to disable automatic scan
+	  offloading (sched_scan)
+	* added optional persistent=<network id> parameter for p2p_connect to
+	  allow forcing of a specific SSID/passphrase for GO Negotiation
+	* added support for OBSS scan requests and 20/40 BSS coexistence reports
+	* reject PD Request for unknown group
+	* removed scripts and notes related to Windows binary releases (which
+	  have not been used starting from 1.x)
+	* added initial support for WNM operations
+	  - Keep-alive based on BSS max idle period
+	  - WNM-Sleep Mode
+	* added autoscan module to control scanning behavior while not connected
+	  - autoscan_periodic and autoscan_exponential modules
+	* added new WPS NFC ctrl_iface mechanism
+	  - added initial support NFC connection handover
+	  - removed obsoleted WPS_OOB command (including support for deprecated
+	    UFD config_method)
+	* added optional framework for external password storage ("ext:<name>")
+	* wpa_cli: added optional support for controlling wpa_supplicant
+	  remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes
+	* wpa_cli: extended tab completion to more commands
+	* changed SSID output to use printf-escaped strings instead of masking
+	  of non-ASCII characters
+	  - SSID can now be configured in the same format: ssid=P"abc\x00test"
+	* removed default ACM=1 from AC_VO and AC_VI
+	* added optional "ht40" argument for P2P ctrl_iface commands to allow
+	  40 MHz channels to be requested on the 5 GHz band
+	* added optional parameters for p2p_invite command to specify channel
+	  when reinvoking a persistent group as the GO
+	* improved FIPS mode builds with OpenSSL
+	  - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the
+	    OpenSSL FIPS object module
+	  - replace low level OpenSSL AES API calls to use EVP
+	  - use OpenSSL keying material exporter when possible
+	  - do not export TLS keys in FIPS mode
+	  - remove MD5 from CONFIG_FIPS=y builds
+	  - use OpenSSL function for PKBDF2 passphrase-to-PSK
+	  - use OpenSSL HMAC implementation
+	  - mix RAND_bytes() output into random_get_bytes() to force OpenSSL
+	    DRBG to be used in FIPS mode
+	  - use OpenSSL CMAC implementation
+	* added mechanism to disable TLS Session Ticket extension
+	  - a workaround for servers that do not support TLS extensions that
+	    was enabled by default in recent OpenSSL versions
+	  - tls_disable_session_ticket=1
+	  - automatically disable TLS Session Ticket extension by default when
+	    using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST)
+	* changed VENDOR-TEST EAP method to use proper private enterprise number
+	  (this will not interoperate with older versions)
+	* disable network block temporarily on authentication failures
+	* improved WPS AP selection during WPS PIN iteration
+	* added support for configuring GCMP cipher for IEEE 802.11ad
+	* added support for Wi-Fi Display extensions
+	  - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements
+	  - SET wifi_display <0/1> to disable/enable WFD support
+	  - WFD service discovery
+	  - an external program is needed to manage the audio/video streaming
+	    and codecs
+	* optimized scan result use for network selection
+	  - use the internal BSS table instead of raw scan results
+	  - allow unnecessary scans to be skipped if fresh information is
+	    available (e.g., after GAS/ANQP round for Interworking)
+	* added support for 256-bit AES with internal TLS implementation
+	* allow peer to propose channel in P2P invitation process for a
+	  persistent group
+	* added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed
+	  from network selection
+	* re-enable the networks disabled during WPS operations
+	* allow P2P functionality to be disabled per interface (p2p_disabled=1)
+	* added secondary device types into P2P_PEER output
+	* added an option to disable use of a separate P2P group interface
+	  (p2p_no_group_iface=1)
+	* fixed P2P Bonjour SD to match entries with both compressed and not
+	  compressed domain name format and support multiple Bonjour PTR matches
+	  for the same key
+	* use deauthentication instead of disassociation for all disconnection
+	  operations; this removes the now unused disassociate() wpa_driver_ops
+	  callback
+	* optimized PSK generation on P2P GO by caching results to avoid
+	  multiple PBKDF2 operations
+	* added okc=1 global configuration parameter to allow OKC to be enabled
+	  by default for all network blocks
+	* added a workaround for WPS PBC session overlap detection to avoid
+	  interop issues with deployed station implementations that do not
+	  remove active PBC indication from Probe Request frames properly
+
 2012-05-10 - v1.0
 	* bsd: Add support for setting HT values in IFM_MMASK.
 	* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 227fb4f..c6c76ec 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -172,6 +172,10 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 CFLAGS += -DCONFIG_IEEE80211V
 OBJS += wnm_sta.o
@@ -588,25 +592,10 @@
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 CFLAGS += -DCONFIG_WPS_NFC
 OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -732,6 +721,7 @@
 OBJS += ../src/ap/drv_callbacks.o
 OBJS += ../src/ap/ap_drv_ops.o
 OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/eap_user_db.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 endif
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 692d5f5..1ea9843 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -130,6 +130,12 @@
 This starts the WPS negotiation in the same way as above with the
 generated PIN.
 
+When the wps_pin command is issued for an AP (including P2P GO) mode
+interface, an optional timeout parameter can be used to specify
+expiration timeout for the PIN in seconds. For example:
+
+wpa_cli wps_pin any 12345670 300
+
 
 If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
 can be used to generate a new PIN without starting WPS negotiation.
@@ -345,3 +351,27 @@
 the ER functionality has been started (wps_er_start), the NFC password
 token is used to enable enrollment of a new station (that was the source
 of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
+contents of a Handover Request Message for connection handover. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 3798f5a..e261ef9 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -174,15 +174,15 @@
 		bss->wpa = ssid->proto;
 	bss->wpa_key_mgmt = ssid->key_mgmt;
 	bss->wpa_pairwise = ssid->pairwise_cipher;
-	if (ssid->passphrase) {
-		bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
-	} else if (ssid->psk_set) {
+	if (ssid->psk_set) {
 		os_free(bss->ssid.wpa_psk);
 		bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
 		if (bss->ssid.wpa_psk == NULL)
 			return -1;
 		os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
 		bss->ssid.wpa_psk->group = 1;
+	} else if (ssid->passphrase) {
+		bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
 	} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
 		   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
 		struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -724,7 +724,8 @@
 
 
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			      const char *pin, char *buf, size_t buflen)
+			      const char *pin, char *buf, size_t buflen,
+			      int timeout)
 {
 	int ret, ret_len = 0;
 
@@ -739,7 +740,7 @@
 		ret_len = os_snprintf(buf, buflen, "%s", pin);
 
 	ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
-				  0);
+				  timeout);
 	if (ret)
 		return -1;
 	return ret_len;
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index bc953d9..536064f 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -18,7 +18,8 @@
 int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			      const u8 *p2p_dev_addr);
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			      const char *pin, char *buf, size_t buflen);
+			      const char *pin, char *buf, size_t buflen,
+			      int timeout);
 int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
 void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
 const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
index d0c040a..a2cf7a5 100644
--- a/wpa_supplicant/autoscan.c
+++ b/wpa_supplicant/autoscan.c
@@ -36,7 +36,7 @@
 
 static void request_scan(struct wpa_supplicant *wpa_s)
 {
-	wpa_s->scan_req = 2;
+	wpa_s->scan_req = MANUAL_SCAN_REQ;
 
 	if (wpa_supplicant_req_sched_scan(wpa_s))
 		wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index adf82d8..07d31e4 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -242,8 +242,11 @@
 
 	idx = data->probe_idx + 1;
 	while (idx != data->probe_idx) {
-		if (data->supp_freqs[idx] == 0)
+		if (data->supp_freqs[idx] == 0) {
+			if (data->probe_idx == 0)
+				break;
 			idx = 0;
+		}
 		if (!in_array(freqs, data->supp_freqs[idx])) {
 			wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
 				   "%u", data->supp_freqs[idx]);
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
index 2e01e7f..e53dc38 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/blacklist.c
@@ -123,14 +123,19 @@
 void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_blacklist *e, *prev;
+	int max_count = 0;
 
 	e = wpa_s->blacklist;
 	wpa_s->blacklist = NULL;
 	while (e) {
+		if (e->count > max_count)
+			max_count = e->count;
 		prev = e;
 		e = e->next;
 		wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
 			   "blacklist (clear)", MAC2STR(prev->bssid));
 		os_free(prev);
 	}
+
+	wpa_s->extra_blacklist_count += max_count;
 }
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 6223beb..0babbd5 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -62,6 +62,60 @@
 }
 
 
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+	struct wpa_bss_anqp *n;
+
+	n = os_zalloc(sizeof(*n));
+	if (n == NULL)
+		return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+	ANQP_DUP(venue_name);
+	ANQP_DUP(network_auth_type);
+	ANQP_DUP(roaming_consortium);
+	ANQP_DUP(ip_addr_type_availability);
+	ANQP_DUP(nai_realm);
+	ANQP_DUP(anqp_3gpp);
+	ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	ANQP_DUP(hs20_operator_friendly_name);
+	ANQP_DUP(hs20_wan_metrics);
+	ANQP_DUP(hs20_connection_capability);
+	ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+	return n;
+}
+
+
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+	struct wpa_bss_anqp *anqp;
+
+	if (bss->anqp && bss->anqp->users > 1) {
+		/* allocated, but shared - clone an unshared copy */
+		anqp = wpa_bss_anqp_clone(bss->anqp);
+		if (anqp == NULL)
+			return -1;
+		anqp->users = 1;
+		bss->anqp->users--;
+		bss->anqp = anqp;
+		return 0;
+	}
+
+	if (bss->anqp)
+		return 0; /* already allocated and not shared */
+
+	/* not allocated - allocate a new storage area */
+	bss->anqp = wpa_bss_anqp_alloc();
+	return bss->anqp ? 0 : -1;
+}
+
+
 static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
 {
 	if (anqp == NULL)
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4a386b6..eb01f2d 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -113,5 +113,6 @@
 int wpa_bss_get_max_rate(const struct wpa_bss *bss);
 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
 struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
 
 #endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index be21029..e157845 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -504,6 +504,12 @@
 		else if (os_strcmp(start, "WPS") == 0)
 			val |= WPA_KEY_MGMT_WPS;
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+		else if (os_strcmp(start, "SAE") == 0)
+			val |= WPA_KEY_MGMT_SAE;
+		else if (os_strcmp(start, "FT-SAE") == 0)
+			val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -2035,6 +2041,10 @@
 	ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
 	ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
 #endif /* CONFIG_HT_OVERRIDES */
+	ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+	ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -3000,6 +3010,9 @@
 	{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
 	{ INT(p2p_group_idle), 0 },
 	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+	{ INT(p2p_go_ht40), 0 },
+	{ INT(p2p_disabled), 0 },
+	{ INT(p2p_no_group_iface), 0 },
 #endif /* CONFIG_P2P */
 	{ FUNC(country), CFG_CHANGED_COUNTRY },
 	{ INT(bss_max_count), 0 },
@@ -3024,6 +3037,8 @@
 	{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
 	{ INT(p2p_go_max_inactivity), 0 },
 	{ INT_RANGE(auto_interworking, 0, 1), 0 },
+	{ INT(okc), 0 },
+	{ INT(pmf), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index b889ab8..c0aea0b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -747,6 +747,50 @@
 	 *     matching network block
 	 */
 	int auto_interworking;
+
+	/**
+	 * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+	 *
+	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+	 * Note that regulatory constraints and driver capabilities are
+	 * consulted anyway, so setting it to 1 can't do real harm.
+	 * By default: 0 (disabled)
+	 */
+	int p2p_go_ht40;
+
+	/**
+	 * p2p_disabled - Whether P2P operations are disabled for this interface
+	 */
+	int p2p_disabled;
+
+	/**
+	 * p2p_no_group_iface - Whether group interfaces can be used
+	 *
+	 * By default, wpa_supplicant will create a separate interface for P2P
+	 * group operations if the driver supports this. This functionality can
+	 * be disabled by setting this parameter to 1. In that case, the same
+	 * interface that was used for the P2P management operations is used
+	 * also for the group operation.
+	 */
+	int p2p_no_group_iface;
+
+	/**
+	 * okc - Whether to enable opportunistic key caching by default
+	 *
+	 * By default, OKC is disabled unless enabled by the per-network
+	 * proactive_key_caching=1 parameter. okc=1 can be used to change this
+	 * default behavior.
+	 */
+	int okc;
+
+	/**
+	 * pmf - Whether to enable/require PMF by default
+	 *
+	 * By default, PMF is disabled unless enabled by the per-network
+	 * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
+	 * this default behavior.
+	 */
+	enum mfp_options pmf;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 531957a..d66eac5 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -676,11 +676,12 @@
 	INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
 #endif /* IEEE8021X_EAPOL */
 	INT(mode);
-	INT(proactive_key_caching);
+	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
 	INT(disabled);
 	INT(peerkey);
 #ifdef CONFIG_IEEE80211W
-	INT(ieee80211w);
+	write_int(f, "ieee80211w", ssid->ieee80211w,
+		  MGMT_FRAME_PROTECTION_DEFAULT);
 #endif /* CONFIG_IEEE80211W */
 	STR(id_str);
 #ifdef CONFIG_P2P
@@ -868,6 +869,13 @@
 		}
 		fprintf(f, "\n");
 	}
+	if (config->p2p_go_ht40)
+		fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+	if (config->p2p_disabled)
+		fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
+	if (config->p2p_no_group_iface)
+		fprintf(f, "p2p_no_group_iface=%u\n",
+			config->p2p_no_group_iface);
 #endif /* CONFIG_P2P */
 	if (config->country[0] && config->country[1]) {
 		fprintf(f, "country=%c%c\n",
@@ -919,6 +927,10 @@
 	if (config->auto_interworking)
 		fprintf(f, "auto_interworking=%d\n",
 			config->auto_interworking);
+	if (config->okc)
+		fprintf(f, "okc=%d\n", config->okc);
+	if (config->pmf)
+		fprintf(f, "pmf=%d\n", config->pmf);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index ff97379..c1184f8 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -228,13 +228,18 @@
 	 *
 	 * This field can be used to enable proactive key caching which is also
 	 * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
-	 * by default. Enable by setting this to 1.
+	 * by default unless default value is changed with the global okc=1
+	 * parameter. Enable by setting this to 1.
 	 *
 	 * Proactive key caching is used to make supplicant assume that the APs
 	 * are using the same PMK and generate PMKSA cache entries without
 	 * doing RSN pre-authentication. This requires support from the AP side
 	 * and is normally used with wireless switches that co-locate the
 	 * authenticator.
+	 *
+	 * Internally, special value -1 is used to indicate that the parameter
+	 * was not specified in the configuration (i.e., default behavior is
+	 * followed).
 	 */
 	int proactive_key_caching;
 
@@ -323,6 +328,14 @@
 	int disabled;
 
 	/**
+	 * disabled_for_connect - Whether this network was temporarily disabled
+	 *
+	 * This flag is used to reenable all the temporarily disabled networks
+	 * after either the success or failure of a WPS connection.
+	 */
+	int disabled_for_connect;
+
+	/**
 	 * peerkey -  Whether PeerKey handshake for direct links is allowed
 	 *
 	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
@@ -348,6 +361,12 @@
 	 *
 	 * This value is used to configure policy for management frame
 	 * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+	 * This is disabled by default unless the default value has been changed
+	 * with the global pmf=1/2 parameter.
+	 *
+	 * Internally, special value 3 is used to indicate that the parameter
+	 * was not specified in the configuration (i.e., default behavior is
+	 * followed).
 	 */
 	enum mfp_options ieee80211w;
 #endif /* CONFIG_IEEE80211W */
@@ -536,6 +555,15 @@
 	 * disabled_until - Network block disabled until this time if non-zero
 	 */
 	struct os_time disabled_until;
+
+	/**
+	 * parent_cred - Pointer to parent wpa_cred entry
+	 *
+	 * This pointer can be used to delete temporary networks when a wpa_cred
+	 * that was used to create them is removed. This pointer should not be
+	 * dereferences since it may not be updated in all cases.
+	 */
+	void *parent_cred;
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 6d9876c..2750b63 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -202,6 +202,7 @@
 static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
 {
 	int errors = 0;
+	int val;
 
 	wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
 	wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
@@ -271,6 +272,10 @@
 	wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
 				  (int *) &config->disassoc_low_ack);
 
+	wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+	wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+	config->pmf = val;
+
 	return errors ? -1 : 0;
 }
 
@@ -609,6 +614,9 @@
 	wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
 				   config->disassoc_low_ack, 0);
 
+	wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+	wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+
 	return 0;
 }
 
@@ -904,11 +912,13 @@
 	INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
 #endif /* IEEE8021X_EAPOL */
 	INT(mode);
-	INT(proactive_key_caching);
+	write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+		  -1);
 	INT(disabled);
 	INT(peerkey);
 #ifdef CONFIG_IEEE80211W
-	INT(ieee80211w);
+	write_int(netw, "ieee80211w", ssid->ieee80211w,
+		  MGMT_FRAME_PROTECTION_DEFAULT);
 #endif /* CONFIG_IEEE80211W */
 	STR(id_str);
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index bcf27be..564c91e 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -37,7 +37,6 @@
 #include "ctrl_iface.h"
 #include "interworking.h"
 #include "blacklist.h"
-#include "wpas_glue.h"
 #include "autoscan.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
@@ -158,6 +157,128 @@
 }
 
 
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+	char *pos;
+	u8 addr[ETH_ALEN], *bssid = NULL, *n;
+	struct wpa_ssid_value *ssid = NULL, *ns;
+	size_t count = 0, ssid_count = 0;
+	struct wpa_ssid *c;
+
+	/*
+	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+	 * SSID_SPEC ::= ssid <SSID_HEX>
+	 * BSSID_SPEC ::= bssid <BSSID_HEX>
+	 */
+
+	pos = val;
+	while (pos) {
+		if (*pos == '\0')
+			break;
+		if (os_strncmp(pos, "bssid ", 6) == 0) {
+			int res;
+			pos += 6;
+			res = hwaddr_aton2(pos, addr);
+			if (res < 0) {
+				os_free(ssid);
+				os_free(bssid);
+				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+					   "BSSID value '%s'", pos);
+				return -1;
+			}
+			pos += res;
+			n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+			if (n == NULL) {
+				os_free(ssid);
+				os_free(bssid);
+				return -1;
+			}
+			bssid = n;
+			os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+			count++;
+		} else if (os_strncmp(pos, "ssid ", 5) == 0) {
+			char *end;
+			pos += 5;
+
+			end = pos;
+			while (*end) {
+				if (*end == '\0' || *end == ' ')
+					break;
+				end++;
+			}
+
+			ns = os_realloc_array(ssid, ssid_count + 1,
+					      sizeof(struct wpa_ssid_value));
+			if (ns == NULL) {
+				os_free(ssid);
+				os_free(bssid);
+				return -1;
+			}
+			ssid = ns;
+
+			if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+			    hexstr2bin(pos, ssid[ssid_count].ssid,
+				       (end - pos) / 2) < 0) {
+				os_free(ssid);
+				os_free(bssid);
+				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+					   "SSID value '%s'", pos);
+				return -1;
+			}
+			ssid[ssid_count].ssid_len = (end - pos) / 2;
+			wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+					  ssid[ssid_count].ssid,
+					  ssid[ssid_count].ssid_len);
+			ssid_count++;
+			pos = end;
+		} else {
+			wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+				   "'%s'", pos);
+			os_free(ssid);
+			os_free(bssid);
+			return -1;
+		}
+
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+	os_free(wpa_s->disallow_aps_bssid);
+	wpa_s->disallow_aps_bssid = bssid;
+	wpa_s->disallow_aps_bssid_count = count;
+
+	wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+	os_free(wpa_s->disallow_aps_ssid);
+	wpa_s->disallow_aps_ssid = ssid;
+	wpa_s->disallow_aps_ssid_count = ssid_count;
+
+	if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+		return 0;
+
+	c = wpa_s->current_ssid;
+	if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+		return 0;
+
+	if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+	    !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+		   "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+	wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+	wpa_s->reassociate = 1;
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 					 char *cmd)
 {
@@ -291,6 +412,8 @@
 #endif /* CONFIG_WIFI_DISPLAY */
 	} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
 		ret = set_bssid_filter(wpa_s, value);
+	} else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+		ret = set_disallow_aps(wpa_s, value);
 	} else {
 		value[-1] = '=';
 		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -540,9 +663,21 @@
 	}
 
 #ifdef CONFIG_AP
-	if (wpa_s->ap_iface)
+	if (wpa_s->ap_iface) {
+		int timeout = 0;
+		char *pos;
+
+		if (pin) {
+			pos = os_strchr(pin, ' ');
+			if (pos) {
+				*pos++ = '\0';
+				timeout = atoi(pos);
+			}
+		}
+
 		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
-						 buf, buflen);
+						 buf, buflen, timeout);
+	}
 #endif /* CONFIG_AP */
 
 	if (pin) {
@@ -614,31 +749,6 @@
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
-					     char *cmd)
-{
-	char *path, *method, *name;
-
-	path = os_strchr(cmd, ' ');
-	if (path == NULL)
-		return -1;
-	*path++ = '\0';
-
-	method = os_strchr(path, ' ');
-	if (method == NULL)
-		return -1;
-	*method++ = '\0';
-
-	name = os_strchr(method, ' ');
-	if (name != NULL)
-		*name++ = '\0';
-
-	return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 
 static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
@@ -710,6 +820,149 @@
 	return ret;
 }
 
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_wps_nfc_handover_req(wpa_s);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+					  char *cmd, char *reply,
+					  size_t max_len)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "NDEF") != 0)
+		return -1;
+
+	if (os_strcmp(pos, "WPS") == 0) {
+		return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+							  max_len);
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_wps_nfc_handover_sel(wpa_s);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+					  char *cmd, char *reply,
+					  size_t max_len)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "NDEF") != 0)
+		return -1;
+
+	if (os_strcmp(pos, "WPS") == 0) {
+		return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+							  max_len);
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+					 char *cmd, char *reply,
+					 size_t max_len)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -1146,6 +1399,45 @@
 			return pos - buf;
 		pos += ret;
 	}
+
+	if (wpa_s->current_ssid) {
+		struct wpa_cred *cred;
+		char *type;
+
+		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+			if (wpa_s->current_ssid->parent_cred != cred)
+				continue;
+			if (!cred->domain)
+				continue;
+
+			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+					  cred->domain);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			if (wpa_s->current_bss == NULL ||
+			    wpa_s->current_bss->anqp == NULL)
+				res = -1;
+			else
+				res = interworking_home_sp_cred(
+					wpa_s, cred,
+					wpa_s->current_bss->anqp->domain_name);
+			if (res > 0)
+				type = "home";
+			else if (res == 0)
+				type = "roaming";
+			else
+				type = "unknown";
+
+			ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			break;
+		}
+	}
 #endif /* CONFIG_HS20 */
 
 	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
@@ -1869,8 +2161,8 @@
 #endif /* CONFIG_SME */
 			wpa_sm_set_config(wpa_s->wpa, NULL);
 			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-			wpa_supplicant_disassociate(wpa_s,
-				                    WLAN_REASON_DEAUTH_LEAVING);
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 		}
 		return 0;
 	}
@@ -1902,7 +2194,8 @@
 		wpa_sm_set_config(wpa_s->wpa, NULL);
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
-		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
 	}
 
 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
@@ -1952,7 +2245,9 @@
 		return -1;
 	}
 
-	wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+	if (os_strcmp(name, "bssid") != 0 &&
+	    os_strcmp(name, "priority") != 0)
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 
 	if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
 		/*
@@ -2069,20 +2364,62 @@
 }
 
 
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+				 struct wpa_cred *cred)
+{
+	struct wpa_ssid *ssid;
+	char str[20];
+
+	if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+		return -1;
+	}
+
+	/* Remove any network entry created based on the removed credential */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (ssid->parent_cred == cred) {
+			wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+				   "used the removed credential", ssid->id);
+			os_snprintf(str, sizeof(str), "%d", ssid->id);
+			ssid = ssid->next;
+			wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+		} else
+			ssid = ssid->next;
+	}
+
+	return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
 						 char *cmd)
 {
 	int id;
-	struct wpa_cred *cred;
+	struct wpa_cred *cred, *prev;
 
-	/* cmd: "<cred id>" or "all" */
+	/* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
 	if (os_strcmp(cmd, "all") == 0) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
 		cred = wpa_s->conf->cred;
 		while (cred) {
-			id = cred->id;
+			prev = cred;
 			cred = cred->next;
-			wpa_config_remove_cred(wpa_s->conf, id);
+			wpas_ctrl_remove_cred(wpa_s, prev);
+		}
+		return 0;
+	}
+
+	if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+			   cmd + 8);
+		cred = wpa_s->conf->cred;
+		while (cred) {
+			prev = cred;
+			cred = cred->next;
+			if (prev->domain &&
+			    os_strcmp(prev->domain, cmd + 8) == 0)
+				wpas_ctrl_remove_cred(wpa_s, prev);
 		}
 		return 0;
 	}
@@ -2091,14 +2428,7 @@
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
 
 	cred = wpa_config_get_cred(wpa_s->conf, id);
-	if (cred == NULL ||
-	    wpa_config_remove_cred(wpa_s->conf, id) < 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
-			   id);
-		return -1;
-	}
-
-	return 0;
+	return wpas_ctrl_remove_cred(wpa_s, cred);
 }
 
 
@@ -3144,7 +3474,7 @@
 	auth = os_strstr(pos, " auth") != NULL;
 	automatic = os_strstr(pos, " auto") != NULL;
 	pd = os_strstr(pos, " provdisc") != NULL;
-	ht40 = os_strstr(pos, " ht40") != NULL;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
 	pos2 = os_strstr(pos, " go_intent=");
 	if (pos2) {
@@ -3575,7 +3905,7 @@
 			return -1;
 	}
 
-	ht40 = os_strstr(cmd, " ht40") != NULL;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
 	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
 }
@@ -3651,7 +3981,7 @@
 	if (pos)
 		freq = atoi(pos + 5);
 
-	ht40 = os_strstr(cmd, "ht40") != NULL;
+	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
 	if (os_strncmp(cmd, "persistent=", 11) == 0)
 		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
@@ -3679,6 +4009,7 @@
 	char *pos, *end;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
 	struct wpa_ssid *ssid;
+	size_t i;
 
 	if (!wpa_s->global->p2p)
 		return -1;
@@ -3732,6 +4063,18 @@
 		return pos - buf;
 	pos += res;
 
+	for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+	{
+		const u8 *t;
+		t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+		res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+				  wps_dev_type_bin2str(t, devtype,
+						       sizeof(devtype)));
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
 	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
 	if (ssid) {
 		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
@@ -3960,6 +4303,30 @@
 	if (os_strcmp(cmd, "disallow_freq") == 0)
 		return p2p_ctrl_disallow_freq(wpa_s, param);
 
+	if (os_strcmp(cmd, "disc_int") == 0) {
+		int min_disc_int, max_disc_int, max_disc_tu;
+		char *pos;
+
+		pos = param;
+
+		min_disc_int = atoi(pos);
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+
+		max_disc_int = atoi(pos);
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+
+		max_disc_tu = atoi(pos);
+
+		return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+					max_disc_int, max_disc_tu);
+	}
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
 		   cmd);
 
@@ -4392,7 +4759,9 @@
 	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, "SET_NETWORK ", 12) == 0 ||
+	    os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 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 {
@@ -4452,25 +4821,15 @@
 	} else if (os_strcmp(buf, "LOGOFF") == 0) {
 		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
 	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
-		wpa_s->normal_scans = 0;
-		wpa_supplicant_reinit_autoscan(wpa_s);
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 			reply_len = -1;
-		else {
-			wpa_s->disconnected = 0;
-			wpa_s->reassociate = 1;
-			wpa_supplicant_req_scan(wpa_s, 0, 0);
-		}
+		else
+			wpas_request_connection(wpa_s);
 	} else if (os_strcmp(buf, "RECONNECT") == 0) {
-		wpa_s->normal_scans = 0;
-		wpa_supplicant_reinit_autoscan(wpa_s);
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 			reply_len = -1;
-		else if (wpa_s->disconnected) {
-			wpa_s->disconnected = 0;
-			wpa_s->reassociate = 1;
-			wpa_supplicant_req_scan(wpa_s, 0, 0);
-		}
+		else if (wpa_s->disconnected)
+			wpas_request_connection(wpa_s);
 #ifdef IEEE8021X_EAPOL
 	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
 		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
@@ -4511,11 +4870,6 @@
 	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
 		if (wpas_wps_cancel(wpa_s))
 			reply_len = -1;
-#ifdef CONFIG_WPS_OOB
-	} else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
-			reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
 #ifdef CONFIG_WPS_NFC
 	} else if (os_strcmp(buf, "WPS_NFC") == 0) {
 		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
@@ -4530,6 +4884,18 @@
 		if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
 							       buf + 17))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+		reply_len = wpas_ctrl_nfc_get_handover_req(
+			wpa_s, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+		reply_len = wpas_ctrl_nfc_get_handover_sel(
+			wpa_s, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+		reply_len = wpas_ctrl_nfc_rx_handover_req(
+			wpa_s, buf + 20, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+		if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+			reply_len = -1;
 #endif /* CONFIG_WPS_NFC */
 	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
 		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
@@ -4762,14 +5128,14 @@
 			    ((wpa_s->wpa_state <= WPA_SCANNING) ||
 			     (wpa_s->wpa_state == WPA_COMPLETED))) {
 				wpa_s->normal_scans = 0;
-				wpa_s->scan_req = 2;
+				wpa_s->scan_req = MANUAL_SCAN_REQ;
 				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 = 2;
+				wpa_s->scan_req = MANUAL_SCAN_REQ;
 				wpa_supplicant_req_scan(wpa_s, 0, 0);
 			} else {
 				wpa_printf(MSG_DEBUG, "Ongoing scan action - "
@@ -4903,6 +5269,7 @@
 						      reply_size);
 #endif
 	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+		pmksa_cache_clear_current(wpa_s->wpa);
 		eapol_sm_request_reauth(wpa_s->eapol);
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 4eeb93a..8bc6618 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1950,6 +1950,10 @@
 	  wpas_dbus_getter_eap_methods,
 	  NULL
 	},
+	{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
+	  wpas_dbus_getter_global_capabilities,
+	  NULL
+	},
 	{ NULL, NULL, NULL, NULL, NULL }
 };
 
@@ -2232,6 +2236,10 @@
 	  wpas_dbus_getter_bss_rsn,
 	  NULL
 	},
+	{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+	  wpas_dbus_getter_bss_wps,
+	  NULL
+	},
 	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
 	  wpas_dbus_getter_bss_ies,
 	  NULL
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 44cde42..363a7e5 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -39,6 +39,7 @@
 	WPAS_DBUS_BSS_PROP_RATES,
 	WPAS_DBUS_BSS_PROP_WPA,
 	WPAS_DBUS_BSS_PROP_RSN,
+	WPAS_DBUS_BSS_PROP_WPS,
 	WPAS_DBUS_BSS_PROP_IES,
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 5668e1a..5e06932 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -21,7 +21,6 @@
 #include "../notify.h"
 #include "../bss.h"
 #include "../scan.h"
-#include "../ctrl_iface.h"
 #include "../autoscan.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
@@ -124,7 +123,7 @@
 static const char *dont_quote[] = {
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-	"bssid", NULL
+	"bssid", "scan_freq", "freq_list", NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
@@ -924,6 +923,44 @@
 }
 
 
+/**
+ * wpas_dbus_getter_global_capabilities - Request supported global capabilities
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property. Handles requests by dbus clients to
+ * return a list of strings with supported capabilities like AP, RSN IBSS,
+ * and P2P that are determined at compile time.
+ */
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+					         DBusError *error,
+					         void *user_data)
+{
+	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+	size_t num_items = 0;
+
+#ifdef CONFIG_AP
+	capabilities[num_items++] = "ap";
+#endif /* CONFIG_AP */
+#ifdef CONFIG_IBSS_RSN
+	capabilities[num_items++] = "ibss-rsn";
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+	capabilities[num_items++] = "p2p";
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+	capabilities[num_items++] = "interworking";
+#endif /* CONFIG_INTERWORKING */
+
+	return wpas_dbus_simple_array_property_getter(iter,
+						      DBUS_TYPE_STRING,
+						      capabilities,
+						      num_items, error);
+}
+
+
 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
 				   char **type, DBusMessage **reply)
 {
@@ -1275,7 +1312,7 @@
 		} else if (params.freqs && params.freqs[0]) {
 			wpa_supplicant_trigger_scan(wpa_s, &params);
 		} else {
-			wpa_s->scan_req = 2;
+			wpa_s->scan_req = MANUAL_SCAN_REQ;
 			wpa_supplicant_req_scan(wpa_s, 0, 0);
 		}
 	} else if (!os_strcmp(type, "active")) {
@@ -1417,12 +1454,7 @@
 					    struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->current_ssid != NULL) {
-		wpa_s->normal_scans = 0;
-		wpa_supplicant_reinit_autoscan(wpa_s);
-		wpa_s->disconnected = 0;
-		wpa_s->reassociate = 1;
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-
+		wpas_request_connection(wpa_s);
 		return NULL;
 	}
 
@@ -1454,13 +1486,15 @@
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
 	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+	if (iface == NULL || net_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
 
+	errno = 0;
 	id = strtoul(net_id, NULL, 10);
-	if (errno == EINVAL) {
+	if (errno != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
@@ -1509,7 +1543,8 @@
 	}
 
 	if (ssid == wpa_s->current_ssid)
-		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
 }
 
 
@@ -1553,13 +1588,15 @@
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
 	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+	if (iface == NULL || net_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
 
+	errno = 0;
 	id = strtoul(net_id, NULL, 10);
-	if (errno == EINVAL) {
+	if (errno != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
@@ -1608,13 +1645,15 @@
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
 	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+	if (iface == NULL || net_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
 
+	errno = 0;
 	id = strtoul(net_id, NULL, 10);
-	if (errno == EINVAL) {
+	if (errno != 0) {
 		reply = wpas_dbus_error_invalid_args(message, net_id);
 		goto out;
 	}
@@ -3366,6 +3405,63 @@
 
 
 /**
+ * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "WPS" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+#ifdef CONFIG_WPS
+	struct wpabuf *wps_ie;
+#endif /* CONFIG_WPS */
+	DBusMessageIter iter_dict, variant_iter;
+	const char *type = "";
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+		goto nomem;
+
+#ifdef CONFIG_WPS
+	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+	if (wps_ie) {
+		if (wps_is_selected_pbc_registrar(wps_ie))
+			type = "pbc";
+		else if (wps_is_selected_pin_registrar(wps_ie))
+			type = "pin";
+	}
+#endif /* CONFIG_WPS */
+
+	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
+		goto nomem;
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+		goto nomem;
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
+		goto nomem;
+
+	return TRUE;
+
+nomem:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
+}
+
+
+/**
  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 178a76b..aa56550 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -80,6 +80,10 @@
 dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
 					 DBusError *error, void *user_data);
 
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+						 DBusError *error,
+						 void *user_data);
+
 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 				     struct wpa_supplicant *wpa_s);
 
@@ -238,6 +242,9 @@
 dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
 				     void *user_data);
 
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
+
 dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
 				     void *user_data);
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index 8489ce7..4ad5e7e 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -273,7 +273,7 @@
 			ret = wpa_supplicant_ap_wps_pin(wpa_s,
 							params.bssid,
 							params.pin,
-							npin, sizeof(npin));
+							npin, sizeof(npin), 0);
 		else
 #endif /* CONFIG_AP */
 		{
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e217a72..68e5515 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -331,7 +331,7 @@
 DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
 				   struct wpa_supplicant *wpa_s)
 {
-	wpa_s->scan_req = 2;
+	wpa_s->scan_req = MANUAL_SCAN_REQ;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 	return wpas_dbus_new_success_reply(message);
 }
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index bc148ca..6bab19c 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -139,16 +139,6 @@
 	return -1;
 }
 
-static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
-				       const u8 *addr, int reason_code)
-{
-	if (wpa_s->driver->disassociate) {
-		return wpa_s->driver->disassociate(wpa_s->drv_priv, addr,
-						   reason_code);
-	}
-	return -1;
-}
-
 static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
 				    const u8 *bssid, const u8 *pmkid)
 {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4b1d992..23b91d2 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -84,6 +84,12 @@
 		return -1;
 	}
 
+	if (disallowed_bssid(wpa_s, wpa_s->bssid) ||
+	    disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed");
+		return -1;
+	}
+
 	res = wpas_temp_disabled(wpa_s, ssid);
 	if (res > 0) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
@@ -423,7 +429,9 @@
 
 #ifdef CONFIG_IEEE80211W
 		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
-		    ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+		    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		     wpa_s->conf->pmf : ssid->ieee80211w) ==
+		    MGMT_FRAME_PROTECTION_REQUIRED) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
 				"frame protection");
 			break;
@@ -675,6 +683,16 @@
 		return NULL;
 	}
 
+	if (disallowed_bssid(wpa_s, bss->bssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID disallowed");
+		return NULL;
+	}
+
+	if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
+		return NULL;
+	}
+
 	wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
 
 	for (ssid = group; ssid; ssid = ssid->pnext) {
@@ -862,6 +880,8 @@
 #endif /* CONFIG_P2P */
 		return;
 	}
+
+	wpa_s->scan_for_connection = 1;
 	wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
 }
 
@@ -1012,6 +1032,12 @@
 		return 1;
 	}
 
+	if (current_bss->level < 0 && current_bss->level > selected->level) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
+			"signal level");
+		return 0;
+	}
+
 	min_diff = 2;
 	if (current_bss->level < 0) {
 		if (current_bss->level < -85)
@@ -1632,7 +1658,7 @@
 
 	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
 		wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
-		wpa_supplicant_disassociate(
+		wpa_supplicant_deauthenticate(
 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 		return;
 	}
@@ -1650,7 +1676,7 @@
 			wpa_clear_keys(wpa_s, bssid);
 		}
 		if (wpa_supplicant_select_config(wpa_s) < 0) {
-			wpa_supplicant_disassociate(
+			wpa_supplicant_deauthenticate(
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 			return;
 		}
@@ -1838,6 +1864,28 @@
 }
 
 
+static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
+				 int locally_generated)
+{
+	if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+	    !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+		return 0; /* Not in 4-way handshake with PSK */
+
+	/*
+	 * It looks like connection was lost while trying to go through PSK
+	 * 4-way handshake. Filter out known disconnection cases that are caused
+	 * by something else than PSK mismatch to avoid confusing reports.
+	 */
+
+	if (locally_generated) {
+		if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS)
+			return 0;
+	}
+
+	return 1;
+}
+
+
 static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
 						 u16 reason_code,
 						 int locally_generated)
@@ -1863,8 +1911,7 @@
 		return;
 	}
 
-	if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
-	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+	if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
 		wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
 			"pre-shared key may be incorrect");
 		wpas_auth_failed(wpa_s);
@@ -2530,9 +2577,8 @@
 				data->assoc_reject.status_code);
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_assoc_reject(wpa_s, data);
-#ifdef ANDROID_P2P
-#ifdef CONFIG_P2P
 		else {
+#ifdef ANDROID_P2P
 			if(!wpa_s->current_ssid) {
 				wpa_printf(MSG_ERROR, "current_ssid == NULL");
 				break;
@@ -2571,9 +2617,14 @@
 				wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
 				wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
 			}
-		}
-#endif
+#else
+			const u8 *bssid = data->assoc_reject.bssid;
+			if (bssid == NULL || is_zero_ether_addr(bssid))
+				bssid = wpa_s->pending_bssid;
+			wpas_connection_failed(wpa_s, bssid);
+			wpa_supplicant_mark_disassoc(wpa_s);
 #endif /* ANDROID_P2P */
+		}
 		break;
 	case EVENT_AUTH_TIMED_OUT:
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
new file mode 100755
index 0000000..0cfc1f6
--- /dev/null
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
+# Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import wpactrl
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+def wpas_connect():
+    ifaces = []
+    if os.path.isdir(wpas_ctrl):
+        try:
+            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+        except OSError, error:
+            print "Could not find wpa_supplicant: ", error
+            return None
+
+    if len(ifaces) < 1:
+        print "No wpa_supplicant control interface found"
+        return None
+
+    for ctrl in ifaces:
+        try:
+            wpas = wpactrl.WPACtrl(ctrl)
+            return wpas
+        except wpactrl.error, error:
+            print "Error: ", error
+            pass
+    return None
+
+
+def wpas_tag_read(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_handover_req():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
+
+
+def wpas_put_handover_sel(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
+
+
+def wps_handover_init(peer):
+    print "Trying to initiate WPS handover"
+
+    data = wpas_get_handover_req()
+    if (data == None):
+        print "Could not get handover request message from wpa_supplicant"
+        return
+    print "Handover request from wpa_supplicant: " + data.encode("hex")
+    message = nfc.ndef.Message(data)
+    print "Parsed handover request: " + message.pretty()
+
+    nfc.llcp.activate(peer);
+    time.sleep(0.5)
+
+    client = nfc.handover.HandoverClient()
+    try:
+        print "Trying handover";
+        client.connect()
+        print "Connected for handover"
+    except nfc.llcp.ConnectRefused:
+        print "Handover connection refused"
+        nfc.llcp.shutdown()
+        client.close()
+        return
+
+    print "Sending handover request"
+
+    if not client.send(message):
+        print "Failed to send handover request"
+
+    print "Receiving handover response"
+    message = client._recv()
+    print "Handover select received"
+    print message.pretty()
+    wpas_put_handover_sel(message)
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    client.close()
+    print "Done with handover"
+
+
+def wps_tag_read(tag):
+    if len(tag.ndef.message):
+        message = nfc.ndef.Message(tag.ndef.message)
+        print "message type " + message.type
+
+        for record in message:
+            print "record type " + record.type
+            if record.type == "application/vnd.wfa.wsc":
+                print "WPS tag - send to wpa_supplicant"
+                wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        print "Empty tag"
+
+    print "Remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    try:
+        while True:
+            print "Waiting for a tag or peer to be touched"
+
+            while True:
+                general_bytes = nfc.llcp.startup({})
+                tag = clf.poll(general_bytes)
+                if tag == None:
+                    continue
+
+                if isinstance(tag, nfc.DEP):
+                    wps_handover_init(tag)
+                    break
+
+                if tag.ndef:
+                    wps_tag_read(tag)
+                    break
+
+                if tag:
+                    print "Not an NDEF tag - remove tag"
+                    while tag.is_present:
+                        time.sleep(0.1)
+                    break
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index efa9be8..0d4ca8e 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -453,6 +453,7 @@
 	if (gas_query_tx(gas, query, req) < 0) {
 		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
 			   MACSTR, MAC2STR(query->addr));
+		dl_list_del(&query->list);
 		os_free(query);
 		return -1;
 	}
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 0eb6119..1404241 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -79,8 +79,10 @@
 
 	freq = wpa_s->assoc_freq;
 	bss = wpa_bss_get_bssid(wpa_s, dst);
-	if (bss)
+	if (bss) {
+		wpa_bss_anqp_unshare_alloc(bss);
 		freq = bss->freq;
+	}
 	if (freq <= 0)
 		return -1;
 
@@ -141,9 +143,16 @@
 		}
 		break;
 	case HS20_STYPE_WAN_METRICS:
+		wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
+		if (slen < 13) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
+				"Metrics value from " MACSTR, MAC2STR(sa));
+			break;
+		}
 		wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
-			" WAN Metrics", MAC2STR(sa));
-		wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
+			" WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
+			pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
+			pos[9], pos[10], WPA_GET_LE16(pos + 11));
 		if (anqp) {
 			wpabuf_free(anqp->hs20_wan_metrics);
 			anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 22f709f..cfe56ea 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -717,9 +717,12 @@
 #endif /* INTERWORKING_3GPP */
 
 
-static int interworking_set_hs20_params(struct wpa_ssid *ssid)
+static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
 {
-	if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0)
+	if (wpa_config_set(ssid, "key_mgmt",
+			   wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
+			   "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
 		return -1;
 	if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
 		return -1;
@@ -786,6 +789,7 @@
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
+	ssid->parent_cred = cred;
 
 	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
@@ -797,7 +801,7 @@
 	os_memcpy(ssid->ssid, ie + 2, ie[1]);
 	ssid->ssid_len = ie[1];
 
-	if (interworking_set_hs20_params(ssid) < 0)
+	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
 
 	eap_type = EAP_TYPE_SIM;
@@ -1046,6 +1050,17 @@
 	    wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
 		return -1;
 
+#ifdef ANDROID
+	if (cred->private_key &&
+	    os_strncmp(cred->private_key, "keystore://", 11) == 0) {
+		/* Use OpenSSL engine configuration for Android keystore */
+		if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
+		    wpa_config_set_quoted(ssid, "key_id",
+					  cred->private_key + 11) < 0 ||
+		    wpa_config_set(ssid, "engine", "1", 0) < 0)
+			return -1;
+	} else
+#endif /* ANDROID */
 	if (cred->private_key && cred->private_key[0] &&
 	    wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
 		return -1;
@@ -1084,6 +1099,7 @@
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
+	ssid->parent_cred = cred;
 	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
@@ -1094,7 +1110,7 @@
 	os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
 	ssid->ssid_len = ssid_ie[1];
 
-	if (interworking_set_hs20_params(ssid) < 0)
+	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
 
 	if (cred->eap_method == NULL) {
@@ -1198,6 +1214,7 @@
 		nai_realm_free(realm, count);
 		return -1;
 	}
+	ssid->parent_cred = cred;
 	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
@@ -1208,7 +1225,7 @@
 	os_memcpy(ssid->ssid, ie + 2, ie[1]);
 	ssid->ssid_len = ie[1];
 
-	if (interworking_set_hs20_params(ssid) < 0)
+	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
 
 	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
@@ -1424,50 +1441,60 @@
 }
 
 
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+			      struct wpa_cred *cred,
+			      struct wpabuf *domain_names)
+{
+#ifdef INTERWORKING_3GPP
+	char nai[100], *realm;
+
+	char *imsi = NULL;
+	int mnc_len = 0;
+	if (cred->imsi)
+		imsi = cred->imsi;
+#ifdef CONFIG_PCSC
+	else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
+		 wpa_s->scard && wpa_s->imsi[0]) {
+		imsi = wpa_s->imsi;
+		mnc_len = wpa_s->mnc_len;
+	}
+#endif /* CONFIG_PCSC */
+	if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
+		realm = os_strchr(nai, '@');
+		if (realm)
+			realm++;
+		wpa_printf(MSG_DEBUG, "Interworking: Search for match "
+			   "with SIM/USIM domain %s", realm);
+		if (realm &&
+		    domain_name_list_contains(domain_names, realm))
+			return 1;
+	}
+#endif /* INTERWORKING_3GPP */
+
+	if (cred->domain == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+		   "home SP FQDN %s", cred->domain);
+	if (domain_name_list_contains(domain_names, cred->domain))
+		return 1;
+
+	return 0;
+}
+
+
 static int interworking_home_sp(struct wpa_supplicant *wpa_s,
 				struct wpabuf *domain_names)
 {
 	struct wpa_cred *cred;
-#ifdef INTERWORKING_3GPP
-	char nai[100], *realm;
-#endif /* INTERWORKING_3GPP */
 
 	if (domain_names == NULL || wpa_s->conf->cred == NULL)
 		return -1;
 
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
-#ifdef INTERWORKING_3GPP
-		char *imsi = NULL;
-		int mnc_len = 0;
-		if (cred->imsi)
-			imsi = cred->imsi;
-#ifdef CONFIG_PCSC
-		else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
-			 wpa_s->scard && wpa_s->imsi[0]) {
-			imsi = wpa_s->imsi;
-			mnc_len = wpa_s->mnc_len;
-		}
-#endif /* CONFIG_PCSC */
-		if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0)
-		    == 0) {
-			realm = os_strchr(nai, '@');
-			if (realm)
-				realm++;
-			wpa_printf(MSG_DEBUG, "Interworking: Search for match "
-				   "with SIM/USIM domain %s", realm);
-			if (realm &&
-			    domain_name_list_contains(domain_names, realm))
-				return 1;
-		}
-#endif /* INTERWORKING_3GPP */
-
-		if (cred->domain == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
-			   "home SP FQDN %s", cred->domain);
-		if (domain_name_list_contains(domain_names, cred->domain))
-			return 1;
+		int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
+		if (res)
+			return res;
 	}
 
 	return 0;
@@ -1714,8 +1741,10 @@
 
 	freq = wpa_s->assoc_freq;
 	bss = wpa_bss_get_bssid(wpa_s, dst);
-	if (bss)
+	if (bss) {
+		wpa_bss_anqp_unshare_alloc(bss);
 		freq = bss->freq;
+	}
 	if (freq <= 0)
 		return -1;
 
@@ -1935,7 +1964,7 @@
 	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
 		   "selection");
 	wpa_s->scan_res_handler = interworking_scan_res_handler;
-	wpa_s->scan_req = 2;
+	wpa_s->scan_req = MANUAL_SCAN_REQ;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 
 	return 0;
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index cb8438e..4a4af82 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -25,5 +25,8 @@
 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
 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,
+			      struct wpa_cred *cred,
+			      struct wpabuf *domain_names);
 
 #endif /* INTERWORKING_H */
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 770907c..4479c09 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -327,6 +327,9 @@
 void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
 				 unsigned int id)
 {
+#ifdef CONFIG_WPS
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
+#endif /* CONFIG_WPS */
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index e6b0128..c2d702e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -89,14 +89,13 @@
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
 			 const u8 *dev_addr, enum p2p_wps_method wps_method,
 			 int auto_join);
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
-					    void *timeout_ctx);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
 					int group_added);
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -746,19 +745,13 @@
 	if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
 	    wpa_s->pending_pd_before_join &&
 	    (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
-	     os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+	     os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+	    wpa_s->p2p_fallback_to_go_neg) {
 		wpa_s->pending_pd_before_join = 0;
-		if (wpa_s->p2p_fallback_to_go_neg) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
-				"during p2p_connect-auto");
-			wpas_p2p_fallback_to_go_neg(wpa_s, 0);
-			return;
-		}
-
-		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
-			   "join-existing-group operation (no ACK for PD "
-			   "Req)");
-		wpas_p2p_join_start(wpa_s);
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+			"during p2p_connect-auto");
+		wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+		return;
 	}
 }
 
@@ -861,7 +854,7 @@
 					  params->peer_device_addr);
 	else if (wpa_s->p2p_pin[0])
 		wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
-					  wpa_s->p2p_pin, NULL, 0);
+					  wpa_s->p2p_pin, NULL, 0, 0);
 	os_free(wpa_s->go_params);
 	wpa_s->go_params = NULL;
 }
@@ -912,7 +905,11 @@
 		wpa_config_remove_network(wpa_s->conf, ssid->id);
 		return;
 	}
-	wpa_config_update_psk(ssid);
+	ssid->psk_set = params->psk_set;
+	if (ssid->psk_set)
+		os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
+	else
+		wpa_config_update_psk(ssid);
 	ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
 
 	wpa_s->ap_configured_cb = p2p_go_configured;
@@ -1268,6 +1265,135 @@
 }
 
 
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+				       u8 **spos, const u8 *end)
+{
+	while (*spos < end) {
+		u8 val = ((*spos)[0] & 0xc0) >> 6;
+		int len;
+
+		if (val == 1 || val == 2) {
+			/* These are reserved values in RFC 1035 */
+			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+				   "sequence starting with 0x%x", val);
+			return -1;
+		}
+
+		if (val == 3) {
+			u16 offset;
+			u8 *spos_tmp;
+
+			/* Offset */
+			if (*spos + 2 > end) {
+				wpa_printf(MSG_DEBUG, "P2P: No room for full "
+					   "DNS offset field");
+				return -1;
+			}
+
+			offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+			if (offset >= *spos - start) {
+				wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+					   "pointer offset %u", offset);
+				return -1;
+			}
+
+			(*spos) += 2;
+			spos_tmp = start + offset;
+			return p2p_sd_dns_uncompress_label(upos, uend, start,
+							   &spos_tmp,
+							   *spos - 2);
+		}
+
+		/* Label */
+		len = (*spos)[0] & 0x3f;
+		if (len == 0)
+			return 0;
+
+		(*spos)++;
+		if (*spos + len > end) {
+			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+				   "sequence - no room for label with length "
+				   "%u", len);
+			return -1;
+		}
+
+		if (*upos + len + 2 > uend)
+			return -2;
+
+		os_memcpy(*upos, *spos, len);
+		*spos += len;
+		*upos += len;
+		(*upos)[0] = '.';
+		(*upos)++;
+		(*upos)[0] = '\0';
+	}
+
+	return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+				 size_t msg_len, size_t offset)
+{
+	/* 27-octet in-memory packet from P2P specification */
+	const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+		"\x04_udp\xC0\x11\x00\x0C\x00\x01";
+	u8 *tmp, *end, *spos;
+	char *upos, *uend;
+	int ret = 0;
+
+	if (buf_len < 2)
+		return -1;
+	if (offset > msg_len)
+		return -1;
+
+	tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+	if (tmp == NULL)
+		return -1;
+	spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+	end = spos + msg_len;
+	spos += offset;
+
+	os_memset(tmp, 0, DNS_HEADER_LEN);
+	os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+	os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+	upos = buf;
+	uend = buf + buf_len;
+
+	ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+	if (ret) {
+		os_free(tmp);
+		return ret;
+	}
+
+	if (upos == buf) {
+		upos[0] = '.';
+		upos[1] = '\0';
+	} else if (upos[-1] == '.')
+		upos[-1] = '\0';
+
+	os_free(tmp);
+	return 0;
+}
+
+
 static struct p2p_srv_bonjour *
 wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
 			     const struct wpabuf *query)
@@ -1358,13 +1484,40 @@
 }
 
 
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+			       size_t query_len)
+{
+	char str_rx[256], str_srv[256];
+
+	if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+		return 0; /* Too short to include DNS Type and Version */
+	if (os_memcmp(query + query_len - 3,
+		      wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+		      3) != 0)
+		return 0; /* Mismatch in DNS Type or Version */
+	if (query_len == wpabuf_len(bsrv->query) &&
+	    os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+		return 1; /* Binary match */
+
+	if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+				  0))
+		return 0; /* Failed to uncompress query */
+	if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+				  wpabuf_head(bsrv->query),
+				  wpabuf_len(bsrv->query) - 3, 0))
+		return 0; /* Failed to uncompress service */
+
+	return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
 static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
 				struct wpabuf *resp, u8 srv_trans_id,
 				const u8 *query, size_t query_len)
 {
 	struct p2p_srv_bonjour *bsrv;
-	struct wpabuf buf;
 	u8 *len_pos;
+	int matches = 0;
 
 	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
 			  query, query_len);
@@ -1380,39 +1533,52 @@
 		return;
 	}
 
-	if (wpabuf_tailroom(resp) < 5)
-		return;
-	/* Length (to be filled) */
-	len_pos = wpabuf_put(resp, 2);
-	wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
-	wpabuf_put_u8(resp, srv_trans_id);
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (!match_bonjour_query(bsrv, query, query_len))
+			continue;
 
-	wpabuf_set(&buf, query, query_len);
-	bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
-	if (bsrv == NULL) {
+		if (wpabuf_tailroom(resp) <
+		    5 + query_len + wpabuf_len(bsrv->resp))
+			return;
+
+		matches++;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+				  wpabuf_head(bsrv->resp),
+				  wpabuf_len(bsrv->resp));
+
+		/* Response Data */
+		wpabuf_put_data(resp, query, query_len); /* Key */
+		wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+	}
+
+	if (matches == 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
 			   "available");
+		if (wpabuf_tailroom(resp) < 5)
+			return;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
 
 		/* Status Code */
 		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
 		/* Response Data: empty */
 		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
 			     2);
-		return;
 	}
-
-	/* Status Code */
-	wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
-			  wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp));
-
-	if (wpabuf_tailroom(resp) >=
-	    wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) {
-		/* Response Data */
-		wpabuf_put_buf(resp, bsrv->query); /* Key */
-		wpabuf_put_buf(resp, bsrv->resp); /* Value */
-	}
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
 }
 
 
@@ -1973,14 +2139,6 @@
 {
 	struct p2p_srv_bonjour *bsrv;
 
-	bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
-	if (bsrv) {
-		wpabuf_free(query);
-		wpabuf_free(bsrv->resp);
-		bsrv->resp = resp;
-		return 0;
-	}
-
 	bsrv = os_zalloc(sizeof(*bsrv));
 	if (bsrv == NULL)
 		return -1;
@@ -2185,18 +2343,15 @@
 		return;
 	}
 
-#ifdef ANDROID_P2P
-	/* If provision discovery failed it is safe to cancel the timer here and
-	 * also do not start the join */
-	if (wpa_s->pending_pd_before_join &&
-	    (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
-	     os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+	if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
 		wpa_s->pending_pd_before_join = 0;
-		wpa_printf(MSG_DEBUG, "P2P: Do not Start pending "
-			   "join-existing-group operation");
-		eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
+		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+			   "join-existing-group operation (no ACK for PD "
+			   "Req attempts)");
+		wpas_p2p_join_start(wpa_s);
+		return;
 	}
-#endif /* ANDROID_P2P */
+
 	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
 		" p2p_dev_addr=" MACSTR " status=%d",
 		MAC2STR(peer), status);
@@ -2327,6 +2482,7 @@
 			wpas_p2p_group_add_persistent(
 				wpa_s, s, go, go ? op_freq : 0, 0);
 		} else if (bssid) {
+			wpa_s->user_initiated_pd = 0;
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
 				      wpa_s->p2p_wps_method, 0);
 		}
@@ -2839,6 +2995,8 @@
 
 	p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
 
+	p2p.max_listen = wpa_s->max_remain_on_chan;
+
 #ifdef ANDROID_P2P
 	if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
 		p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
@@ -2888,7 +3046,6 @@
 	wpa_s->go_params = NULL;
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
-	eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
 	wpa_s->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
@@ -2949,6 +3106,8 @@
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->conf->p2p_no_group_iface)
+		return 0; /* separate interface disabled per configuration */
 	if (wpa_s->drv_flags &
 	    (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
 	     WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
@@ -2969,7 +3128,7 @@
 				 enum p2p_wps_method wps_method,
 				 int go_intent, const u8 *own_interface_addr,
 				 unsigned int force_freq, int persistent_group,
-				 struct wpa_ssid *ssid)
+				 struct wpa_ssid *ssid, unsigned int pref_freq)
 {
 	if (persistent_group && wpa_s->conf->persistent_reconnect)
 		persistent_group = 2;
@@ -2991,7 +3150,7 @@
 			   go_intent, own_interface_addr, force_freq,
 			   persistent_group, ssid ? ssid->ssid : NULL,
 			   ssid ? ssid->ssid_len : 0,
-			   wpa_s->p2p_pd_before_go_neg);
+			   wpa_s->p2p_pd_before_go_neg, pref_freq);
 }
 
 
@@ -3000,7 +3159,7 @@
 				enum p2p_wps_method wps_method,
 				int go_intent, const u8 *own_interface_addr,
 				unsigned int force_freq, int persistent_group,
-				struct wpa_ssid *ssid)
+				struct wpa_ssid *ssid, unsigned int pref_freq)
 {
 	if (persistent_group && wpa_s->conf->persistent_reconnect)
 		persistent_group = 2;
@@ -3011,7 +3170,7 @@
 	return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
 			     go_intent, own_interface_addr, force_freq,
 			     persistent_group, ssid ? ssid->ssid : NULL,
-			     ssid ? ssid->ssid_len : 0);
+			     ssid ? ssid->ssid_len : 0, pref_freq);
 }
 
 
@@ -3038,21 +3197,6 @@
 }
 
 
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	if (!wpa_s->pending_pd_before_join)
-		return;
-	/*
-	 * Provision Discovery Response may have been lost - try to connect
-	 * anyway since we do not need any information from this PD.
-	 */
-	wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
-		   "try to connect anyway");
-	wpas_p2p_join_start(wpa_s);
-}
-
-
 static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
 {
 	struct wpa_supplicant *iface;
@@ -3170,7 +3314,7 @@
 		if (p2p_prov_disc_req(wpa_s->global->p2p,
 				      wpa_s->pending_join_dev_addr,
 				      wpa_s->pending_pd_config_methods, join,
-				      0) < 0) {
+				      0, wpa_s->user_initiated_pd) < 0) {
 			wpa_s->p2p_auto_pd = 0;
 			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
 				" p2p_dev_addr=" MACSTR " status=N/A",
@@ -3280,25 +3424,13 @@
 
 		if (p2p_prov_disc_req(wpa_s->global->p2p,
 				      wpa_s->pending_join_dev_addr, method, 1,
-				      freq) < 0) {
+				      freq, wpa_s->user_initiated_pd) < 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
 				   "Discovery Request before joining an "
 				   "existing group");
 			wpa_s->pending_pd_before_join = 0;
 			goto start;
 		}
-
-		/*
-		 * Actual join operation will be started from the Action frame
-		 * TX status callback (if no ACK is received) or when the
-		 * Provision Discovery Response is received. Use a short
-		 * timeout as a backup mechanism should the Provision Discovery
-		 * Response be lost for any reason.
-		 */
-		eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
-				     NULL);
-		eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
-				       wpa_s, NULL);
 		return;
 	}
 
@@ -3425,7 +3557,6 @@
 	struct p2p_go_neg_results res;
 	struct wpa_bss *bss;
 
-	eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
 	group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
 	if (group == NULL)
 		return -1;
@@ -3499,7 +3630,7 @@
 		     int go_intent, int freq, int persistent_id, int pd,
 		     int ht40)
 {
-	int force_freq = 0, oper_freq = 0;
+	int force_freq = 0, pref_freq = 0, oper_freq = 0;
 	u8 bssid[ETH_ALEN];
 	int ret = 0;
 	enum wpa_driver_if_type iftype;
@@ -3565,6 +3696,7 @@
 				   wpa_s->p2p_auto_started.sec,
 				   wpa_s->p2p_auto_started.usec);
 		}
+		wpa_s->user_initiated_pd = 1;
 		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
 				  auto_join) < 0)
 			return -1;
@@ -3612,6 +3744,13 @@
 			   "(%u MHz) not available for P2P - try to use "
 			   "another channel", oper_freq);
 		force_freq = 0;
+	} else if (oper_freq > 0 &&
+		   (wpa_s->drv_flags &
+		    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+			   "are already using (%u MHz) on another interface",
+			   oper_freq);
+		pref_freq = oper_freq;
 	} else if (oper_freq > 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
 			   "channel we are already using (%u MHz) on another "
@@ -3639,15 +3778,15 @@
 	if (auth) {
 		if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
 					 go_intent, if_addr,
-					 force_freq, persistent_group, ssid) <
-		    0)
+					 force_freq, persistent_group, ssid,
+					 pref_freq) < 0)
 			return -1;
 		return ret;
 	}
 
 	if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
 				  go_intent, if_addr, force_freq,
-				  persistent_group, ssid) < 0) {
+				  persistent_group, ssid, pref_freq) < 0) {
 		if (wpa_s->create_p2p_iface)
 			wpas_p2p_remove_pending_group_interface(wpa_s);
 		return -1;
@@ -3899,7 +4038,7 @@
 
 	/* Make sure we are not running find during connection establishment */
 	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
-	wpas_p2p_stop_find(wpa_s);
+	wpas_p2p_stop_find_oper(wpa_s);
 
 	if (freq == 2) {
 		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
@@ -4030,7 +4169,7 @@
 	}
 
 	/* Make sure we are not running find during connection establishment */
-	wpas_p2p_stop_find(wpa_s);
+	wpas_p2p_stop_find_oper(wpa_s);
 
 	wpa_s->p2p_fallback_to_go_neg = 0;
 
@@ -4044,6 +4183,9 @@
 		return -1;
 
 	params.role_go = 1;
+	params.psk_set = ssid->psk_set;
+	if (params.psk_set)
+		os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
 	if (ssid->passphrase == NULL ||
 	    os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
 		wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
@@ -4253,7 +4395,7 @@
 
 	return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
 				 config_methods, use == WPAS_P2P_PD_FOR_JOIN,
-				 0);
+				 0, 1);
 }
 
 
@@ -4299,7 +4441,7 @@
 }
 
 
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_clear_pending_action_tx(wpa_s);
 	wpa_s->p2p_long_listen = 0;
@@ -4309,12 +4451,20 @@
 
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
 		wpa_drv_p2p_stop_find(wpa_s);
-		return;
+		return 1;
 	}
 
 	if (wpa_s->global->p2p)
 		p2p_stop_find(wpa_s->global->p2p);
 
+	return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+	if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+		return;
 	wpas_p2p_remove_pending_group_interface(wpa_s);
 }
 
@@ -4743,8 +4893,15 @@
 
 static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
 {
-	return wpa_s->current_ssid != NULL &&
-		wpa_s->current_ssid->p2p_group &&
+	if (wpa_s->current_ssid == NULL) {
+		/*
+		 * current_ssid can be cleared when P2P client interface gets
+		 * disconnected, so assume this interface was used as P2P
+		 * client.
+		 */
+		return 1;
+	}
+	return wpa_s->current_ssid->p2p_group &&
 		wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
 }
 
@@ -5366,7 +5523,6 @@
 					int group_added)
 {
 	struct wpa_supplicant *group = wpa_s;
-	eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
 	if (wpa_s->global->p2p_group_formation)
 		group = wpa_s->global->p2p_group_formation;
 	wpa_s = wpa_s->parent;
@@ -5438,7 +5594,8 @@
 }
 
 #ifdef ANDROID_P2P
-int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+	struct wpa_ssid *ssid)
 {
 	struct wpa_supplicant *iface = NULL;
 	struct p2p_data *p2p = wpa_s->global->p2p;
@@ -5464,17 +5621,32 @@
 			/* If GO cannot be moved or if the conflicting interface is a
 			 * P2P Client, remove the interface depending up on the connection
 			 * priority */
-			if (!wpas_is_p2p_prioritized(wpa_s)) {
+			if(!wpas_is_p2p_prioritized(iface)) {
 				/* STA connection has priority over existing
 				 * P2P connection. So remove the interface */
-				wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel "
+				wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
 						"concurrent mode frequency conflict");
 				wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+				/* If connection in progress is p2p connection, do not proceed for the connection */
+				if (wpa_s == iface)
+					return -1;
+				else
+					/* If connection in progress is STA connection, proceed for the connection */
+					return 0;
 			} else {
-				/* Existing connection has the priority. Disable the newly
-				 * selected network and let the application know about it.
- 				 */
-				return -1;
+				/* P2p connection has priority, disable the STA network*/
+				wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
+				wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
+					" id=%d", ssid->id);
+				os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
+				if (wpa_s == iface) {
+					/* p2p connection is in progress, continue connecting...*/
+					return 0;
+				}
+				else {
+					/* STA connection is in progress, do not allow to continue */
+					return -1;
+				}
 			}
 		}
 	}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 6e4cc1d..a27c1b6 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -28,7 +28,7 @@
 					  unsigned int freq);
 #ifdef ANDROID_P2P
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
-                                          int freq);
+                                          int freq, struct wpa_ssid *ssid);
 #endif
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 62b7538..3503e65 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -38,12 +38,6 @@
 };
 
 
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
-	wpa_supplicant_disassociate(wpa_s, reason_code);
-}
-
-
 static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
 {
 	wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -238,7 +232,6 @@
 	ctx->set_state = _wpa_supplicant_set_state;
 	ctx->get_state = _wpa_supplicant_get_state;
 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-	ctx->disassociate = _wpa_supplicant_disassociate;
 	ctx->set_key = wpa_supplicant_set_key;
 	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
 	ctx->get_bssid = wpa_supplicant_get_bssid;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 0f6433b..048e6d0 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -66,7 +66,8 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p) {
+	if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
+	    !wpa_s->conf->p2p_disabled) {
 		wpa_s->wps->dev.p2p = 1;
 		if (!wps) {
 			wps = 1;
@@ -439,11 +440,78 @@
 }
 
 
+#ifdef CONFIG_P2P
+
+/*
+ * Check whether there are any enabled networks or credentials that could be
+ * used for a non-P2P connection.
+ */
+static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (wpas_network_disabled(wpa_s, ssid))
+			continue;
+		if (!ssid->p2p_group)
+			return 1;
+	}
+
+	if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+	    wpa_s->conf->auto_interworking)
+		return 1;
+
+	return 0;
+}
+
+
+/*
+ * Find the operating frequency of any other virtual interface that is using
+ * the same radio concurrently.
+ */
+static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+	u8 bssid[ETH_ALEN];
+
+	if (!wpa_s->driver->get_radio_name)
+		return -1;
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return -1;
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (!rn2 || os_strcmp(rn, rn2) != 0)
+			continue;
+
+		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+			continue;
+
+		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+			return ifs->current_ssid->frequency;
+		if (wpa_drv_get_bssid(ifs, bssid) == 0)
+			return ifs->assoc_freq;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
 static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct wpa_ssid *ssid;
-	int scan_req = 0, ret;
+	enum scan_req_type scan_req = NORMAL_SCAN_REQ;
+	int ret;
 	struct wpabuf *extra_ie = NULL;
 	struct wpa_driver_scan_params params;
 	struct wpa_driver_scan_params *scan_params;
@@ -455,7 +523,7 @@
 		return;
 	}
 
-	if (wpa_s->disconnected && !wpa_s->scan_req) {
+	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);
 		return;
@@ -468,7 +536,7 @@
 	}
 #endif
 	if (!wpa_supplicant_enabled_networks(wpa_s) &&
-	    !wpa_s->scan_req) {
+	    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);
 #ifdef CONFIG_P2P
@@ -516,7 +584,7 @@
 	}
 
 	scan_req = wpa_s->scan_req;
-	wpa_s->scan_req = 0;
+	wpa_s->scan_req = NORMAL_SCAN_REQ;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -533,7 +601,7 @@
 		goto scan;
 	}
 
-	if (scan_req != 2 && wpa_s->connect_without_scan) {
+	if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
 		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
 			if (ssid == wpa_s->connect_without_scan)
 				break;
@@ -571,7 +639,7 @@
 		}
 	}
 
-	if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+	if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
 		wpa_s->connect_without_scan = NULL;
 		wpa_s->prev_scan_wildcard = 0;
 		wpa_supplicant_assoc_try(wpa_s, ssid);
@@ -698,6 +766,35 @@
 	scan_params = &params;
 
 scan:
+#ifdef CONFIG_P2P
+	/*
+	 * If the driver does not support multi-channel concurrency and a
+	 * virtual interface that shares the same radio with the wpa_s interface
+	 * is operating there may not be need to scan other channels apart from
+	 * the current operating channel on the other virtual interface. Filter
+	 * out other channels in case we are trying to find a connection for a
+	 * station interface when we are not configured to prefer station
+	 * connection and a concurrent operation is already in process.
+	 */
+	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+	    !scan_params->freqs && !params.freqs &&
+	    wpas_is_p2p_prioritized(wpa_s) &&
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+	    non_p2p_network_enabled(wpa_s)) {
+		int freq = shared_vif_oper_freq(wpa_s);
+		if (freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
+				"operating channel (%d MHz) since driver does "
+				"not support multi-channel concurrency", freq);
+			params.freqs = os_zalloc(sizeof(int) * 2);
+			if (params.freqs)
+				params.freqs[0] = freq;
+			scan_params->freqs = params.freqs;
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
 
 	wpabuf_free(extra_ie);
@@ -706,15 +803,13 @@
 
 	if (ret) {
 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
-#ifdef ANDROID_P2P
-		/* Restore back the wpa_s->scan_req if we failed the scan because of any reason */
-		wpa_msg(wpa_s, MSG_DEBUG, "Restoring back the wpa_s->scan_req "
-			"to the original value %d", scan_req);
-		wpa_s->scan_req = scan_req;
-#endif
 		if (prev_state != wpa_s->wpa_state)
 			wpa_supplicant_set_state(wpa_s, prev_state);
+		/* Restore scan_req since we will try to scan again */
+		wpa_s->scan_req = scan_req;
 		wpa_supplicant_req_scan(wpa_s, 1, 0);
+	} else {
+		wpa_s->scan_for_connection = 0;
 	}
 }
 
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index b09e5f1..e273cb3 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -39,8 +39,50 @@
 #endif /* CONFIG_IEEE80211W */
 
 
-void sme_authenticate(struct wpa_supplicant *wpa_s,
-		      struct wpa_bss *bss, struct wpa_ssid *ssid)
+#ifdef CONFIG_SAE
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(4 + 2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, 1); /* Transaction seq# */
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+	/* TODO: Anti-Clogging Token (if requested) */
+	/* TODO: Scalar */
+	/* TODO: Element */
+
+	return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(4 + 2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, 2); /* Transaction seq# */
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	wpabuf_put_le16(buf, wpa_s->sme.sae_send_confirm);
+	wpa_s->sme.sae_send_confirm++;
+	/* TODO: Confirm */
+
+	return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+static void sme_send_authentication(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss, struct wpa_ssid *ssid,
+				    int start)
 {
 	struct wpa_driver_auth_params params;
 	struct wpa_ssid *old_ssid;
@@ -51,6 +93,7 @@
 	const u8 *md = NULL;
 #endif /* CONFIG_IEEE80211R */
 	int i, bssid_changed;
+	struct wpabuf *resp = NULL;
 
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -95,6 +138,21 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
 			"0x%x", params.auth_alg);
 	}
+#ifdef CONFIG_SAE
+	if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
+		const u8 *rsn;
+		struct wpa_ie_data ied;
+
+		rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (rsn &&
+		    wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
+			if (wpa_key_mgmt_sae(ied.key_mgmt)) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+				params.auth_alg = WPA_AUTH_ALG_SAE;
+			}
+		}
+	}
+#endif /* CONFIG_SAE */
 
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
 		if (ssid->wep_key_len[i])
@@ -113,7 +171,9 @@
 	     wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
 	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
 		int try_opportunistic;
-		try_opportunistic = ssid->proactive_key_caching &&
+		try_opportunistic = (ssid->proactive_key_caching < 0 ?
+				     wpa_s->conf->okc :
+				     ssid->proactive_key_caching) &&
 			(ssid->proto & WPA_PROTO_RSN);
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    wpa_s->current_ssid,
@@ -203,8 +263,9 @@
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
-	wpa_s->sme.mfp = ssid->ieee80211w;
-	if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+	wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		wpa_s->conf->pmf : ssid->ieee80211w;
+	if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
 		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 		struct wpa_ie_data _ie;
 		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
@@ -265,6 +326,20 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_SAE
+	if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+		if (start)
+			resp = sme_auth_build_sae_commit(wpa_s);
+		else
+			resp = sme_auth_build_sae_confirm(wpa_s);
+		if (resp == NULL)
+			return;
+		params.sae_data = wpabuf_head(resp);
+		params.sae_data_len = wpabuf_len(resp);
+		wpa_s->sme.sae_state = start ? SME_SAE_COMMIT : SME_SAE_CONFIRM;
+	}
+#endif /* CONFIG_SAE */
+
 	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_cancel_scan(wpa_s);
 
@@ -287,6 +362,7 @@
 			"driver failed");
 		wpas_connection_failed(wpa_s, bss->bssid);
 		wpa_supplicant_mark_disassoc(wpa_s);
+		wpabuf_free(resp);
 		return;
 	}
 
@@ -297,9 +373,91 @@
 	 * Association will be started based on the authentication event from
 	 * the driver.
 	 */
+
+	wpabuf_free(resp);
 }
 
 
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+		      struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+	wpa_s->sme.sae_state = SME_SAE_INIT;
+	wpa_s->sme.sae_send_confirm = 0;
+	sme_send_authentication(wpa_s, bss, ssid, 1);
+}
+
+
+#ifdef CONFIG_SAE
+
+static int sme_sae_process_commit(struct wpa_supplicant *wpa_s, const u8 *data,
+				  size_t len)
+{
+	/* Check Finite Cyclic Group */
+	if (len < 2)
+		return -1;
+	if (WPA_GET_LE16(data) != 19) {
+		wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+			   WPA_GET_LE16(data));
+		return -1;
+	}
+
+	/* TODO */
+
+	return 0;
+}
+
+
+static int sme_sae_process_confirm(struct wpa_supplicant *wpa_s, const u8 *data,
+				   size_t len)
+{
+	u16 rc;
+
+	if (len < 2)
+		return -1;
+	rc = WPA_GET_LE16(data);
+	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+	/* TODO */
+	return 0;
+}
+
+
+static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
+			u16 status_code, const u8 *data, size_t len)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
+		"status code %u", auth_transaction, status_code);
+	wpa_hexdump(MSG_DEBUG, "SME: SAE fields", data, len);
+
+	if (status_code != WLAN_STATUS_SUCCESS)
+		return -1;
+
+	if (auth_transaction == 1) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
+		if (wpa_s->current_bss == NULL ||
+		    wpa_s->current_ssid == NULL)
+			return -1;
+		if (wpa_s->sme.sae_state != SME_SAE_COMMIT)
+			return -1;
+		if (sme_sae_process_commit(wpa_s, data, len) < 0)
+			return -1;
+		sme_send_authentication(wpa_s, wpa_s->current_bss,
+					wpa_s->current_ssid, 0);
+		return 0;
+	} else if (auth_transaction == 2) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
+		if (wpa_s->sme.sae_state != SME_SAE_CONFIRM)
+			return -1;
+		if (sme_sae_process_confirm(wpa_s, data, len) < 0)
+			return -1;
+		return 1;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_SAE */
+
+
 void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
 {
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -324,14 +482,30 @@
 	}
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-		" auth_type=%d status_code=%d",
+		" auth_type=%d auth_transaction=%d status_code=%d",
 		MAC2STR(data->auth.peer), data->auth.auth_type,
-		data->auth.status_code);
+		data->auth.auth_transaction, data->auth.status_code);
 	wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
 		    data->auth.ies, data->auth.ies_len);
 
 	eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
 
+#ifdef CONFIG_SAE
+	if (data->auth.auth_type == WLAN_AUTH_SAE) {
+		int res;
+		res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
+				   data->auth.status_code, data->auth.ies,
+				   data->auth.ies_len);
+		if (res < 0) {
+			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+		}
+		if (res != 1)
+			return;
+	}
+#endif /* CONFIG_SAE */
+
 	if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
 			"code %d)", data->auth.status_code);
@@ -860,9 +1034,14 @@
 	if (!enable)
 		return;
 
-	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || ssid == NULL ||
-	    ssid->mode != IEEE80211_MODE_INFRA)
-		return; /* Not using station SME in wpa_supplicant */
+	/*
+	 * Schedule OBSS scan if driver is using station SME in wpa_supplicant
+	 * or it expects OBSS scan to be performed by wpa_supplicant.
+	 */
+	if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+	      (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
+	    ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA)
+		return;
 
 	if (!wpa_s->hw.modes)
 		return;
@@ -1012,7 +1191,9 @@
 	if (wpa_s->wpa_state != WPA_COMPLETED)
 		return;
 	ssid = wpa_s->current_ssid;
-	if (ssid == NULL || ssid->ieee80211w == 0)
+	if (ssid == NULL ||
+	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
 		return;
 	if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
 		return;
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
new file mode 100644
index 0000000..76aba12
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
new file mode 100644
index 0000000..ff384ae
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and wired driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-wired@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
new file mode 100644
index 0000000..c215567
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
new file mode 100644
index 0000000..4351ad8
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=WPA supplicant
+
+[Service]
+Type=dbus
+BusName=fi.epitest.hostap.WPASupplicant
+ExecStart=@BINDIR@/wpa_supplicant -u
+
+[Install]
+WantedBy=multi-user.target
+Alias=dbus-fi.epitest.hostap.WPASupplicant.service
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
new file mode 100755
index 0000000..65e2fa1
--- /dev/null
+++ b/wpa_supplicant/utils/log2pcap.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012, Intel Corporation
+#
+# Author: Johannes Berg <johannes@sipsolutions.net>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import sys, struct, re
+
+def write_pcap_header(pcap_file):
+    pcap_file.write(
+        struct.pack('<IHHIIII',
+                    0xa1b2c3d4, 2, 4, 0, 0, 65535,
+                    105 # raw 802.11 format
+                    ))
+
+def pcap_addpacket(pcap_file, ts, data):
+    # ts in seconds, float
+    pcap_file.write(struct.pack('<IIII',
+        int(ts), int(1000000 * ts) % 1000000,
+        len(data), len(data)))
+    pcap_file.write(data)
+
+if __name__ == "__main__":
+    try:
+        input = sys.argv[1]
+        pcap = sys.argv[2]
+    except IndexError:
+        print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+        sys.exit(2)
+
+    input_file = open(input, 'r')
+    pcap_file = open(pcap, 'w')
+    frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)')
+
+    write_pcap_header(pcap_file)
+
+    for line in input_file:
+        m = frame_re.match(line)
+        if m is None:
+            continue
+        if m.group(2):
+            ts = float(m.group(2))
+        else:
+            ts = 0
+        hexdata = m.group(3)
+        hexdata = hexdata.split()
+        data = ''.join([chr(int(x, 16)) for x in hexdata])
+        pcap_addpacket(pcap_file, ts, data)
+
+    input_file.close()
+    pcap_file.close()
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 3986b9b..4e7c81c 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -762,26 +762,6 @@
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	if (argc != 3 && argc != 4) {
-		printf("Invalid WPS_OOB command: need three or four "
-		       "arguments:\n"
-		       "- DEV_TYPE: use 'ufd' or 'nfc'\n"
-		       "- PATH: path of OOB device like '/mnt'\n"
-		       "- METHOD: OOB method 'pin-e' or 'pin-r', "
-		       "'cred'\n"
-		       "- DEV_NAME: (only for NFC) device name like "
-		       "'pn531'\n");
-		return -1;
-	}
-
-	return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 
 static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -822,6 +802,72 @@
 	return ret;
 }
 
+
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+					   char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'nfc_rx_handover_req' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 21 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+					   char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 21 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -1330,7 +1376,7 @@
 		return 0;
 	}
 
-	if (argc != 3) {
+	if (argc < 3) {
 		printf("Invalid SET_NETWORK command: needs three arguments\n"
 		       "(network id, variable name, and value)\n");
 		return -1;
@@ -2469,11 +2515,6 @@
 	  "<PIN> = verify PIN checksum" },
 	{ "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
 	  "Cancels the pending WPS operation" },
-#ifdef CONFIG_WPS_OOB
-	{ "wps_oob", wpa_cli_cmd_wps_oob, NULL,
-	  cli_cmd_flag_sensitive,
-	  "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
-#endif /* CONFIG_WPS_OOB */
 #ifdef CONFIG_WPS_NFC
 	{ "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
 	  cli_cmd_flag_none,
@@ -2484,6 +2525,18 @@
 	{ "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
 	  cli_cmd_flag_sensitive,
 	  "<hexdump of payload> = report read NFC tag with WPS data" },
+	{ "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+	  cli_cmd_flag_none,
+	  "<NDEF> <WPS> = create NFC handover request" },
+	{ "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+	  cli_cmd_flag_none,
+	  "<NDEF> <WPS> = create NFC handover select" },
+	{ "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+	  cli_cmd_flag_none,
+	  "<hexdump of payload> = report received NFC handover request" },
+	{ "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+	  cli_cmd_flag_none,
+	  "<hexdump of payload> = report received NFC handover select" },
 #endif /* CONFIG_WPS_NFC */
 	{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
 	  cli_cmd_flag_sensitive,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d8f3c44..3dcd7d6 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -190,7 +190,7 @@
 		MAC2STR(bssid));
 	wpa_blacklist_add(wpa_s, bssid);
 	wpa_sm_notify_disassoc(wpa_s->wpa);
-	wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 	wpa_s->reassociate = 1;
 
 	/*
@@ -470,6 +470,11 @@
 	os_free(wpa_s->bssid_filter);
 	wpa_s->bssid_filter = NULL;
 
+	os_free(wpa_s->disallow_aps_bssid);
+	wpa_s->disallow_aps_bssid = NULL;
+	os_free(wpa_s->disallow_aps_ssid);
+	wpa_s->disallow_aps_ssid = NULL;
+
 	wnm_bss_keep_alive_deinit(wpa_s);
 
 	ext_password_deinit(wpa_s->ext_pw);
@@ -666,6 +671,7 @@
 			ssid && ssid->id_str ? ssid->id_str : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+		wpa_s->extra_blacklist_count = 0;
 		wpa_s->new_connection = 0;
 		wpa_s->reassociated_connection = 1;
 		wpa_drv_set_operstate(wpa_s, 1);
@@ -931,7 +937,9 @@
 
 #ifdef CONFIG_IEEE80211W
 	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
-	    ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) ==
+	    MGMT_FRAME_PROTECTION_REQUIRED) {
 		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
 			"that does not support management frame protection - "
 			"reject");
@@ -1074,6 +1082,10 @@
 	}
 
 	sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
 	if (0) {
 #ifdef CONFIG_IEEE80211R
 	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
@@ -1083,6 +1095,14 @@
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	} else if (sel & WPA_KEY_MGMT_SAE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+	} else if (sel & WPA_KEY_MGMT_FT_SAE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
 #ifdef CONFIG_IEEE80211W
 	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1115,7 +1135,8 @@
 
 #ifdef CONFIG_IEEE80211W
 	sel = ie.mgmt_group_cipher;
-	if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+	if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
 	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
 		sel = 0;
 	if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1128,7 +1149,9 @@
 	}
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
 			 wpa_s->mgmt_group_cipher);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+			 (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+			  wpa_s->conf->pmf : ssid->ieee80211w));
 #endif /* CONFIG_IEEE80211W */
 
 	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1309,7 +1332,7 @@
 		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
 		/* Use ap_scan==1 style network selection to find the network
 		 */
-		wpa_s->scan_req = 2;
+		wpa_s->scan_req = MANUAL_SCAN_REQ;
 		wpa_s->reassociate = 1;
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 		return;
@@ -1347,7 +1370,9 @@
 		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
 	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
 		int try_opportunistic;
-		try_opportunistic = ssid->proactive_key_caching &&
+		try_opportunistic = (ssid->proactive_key_caching < 0 ?
+				     wpa_s->conf->okc :
+				     ssid->proactive_key_caching) &&
 			(ssid->proto & WPA_PROTO_RSN);
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    wpa_s->current_ssid,
@@ -1552,8 +1577,10 @@
 	params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
-	params.mgmt_frame_protection = ssid->ieee80211w;
-	if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
+	params.mgmt_frame_protection =
+		ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		wpa_s->conf->pmf : ssid->ieee80211w;
+	if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
 		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 		struct wpa_ie_data ie;
 		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
@@ -1590,16 +1617,8 @@
 		((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
 		wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)"
 																, freq, params.freq);
-		if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq) < 0) {
-			/* Handling conflicts failed. Disable the current connect req and
-			 * notify the userspace to take appropriate action */
-			wpa_printf(MSG_DEBUG, "proiritize is not set. Notifying user space to handle the case");
-			wpa_supplicant_disable_network(wpa_s, ssid);
-			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
-				" id=%d", ssid->id);
-			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+		if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq, ssid) < 0) 
 			return;
-		}
 	}
 #endif
 	ret = wpa_drv_associate(wpa_s, &params);
@@ -1694,33 +1713,6 @@
 
 
 /**
- * wpa_supplicant_disassociate - Disassociate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the disassociate frame
- *
- * This function is used to request %wpa_supplicant to disassociate with the
- * current AP.
- */
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-				 int reason_code)
-{
-	u8 *addr = NULL;
-	union wpa_event_data event;
-
-	if (!is_zero_ether_addr(wpa_s->bssid)) {
-		wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
-		addr = wpa_s->bssid;
-		os_memset(&event, 0, sizeof(event));
-		event.disassoc_info.reason_code = (u16) reason_code;
-		event.disassoc_info.locally_generated = 1;
-		wpa_supplicant_event(wpa_s, EVENT_DISASSOC, &event);
-	}
-
-	wpa_supplicant_clear_connection(wpa_s, addr);
-}
-
-
-/**
  * wpa_supplicant_deauthenticate - Deauthenticate the current connection
  * @wpa_s: Pointer to wpa_supplicant data
  * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
@@ -1733,14 +1725,38 @@
 {
 	u8 *addr = NULL;
 	union wpa_event_data event;
+	int zero_addr = 0;
 
-	if (!is_zero_ether_addr(wpa_s->bssid)) {
-		wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+		" pending_bssid=" MACSTR " reason=%d state=%s",
+		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+		reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+
+	if (!is_zero_ether_addr(wpa_s->bssid))
 		addr = wpa_s->bssid;
+	else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+		 (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+		  wpa_s->wpa_state == WPA_ASSOCIATING))
+		addr = wpa_s->pending_bssid;
+	else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+		/*
+		 * When using driver-based BSS selection, we may not know the
+		 * BSSID with which we are currently trying to associate. We
+		 * need to notify the driver of this disconnection even in such
+		 * a case, so use the all zeros address here.
+		 */
+		addr = wpa_s->bssid;
+		zero_addr = 1;
+	}
+
+	if (addr) {
+		wpa_drv_deauthenticate(wpa_s, addr, reason_code);
 		os_memset(&event, 0, sizeof(event));
 		event.deauth_info.reason_code = (u16) reason_code;
 		event.deauth_info.locally_generated = 1;
 		wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
+		if (zero_addr)
+			addr = NULL;
 	}
 
 	wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1831,11 +1847,11 @@
 					wpa_s, other_ssid);
 		}
 		if (wpa_s->current_ssid)
-			wpa_supplicant_disassociate(
+			wpa_supplicant_deauthenticate(
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 	} else if (ssid->disabled != 2) {
 		if (ssid == wpa_s->current_ssid)
-			wpa_supplicant_disassociate(
+			wpa_supplicant_deauthenticate(
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
 		was_disabled = ssid->disabled;
@@ -1861,7 +1877,7 @@
 	int disconnected = 0;
 
 	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
-		wpa_supplicant_disassociate(
+		wpa_supplicant_deauthenticate(
 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 		disconnected = 1;
 	}
@@ -2419,7 +2435,7 @@
 	wpa_s = os_zalloc(sizeof(*wpa_s));
 	if (wpa_s == NULL)
 		return NULL;
-	wpa_s->scan_req = 1;
+	wpa_s->scan_req = INITIAL_SCAN_REQ;
 	wpa_s->scan_interval = 5;
 	wpa_s->new_connection = 1;
 	wpa_s->parent = wpa_s;
@@ -3452,6 +3468,12 @@
 		}
 	}
 
+	/*
+	 * Add previous failure count in case the temporary blacklist was
+	 * cleared due to no other BSSes being available.
+	 */
+	count += wpa_s->extra_blacklist_count;
+
 	switch (count) {
 	case 1:
 		timeout = 100;
@@ -3462,10 +3484,17 @@
 	case 3:
 		timeout = 1000;
 		break;
-	default:
+	case 4:
 		timeout = 5000;
+		break;
+	default:
+		timeout = 10000;
+		break;
 	}
 
+	wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
+		"ms", count, timeout);
+
 	/*
 	 * TODO: if more than one possible AP is available in scan results,
 	 * could try the other ones before requesting a new scan.
@@ -3672,3 +3701,58 @@
 	if (clear_failures)
 		ssid->auth_failures = 0;
 }
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	size_t i;
+
+	if (wpa_s->disallow_aps_bssid == NULL)
+		return 0;
+
+	for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+		if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+			      bssid, ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+		    size_t ssid_len)
+{
+	size_t i;
+
+	if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+		return 0;
+
+	for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+		struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+		if (ssid_len == s->ssid_len &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpas_request_connection - Request a new connection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request a new connection to be found. It will mark
+ * the interface to allow reassociation and request a new scan to find a
+ * suitable network to connect to.
+ */
+void wpas_request_connection(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->normal_scans = 0;
+	wpa_supplicant_reinit_autoscan(wpa_s);
+	wpa_s->extra_blacklist_count = 0;
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 0b0ea88..5f0dec6 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -265,6 +265,21 @@
 # inactive stations.
 #p2p_go_max_inactivity=300
 
+# Opportunistic Key Caching (also known as Proactive Key Caching) default
+# This parameter can be used to set the default behavior for the
+# proactive_key_caching parameter. By default, OKC is disabled unless enabled
+# with the global okc=1 parameter or with the per-network
+# proactive_key_caching=1 parameter. With okc=1, OKC is enabled by default, but
+# can be disabled with per-network proactive_key_caching=0 parameter.
+#okc=0
+
+# Protected Management Frames default
+# This parameter can be used to set the default behavior for the ieee80211w
+# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
+# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
+# is enabled/required by default, but can be disabled with the per-network
+# ieee80211w parameter.
+#pmf=0
 
 # Interworking (IEEE 802.11u)
 
@@ -490,7 +505,7 @@
 # If not set, this defaults to: WPA-PSK WPA-EAP
 #
 # ieee80211w: whether management frame protection is enabled
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global pmf parameter)
 # 1 = optional
 # 2 = required
 # The most common configuration options for this based on the PMF (protected
@@ -548,7 +563,7 @@
 #
 # proactive_key_caching:
 # Enable/disable opportunistic PMKSA caching for WPA2.
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global okc parameter)
 # 1 = enabled
 #
 # wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 55f3d88..a92d0c1 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -267,6 +267,11 @@
 	struct os_time last_attempt;
 };
 
+struct wpa_ssid_value {
+	u8 ssid[32];
+	size_t ssid_len;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -323,6 +328,11 @@
 	u8 *bssid_filter;
 	size_t bssid_filter_count;
 
+	u8 *disallow_aps_bssid;
+	size_t disallow_aps_bssid_count;
+	struct wpa_ssid_value *disallow_aps_ssid;
+	size_t disallow_aps_ssid_count;
+
 	/* previous scan was wildcard when interleaving between
 	 * wildcard scans and specific SSID scan when max_ssids=1 */
 	int prev_scan_wildcard;
@@ -387,12 +397,54 @@
 
 	struct wpa_blacklist *blacklist;
 
-	int scan_req; /* manual scan request; this forces a scan even if there
-		       * are no enabled networks in the configuration */
+	/**
+	 * extra_blacklist_count - Sum of blacklist counts after last connection
+	 *
+	 * This variable is used to maintain a count of temporary blacklisting
+	 * failures (maximum number for any BSS) over blacklist clear
+	 * operations. This is needed for figuring out whether there has been
+	 * failures prior to the last blacklist clear operation which happens
+	 * whenever no other not-blacklisted BSS candidates are available. This
+	 * gets cleared whenever a connection has been established successfully.
+	 */
+	int extra_blacklist_count;
+
+	/**
+	 * scan_req - Type of the scan request
+	 */
+	enum scan_req_type {
+		/**
+		 * NORMAL_SCAN_REQ - Normal scan request
+		 *
+		 * This is used for scans initiated by wpa_supplicant to find an
+		 * AP for a connection.
+		 */
+		NORMAL_SCAN_REQ,
+
+		/**
+		 * INITIAL_SCAN_REQ - Initial scan request
+		 *
+		 * This is used for the first scan on an interface to force at
+		 * least one scan to be run even if the configuration does not
+		 * include any enabled networks.
+		 */
+		INITIAL_SCAN_REQ,
+
+		/**
+		 * MANUAL_SCAN_REQ - Manual scan request
+		 *
+		 * This is used for scans where the user request a scan or
+		 * a specific wpa_supplicant operation (e.g., WPS) requires scan
+		 * to be run.
+		 */
+		MANUAL_SCAN_REQ
+	} scan_req;
 	int scan_runs; /* number of scan runs since WPS was started */
 	int *next_scan_freqs;
 	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
+				  * finding a connection */
 
 	unsigned int drv_flags;
 	unsigned int drv_enc;
@@ -457,6 +509,12 @@
 		u8 sched_obss_scan;
 		u16 obss_scan_int;
 		u16 bss_max_idle_period;
+		enum {
+			SME_SAE_INIT,
+			SME_SAE_COMMIT,
+			SME_SAE_CONFIRM
+		} sae_state;
+		u16 sae_send_confirm;
 	} sme;
 #endif /* CONFIG_SME */
 
@@ -549,6 +607,7 @@
 	unsigned int p2p_fallback_to_go_neg:1;
 	unsigned int p2p_pd_before_go_neg:1;
 	unsigned int p2p_go_ht40:1;
+	unsigned int user_initiated_pd:1;
 	int p2p_persistent_go_freq;
 	int p2p_persistent_id;
 	int p2p_go_intent;
@@ -573,6 +632,7 @@
 	int after_wps;
 	int known_wps_freq;
 	unsigned int wps_freq;
+	u16 wps_ap_channel;
 	int wps_fragment_size;
 	int auto_reconnect_disabled;
 
@@ -643,8 +703,6 @@
 void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 				   int reason_code);
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-				 int reason_code);
 
 void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid);
@@ -693,7 +751,10 @@
 void wpas_auth_failed(struct wpa_supplicant *wpa_s);
 void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
 			      struct wpa_ssid *ssid, int clear_failures);
-void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+		    size_t ssid_len);
+void wpas_request_connection(struct wpa_supplicant *wpa_s);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6aa5205..1ba4c92 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -406,14 +406,6 @@
 }
 
 
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
-	wpa_supplicant_disassociate(wpa_s, reason_code);
-	/* Schedule a scan to make sure we continue looking for networks */
-	wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
 static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
 {
 	wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -839,7 +831,6 @@
 	ctx->set_state = _wpa_supplicant_set_state;
 	ctx->get_state = _wpa_supplicant_get_state;
 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-	ctx->disassociate = _wpa_supplicant_disassociate;
 	ctx->set_key = wpa_supplicant_set_key;
 	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
 	ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -889,7 +880,8 @@
 		conf.peerkey_enabled = ssid->peerkey;
 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
 #ifdef IEEE8021X_EAPOL
-		conf.proactive_key_caching = ssid->proactive_key_caching;
+		conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
+			wpa_s->conf->okc : ssid->proactive_key_caching;
 		conf.eap_workaround = ssid->eap_workaround;
 		conf.eap_conf_ctx = &ssid->eap;
 #endif /* IEEE8021X_EAPOL */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 915ca57..0239c55 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -256,6 +256,15 @@
 		return 0;
 	}
 
+	if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+		if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+			wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+				   "invalid Network Key length %lu",
+				   (unsigned long) cred->key_len);
+			return -1;
+		}
+	}
+
 	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
 		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
 			   "on the received credential");
@@ -403,6 +412,9 @@
 
 	wpas_wps_security_workaround(wpa_s, ssid, cred);
 
+	if (cred->ap_channel)
+		wpa_s->wps_ap_channel = cred->ap_channel;
+
 #ifndef CONFIG_NO_CONFIG_WRITE
 	if (wpa_s->conf->update_config &&
 	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -487,11 +499,46 @@
 }
 
 
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->disabled_for_connect && ssid->disabled) {
+			ssid->disabled_for_connect = 0;
+			ssid->disabled = 0;
+			wpas_notify_network_enabled_changed(wpa_s, ssid);
+		}
+	}
+}
+
+
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	/* Enable the networks disabled during wpas_wps_reassoc */
+	wpas_wps_reenable_networks(wpa_s);
+}
+
+
 static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
 {
 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
 	wpa_s->wps_success = 1;
 	wpas_notify_wps_event_success(wpa_s);
+
+	/*
+	 * Enable the networks disabled during wpas_wps_reassoc after 10
+	 * seconds. The 10 seconds timer is to allow the data connection to be
+	 * formed before allowing other networks to be selected.
+	 */
+	eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+			       NULL);
+
 #ifdef CONFIG_P2P
 	wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
 #endif /* CONFIG_P2P */
@@ -690,6 +737,9 @@
 
 	prev_current = wpa_s->current_ssid;
 
+	/* Enable the networks disabled during wpas_wps_reassoc */
+	wpas_wps_reenable_networks(wpa_s);
+
 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
 
 	/* Remove any existing WPS network from configuration */
@@ -819,6 +869,7 @@
 	ssid = wpa_s->conf->ssid;
 	while (ssid) {
 		int was_disabled = ssid->disabled;
+		ssid->disabled_for_connect = 0;
 		/*
 		 * In case the network object corresponds to a persistent group
 		 * then do not send out network disabled signal. In addition,
@@ -827,9 +878,12 @@
 		 */
 		if (was_disabled != 2) {
 			ssid->disabled = ssid != selected;
-			if (was_disabled != ssid->disabled)
+			if (was_disabled != ssid->disabled) {
+				if (ssid->disabled)
+					ssid->disabled_for_connect = 1;
 				wpas_notify_network_enabled_changed(wpa_s,
 								    ssid);
+			}
 		}
 		ssid = ssid->next;
 	}
@@ -940,62 +994,13 @@
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 		wpas_clear_wps(wpa_s);
-	} else
+	} else {
+		wpas_wps_reenable_networks(wpa_s);
 		wpas_wps_clear_ap_info(wpa_s);
-
-	return 0;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
-		       char *path, char *method, char *name)
-{
-	struct wps_context *wps = wpa_s->wps;
-	struct oob_device_data *oob_dev;
-
-	oob_dev = wps_get_oob_device(device_type);
-	if (oob_dev == NULL)
-		return -1;
-	oob_dev->device_path = path;
-	oob_dev->device_name = name;
-	wps->oob_conf.oob_method = wps_get_oob_method(method);
-
-	if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E) {
-		/*
-		 * Use pre-configured DH keys in order to be able to write the
-		 * key hash into the OOB file.
-		 */
-		wpabuf_free(wps->dh_pubkey);
-		wpabuf_free(wps->dh_privkey);
-		wps->dh_privkey = NULL;
-		wps->dh_pubkey = NULL;
-		dh5_free(wps->dh_ctx);
-		wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
-		wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
-		if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
-			wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
-				   "Diffie-Hellman handshake");
-			return -1;
-		}
 	}
 
-	if (wps->oob_conf.oob_method == OOB_METHOD_CRED)
-		wpas_clear_wps(wpa_s);
-
-	if (wps_process_oob(wps, oob_dev, 0) < 0)
-		return -1;
-
-	if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
-	     wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-	    wpas_wps_start_pin(wpa_s, NULL,
-			       wpabuf_head(wps->oob_conf.dev_password), 0,
-			       DEV_PW_DEFAULT) < 0)
-			return -1;
-
 	return 0;
 }
-#endif /* CONFIG_WPS_OOB */
 
 
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
@@ -1247,6 +1252,7 @@
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 {
 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
 	wpas_wps_clear_ap_info(wpa_s);
 
 	if (wpa_s->wps == NULL)
@@ -1260,8 +1266,6 @@
 	wps_registrar_deinit(wpa_s->wps->registrar);
 	wpabuf_free(wpa_s->wps->dh_pubkey);
 	wpabuf_free(wpa_s->wps->dh_privkey);
-	wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
-	wpabuf_free(wpa_s->wps->oob_conf.dev_password);
 	wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
 	os_free(wpa_s->wps->network_key);
 	os_free(wpa_s->wps);
@@ -1851,6 +1855,8 @@
 static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
 			     struct wps_parse_attr *attr)
 {
+	wpa_s->wps_ap_channel = 0;
+
 	if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
 		return -1;
 
@@ -1861,6 +1867,24 @@
 		   "based on the received credential added");
 	wpa_s->normal_scans = 0;
 	wpa_supplicant_reinit_autoscan(wpa_s);
+	if (wpa_s->wps_ap_channel) {
+		u16 chan = wpa_s->wps_ap_channel;
+		int freq = 0;
+
+		if (chan >= 1 && chan <= 13)
+			freq = 2407 + 5 * chan;
+		else if (chan == 14)
+			freq = 2484;
+		else if (chan >= 30)
+			freq = 5000 + 5 * chan;
+
+		if (freq) {
+			wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
+				   "AP channel %u -> %u MHz", chan, freq);
+			wpa_s->after_wps = 5;
+			wpa_s->wps_freq = freq;
+		}
+	}
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1930,6 +1954,45 @@
 	return ret;
 }
 
+
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+{
+	return ndef_build_wifi_hr();
+}
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+{
+	return NULL;
+}
+
+
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data)
+{
+	struct wpabuf *wps;
+	int ret;
+
+	wps = ndef_parse_wifi(data);
+	if (wps == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+		   "payload from NFC connection handover");
+	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
+	ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+	wpabuf_free(wps);
+
+	return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index d5eb3b6..dd0dc60 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -9,7 +9,6 @@
 #ifndef WPS_SUPPLICANT_H
 #define WPS_SUPPLICANT_H
 
-struct wpa_scan_res;
 struct wpa_scan_results;
 
 #ifdef CONFIG_WPS
@@ -35,8 +34,6 @@
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		       const char *pin, int p2p_group, u16 dev_pw_id);
 int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
-		       char *path, char *method, char *name);
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		       const char *pin, struct wps_new_ap_settings *settings);
 int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
@@ -69,6 +66,12 @@
 int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
 			  const struct wpabuf *data);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data);
 void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
 			     struct wpa_scan_results *scan_res);
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -96,14 +99,14 @@
 
 static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
 					  struct wpa_ssid *ssid,
-					  struct wpa_scan_res *bss)
+					  struct wpa_bss *bss)
 {
 	return -1;
 }
 
 static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
 					    struct wpa_ssid *ssid,
-					    struct wpa_scan_res *bss)
+					    struct wpa_bss *bss)
 {
 	return 0;
 }