Accumulative patch from commit 17b8995cf5813d7c027cd7a6884700e791d72392

17b8995 Interworking: Try to use same BSS entry for storing GAS results
3db5439 Optimize Extended Capabilities element to be of minimal length
8cd6b7b hostapd/wpa_s: Use driver's extended capabilities
acb5464 Add ctrl_iface command FLUSH for clearing wpa_supplicant state
97236ce WPS: Skip rescanning after provisioning if AP was configured
4342326 Add ignore_old_scan_res configuration parameter
9599ccc WPS: Clear after_wps on new WPS connection
702621e WPS: Use latest updated BSS entry if multiple BSSID matches found
ab547b5 WPS: Add more helpful debug for invalid WPS_REG command parsing
a679c0f WPS: Allow hostapd process to control independent WPS interfaces
ccdff94 WPS AP: Add support for reconfiguration with in-memory config
8970bae nl80211: Use nla_nest_start/end instead of nla_put_nested
558d69e P2P: Omit P2P Group Info in case of no connected peers
65a32cd AP: Fix infinite loop in WPA state machine when out of random bytes
a5f61b2 Fix OLBC non-HT AP detection to check channel
69554d7 ap_list: Remove unused functions
08c99ca ap_list: Remove unused iteration list pointers
6b16917 ap_list: Remove unused fields
66f1f75 P2P: Fix provision discovery response handling in some cases
2f9b66d Extend ROAM command to handle multiple SSIDs per BSS

Change-Id: I46002b1d3bbf6e376c2ae09bcb2c824c54805bbd
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 6606f72..d9ef984 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -340,6 +340,7 @@
 
 	int wps_state;
 #ifdef CONFIG_WPS
+	int wps_independent;
 	int ap_setup_locked;
 	u8 uuid[16];
 	char *wps_pin_requests;
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 18090ca..9f02151 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -50,7 +50,7 @@
 }
 
 
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
+static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
 {
 	struct ap_info *s;
 
@@ -87,34 +87,6 @@
 }
 
 
-static void ap_ap_iter_list_add(struct hostapd_iface *iface,
-				struct ap_info *ap)
-{
-	if (iface->ap_iter_list) {
-		ap->iter_prev = iface->ap_iter_list->iter_prev;
-		iface->ap_iter_list->iter_prev = ap;
-	} else
-		ap->iter_prev = ap;
-	ap->iter_next = iface->ap_iter_list;
-	iface->ap_iter_list = ap;
-}
-
-
-static void ap_ap_iter_list_del(struct hostapd_iface *iface,
-				struct ap_info *ap)
-{
-	if (iface->ap_iter_list == ap)
-		iface->ap_iter_list = ap->iter_next;
-	else
-		ap->iter_prev->iter_next = ap->iter_next;
-
-	if (ap->iter_next)
-		ap->iter_next->iter_prev = ap->iter_prev;
-	else if (iface->ap_iter_list)
-		iface->ap_iter_list->iter_prev = ap->iter_prev;
-}
-
-
 static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
 {
 	ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
@@ -148,7 +120,6 @@
 {
 	ap_ap_hash_del(iface, ap);
 	ap_ap_list_del(iface, ap);
-	ap_ap_iter_list_del(iface, ap);
 
 	iface->num_ap--;
 	os_free(ap);
@@ -171,25 +142,6 @@
 }
 
 
-int ap_ap_for_each(struct hostapd_iface *iface,
-		   int (*func)(struct ap_info *s, void *data), void *data)
-{
-	struct ap_info *s;
-	int ret = 0;
-
-	s = iface->ap_list;
-
-	while (s) {
-		ret = func(s, data);
-		if (ret)
-			break;
-		s = s->next;
-	}
-
-	return ret;
-}
-
-
 static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
 {
 	struct ap_info *ap;
@@ -203,7 +155,6 @@
 	ap_ap_list_add(iface, ap);
 	iface->num_ap++;
 	ap_ap_hash_add(iface, ap);
-	ap_ap_iter_list_add(iface, ap);
 
 	if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
 		wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
@@ -223,7 +174,6 @@
 	struct ap_info *ap;
 	struct os_time now;
 	int new_ap = 0;
-	size_t len;
 	int set_beacon = 0;
 
 	if (iface->conf->ap_table_max_size < 1)
@@ -239,24 +189,10 @@
 		new_ap = 1;
 	}
 
-	ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
-	ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
-	if (elems->ssid) {
-		len = elems->ssid_len;
-		if (len >= sizeof(ap->ssid))
-			len = sizeof(ap->ssid) - 1;
-		os_memcpy(ap->ssid, elems->ssid, len);
-		ap->ssid[len] = '\0';
-		ap->ssid_len = len;
-	}
-
 	merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
 			  elems->supp_rates, elems->supp_rates_len,
 			  elems->ext_supp_rates, elems->ext_supp_rates_len);
 
-	ap->wpa = elems->wpa_ie != NULL;
-
 	if (elems->erp_info && elems->erp_info_len == 1)
 		ap->erp = elems->erp_info[0];
 	else
@@ -264,6 +200,8 @@
 
 	if (elems->ds_params && elems->ds_params_len == 1)
 		ap->channel = elems->ds_params[0];
+	else if (elems->ht_operation && elems->ht_operation_len >= 1)
+		ap->channel = elems->ht_operation[0];
 	else if (fi)
 		ap->channel = fi->channel;
 
@@ -272,11 +210,8 @@
 	else
 		ap->ht_support = 0;
 
-	ap->num_beacons++;
 	os_get_time(&now);
 	ap->last_beacon = now.sec;
-	if (fi)
-		ap->datarate = fi->datarate;
 
 	if (!new_ap && ap != iface->ap_list) {
 		/* move AP entry into the beginning of the list so that the
@@ -288,17 +223,23 @@
 	if (!iface->olbc &&
 	    ap_list_beacon_olbc(iface, ap)) {
 		iface->olbc = 1;
-		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
-			   "protection", MAC2STR(ap->addr));
+		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
+			   " (channel %d) - enable protection",
+			   MAC2STR(ap->addr), ap->channel);
 		set_beacon++;
 	}
 
 #ifdef CONFIG_IEEE80211N
-	if (!iface->olbc_ht && !ap->ht_support) {
+	if (!iface->olbc_ht && !ap->ht_support &&
+	    (ap->channel == 0 ||
+	     ap->channel == iface->conf->channel ||
+	     ap->channel == iface->conf->channel +
+	     iface->conf->secondary_channel * 4)) {
 		iface->olbc_ht = 1;
 		hostapd_ht_operation_update(iface);
 		wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
-			   " - enable protection", MAC2STR(ap->addr));
+			   " (channel %d) - enable protection",
+			   MAC2STR(ap->addr), ap->channel);
 		set_beacon++;
 	}
 #endif /* CONFIG_IEEE80211N */
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index f0b4125..d0529a1 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -14,42 +14,24 @@
 struct ap_info {
 	/* Note: next/prev pointers are updated whenever a new beacon is
 	 * received because these are used to find the least recently used
-	 * entries. iter_next/iter_prev are updated only when adding new BSSes
-	 * and when removing old ones. These should be used when iterating
-	 * through the table in a manner that allows beacons to be received
-	 * during the iteration. */
+	 * entries. */
 	struct ap_info *next; /* next entry in AP list */
 	struct ap_info *prev; /* previous entry in AP list */
 	struct ap_info *hnext; /* next entry in hash table list */
-	struct ap_info *iter_next; /* next entry in AP iteration list */
-	struct ap_info *iter_prev; /* previous entry in AP iteration list */
 	u8 addr[6];
-	u16 beacon_int;
-	u16 capability;
 	u8 supported_rates[WLAN_SUPP_RATES_MAX];
-	u8 ssid[33];
-	size_t ssid_len;
-	int wpa;
 	int erp; /* ERP Info or -1 if ERP info element not present */
 
 	int channel;
-	int datarate; /* in 100 kbps */
 
 	int ht_support;
 
-	unsigned int num_beacons; /* number of beacon frames received */
 	os_time_t last_beacon;
-
-	int already_seen; /* whether API call AP-NEW has already fetched
-			   * information about this AP */
 };
 
 struct ieee802_11_elems;
 struct hostapd_frame_info;
 
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
-int ap_ap_for_each(struct hostapd_iface *iface,
-		   int (*func)(struct ap_info *s, void *data), void *data);
 void ap_list_process_beacon(struct hostapd_iface *iface,
 			    const struct ieee80211_mgmt *mgmt,
 			    struct ieee802_11_elems *elems,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 92fda56..a0ac38c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -108,19 +108,10 @@
 }
 
 
-int hostapd_reload_config(struct hostapd_iface *iface)
+static void hostapd_clear_old(struct hostapd_iface *iface)
 {
-	struct hostapd_data *hapd = iface->bss[0];
-	struct hostapd_config *newconf, *oldconf;
 	size_t j;
 
-	if (iface->interfaces == NULL ||
-	    iface->interfaces->config_read_cb == NULL)
-		return -1;
-	newconf = iface->interfaces->config_read_cb(iface->config_fname);
-	if (newconf == NULL)
-		return -1;
-
 	/*
 	 * Deauthenticate all stations since the new configuration may not
 	 * allow them to use the BSS anymore.
@@ -136,6 +127,31 @@
 		radius_client_flush(iface->bss[j]->radius, 0);
 #endif /* CONFIG_NO_RADIUS */
 	}
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_config *newconf, *oldconf;
+	size_t j;
+
+	if (iface->config_fname == NULL) {
+		/* Only in-memory config in use - assume it has been updated */
+		hostapd_clear_old(iface);
+		for (j = 0; j < iface->num_bss; j++)
+			hostapd_reload_bss(iface->bss[j]);
+		return 0;
+	}
+
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->config_read_cb == NULL)
+		return -1;
+	newconf = iface->interfaces->config_read_cb(iface->config_fname);
+	if (newconf == NULL)
+		return -1;
+
+	hostapd_clear_old(iface);
 
 	oldconf = hapd->iconf;
 	iface->conf = newconf;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f5aed99..9a3bb68 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -220,7 +220,6 @@
 	int num_ap; /* number of entries in ap_list */
 	struct ap_info *ap_list; /* AP info list head */
 	struct ap_info *ap_hash[STA_HASH_SIZE];
-	struct ap_info *ap_iter_list;
 
 	unsigned int drv_flags;
 
@@ -230,6 +229,10 @@
 	 */
 	unsigned int probe_resp_offloads;
 
+	/* extended capabilities supported by the driver */
+	const u8 *extended_capa, *extended_capa_mask;
+	unsigned int extended_capa_len;
+
 	struct hostapd_hw_modes *hw_features;
 	int num_hw_features;
 	struct hostapd_hw_modes *current_mode;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 76f78a7..c36bbe3 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -164,10 +164,52 @@
 #endif /* CONFIG_IEEE80211W */
 
 
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+	*pos = 0x00;
+
+	switch (idx) {
+	case 0: /* Bits 0-7 */
+		break;
+	case 1: /* Bits 8-15 */
+		break;
+	case 2: /* Bits 16-23 */
+		if (hapd->conf->wnm_sleep_mode)
+			*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+		if (hapd->conf->bss_transition)
+			*pos |= 0x08; /* Bit 19 - BSS Transition */
+		break;
+	case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+		*pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+		if (hapd->conf->time_advertisement == 2)
+			*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+		if (hapd->conf->interworking)
+			*pos |= 0x80; /* Bit 31 - Interworking */
+		break;
+	case 4: /* Bits 32-39 */
+		if (hapd->conf->tdls & TDLS_PROHIBIT)
+			*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+		if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+			/* Bit 39 - TDLS Channel Switching Prohibited */
+			*pos |= 0x80;
+		}
+		break;
+	case 5: /* Bits 40-47 */
+		break;
+	case 6: /* Bits 48-55 */
+		if (hapd->conf->ssid.utf8_ssid)
+			*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+		break;
+	}
+}
+
+
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
 {
 	u8 *pos = eid;
-	u8 len = 0;
+	u8 len = 0, i;
 
 	if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
 		len = 5;
@@ -181,55 +223,30 @@
 	if (len < 4)
 		len = 4;
 #endif /* CONFIG_WNM */
+	if (len < hapd->iface->extended_capa_len)
+		len = hapd->iface->extended_capa_len;
 	if (len == 0)
 		return eid;
 
 	*pos++ = WLAN_EID_EXT_CAPAB;
 	*pos++ = len;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
+	for (i = 0; i < len; i++, pos++) {
+		hostapd_ext_capab_byte(hapd, pos, i);
 
-	*pos = 0x00;
-	if (hapd->conf->wnm_sleep_mode)
-		*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
-	if (hapd->conf->bss_transition)
-		*pos |= 0x08; /* Bit 19 - BSS Transition */
-	pos++;
+		if (i < hapd->iface->extended_capa_len) {
+			*pos &= ~hapd->iface->extended_capa_mask[i];
+			*pos |= hapd->iface->extended_capa[i];
+		}
+	}
 
-	if (len < 4)
-		return pos;
-	*pos = 0x00;
-#ifdef CONFIG_WNM
-	*pos |= 0x02; /* Bit 25 - SSID List */
-#endif /* CONFIG_WNM */
-	if (hapd->conf->time_advertisement == 2)
-		*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
-	if (hapd->conf->interworking)
-		*pos |= 0x80; /* Bit 31 - Interworking */
-	pos++;
+	while (len > 0 && eid[1 + len] == 0) {
+		len--;
+		eid[1] = len;
+	}
+	if (len == 0)
+		return eid;
 
-	if (len < 5)
-		return pos;
-	*pos = 0x00;
-	if (hapd->conf->tdls & TDLS_PROHIBIT)
-		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
-	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
-		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
-	pos++;
-
-	if (len < 6)
-		return pos;
-	*pos = 0x00;
-	pos++;
-
-	if (len < 7)
-		return pos;
-	*pos = 0x00;
-	if (hapd->conf->ssid.utf8_ssid)
-		*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
-	pos++;
-
-	return pos;
+	return eid + 2 + len;
 }
 
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index fa4b1cb..4f1f6fb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1598,6 +1598,7 @@
 	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
 
 	wpa_group_ensure_init(sm->wpa_auth, sm->group);
+	sm->ReAuthenticationRequest = FALSE;
 
 	/*
 	 * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1611,12 +1612,11 @@
 	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
 		wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
 			   "ANonce.");
-		wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+		sm->Disconnect = TRUE;
 		return;
 	}
 	wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
 		    WPA_NONCE_LEN);
-	sm->ReAuthenticationRequest = FALSE;
 	/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
 	 * logical place than INITIALIZE since AUTHENTICATION2 can be
 	 * re-entered on ReAuthenticationRequest without going through
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index e017972..69b34fe 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -45,6 +45,7 @@
 struct wps_for_each_data {
 	int (*func)(struct hostapd_data *h, void *ctx);
 	void *ctx;
+	struct hostapd_data *calling_hapd;
 };
 
 
@@ -57,7 +58,14 @@
 		return 0;
 	for (j = 0; j < iface->num_bss; j++) {
 		struct hostapd_data *hapd = iface->bss[j];
-		int ret = data->func(hapd, data->ctx);
+		int ret;
+
+		if (hapd != data->calling_hapd &&
+		    (hapd->conf->wps_independent ||
+		     data->calling_hapd->conf->wps_independent))
+			continue;
+
+		ret = data->func(hapd, data->ctx);
 		if (ret)
 			return ret;
 	}
@@ -74,6 +82,7 @@
 	struct wps_for_each_data data;
 	data.func = func;
 	data.ctx = ctx;
+	data.calling_hapd = hapd;
 	if (iface->interfaces == NULL ||
 	    iface->interfaces->for_each_interface == NULL)
 		return wps_for_each(iface, &data);
@@ -277,6 +286,114 @@
 }
 
 
+static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
+				       const struct wps_credential *cred)
+{
+	struct hostapd_bss_config *bss = hapd->conf;
+
+	wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
+
+	bss->wps_state = 2;
+	if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+		os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
+		bss->ssid.ssid_len = cred->ssid_len;
+		bss->ssid.ssid_set = 1;
+	}
+
+	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+		bss->wpa = 3;
+	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+		bss->wpa = 2;
+	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+		bss->wpa = 1;
+	else
+		bss->wpa = 0;
+
+	if (bss->wpa) {
+		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+		bss->wpa_pairwise = 0;
+		if (cred->encr_type & WPS_ENCR_AES)
+			bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+		if (cred->encr_type & WPS_ENCR_TKIP)
+			bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+		bss->rsn_pairwise = bss->wpa_pairwise;
+		bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+							    bss->wpa_pairwise,
+							    bss->rsn_pairwise);
+
+		if (cred->key_len >= 8 && cred->key_len < 64) {
+			os_free(bss->ssid.wpa_passphrase);
+			bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
+			if (bss->ssid.wpa_passphrase)
+				os_memcpy(bss->ssid.wpa_passphrase, cred->key,
+					  cred->key_len);
+			os_free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk = NULL;
+		} else if (cred->key_len == 64) {
+			os_free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk =
+				os_zalloc(sizeof(struct hostapd_wpa_psk));
+			if (bss->ssid.wpa_psk &&
+			    hexstr2bin((const char *) cred->key,
+				       bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
+				bss->ssid.wpa_psk->group = 1;
+				os_free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = NULL;
+			}
+		}
+		bss->auth_algs = 1;
+	} else {
+		if ((cred->auth_type & WPS_AUTH_OPEN) &&
+		    (cred->auth_type & WPS_AUTH_SHARED))
+			bss->auth_algs = 3;
+		else if (cred->auth_type & WPS_AUTH_SHARED)
+			bss->auth_algs = 2;
+		else
+			bss->auth_algs = 1;
+		if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 &&
+		    cred->key_idx <= 4) {
+			struct hostapd_wep_keys *wep = &bss->ssid.wep;
+			int idx = cred->key_idx;
+			if (idx)
+				idx--;
+			wep->idx = idx;
+			if (cred->key_len == 10 || cred->key_len == 26) {
+				os_free(wep->key[idx]);
+				wep->key[idx] = os_malloc(cred->key_len / 2);
+				if (wep->key[idx] == NULL ||
+				    hexstr2bin((const char *) cred->key,
+					       wep->key[idx],
+					       cred->key_len / 2))
+					return -1;
+				wep->len[idx] = cred->key_len / 2;
+			} else {
+				os_free(wep->key[idx]);
+				wep->key[idx] = os_malloc(cred->key_len);
+				if (wep->key[idx] == NULL)
+					return -1;
+				os_memcpy(wep->key[idx], cred->key,
+					  cred->key_len);
+				wep->len[idx] = cred->key_len;
+			}
+			wep->keys_set = 1;
+		}
+	}
+
+	/* Schedule configuration reload after short period of time to allow
+	 * EAP-WSC to be finished.
+	 */
+	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+			       NULL);
+
+	return 0;
+}
+
+
 static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 {
 	const struct wps_credential *cred = ctx;
@@ -344,7 +461,7 @@
 	hapd->wps->wps_state = WPS_STATE_CONFIGURED;
 
 	if (hapd->iface->config_fname == NULL)
-		return 0;
+		return hapd_wps_reconfig_in_memory(hapd, cred);
 	len = os_strlen(hapd->iface->config_fname) + 5;
 	tmp_fname = os_malloc(len);
 	if (tmp_fname == NULL)
@@ -706,7 +823,8 @@
 		return 0;
 	for (j = 0; j < iface->num_bss; j++) {
 		struct hostapd_data *hapd = iface->bss[j];
-		if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+		if (hapd->wps && !hapd->conf->wps_independent &&
+		    !is_nil_uuid(hapd->wps->uuid)) {
 			*uuid = hapd->wps->uuid;
 			return 1;
 		}
@@ -799,7 +917,7 @@
 	if (is_nil_uuid(hapd->conf->uuid)) {
 		const u8 *uuid;
 		uuid = get_own_uuid(hapd->iface);
-		if (uuid) {
+		if (uuid && !conf->wps_independent) {
 			os_memcpy(wps->uuid, uuid, UUID_LEN);
 			wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
 				    "interface", wps->uuid, UUID_LEN);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 63f90bc..14b64a6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -897,6 +897,15 @@
 /* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
 	unsigned int probe_resp_offloads;
+
+	/**
+	 * extended_capa - extended capabilities in driver/device
+	 *
+	 * Must be allocated and freed by driver and the pointers must be
+	 * valid for the lifetime of the driver, i.e., freed in deinit()
+	 */
+	const u8 *extended_capa, *extended_capa_mask;
+	unsigned int extended_capa_len;
 };
 
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c2b9fff..cd266b4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -214,6 +214,8 @@
 	int ignore_if_down_event;
 	struct rfkill_data *rfkill;
 	struct wpa_driver_capa capa;
+	u8 *extended_capa, *extended_capa_mask;
+	unsigned int extended_capa_len;
 	int has_capability;
 
 	int operstate;
@@ -2554,6 +2556,7 @@
 
 
 struct wiphy_info_data {
+	struct wpa_driver_nl80211_data *drv;
 	struct wpa_driver_capa *capa;
 
 	unsigned int error:1;
@@ -2795,6 +2798,7 @@
 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 	struct wiphy_info_data *info = arg;
 	struct wpa_driver_capa *capa = info->capa;
+	struct wpa_driver_nl80211_data *drv = info->drv;
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
@@ -2842,6 +2846,30 @@
 	wiphy_info_probe_resp_offload(capa,
 				      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
 
+	if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+	    drv->extended_capa == NULL) {
+		drv->extended_capa =
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		if (drv->extended_capa) {
+			os_memcpy(drv->extended_capa,
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+			drv->extended_capa_len =
+				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+		}
+		drv->extended_capa_mask =
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		if (drv->extended_capa_mask) {
+			os_memcpy(drv->extended_capa_mask,
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		} else {
+			os_free(drv->extended_capa);
+			drv->extended_capa = NULL;
+			drv->extended_capa_len = 0;
+		}
+	}
+
 	return NL_SKIP;
 }
 
@@ -2854,6 +2882,7 @@
 
 	os_memset(info, 0, sizeof(*info));
 	info->capa = &drv->capa;
+	info->drv = drv;
 
 	msg = nlmsg_alloc();
 	if (!msg)
@@ -3751,6 +3780,8 @@
 	if (drv->in_interface_list)
 		dl_list_del(&drv->list);
 
+	os_free(drv->extended_capa);
+	os_free(drv->extended_capa_mask);
 	os_free(drv);
 }
 
@@ -3781,7 +3812,6 @@
 		    struct wpa_driver_scan_params *params)
 {
 	struct nl_msg *msg;
-	int err;
 	size_t i;
 
 	msg = nlmsg_alloc();
@@ -3794,23 +3824,20 @@
 		goto fail;
 
 	if (params->num_ssids) {
-		struct nl_msg *ssids = nlmsg_alloc();
+		struct nlattr *ssids;
+
+		ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
 		if (ssids == NULL)
 			goto fail;
 		for (i = 0; i < params->num_ssids; i++) {
 			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
 					  params->ssids[i].ssid,
 					  params->ssids[i].ssid_len);
-			if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
-				    params->ssids[i].ssid) < 0) {
-				nlmsg_free(ssids);
+			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+				    params->ssids[i].ssid) < 0)
 				goto fail;
-			}
 		}
-		err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-		nlmsg_free(ssids);
-		if (err < 0)
-			goto fail;
+		nla_nest_end(msg, ssids);
 	}
 
 	if (params->extra_ies) {
@@ -3822,22 +3849,17 @@
 	}
 
 	if (params->freqs) {
-		struct nl_msg *freqs = nlmsg_alloc();
+		struct nlattr *freqs;
+		freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
 		if (freqs == NULL)
 			goto fail;
 		for (i = 0; params->freqs[i]; i++) {
 			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
 				   "MHz", params->freqs[i]);
-			if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
-				nlmsg_free(freqs);
+			if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
 				goto fail;
-			}
 		}
-		err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
-				     freqs);
-		nlmsg_free(freqs);
-		if (err < 0)
-			goto fail;
+		nla_nest_end(msg, freqs);
 	}
 
 	os_free(drv->filter_ssids);
@@ -3864,7 +3886,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1, timeout;
-	struct nl_msg *msg, *rates = NULL;
+	struct nl_msg *msg = NULL;
 
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
 	drv->scan_for_auth = 0;
@@ -3874,9 +3896,11 @@
 		return -1;
 
 	if (params->p2p_probe) {
+		struct nlattr *rates;
+
 		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
 
-		rates = nlmsg_alloc();
+		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
 		if (rates == NULL)
 			goto nla_put_failure;
 
@@ -3886,11 +3910,9 @@
 		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
 		 * rates are left enabled.
 		 */
-		NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+		NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
 			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-		if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
-		    0)
-			goto nla_put_failure;
+		nla_nest_end(msg, rates);
 
 		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
 	}
@@ -3944,7 +3966,6 @@
 
 nla_put_failure:
 	nlmsg_free(msg);
-	nlmsg_free(rates);
 	return ret;
 }
 
@@ -3964,8 +3985,6 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1;
 	struct nl_msg *msg;
-	struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
-	struct nl_msg *match_set_rssi = NULL;
 	size_t i;
 
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
@@ -3984,46 +4003,42 @@
 	if ((drv->num_filter_ssids &&
 	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
 	    params->filter_rssi) {
-		match_sets = nlmsg_alloc();
+		struct nlattr *match_sets;
+		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
 		if (match_sets == NULL)
 			goto nla_put_failure;
 
 		for (i = 0; i < drv->num_filter_ssids; i++) {
+			struct nlattr *match_set_ssid;
 			wpa_hexdump_ascii(MSG_MSGDUMP,
 					  "nl80211: Sched scan filter SSID",
 					  drv->filter_ssids[i].ssid,
 					  drv->filter_ssids[i].ssid_len);
 
-			match_set_ssid = nlmsg_alloc();
+			match_set_ssid = nla_nest_start(msg, i + 1);
 			if (match_set_ssid == NULL)
 				goto nla_put_failure;
-			NLA_PUT(match_set_ssid,
-				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
 				drv->filter_ssids[i].ssid_len,
 				drv->filter_ssids[i].ssid);
 
-			if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
-			    0)
-				goto nla_put_failure;
+			nla_nest_end(msg, match_sets);
 		}
 
 		if (params->filter_rssi) {
-			match_set_rssi = nlmsg_alloc();
+			struct nlattr *match_set_rssi;
+			match_set_rssi = nla_nest_start(msg, 0);
 			if (match_set_rssi == NULL)
 				goto nla_put_failure;
-			NLA_PUT_U32(match_set_rssi,
-				    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+			NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 				    params->filter_rssi);
 			wpa_printf(MSG_MSGDUMP,
 				   "nl80211: Sched scan RSSI filter %d dBm",
 				   params->filter_rssi);
-			if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
-				goto nla_put_failure;
+			nla_nest_end(msg, match_set_rssi);
 		}
 
-		if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-				   match_sets) < 0)
-			goto nla_put_failure;
+		nla_nest_end(msg, match_sets);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4041,9 +4056,6 @@
 		   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-	nlmsg_free(match_set_ssid);
-	nlmsg_free(match_sets);
-	nlmsg_free(match_set_rssi);
 	nlmsg_free(msg);
 	return ret;
 }
@@ -4532,18 +4544,15 @@
 				    NL80211_KEYTYPE_GROUP);
 		}
 	} else if (addr && is_broadcast_ether_addr(addr)) {
-		struct nl_msg *types;
-		int err;
+		struct nlattr *types;
+
 		wpa_printf(MSG_DEBUG, "   broadcast key");
-		types = nlmsg_alloc();
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		nla_nest_end(msg, types);
 	}
 	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4577,29 +4586,21 @@
 	else
 		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
 	if (addr && is_broadcast_ether_addr(addr)) {
-		struct nl_msg *types;
-		int err;
-		types = nlmsg_alloc();
+		struct nlattr *types;
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		nla_nest_end(msg, types);
 	} else if (addr) {
-		struct nl_msg *types;
-		int err;
-		types = nlmsg_alloc();
+		struct nlattr *types;
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+		nla_nest_end(msg, types);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6071,7 +6072,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *wme = NULL;
+	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
 	int ret = -ENOBUFS;
 
@@ -6138,18 +6139,18 @@
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
 	if (params->flags & WPA_STA_WMM) {
-		wme = nlmsg_alloc();
+		struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
 		if (!wme)
 			goto nla_put_failure;
 
 		wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
-		NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+		NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
 				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
-		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+		NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
 				(params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
 				WMM_QOSINFO_STA_SP_MASK);
-		if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
-			goto nla_put_failure;
+		nla_nest_end(msg, wme);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6161,7 +6162,6 @@
 	if (ret == -EEXIST)
 		ret = 0;
  nla_put_failure:
-	nlmsg_free(wme);
 	nlmsg_free(msg);
 	return ret;
 }
@@ -6245,7 +6245,7 @@
 				     enum nl80211_iftype iftype,
 				     const u8 *addr, int wds)
 {
-	struct nl_msg *msg, *flags = NULL;
+	struct nl_msg *msg;
 	int ifidx;
 	int ret = -ENOBUFS;
 
@@ -6262,20 +6262,15 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
 	if (iftype == NL80211_IFTYPE_MONITOR) {
-		int err;
+		struct nlattr *flags;
 
-		flags = nlmsg_alloc();
+		flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
 		if (!flags)
 			goto nla_put_failure;
 
-		NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+		NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-		err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-		nlmsg_free(flags);
-
-		if (err)
-			goto nla_put_failure;
+		nla_nest_end(msg, flags);
 	} else if (wds) {
 		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
 	}
@@ -6908,19 +6903,14 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *flags = NULL;
+	struct nl_msg *msg;
+	struct nlattr *flags;
 	struct nl80211_sta_flag_update upd;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	flags = nlmsg_alloc();
-	if (!flags) {
-		nlmsg_free(msg);
-		return -ENOMEM;
-	}
-
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -6931,35 +6921,34 @@
 	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
 	 * can be removed eventually.
 	 */
+	flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+	if (!flags)
+		goto nla_put_failure;
 	if (total_flags & WPA_STA_AUTHORIZED)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
 
 	if (total_flags & WPA_STA_WMM)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
 
 	if (total_flags & WPA_STA_SHORT_PREAMBLE)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
 	if (total_flags & WPA_STA_MFP)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
 
 	if (total_flags & WPA_STA_TDLS_PEER)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
 
-	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-		goto nla_put_failure;
+	nla_nest_end(msg, flags);
 
 	os_memset(&upd, 0, sizeof(upd));
 	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
 	upd.set = sta_flags_nl80211(flags_or);
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
-	nlmsg_free(flags);
-
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
 	nlmsg_free(msg);
-	nlmsg_free(flags);
 	return -ENOBUFS;
 }
 
@@ -7664,6 +7653,11 @@
 	if (!drv->has_capability)
 		return -1;
 	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	if (drv->extended_capa && drv->extended_capa_mask) {
+		capa->extended_capa = drv->extended_capa;
+		capa->extended_capa_mask = drv->extended_capa_mask;
+		capa->extended_capa_len = drv->extended_capa_len;
+	}
 	return 0;
 }
 
@@ -9032,7 +9026,8 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *cqm = NULL;
+	struct nl_msg *msg;
+	struct nlattr *cqm;
 	int ret = -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
@@ -9046,20 +9041,18 @@
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
-	cqm = nlmsg_alloc();
+	cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
 	if (cqm == NULL)
 		goto nla_put_failure;
 
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-	if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
-		goto nla_put_failure;
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+	nla_nest_end(msg, cqm);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 
 nla_put_failure:
-	nlmsg_free(cqm);
 	nlmsg_free(msg);
 	return ret;
 }
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 81ad0ce..8edb1ca 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -77,25 +77,33 @@
 	else
 		len = end - pos;
 	if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
-	    hexstr2bin(pos, cred->ssid, len / 2))
+	    hexstr2bin(pos, cred->ssid, len / 2)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
 		return -1;
+	}
 	cred->ssid_len = len / 2;
 
 	pos = os_strstr(params, "new_auth=");
-	if (pos == NULL)
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
 		return -1;
+	}
 	if (os_strncmp(pos + 9, "OPEN", 4) == 0)
 		cred->auth_type = WPS_AUTH_OPEN;
 	else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
 		cred->auth_type = WPS_AUTH_WPAPSK;
 	else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
 		cred->auth_type = WPS_AUTH_WPA2PSK;
-	else
+	else {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
 		return -1;
+	}
 
 	pos = os_strstr(params, "new_encr=");
-	if (pos == NULL)
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
 		return -1;
+	}
 	if (os_strncmp(pos + 9, "NONE", 4) == 0)
 		cred->encr_type = WPS_ENCR_NONE;
 	else if (os_strncmp(pos + 9, "WEP", 3) == 0)
@@ -104,8 +112,10 @@
 		cred->encr_type = WPS_ENCR_TKIP;
 	else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
 		cred->encr_type = WPS_ENCR_AES;
-	else
+	else {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
 		return -1;
+	}
 
 	pos = os_strstr(params, "new_key=");
 	if (pos == NULL)
@@ -117,8 +127,10 @@
 	else
 		len = end - pos;
 	if ((len & 1) || len > 2 * sizeof(cred->key) ||
-	    hexstr2bin(pos, cred->key, len / 2))
+	    hexstr2bin(pos, cred->key, len / 2)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
 		return -1;
+	}
 	cred->key_len = len / 2;
 
 	return 1;
@@ -211,6 +223,8 @@
 	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
 	if (res < 0) {
 		os_free(data);
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
+			   "settings");
 		return NULL;
 	}
 	if (res == 1) {
@@ -222,6 +236,7 @@
 	data->wps = wps_init(&cfg);
 	if (data->wps == NULL) {
 		os_free(data);
+		wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
 		return NULL;
 	}
 	res = eap_get_config_fragment_size(sm);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index edb8d72..852ddf5 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -399,7 +399,6 @@
 
 static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
 {
-	u8 *group_info;
 	struct wpabuf *p2p_subelems, *ie;
 	struct p2p_group_member *m;
 
@@ -413,14 +412,18 @@
 	/* P2P Device Info */
 	p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
 
-	/* P2P Group Info */
-	group_info = wpabuf_put(p2p_subelems, 0);
-	wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
-	wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
-	for (m = group->members; m; m = m->next)
-		p2p_client_info(p2p_subelems, m);
-	WPA_PUT_LE16(group_info + 1,
-		     (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3);
+	/* P2P Group Info: Only when at least one P2P Client is connected */
+	if (group->members) {
+		u8 *group_info;
+		group_info = wpabuf_put(p2p_subelems, 0);
+		wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
+		wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
+		for (m = group->members; m; m = m->next)
+			p2p_client_info(p2p_subelems, m);
+		WPA_PUT_LE16(group_info + 1,
+			     (u8 *) wpabuf_put(p2p_subelems, 0) - group_info -
+			     3);
+	}
 
 	ie = p2p_group_encaps_probe_resp(p2p_subelems);
 	wpabuf_free(p2p_subelems);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index d8f33b1..a1268e4 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -259,7 +259,7 @@
 {
 	struct p2p_message msg;
 	struct p2p_device *dev;
-	u16 report_config_methods = 0;
+	u16 report_config_methods = 0, req_config_methods;
 	int success = 0;
 
 	if (p2p_parse(data, len, &msg))
@@ -294,6 +294,12 @@
 	}
 
 	/*
+	 * Use a local copy of the requested config methods since
+	 * p2p_reset_pending_pd() can clear this in the peer entry.
+	 */
+	req_config_methods = dev->req_config_methods;
+
+	/*
 	 * If the response is from the peer to whom a user initiated request
 	 * was sent earlier, we reset that state info here.
 	 */
@@ -301,9 +307,11 @@
 	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
 		p2p_reset_pending_pd(p2p);
 
-	if (msg.wps_config_methods != dev->req_config_methods) {
+	if (msg.wps_config_methods != req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
-			"our Provision Discovery Request");
+			"our Provision Discovery Request (received "
+			"config_methods 0x%x expected 0x%x",
+			msg.wps_config_methods, req_config_methods);
 		if (p2p->cfg->prov_disc_fail)
 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
 						 P2P_PROV_DISC_REJECTED);
@@ -311,10 +319,10 @@
 		goto out;
 	}
 
-	report_config_methods = dev->req_config_methods;
+	report_config_methods = req_config_methods;
 	dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
 			P2P_DEV_PD_PEER_KEYPAD);
-	if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
+	if (req_config_methods & WPS_CONFIG_DISPLAY) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
 			" accepted to show a PIN on display", MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_DISPLAY;