Cumulative patch from commit efc64886b8a285440e9954b5395a5370d8c5f84f

efc6488 nl80211: Pass station supported channel and oper class info
3ed9727 TDLS: Pass peer's Supported channel and oper class info during sta_add
eed65aa hostapd: DFS setup seg0 correctly for HT40-
25592b2 hostapd: DFS/CSA check if CSA in progress
b19ef32 Android: Remove hostapd dump_file functionality
c48414a P2P: Limit join-a-group scans based on SSID from invitation
78f0c93 Flush secondary device types on FLUSH command
2b38410 P2P: Allow requested device type to be specified with p2p_find
d9bb282 Clear configuration blobs on FLUSH command
c60ba9f Skip network disabling on expected EAP failure
7185e16 EAP-FAST peer: Make debug clearer on missing pac_file configuration
7b88b64 EXT PW: Fix hash return in password fetching
08081ad hostapd: Skip full AP configuration validation on SET command
1785d2e P2P: Wait on GO Negotiation Confirm transmit
472fa21 P2P: Cancel action frame offchan wait after recv GO Neg Conf
bfdc2a3 bsd: Fix NULL pointer dereference on error path
38bbd06 bsd: Prepare event buffer on init process
3043b4f nl80211: Document how to configure for libnl 2.0 and 3.2

Change-Id: Ia592bc948eaa43dbfaf0b4a20231efca61acb11f
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 4198834..54e4af9 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2989,7 +2989,7 @@
 	for (i = 0; i < conf->num_bss; i++)
 		hostapd_set_security_params(conf->bss[i]);
 
-	if (hostapd_config_check(conf))
+	if (hostapd_config_check(conf, 1))
 		errors++;
 
 #ifndef WPA_IGNORE_CONFIG_ERRORS
@@ -3021,7 +3021,7 @@
 	for (i = 0; i < conf->num_bss; i++)
 		hostapd_set_security_params(conf->bss[i]);
 
-	if (hostapd_config_check(conf)) {
+	if (hostapd_config_check(conf, 0)) {
 		wpa_printf(MSG_ERROR, "Configuration check failed");
 		return -1;
 	}
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 60f2c04..e329a11 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -22,6 +22,19 @@
 # Driver interface for drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index a29f4d0..79ab4ba 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -670,9 +670,10 @@
 
 
 static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
-				    struct hostapd_config *conf)
+				    struct hostapd_config *conf,
+				    int full_config)
 {
-	if (bss->ieee802_1x && !bss->eap_server &&
+	if (full_config && bss->ieee802_1x && !bss->eap_server &&
 	    !bss->radius->auth_servers) {
 		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
 			   "EAP authenticator configured).");
@@ -697,14 +698,15 @@
 		}
 	}
 
-	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	if (full_config && bss->wpa &&
+	    bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
 	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
 		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
 			   "RADIUS checking (macaddr_acl=2) enabled.");
 		return -1;
 	}
 
-	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
 	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
 	    bss->ssid.wpa_psk_file == NULL &&
 	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
@@ -714,7 +716,7 @@
 		return -1;
 	}
 
-	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+	if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
 		size_t i;
 
 		for (i = 0; i < conf->num_bss; i++) {
@@ -731,7 +733,7 @@
 	}
 
 #ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
 	    (bss->nas_identifier == NULL ||
 	     os_strlen(bss->nas_identifier) < 1 ||
 	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
@@ -743,20 +745,21 @@
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211N
-	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+	if (full_config && conf->ieee80211n &&
+	    conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
 		bss->disable_11n = 1;
 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
 			   "allowed, disabling HT capabilites");
 	}
 
-	if (conf->ieee80211n &&
+	if (full_config && conf->ieee80211n &&
 	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
 		bss->disable_11n = 1;
 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
 			   "allowed, disabling HT capabilities");
 	}
 
-	if (conf->ieee80211n && bss->wpa &&
+	if (full_config && conf->ieee80211n && bss->wpa &&
 	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
 	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
 				   WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
@@ -769,19 +772,20 @@
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_WPS2
-	if (bss->wps_state && bss->ignore_broadcast_ssid) {
+	if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
 		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
 			   "configuration forced WPS to be disabled");
 		bss->wps_state = 0;
 	}
 
-	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+	if (full_config && bss->wps_state &&
+	    bss->ssid.wep.keys_set && bss->wpa == 0) {
 		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
 			   "disabled");
 		bss->wps_state = 0;
 	}
 
-	if (bss->wps_state && bss->wpa &&
+	if (full_config && bss->wps_state && bss->wpa &&
 	    (!(bss->wpa & 2) ||
 	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
 		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
@@ -791,7 +795,7 @@
 #endif /* CONFIG_WPS2 */
 
 #ifdef CONFIG_HS20
-	if (bss->hs20 &&
+	if (full_config && bss->hs20 &&
 	    (!(bss->wpa & 2) ||
 	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
 				    WPA_CIPHER_CCMP_256 |
@@ -807,24 +811,25 @@
 }
 
 
-int hostapd_config_check(struct hostapd_config *conf)
+int hostapd_config_check(struct hostapd_config *conf, int full_config)
 {
 	size_t i;
 
-	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+	if (full_config && conf->ieee80211d &&
+	    (!conf->country[0] || !conf->country[1])) {
 		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
 			   "setting the country_code");
 		return -1;
 	}
 
-	if (conf->ieee80211h && !conf->ieee80211d) {
+	if (full_config && conf->ieee80211h && !conf->ieee80211d) {
 		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
 			   "IEEE 802.11d enabled");
 		return -1;
 	}
 
 	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_config_check_bss(conf->bss[i], conf))
+		if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
 			return -1;
 	}
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index af30ac4..0bb937e 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -570,7 +570,7 @@
 					int vlan_id);
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
-int hostapd_config_check(struct hostapd_config *conf);
+int hostapd_config_check(struct hostapd_config *conf, int full_config);
 void hostapd_set_security_params(struct hostapd_bss_config *bss);
 
 #endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index caf4092..e4c00f8 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -176,6 +176,7 @@
 
 static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
 				       struct hostapd_channel_data *chan,
+				       int secondary_channel,
 				       u8 *vht_oper_centr_freq_seg0_idx,
 				       u8 *vht_oper_centr_freq_seg1_idx)
 {
@@ -189,9 +190,9 @@
 
 	switch (iface->conf->vht_oper_chwidth) {
 	case VHT_CHANWIDTH_USE_HT:
-		if (iface->conf->secondary_channel == 1)
+		if (secondary_channel == 1)
 			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
-		else if (iface->conf->secondary_channel == -1)
+		else if (secondary_channel == -1)
 			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
 		else
 			*vht_oper_centr_freq_seg0_idx = chan->chan;
@@ -366,6 +367,7 @@
 		*secondary_channel = 0;
 
 	dfs_adjust_vht_center_freq(iface, chan,
+				   *secondary_channel,
 				   vht_oper_centr_freq_seg0_idx,
 				   vht_oper_centr_freq_seg1_idx);
 
@@ -680,14 +682,18 @@
 	struct hostapd_data *hapd = iface->bss[0];
 	int err = 1;
 
-	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s)", __func__,
-		   iface->cac_started ? "yes" : "no");
+	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
+		   __func__, iface->cac_started ? "yes" : "no",
+		   iface->csa_in_progress ? "yes" : "no");
+
+	/* Check if CSA in progress */
+	if (iface->csa_in_progress)
+		return 0;
 
 	/* Check if active CAC */
 	if (iface->cac_started)
 		return hostapd_dfs_start_channel_switch_cac(iface);
 
-
 	/* Perform channel switch/CSA */
 	channel = dfs_get_valid_channel(iface, &secondary_channel,
 					&vht_oper_centr_freq_seg0_idx,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 44d05c5..220211c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1537,6 +1537,11 @@
 	wpa_printf(MSG_DEBUG, "Enable interface %s",
 		   hapd_iface->conf->bss[0]->iface);
 
+	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
+		wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
+		return -1;
+	}
+
 	if (hapd_iface->interfaces == NULL ||
 	    hapd_iface->interfaces->driver_init == NULL ||
 	    hapd_iface->interfaces->driver_init(hapd_iface))
@@ -1569,7 +1574,7 @@
 		   hapd_iface->conf->bss[0]->iface);
 	for (j = 0; j < hapd_iface->num_bss; j++)
 		hostapd_set_security_params(hapd_iface->conf->bss[j]);
-	if (hostapd_config_check(hapd_iface->conf) < 0) {
+	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
 		wpa_printf(MSG_ERROR, "Updated configuration is invalid");
 		return -1;
 	}
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 7d78648..12dc83e 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -227,6 +227,7 @@
 #define WLAN_EID_FAST_BSS_TRANSITION 55
 #define WLAN_EID_TIMEOUT_INTERVAL 56
 #define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
 #define WLAN_EID_WAPI 68
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index db34ed1..4fd16ed 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1012,6 +1012,10 @@
 	u8 qosinfo;
 	const u8 *ext_capab;
 	size_t ext_capab_len;
+	const u8 *supp_channels;
+	size_t supp_channels_len;
+	const u8 *supp_oper_classes;
+	size_t supp_oper_classes_len;
 };
 
 struct hostapd_freq_params {
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 7f5e231..71c9ce9 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -62,6 +62,8 @@
 	int	prev_privacy;	/* privacy state to restore on deinit */
 	int	prev_wpa;	/* wpa state to restore on deinit */
 	enum ieee80211_opmode opmode;	/* operation mode */
+	char	*event_buf;
+	size_t	event_buf_len;
 };
 
 /* Generic functions for hostapd and wpa_supplicant */
@@ -642,7 +644,7 @@
 	return 0;
 }
 
-static int
+static size_t
 rtbuf_len(void)
 {
 	size_t len;
@@ -779,37 +781,26 @@
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
 	struct bsd_driver_data *drv = ctx;
-	char *buf;
 	struct if_announcemsghdr *ifan;
 	struct rt_msghdr *rtm;
 	struct ieee80211_michael_event *mic;
 	struct ieee80211_join_event *join;
 	struct ieee80211_leave_event *leave;
-	int n, len;
+	int n;
 	union wpa_event_data data;
 
-	len = rtbuf_len();
-
-	buf = os_malloc(len);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
-		return;
-	}
-
-	n = read(sock, buf, len);
+	n = read(sock, drv->event_buf, drv->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
 				   __func__, strerror(errno));
-		os_free(buf);
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) buf;
+	rtm = (struct rt_msghdr *) drv->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
-		os_free(buf);
 		return;
 	}
 	ifan = (struct if_announcemsghdr *) rtm;
@@ -850,7 +841,6 @@
 		}
 		break;
 	}
-	os_free(buf);
 }
 
 static void
@@ -867,7 +857,15 @@
 
 	drv = os_zalloc(sizeof(struct bsd_driver_data));
 	if (drv == NULL) {
-		printf("Could not allocate memory for bsd driver data\n");
+		wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data");
+		return NULL;
+	}
+
+	drv->event_buf_len = rtbuf_len();
+
+	drv->event_buf = os_malloc(drv->event_buf_len);
+	if (drv->event_buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
 		goto bad;
 	}
 
@@ -910,6 +908,7 @@
 		l2_packet_deinit(drv->sock_xmit);
 	if (drv->sock >= 0)
 		close(drv->sock);
+	os_free(drv->event_buf);
 	if (drv != NULL)
 		os_free(drv);
 	return NULL;
@@ -930,6 +929,7 @@
 		close(drv->sock);
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
+	os_free(drv->event_buf);
 	os_free(drv);
 }
 
@@ -1208,7 +1208,6 @@
 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 {
 	struct bsd_driver_data *drv = sock_ctx;
-	char *buf;
 	struct if_announcemsghdr *ifan;
 	struct if_msghdr *ifm;
 	struct rt_msghdr *rtm;
@@ -1216,30 +1215,20 @@
 	struct ieee80211_michael_event *mic;
 	struct ieee80211_leave_event *leave;
 	struct ieee80211_join_event *join;
-	int n, len;
+	int n;
 
-	len = rtbuf_len();
-
-	buf = os_malloc(len);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
-		return;
-	}
-
-	n = read(sock, buf, len);
+	n = read(sock, drv->event_buf, drv->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
 				   __func__, strerror(errno));
-		os_free(buf);
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) buf;
+	rtm = (struct rt_msghdr *) drv->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
-		os_free(buf);
 		return;
 	}
 	os_memset(&event, 0, sizeof(event));
@@ -1254,7 +1243,6 @@
 		case IFAN_DEPARTURE:
 			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
 		default:
-			os_free(buf);
 			return;
 		}
 		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
@@ -1327,7 +1315,6 @@
 		}
 		break;
 	}
-	os_free(buf);
 }
 
 static void
@@ -1508,6 +1495,15 @@
 	drv = os_zalloc(sizeof(*drv));
 	if (drv == NULL)
 		return NULL;
+
+	drv->event_buf_len = rtbuf_len();
+
+	drv->event_buf = os_malloc(drv->event_buf_len);
+	if (drv->event_buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+		goto fail1;
+	}
+
 	/*
 	 * NB: We require the interface name be mappable to an index.
 	 *     This implies we do not support having wpa_supplicant
@@ -1562,6 +1558,7 @@
 fail:
 	close(drv->sock);
 fail1:
+	os_free(drv->event_buf);
 	os_free(drv);
 	return NULL;
 #undef GETPARAM
@@ -1587,6 +1584,7 @@
 		l2_packet_deinit(drv->sock_xmit);
 	(void) close(drv->route);		/* ioctl socket */
 	(void) close(drv->sock);		/* event socket */
+	os_free(drv->event_buf);
 	os_free(drv);
 }
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index fce6efd..0b8eed5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -7208,6 +7208,22 @@
 			params->ext_capab_len, params->ext_capab);
 	}
 
+	if (params->supp_channels) {
+		wpa_hexdump(MSG_DEBUG, "  * supported channels",
+			    params->supp_channels, params->supp_channels_len);
+		NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+			params->supp_channels_len, params->supp_channels);
+	}
+
+	if (params->supp_oper_classes) {
+		wpa_hexdump(MSG_DEBUG, "  * supported operating classes",
+			    params->supp_oper_classes,
+			    params->supp_oper_classes_len);
+		NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+			params->supp_oper_classes_len,
+			params->supp_oper_classes);
+	}
+
 	os_memset(&upd, 0, sizeof(upd));
 	upd.mask = sta_flags_nl80211(params->flags);
 	upd.set = upd.mask;
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 98abd4e..47cbbee 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -179,6 +179,7 @@
 	eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
 	sm->num_rounds = 0;
 	sm->prev_failure = 0;
+	sm->expected_failure = 0;
 }
 
 
@@ -2046,6 +2047,8 @@
 	if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
 		if (eap_get_ext_password(sm, config) < 0)
 			return NULL;
+		if (hash)
+			*hash = 0;
 		*len = wpabuf_len(sm->ext_pw_buf);
 		return wpabuf_head(sm->ext_pw_buf);
 	}
@@ -2415,3 +2418,9 @@
 	if (sm->eapol_cb->set_anon_id)
 		sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
 }
+
+
+int eap_peer_was_failure_expected(struct eap_sm *sm)
+{
+	return sm->expected_failure;
+}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 711f41f..712e929 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -320,6 +320,7 @@
 struct ext_password_data;
 void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
 void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
+int eap_peer_was_failure_expected(struct eap_sm *sm);
 
 #endif /* IEEE8021X_EAPOL */
 
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 3b8d803..1b0c562 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -196,14 +196,22 @@
 			   "workarounds");
 	}
 
+	if (!config->pac_file) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No PAC file configured");
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
 	if (data->use_pac_binary_format &&
 	    eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
 		eap_fast_deinit(sm, data);
 		return NULL;
 	}
 
 	if (!data->use_pac_binary_format &&
 	    eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
 		eap_fast_deinit(sm, data);
 		return NULL;
 	}
@@ -1047,6 +1055,7 @@
 		}
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
 			   "- Provisioning completed successfully");
+		sm->expected_failure = 1;
 	} else {
 		/*
 		 * This is PAC refreshing, i.e., normal authentication that is
@@ -1244,6 +1253,7 @@
 				   "provisioning completed successfully.");
 			ret->methodState = METHOD_DONE;
 			ret->decision = DECISION_FAIL;
+			sm->expected_failure = 1;
 		} else {
 			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
 				   "completed successfully.");
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 9307f3f..8288ba5 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -350,6 +350,8 @@
 	struct wpabuf *ext_pw_buf;
 
 	int external_sim;
+
+	unsigned int expected_failure:1;
 };
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 05b9851..cbcde7e 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -940,9 +940,15 @@
 	}
 
 	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
-		int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
+		enum eapol_supp_result result;
+		if (sm->cb_status == EAPOL_CB_SUCCESS)
+			result = EAPOL_SUPP_RESULT_SUCCESS;
+		else if (eap_peer_was_failure_expected(sm->eap))
+			result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+		else
+			result = EAPOL_SUPP_RESULT_FAILURE;
 		sm->cb_status = EAPOL_CB_IN_PROGRESS;
-		sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
+		sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
 	}
 }
 
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 54e8a27..934eda0 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -63,6 +63,12 @@
 struct eapol_sm;
 struct wpa_config_blob;
 
+enum eapol_supp_result {
+	EAPOL_SUPP_RESULT_FAILURE,
+	EAPOL_SUPP_RESULT_SUCCESS,
+	EAPOL_SUPP_RESULT_EXPECTED_FAILURE
+};
+
 /**
  * struct eapol_ctx - Global (for all networks) EAPOL state machine context
  */
@@ -83,7 +89,7 @@
 	/**
 	 * cb - Function to be called when EAPOL negotiation has been completed
 	 * @eapol: Pointer to EAPOL state machine data
-	 * @success: Whether the authentication was completed successfully
+	 * @result: Whether the authentication was completed successfully
 	 * @ctx: Pointer to context data (cb_ctx)
 	 *
 	 * This optional callback function will be called when the EAPOL
@@ -91,7 +97,8 @@
 	 * EAPOL state machine to process the key and terminate the EAPOL state
 	 * machine. Currently, this is used only in RSN pre-authentication.
 	 */
-	void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
+	void (*cb)(struct eapol_sm *eapol, enum eapol_supp_result result,
+		   void *ctx);
 
 	/**
 	 * cb_ctx - Callback context for cb()
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 0e688a9..874f434 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -1037,7 +1037,7 @@
 	else
 		freq = dev->listen_freq;
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
-			    wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
+			    wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
 		p2p_dbg(p2p, "Failed to send Action frame");
 		p2p_go_neg_failed(p2p, dev, -1);
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -1079,6 +1079,7 @@
 		return;
 	}
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
 	if (msg.dialog_token != dev->dialog_token) {
 		p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index c51620e..915f85e 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -70,13 +70,14 @@
 }
 
 
-static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
+				 enum eapol_supp_result result,
 				 void *ctx)
 {
 	struct wpa_sm *sm = ctx;
 	u8 pmk[PMK_LEN];
 
-	if (success) {
+	if (result == EAPOL_SUPP_RESULT_SUCCESS) {
 		int res, pmk_len;
 		pmk_len = PMK_LEN;
 		res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
@@ -100,13 +101,14 @@
 			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 				"RSN: failed to get master session key from "
 				"pre-auth EAPOL state machines");
-			success = 0;
+			result = EAPOL_SUPP_RESULT_FAILURE;
 		}
 	}
 
 	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
 		MACSTR " %s", MAC2STR(sm->preauth_bssid),
-		success ? "completed successfully" : "failed");
+		result == EAPOL_SUPP_RESULT_SUCCESS ? "completed successfully" :
+		"failed");
 
 	rsn_preauth_deinit(sm);
 	rsn_preauth_candidate_process(sm);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index efc6431..8a978f7 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -136,6 +136,12 @@
 
 	u8 *ext_capab;
 	size_t ext_capab_len;
+
+	u8 *supp_channels;
+	size_t supp_channels_len;
+
+	u8 *supp_oper_classes;
+	size_t supp_oper_classes_len;
 };
 
 
@@ -633,6 +639,10 @@
 	peer->vht_capabilities = NULL;
 	os_free(peer->ext_capab);
 	peer->ext_capab = NULL;
+	os_free(peer->supp_channels);
+	peer->supp_channels = NULL;
+	os_free(peer->supp_oper_classes);
+	peer->supp_oper_classes = NULL;
 	peer->rsnie_i_len = peer->rsnie_p_len = 0;
 	peer->cipher = 0;
 	peer->tpk_set = peer->tpk_success = 0;
@@ -1456,6 +1466,58 @@
 }
 
 
+static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde,
+				   struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_channels) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported channels received");
+		return 0;
+	}
+
+	if (!peer->supp_channels ||
+	    peer->supp_channels_len < kde->supp_channels_len) {
+		os_free(peer->supp_channels);
+		peer->supp_channels = os_zalloc(kde->supp_channels_len);
+		if (peer->supp_channels == NULL)
+			return -1;
+	}
+
+	peer->supp_channels_len = kde->supp_channels_len;
+
+	os_memcpy(peer->supp_channels, kde->supp_channels,
+		  peer->supp_channels_len);
+	wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels",
+		    (u8 *) peer->supp_channels, peer->supp_channels_len);
+	return 0;
+}
+
+
+static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde,
+				       struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_oper_classes) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received");
+		return 0;
+	}
+
+	if (!peer->supp_oper_classes ||
+	    peer->supp_oper_classes_len < kde->supp_oper_classes_len) {
+		os_free(peer->supp_oper_classes);
+		peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len);
+		if (peer->supp_oper_classes == NULL)
+			return -1;
+	}
+
+	peer->supp_oper_classes_len = kde->supp_oper_classes_len;
+	os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes,
+		  peer->supp_oper_classes_len);
+	wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes",
+		    (u8 *) peer->supp_oper_classes,
+		    peer->supp_oper_classes_len);
+	return 0;
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1568,6 +1630,12 @@
 	if (copy_peer_ext_capab(&kde, peer) < 0)
 		goto error;
 
+	if (copy_peer_supp_channels(&kde, peer) < 0)
+		goto error;
+
+	if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+		goto error;
+
 	peer->qos_info = kde.qosinfo;
 
 	peer->aid = kde.aid;
@@ -1761,7 +1829,7 @@
 skip_rsn_check:
 	/* add the peer to the driver as a "setup in progress" peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
-				NULL, 0);
+				NULL, 0, NULL, 0, NULL, 0);
 	peer->tpk_in_progress = 1;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
@@ -1810,7 +1878,11 @@
 				    peer->ht_capabilities,
 				    peer->vht_capabilities,
 				    peer->qos_info, peer->ext_capab,
-				    peer->ext_capab_len) < 0)
+				    peer->ext_capab_len,
+				    peer->supp_channels,
+				    peer->supp_channels_len,
+				    peer->supp_oper_classes,
+				    peer->supp_oper_classes_len) < 0)
 		return -1;
 
 	if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
@@ -1938,6 +2010,12 @@
 	if (copy_peer_ext_capab(&kde, peer) < 0)
 		goto error;
 
+	if (copy_peer_supp_channels(&kde, peer) < 0)
+		goto error;
+
+	if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+		goto error;
+
 	peer->qos_info = kde.qosinfo;
 
 	peer->aid = kde.aid;
@@ -2289,7 +2367,7 @@
 
 	/* add the peer to the driver as a "setup in progress" peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
-				NULL, 0);
+				NULL, 0, NULL, 0, NULL, 0);
 
 	peer->tpk_in_progress = 1;
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e189a58..9884ce1 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -62,7 +62,10 @@
 				const struct ieee80211_ht_capabilities *ht_capab,
 				const struct ieee80211_vht_capabilities *vht_capab,
 				u8 qosinfo, const u8 *ext_capab,
-				size_t ext_capab_len);
+				size_t ext_capab_len, const u8 *supp_channels,
+				size_t supp_channels_len,
+				const u8 *supp_oper_classes,
+				size_t supp_oper_classes_len);
 #endif /* CONFIG_TDLS */
 	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
 				  const u8 *replay_ctr);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 0e0d373..cad6c8d 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -286,14 +286,21 @@
 			size_t supp_rates_len,
 			const struct ieee80211_ht_capabilities *ht_capab,
 			const struct ieee80211_vht_capabilities *vht_capab,
-			u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
+			u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
+			const u8 *supp_channels, size_t supp_channels_len,
+			const u8 *supp_oper_classes,
+			size_t supp_oper_classes_len)
 {
 	if (sm->ctx->tdls_peer_addset)
 		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
 						 aid, capability, supp_rates,
 						 supp_rates_len, ht_capab,
 						 vht_capab, qosinfo,
-						 ext_capab, ext_capab_len);
+						 ext_capab, ext_capab_len,
+						 supp_channels,
+						 supp_channels_len,
+						 supp_oper_classes,
+						 supp_oper_classes_len);
 	return -1;
 }
 #endif /* CONFIG_TDLS */
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 50b9272..ab8d104 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -434,6 +434,12 @@
 			ie->vht_capabilities_len = pos[1];
 		} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
 			ie->qosinfo = pos[2];
+		} else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+			ie->supp_channels = pos + 2;
+			ie->supp_channels_len = pos[1];
+		} else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+			ie->supp_oper_classes = pos + 2;
+			ie->supp_oper_classes_len = pos[1];
 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
 			ret = wpa_parse_generic(pos, end, ie);
 			if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 2c78801..0375767 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -53,6 +53,10 @@
 	size_t ht_capabilities_len;
 	const u8 *vht_capabilities;
 	size_t vht_capabilities_len;
+	const u8 *supp_channels;
+	size_t supp_channels_len;
+	const u8 *supp_oper_classes;
+	size_t supp_oper_classes_len;
 	u8 qosinfo;
 	u16 aid;
 };
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 08d39e2..7354bbf 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -72,7 +72,8 @@
 Device Discovery
 
 p2p_find [timeout in seconds] [type=<social|progressive>] \
-	[dev_id=<addr>] [delay=<search delay in ms>]
+	[dev_id=<addr>] [dev_type=<device type>] \
+	[delay=<search delay in ms>]
 
 The default behavior is to run a single full scan in the beginning and
 then scan only social channels. type=social will scan only social
@@ -87,6 +88,10 @@
 delay to be used between search iterations (e.g., to free up radio
 resources for concurrent operations).
 
+The optional dev_type option can be used to specify a single device type
+(primary or secondary) to search for, e.g.,
+"p2p_find dev_type=1-0050F204-1".
+
 p2p_listen [timeout in seconds]
 
 Start Listen-only state (become discoverable without searching for
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 5301ed7..884acf6 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1926,6 +1926,22 @@
 }
 
 
+void wpa_config_flush_blobs(struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct wpa_config_blob *blob, *prev;
+
+	blob = config->blobs;
+	config->blobs = NULL;
+	while (blob) {
+		prev = blob;
+		blob = blob->next;
+		wpa_config_free_blob(prev);
+	}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
 /**
  * wpa_config_free - Free configuration data
  * @config: Configuration data from wpa_config_read()
@@ -1935,9 +1951,6 @@
  */
 void wpa_config_free(struct wpa_config *config)
 {
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	struct wpa_config_blob *blob, *prevblob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
 	struct wpa_ssid *ssid, *prev = NULL;
 	struct wpa_cred *cred, *cprev;
 
@@ -1955,15 +1968,7 @@
 		wpa_config_free_cred(cprev);
 	}
 
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	blob = config->blobs;
-	prevblob = NULL;
-	while (blob) {
-		prevblob = blob;
-		blob = blob->next;
-		wpa_config_free_blob(prevblob);
-	}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
+	wpa_config_flush_blobs(config);
 
 	wpabuf_free(config->wps_vendor_ext_m1);
 	os_free(config->ctrl_interface);
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index e24772d..a98a5aa 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -979,6 +979,7 @@
 			 struct wpa_config_blob *blob);
 void wpa_config_free_blob(struct wpa_config_blob *blob);
 int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+void wpa_config_flush_blobs(struct wpa_config *config);
 
 struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
 struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index cb299db..de97368 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3652,6 +3652,7 @@
 	unsigned int timeout = atoi(cmd);
 	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
 	u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+	u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
 	char *pos;
 	unsigned int search_delay;
 
@@ -3668,6 +3669,14 @@
 		_dev_id = dev_id;
 	}
 
+	pos = os_strstr(cmd, "dev_type=");
+	if (pos) {
+		pos += 9;
+		if (wps_dev_type_str2bin(pos, dev_type) < 0)
+			return -1;
+		_dev_type = dev_type;
+	}
+
 	pos = os_strstr(cmd, "delay=");
 	if (pos) {
 		pos += 6;
@@ -3675,8 +3684,8 @@
 	} else
 		search_delay = wpas_p2p_search_delay(wpa_s);
 
-	return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
-			     search_delay);
+	return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
+			     _dev_id, search_delay);
 }
 
 
@@ -5252,6 +5261,7 @@
 	wpas_p2p_service_flush(wpa_s);
 	wpa_s->global->p2p_disabled = 0;
 	wpa_s->global->p2p_per_sta_psk = 0;
+	wpa_s->conf->num_sec_device_types = 0;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
@@ -5296,6 +5306,7 @@
 	wpa_s->extra_blacklist_count = 0;
 	wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
 	wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+	wpa_config_flush_blobs(wpa_s->conf);
 
 	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
 	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 0627661..6684782 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -31,6 +31,19 @@
 # Driver interface for Linux drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index cb71475..ac0ab0b 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -365,10 +365,11 @@
 }
 
 
-static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
+static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result,
+			void *ctx)
 {
 	struct eapol_test_data *e = ctx;
-	printf("eapol_sm_cb: success=%d\n", success);
+	printf("eapol_sm_cb: result=%d\n", result);
 	e->eapol_test_num_reauths--;
 	if (e->eapol_test_num_reauths < 0)
 		eloop_terminate();
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 49c4058..fa265bc 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2551,10 +2551,11 @@
 
 	wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
 
-	if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
-	    ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-	      (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
-	     eapol_sm_failed(wpa_s->eapol)))
+	if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+	      ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+		(wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+	       eapol_sm_failed(wpa_s->eapol))) &&
+	     !wpa_s->eap_expected_failure))
 		wpas_auth_failed(wpa_s);
 
 #ifdef CONFIG_P2P
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 41d5102..3ac6713 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -104,11 +104,12 @@
 wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
 			 int go);
 static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+				   const u8 *ssid, size_t ssid_len);
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
 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);
+			 int auto_join, const u8 *ssid, size_t ssid_len);
 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);
@@ -2868,7 +2869,8 @@
 
 	if (!persistent_group) {
 		wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
-			   " to join an active group", MAC2STR(sa));
+			   " to join an active group (SSID: %s)",
+			   MAC2STR(sa), wpa_ssid_txt(ssid, ssid_len));
 		if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
 		    (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
 		     == 0 ||
@@ -2991,8 +2993,8 @@
 
 	if (status == P2P_SC_SUCCESS) {
 		wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
-			   " was accepted; op_freq=%d MHz",
-			   MAC2STR(sa), op_freq);
+			   " was accepted; op_freq=%d MHz, SSID=%s",
+			   MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
 		if (s) {
 			int go = s->mode == WPAS_MODE_P2P_GO;
 			wpas_p2p_group_add_persistent(
@@ -3001,7 +3003,8 @@
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
-				      wpa_s->p2p_wps_method, 0);
+				      wpa_s->p2p_wps_method, 0,
+				      ssid, ssid_len);
 		}
 		return;
 	}
@@ -4037,7 +4040,7 @@
 static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 				   struct wpa_scan_results *scan_res)
 {
-	struct wpa_bss *bss;
+	struct wpa_bss *bss = NULL;
 	int freq;
 	u8 iface_addr[ETH_ALEN];
 
@@ -4069,7 +4072,7 @@
 					   MAC2STR(wpa_s->
 						   pending_join_dev_addr),
 					   freq);
-				wpas_p2p_join_scan_req(wpa_s, freq);
+				wpas_p2p_join_scan_req(wpa_s, freq, NULL, 0);
 				return;
 			}
 		}
@@ -4142,7 +4145,22 @@
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
 			   "from P2P peer table: %d MHz", freq);
 	}
-	bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
+	if (wpa_s->p2p_join_ssid_len) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+			   MACSTR " and SSID %s",
+			   MAC2STR(wpa_s->pending_join_iface_addr),
+			   wpa_ssid_txt(wpa_s->p2p_join_ssid,
+					wpa_s->p2p_join_ssid_len));
+		bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
+				  wpa_s->p2p_join_ssid,
+				  wpa_s->p2p_join_ssid_len);
+	}
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+			   MACSTR, MAC2STR(wpa_s->pending_join_iface_addr));
+		bss = wpa_bss_get_bssid_latest(wpa_s,
+					       wpa_s->pending_join_iface_addr);
+	}
 	if (bss) {
 		freq = bss->freq;
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
@@ -4219,7 +4237,8 @@
 }
 
 
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+				   const u8 *ssid, size_t ssid_len)
 {
 	int ret;
 	struct wpa_driver_scan_params params;
@@ -4241,8 +4260,16 @@
 
 	/* P2P Wildcard SSID */
 	params.num_ssids = 1;
-	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
-	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+	if (ssid && ssid_len) {
+		params.ssids[0].ssid = ssid;
+		params.ssids[0].ssid_len = ssid_len;
+		os_memcpy(wpa_s->p2p_join_ssid, ssid, ssid_len);
+		wpa_s->p2p_join_ssid_len = ssid_len;
+	} else {
+		params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+		params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+		wpa_s->p2p_join_ssid_len = 0;
+	}
 
 	wpa_s->wps->dev.p2p = 1;
 	wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
@@ -4299,18 +4326,22 @@
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
-	wpas_p2p_join_scan_req(wpa_s, 0);
+	wpas_p2p_join_scan_req(wpa_s, 0, NULL, 0);
 }
 
 
 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)
+			 int auto_join, const u8 *ssid, size_t ssid_len)
 {
 	wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
 		   MACSTR " dev " MACSTR ")%s",
 		   MAC2STR(iface_addr), MAC2STR(dev_addr),
 		   auto_join ? " (auto_join)" : "");
+	if (ssid && ssid_len) {
+		wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s",
+			   wpa_ssid_txt(ssid, ssid_len));
+	}
 
 	wpa_s->p2p_auto_pd = 0;
 	wpa_s->p2p_auto_join = !!auto_join;
@@ -4322,7 +4353,7 @@
 	wpas_p2p_stop_find(wpa_s);
 
 	wpa_s->p2p_join_scan_count = 0;
-	wpas_p2p_join_scan(wpa_s, NULL);
+	wpas_p2p_join_scan_req(wpa_s, 0, ssid, ssid_len);
 	return 0;
 }
 
@@ -4577,7 +4608,7 @@
 		}
 		wpa_s->user_initiated_pd = 1;
 		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
-				  auto_join) < 0)
+				  auto_join, NULL, 0) < 0)
 			return -1;
 		return ret;
 	}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 187e5d9..78e2749 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1410,6 +1410,7 @@
 
 	os_memset(&params, 0, sizeof(params));
 	wpa_s->reassociate = 0;
+	wpa_s->eap_expected_failure = 0;
 	if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
 		const u8 *ie, *md = NULL;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d1ea77b..3a28534 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -571,6 +571,7 @@
 	struct os_reltime pending_eapol_rx_time;
 	u8 pending_eapol_rx_src[ETH_ALEN];
 	unsigned int last_eapol_matches_bssid:1;
+	unsigned int eap_expected_failure:1;
 
 	struct ibss_rsn *ibss_rsn;
 
@@ -669,6 +670,8 @@
 	u8 pending_join_iface_addr[ETH_ALEN];
 	u8 pending_join_dev_addr[ETH_ALEN];
 	int pending_join_wps_method;
+	u8 p2p_join_ssid[32];
+	size_t p2p_join_ssid_len;
 	int p2p_join_scan_count;
 	int auto_pd_scan_retry;
 	int force_long_sd;
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index ab6cdca..ad0895b 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -216,20 +216,38 @@
 }
 
 
-static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+static const char * result_str(enum eapol_supp_result result)
+{
+	switch (result) {
+	case EAPOL_SUPP_RESULT_FAILURE:
+		return "FAILURE";
+	case EAPOL_SUPP_RESULT_SUCCESS:
+		return "SUCCESS";
+	case EAPOL_SUPP_RESULT_EXPECTED_FAILURE:
+		return "EXPECTED_FAILURE";
+	}
+	return "?";
+}
+
+
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
+				    enum eapol_supp_result result,
 				    void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	int res, pmk_len;
 	u8 pmk[PMK_LEN];
 
-	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
-		   success ? "" : "un");
+	wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s",
+		   result_str(result));
 
 	if (wpas_wps_eapol_cb(wpa_s) > 0)
 		return;
 
-	if (!success) {
+	wpa_s->eap_expected_failure = result ==
+		EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+
+	if (result != EAPOL_SUPP_RESULT_SUCCESS) {
 		/*
 		 * Make sure we do not get stuck here waiting for long EAPOL
 		 * timeout if the AP does not disconnect in case of
@@ -238,7 +256,8 @@
 		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
 	}
 
-	if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+	if (result != EAPOL_SUPP_RESULT_SUCCESS ||
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
 		return;
 
 	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -560,7 +579,9 @@
 	const u8 *supp_rates, size_t supp_rates_len,
 	const struct ieee80211_ht_capabilities *ht_capab,
 	const struct ieee80211_vht_capabilities *vht_capab,
-	u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
+	u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
+	const u8 *supp_channels, size_t supp_channels_len,
+	const u8 *supp_oper_classes, size_t supp_oper_classes_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct hostapd_sta_add_params params;
@@ -588,6 +609,10 @@
 	params.set = !add;
 	params.ext_capab = ext_capab;
 	params.ext_capab_len = ext_capab_len;
+	params.supp_channels = supp_channels;
+	params.supp_channels_len = supp_channels_len;
+	params.supp_oper_classes = supp_oper_classes;
+	params.supp_oper_classes_len = supp_oper_classes_len;
 
 	return wpa_drv_sta_add(wpa_s, &params);
 }