Cumulative patch from commit f4e3860f8a770a0db3816196c77baf894c7ccc1e

f4e3860 Fix AP mode default TXOP Limit values for AC_VI and AC_VO
47bd94a TLS testing: Add new test cases for RSA-DHE primes
f5bbb2f TLS client: Reject RSA-DHE prime if it shorter than 768 bits
817742f TLS testing: Fix test_flags check for ApplData report
1120e45 Allow config blobs to be set through ctrl_iface
c3722e1 ACS: Fix VHT20
49b7443 Fix HT40 co-ex scan for some pri/sec channel switches
5bdac4a Remove unused STA entry information
c9d9ee9 Fix hostapd_add_iface error path to deinit partially initialized BSS
6829da3 Fix external radio_work deinit path
8dd9f9c Allow management group cipher to be configured
67d39cf P2P: Do not create another group interface on NFC Token enable
6aa1cd4 wpa_supplicant: Apply VHT_OVERRIDES to wpas_start_assoc_cb()
db63757 hostapd: Supply default parameters for OBSS scan
6e9375e TDLS: Add get_capability tdls command
67e1a40 hostapd: For VHT 20/40, allow center segment 0 to be zero
d0bf06f GAS server: Remove incomplete remote ANQP processing
fdb4535 WPS: Extend per-station PSK to support ER case as well
9a1a538 wpa_supplicant AP: Allow PMF to be enabled with ieee80211w
ce6b9cd Allow reason code to be specified for DEAUTH/DISASSOC test frame
dda8be7 TDLS: Use QoS info from WMM IE obtained in TDLS frames
daa70bd Fix CONFIG_NO_SCAN_PROCESSING=y build
3a8ec73 P2P: Report dev_found event (if not yet done) from GO Neg Req RX
0f23a5e Mark AP disabled if initialization steps fail

Change-Id: I7e499241552147c734fec9b77351b47ffd6e3a7c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 3e0155c..2491b78 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -639,23 +639,26 @@
 
 static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
 {
+	int offset;
+
 	wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
 
 	switch (iface->conf->vht_oper_chwidth) {
 	case VHT_CHANWIDTH_USE_HT:
-		iface->conf->vht_oper_centr_freq_seg0_idx =
-			iface->conf->channel + 2;
+		offset = 2 * iface->conf->secondary_channel;
 		break;
 	case VHT_CHANWIDTH_80MHZ:
-		iface->conf->vht_oper_centr_freq_seg0_idx =
-			iface->conf->channel + 6;
+		offset = 6;
 		break;
 	default:
 		/* TODO: How can this be calculated? Adjust
 		 * acs_find_ideal_chan() */
 		wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
-		break;
+		return;
 	}
+
+	iface->conf->vht_oper_centr_freq_seg0_idx =
+		iface->conf->channel + offset;
 }
 
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 3ca85a0..14d9ae9 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -73,6 +73,7 @@
 #ifdef CONFIG_IEEE80211W
 	bss->assoc_sa_query_max_timeout = 1000;
 	bss->assoc_sa_query_retry_timeout = 201;
+	bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
 #endif /* CONFIG_IEEE80211W */
 #ifdef EAP_SERVER_FAST
 	 /* both anonymous and authenticated provisioning */
@@ -106,9 +107,9 @@
 	const struct hostapd_wmm_ac_params ac_be =
 		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
 	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
-		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+		{ aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
 	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
-		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+		{ aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
 	const struct hostapd_tx_queue_params txq_bk =
 		{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
 	const struct hostapd_tx_queue_params txq_be =
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index aa3a51a..25eb490 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -254,6 +254,7 @@
 	int wpa_key_mgmt;
 #ifdef CONFIG_IEEE80211W
 	enum mfp_options ieee80211w;
+	int group_mgmt_cipher;
 	/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
 	unsigned int assoc_sa_query_max_timeout;
 	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 5ba48c9..83cfd0f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -503,7 +503,8 @@
 	case VHT_CHANWIDTH_USE_HT:
 		if (center_segment1)
 			return -1;
-		if (5000 + center_segment0 * 5 != data->center_freq1 &&
+		if (center_segment0 != 0 &&
+		    5000 + center_segment0 * 5 != data->center_freq1 &&
 		    2407 + center_segment0 * 5 != data->center_freq1)
 			return -1;
 		break;
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index a7129f1..13604ed 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -120,8 +120,6 @@
  * reassociation procedure that was initiated by that specific peer MAC entity.
  *
  * PeerSTAAddress = sta->addr
- *
- * sta->previous_ap contains the "Current AP" information from ReassocReq.
  */
 void mlme_reassociate_indication(struct hostapd_data *hapd,
 				 struct sta_info *sta)
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c27cf3b..11351c4 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -281,6 +281,10 @@
 	if (hwaddr_aton(txtaddr, addr))
 		return -1;
 
+	pos = os_strstr(txtaddr, " reason=");
+	if (pos)
+		reason = atoi(pos + 8);
+
 	pos = os_strstr(txtaddr, " test=");
 	if (pos) {
 		struct ieee80211_mgmt mgmt;
@@ -295,8 +299,7 @@
 		os_memcpy(mgmt.da, addr, ETH_ALEN);
 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-		mgmt.u.deauth.reason_code =
-			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		mgmt.u.deauth.reason_code = host_to_le16(reason);
 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
 					     IEEE80211_HDRLEN +
 					     sizeof(mgmt.u.deauth),
@@ -313,10 +316,6 @@
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
-	pos = os_strstr(txtaddr, " reason=");
-	if (pos)
-		reason = atoi(pos + 8);
-
 	hostapd_drv_sta_deauth(hapd, addr, reason);
 	sta = ap_get_sta(hapd, addr);
 	if (sta)
@@ -342,6 +341,10 @@
 	if (hwaddr_aton(txtaddr, addr))
 		return -1;
 
+	pos = os_strstr(txtaddr, " reason=");
+	if (pos)
+		reason = atoi(pos + 8);
+
 	pos = os_strstr(txtaddr, " test=");
 	if (pos) {
 		struct ieee80211_mgmt mgmt;
@@ -356,8 +359,7 @@
 		os_memcpy(mgmt.da, addr, ETH_ALEN);
 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-		mgmt.u.disassoc.reason_code =
-			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		mgmt.u.disassoc.reason_code = host_to_le16(reason);
 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
 					     IEEE80211_HDRLEN +
 					     sizeof(mgmt.u.deauth),
@@ -374,10 +376,6 @@
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
-	pos = os_strstr(txtaddr, " reason=");
-	if (pos)
-		reason = atoi(pos + 8);
-
 	hostapd_drv_sta_disassoc(hapd, addr, reason);
 	sta = ap_get_sta(hapd, addr);
 	if (sta)
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index fd1041e..49f6e87 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -71,7 +71,6 @@
 			continue;
 		dia = &sta->gas_dialog[i];
 		dia->valid = 1;
-		dia->index = i;
 		dia->dialog_token = dialog_token;
 		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
 		return dia;
@@ -744,40 +743,21 @@
 }
 
 
-static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
-{
-	struct gas_dialog_info *dia = eloop_data;
-
-	wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
-		   "dialog token %d", dia->dialog_token);
-
-	gas_serv_dialog_clear(dia);
-}
-
-
 struct anqp_query_info {
 	unsigned int request;
-	unsigned int remote_request;
 	const u8 *home_realm_query;
 	size_t home_realm_query_len;
 	const u8 *icon_name;
 	size_t icon_name_len;
-	u16 remote_delay;
 };
 
 
 static void set_anqp_req(unsigned int bit, const char *name, int local,
-			 unsigned int remote, u16 remote_delay,
 			 struct anqp_query_info *qi)
 {
 	qi->request |= bit;
 	if (local) {
 		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
-	} else if (bit & remote) {
-		wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
-		qi->remote_request |= bit;
-		if (remote_delay > qi->remote_delay)
-			qi->remote_delay = remote_delay;
 	} else {
 		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
 	}
@@ -789,43 +769,38 @@
 {
 	switch (info_id) {
 	case ANQP_CAPABILITY_LIST:
-		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
-			     0, qi);
+		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
+			     qi);
 		break;
 	case ANQP_VENUE_NAME:
 		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
-			     hapd->conf->venue_name != NULL, 0, 0, qi);
+			     hapd->conf->venue_name != NULL, qi);
 		break;
 	case ANQP_NETWORK_AUTH_TYPE:
 		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
-			     hapd->conf->network_auth_type != NULL,
-			     0, 0, qi);
+			     hapd->conf->network_auth_type != NULL, qi);
 		break;
 	case ANQP_ROAMING_CONSORTIUM:
 		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
-			     hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+			     hapd->conf->roaming_consortium != NULL, qi);
 		break;
 	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
 		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
 			     "IP Addr Type Availability",
-			     hapd->conf->ipaddr_type_configured,
-			     0, 0, qi);
+			     hapd->conf->ipaddr_type_configured, qi);
 		break;
 	case ANQP_NAI_REALM:
 		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
-			     hapd->conf->nai_realm_data != NULL,
-			     0, 0, qi);
+			     hapd->conf->nai_realm_data != NULL, qi);
 		break;
 	case ANQP_3GPP_CELLULAR_NETWORK:
 		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
 			     "3GPP Cellular Network",
-			     hapd->conf->anqp_3gpp_cell_net != NULL,
-			     0, 0, qi);
+			     hapd->conf->anqp_3gpp_cell_net != NULL, qi);
 		break;
 	case ANQP_DOMAIN_NAME:
 		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
-			     hapd->conf->domain_name != NULL,
-			     0, 0, qi);
+			     hapd->conf->domain_name != NULL, qi);
 		break;
 	default:
 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
@@ -857,33 +832,30 @@
 	switch (subtype) {
 	case HS20_STYPE_CAPABILITY_LIST:
 		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
-			     1, 0, 0, qi);
+			     1, qi);
 		break;
 	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
 		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
 			     "Operator Friendly Name",
-			     hapd->conf->hs20_oper_friendly_name != NULL,
-			     0, 0, qi);
+			     hapd->conf->hs20_oper_friendly_name != NULL, qi);
 		break;
 	case HS20_STYPE_WAN_METRICS:
 		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
-			     hapd->conf->hs20_wan_metrics != NULL,
-			     0, 0, qi);
+			     hapd->conf->hs20_wan_metrics != NULL, qi);
 		break;
 	case HS20_STYPE_CONNECTION_CAPABILITY:
 		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
 			     "Connection Capability",
 			     hapd->conf->hs20_connection_capability != NULL,
-			     0, 0, qi);
+			     qi);
 		break;
 	case HS20_STYPE_OPERATING_CLASS:
 		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
-			     hapd->conf->hs20_operating_class != NULL,
-			     0, 0, qi);
+			     hapd->conf->hs20_operating_class != NULL, qi);
 		break;
 	case HS20_STYPE_OSU_PROVIDERS_LIST:
 		set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
-			     hapd->conf->hs20_osu_providers_count, 0, 0, qi);
+			     hapd->conf->hs20_osu_providers_count, qi);
 		break;
 	default:
 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
@@ -1150,97 +1122,6 @@
 }
 
 
-void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
-			      struct gas_dialog_info *dialog)
-{
-	struct wpabuf *buf, *tx_buf;
-	u8 dialog_token = dialog->dialog_token;
-	size_t frag_len;
-
-	if (dialog->sd_resp == NULL) {
-		buf = gas_serv_build_gas_resp_payload(hapd,
-						      dialog->all_requested,
-						      dialog, NULL, 0, NULL, 0);
-		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
-			buf);
-		if (!buf)
-			goto tx_gas_response_done;
-		dialog->sd_resp = buf;
-		dialog->sd_resp_pos = 0;
-	}
-	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
-	if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
-	    hapd->conf->gas_comeback_delay) {
-		u16 comeback_delay_tus = dialog->comeback_delay +
-			GAS_SERV_COMEBACK_DELAY_FUDGE;
-		u32 comeback_delay_secs, comeback_delay_usecs;
-
-		if (hapd->conf->gas_comeback_delay) {
-			/* Testing - allow overriding of the delay value */
-			comeback_delay_tus = hapd->conf->gas_comeback_delay;
-		}
-
-		wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
-			   "%u) and comeback delay %u, "
-			   "requesting comebacks", (unsigned int) frag_len,
-			   (unsigned int) hapd->gas_frag_limit,
-			   dialog->comeback_delay);
-		tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
-							 WLAN_STATUS_SUCCESS,
-							 comeback_delay_tus,
-							 NULL);
-		if (tx_buf) {
-			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
-				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
-			if (dialog->prot)
-				convert_to_protected_dual(tx_buf);
-			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
-						dst,
-						wpabuf_head(tx_buf),
-						wpabuf_len(tx_buf));
-		}
-		wpabuf_free(tx_buf);
-
-		/* start a timer of 1.5 * comeback-delay */
-		comeback_delay_tus = comeback_delay_tus +
-			(comeback_delay_tus / 2);
-		comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
-		comeback_delay_usecs = (comeback_delay_tus * 1024) -
-			(comeback_delay_secs * 1000000);
-		eloop_register_timeout(comeback_delay_secs,
-				       comeback_delay_usecs,
-				       gas_serv_clear_cached_ies, dialog,
-				       NULL);
-		goto tx_gas_response_done;
-	}
-
-	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
-				dialog->sd_resp_pos, frag_len);
-	if (buf == NULL) {
-		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
-			"failed");
-		goto tx_gas_response_done;
-	}
-	tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
-						 WLAN_STATUS_SUCCESS, 0, buf);
-	wpabuf_free(buf);
-	if (tx_buf == NULL)
-		goto tx_gas_response_done;
-	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
-		"Response (frag_id %d frag_len %d)",
-		dialog->sd_frag_id, (int) frag_len);
-	dialog->sd_frag_id++;
-
-	if (dialog->prot)
-		convert_to_protected_dual(tx_buf);
-	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
-				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
-	wpabuf_free(tx_buf);
-tx_gas_response_done:
-	gas_serv_clear_cached_ies(dialog, NULL);
-}
-
-
 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
 					 const u8 *sa,
 					 const u8 *data, size_t len, int prot)
@@ -1274,33 +1155,6 @@
 		goto send_resp;
 	}
 
-	if (dialog->sd_resp == NULL) {
-		wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
-			   dialog->requested, dialog->received);
-		if ((dialog->requested & dialog->received) !=
-		    dialog->requested) {
-			wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
-				   "from remote processing");
-			gas_serv_dialog_clear(dialog);
-			tx_buf = gas_anqp_build_comeback_resp_buf(
-				dialog_token,
-				WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
-				NULL);
-			if (tx_buf == NULL)
-				return;
-			goto send_resp;
-		}
-
-		buf = gas_serv_build_gas_resp_payload(hapd,
-						      dialog->all_requested,
-						      dialog, NULL, 0, NULL, 0);
-		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
-			buf);
-		if (!buf)
-			goto rx_gas_comeback_req_done;
-		dialog->sd_resp = buf;
-		dialog->sd_resp_pos = 0;
-	}
 	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
 	if (frag_len > hapd->gas_frag_limit) {
 		frag_len = hapd->gas_frag_limit;
@@ -1313,15 +1167,18 @@
 	if (buf == NULL) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
 			"buffer");
-		goto rx_gas_comeback_req_done;
+		gas_serv_dialog_clear(dialog);
+		return;
 	}
 	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
 						  WLAN_STATUS_SUCCESS,
 						  dialog->sd_frag_id,
 						  more, 0, buf);
 	wpabuf_free(buf);
-	if (tx_buf == NULL)
-		goto rx_gas_comeback_req_done;
+	if (tx_buf == NULL) {
+		gas_serv_dialog_clear(dialog);
+		return;
+	}
 	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
 		"(frag_id %d more=%d frag_len=%d)",
 		dialog->sd_frag_id, more, (int) frag_len);
@@ -1346,10 +1203,6 @@
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
-	return;
-
-rx_gas_comeback_req_done:
-	gas_serv_clear_cached_ies(dialog, NULL);
 }
 
 
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 7e392b3..4ec3201 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -42,29 +42,17 @@
 #define ANQP_REQ_ICON_REQUEST \
 	(0x10000 << HS20_STYPE_ICON_REQUEST)
 
-/* To account for latencies between hostapd and external ANQP processor */
-#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
-#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
-
 struct gas_dialog_info {
 	u8 valid;
-	u8 index;
 	struct wpabuf *sd_resp; /* Fragmented response */
 	u8 dialog_token;
 	size_t sd_resp_pos; /* Offset in sd_resp */
 	u8 sd_frag_id;
-	u16 comeback_delay;
 	int prot; /* whether Protected Dual of Public Action frame is used */
-
-	unsigned int requested;
-	unsigned int received;
-	unsigned int all_requested;
 };
 
 struct hostapd_data;
 
-void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
-			      struct gas_dialog_info *dialog);
 struct gas_dialog_info *
 gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
 		     u8 dialog_token);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index bc5bb6c..4ed718c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1093,7 +1093,7 @@
 		if (ret < 0) {
 			wpa_printf(MSG_ERROR, "Could not select hw_mode and "
 				   "channel. (%d)", ret);
-			return -1;
+			goto fail;
 		}
 		if (ret == 1) {
 			wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
@@ -1101,7 +1101,7 @@
 		}
 		ret = hostapd_check_ht_capab(iface);
 		if (ret < 0)
-			return -1;
+			goto fail;
 		if (ret == 1) {
 			wpa_printf(MSG_DEBUG, "Interface initialization will "
 				   "be completed in a callback");
@@ -1112,6 +1112,13 @@
 			wpa_printf(MSG_DEBUG, "DFS support is enabled");
 	}
 	return hostapd_setup_interface_complete(iface, 0);
+
+fail:
+	hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+	if (iface->interfaces && iface->interfaces->terminate_on_error)
+		eloop_terminate();
+	return -1;
 }
 
 
@@ -1129,13 +1136,8 @@
 	size_t j;
 	u8 *prev_addr;
 
-	if (err) {
-		wpa_printf(MSG_ERROR, "Interface initialization failed");
-		hostapd_set_state(iface, HAPD_IFACE_DISABLED);
-		if (iface->interfaces && iface->interfaces->terminate_on_error)
-			eloop_terminate();
-		return -1;
-	}
+	if (err)
+		goto fail;
 
 	wpa_printf(MSG_DEBUG, "Completing interface initialization");
 	if (iface->conf->channel) {
@@ -1152,8 +1154,11 @@
 #ifdef NEED_AP_MLME
 		/* Check DFS */
 		res = hostapd_handle_dfs(iface);
-		if (res <= 0)
+		if (res <= 0) {
+			if (res < 0)
+				goto fail;
 			return res;
+		}
 #endif /* NEED_AP_MLME */
 
 		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
@@ -1166,7 +1171,7 @@
 				     hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
 			wpa_printf(MSG_ERROR, "Could not set channel for "
 				   "kernel driver");
-			return -1;
+			goto fail;
 		}
 	}
 
@@ -1177,7 +1182,7 @@
 			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_WARNING,
 				       "Failed to prepare rates table.");
-			return -1;
+			goto fail;
 		}
 	}
 
@@ -1185,14 +1190,14 @@
 	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
 		wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
 			   "kernel driver");
-		return -1;
+		goto fail;
 	}
 
 	if (hapd->iconf->fragm_threshold > -1 &&
 	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
 		wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
 			   "for kernel driver");
-		return -1;
+		goto fail;
 	}
 
 	prev_addr = hapd->own_addr;
@@ -1202,7 +1207,7 @@
 		if (j)
 			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
 		if (hostapd_setup_bss(hapd, j == 0))
-			return -1;
+			goto fail;
 		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
 			prev_addr = hapd->own_addr;
 	}
@@ -1217,7 +1222,7 @@
 	if (hostapd_driver_commit(hapd) < 0) {
 		wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
 			   "configuration", __func__);
-		return -1;
+		goto fail;
 	}
 
 	/*
@@ -1228,7 +1233,7 @@
 	 */
 	for (j = 0; j < iface->num_bss; j++) {
 		if (hostapd_init_wps_complete(iface->bss[j]))
-			return -1;
+			goto fail;
 	}
 
 	hostapd_set_state(iface, HAPD_IFACE_ENABLED);
@@ -1242,6 +1247,14 @@
 		iface->interfaces->terminate_on_error--;
 
 	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Interface initialization failed");
+	hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+	if (iface->interfaces && iface->interfaces->terminate_on_error)
+		eloop_terminate();
+	return -1;
 }
 
 
@@ -1824,6 +1837,7 @@
 			if (start_ctrl_iface_bss(hapd) < 0 ||
 			    (hapd_iface->state == HAPD_IFACE_ENABLED &&
 			     hostapd_setup_bss(hapd, -1))) {
+				hostapd_cleanup(hapd);
 				hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
 				hapd_iface->conf->num_bss--;
 				hapd_iface->num_bss--;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 28e92fd..d319ce0 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -327,7 +327,7 @@
 	int match;
 
 	pri_chan = iface->conf->channel;
-	sec_chan = iface->conf->secondary_channel * 4;
+	sec_chan = pri_chan + iface->conf->secondary_channel * 4;
 	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
 	if (iface->conf->secondary_channel > 0)
 		sec_freq = pri_freq + 20;
@@ -351,6 +351,7 @@
 			   "channel to get secondary channel with no Beacons "
 			   "from other BSSes");
 		ieee80211n_switch_pri_sec(iface);
+		return 1;
 	}
 
 	/*
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index bad080f..9b2900f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -242,29 +242,22 @@
  */
 void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
 {
-	struct ieee80211_mgmt *assoc;
-	u16 seq;
+	u16 seq = 0; /* TODO */
 
 	if (iapp == NULL)
 		return;
 
-	assoc = sta->last_assoc_req;
-	seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
-
 	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
 	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
 		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
 	iapp_send_layer2_update(iapp, sta->addr);
 	iapp_send_add(iapp, sta->addr, seq);
 
-	if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
-	    WLAN_FC_STYPE_REASSOC_REQ) {
-		/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
-		 *                   Context Block, Timeout)
-		 */
-		/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
-		 * IP address */
-	}
+	/* TODO: If this was reassociation:
+	 * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
+	 *                   Context Block, Timeout)
+	 * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
+	 * IP address */
 }
 
 
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c97cef1..14fb567 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1445,17 +1445,6 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
-	if (reassoc) {
-		os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
-			  ETH_ALEN);
-	}
-
-	if (sta->last_assoc_req)
-		os_free(sta->last_assoc_req);
-	sta->last_assoc_req = os_malloc(len);
-	if (sta->last_assoc_req)
-		os_memcpy(sta->last_assoc_req, mgmt, len);
-
 	/* Make sure that the previously registered inactivity timer will not
 	 * remove the STA immediately. */
 	sta->timeout_next = STA_NULLFUNC;
@@ -1924,7 +1913,7 @@
 		status = le_to_host16(mgmt->u.assoc_resp.status_code);
 
 	if (status != WLAN_STATUS_SUCCESS)
-		goto fail;
+		return;
 
 	/* Stop previous accounting session, if one is started, and allocate
 	 * new session id for the new session. */
@@ -1986,7 +1975,7 @@
 		ap_sta_disconnect(hapd, sta, sta->addr,
 				  WLAN_REASON_DISASSOC_AP_BUSY);
 
-		goto fail;
+		return;
 	}
 
 	if (sta->flags & WLAN_STA_WDS) {
@@ -2006,11 +1995,11 @@
 		 * interface selection is not going to change anymore.
 		 */
 		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
-			goto fail;
+			return;
 	} else if (sta->vlan_id) {
 		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
 		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
-			goto fail;
+			return;
 	}
 
 	hostapd_set_sta_flags(hapd, sta);
@@ -2022,13 +2011,6 @@
 	hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
 
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
-
- fail:
-	/* Copy of the association request is not needed anymore */
-	if (sta->last_assoc_req) {
-		os_free(sta->last_assoc_req);
-		sta->last_assoc_req = NULL;
-	}
 }
 
 
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index a166178..138d049 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -54,7 +54,20 @@
 		scan_params->width_trigger_scan_interval =
 			host_to_le16(hapd->iconf->obss_interval);
 
-		/* TODO: Fill in more parameters (supplicant ignores them) */
+		/* Fill in default values for remaining parameters
+		 * (IEEE Std 802.11-2012, 8.4.2.61 and MIB defval) */
+		scan_params->scan_passive_dwell =
+			host_to_le16(20);
+		scan_params->scan_active_dwell =
+			host_to_le16(10);
+		scan_params->scan_passive_total_per_channel =
+			host_to_le16(200);
+		scan_params->scan_active_total_per_channel =
+			host_to_le16(20);
+		scan_params->channel_transition_delay_factor =
+			host_to_le16(5);
+		scan_params->scan_activity_threshold =
+			host_to_le16(25);
 
 		pos += sizeof(*scan_params);
 	}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index b78fd01..12403f9 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -170,6 +170,8 @@
 
 	switch (idx) {
 	case 0: /* Bits 0-7 */
+		if (hapd->iconf->obss_interval)
+			*pos |= 0x01; /* Bit 0 - Coexistence management */
 		break;
 	case 1: /* Bits 8-15 */
 		break;
@@ -223,6 +225,8 @@
 		len = 4;
 	if (len < 3 && hapd->conf->wnm_sleep_mode)
 		len = 3;
+	if (len < 1 && hapd->iconf->obss_interval)
+		len = 1;
 	if (len < 7 && hapd->conf->ssid.utf8_ssid)
 		len = 7;
 #ifdef CONFIG_WNM
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index c7d051b..f5417de 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -239,7 +239,6 @@
 		radius_client_flush_auth(hapd->radius, sta->addr);
 #endif /* CONFIG_NO_RADIUS */
 
-	os_free(sta->last_assoc_req);
 	os_free(sta->challenge);
 
 #ifdef CONFIG_IEEE80211W
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index c0bab6f..2dbdeb1 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -61,7 +61,6 @@
 	unsigned int hs20_deauth_requested:1;
 
 	u16 auth_alg;
-	u8 previous_ap[6];
 
 	enum {
 		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE,
@@ -74,9 +73,6 @@
 	/* IEEE 802.1X related data */
 	struct eapol_state_machine *eapol_sm;
 
-	/* IEEE 802.11f (IAPP) related data */
-	struct ieee80211_mgmt *last_assoc_req;
-
 	u32 acct_session_id_hi;
 	u32 acct_session_id_lo;
 	struct os_reltime acct_session_start;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7d89edf..4d19bb0 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1918,7 +1918,9 @@
 static int ieee80211w_kde_len(struct wpa_state_machine *sm)
 {
 	if (sm->mgmt_frame_prot) {
-		return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+		size_t len;
+		len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+		return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
 	}
 
 	return 0;
@@ -1930,6 +1932,7 @@
 	struct wpa_igtk_kde igtk;
 	struct wpa_group *gsm = sm->group;
 	u8 rsc[WPA_KEY_RSC_LEN];
+	size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
 
 	if (!sm->mgmt_frame_prot)
 		return pos;
@@ -1941,17 +1944,18 @@
 		os_memset(igtk.pn, 0, sizeof(igtk.pn));
 	else
 		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
-	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
 	if (sm->wpa_auth->conf.disable_gtk) {
 		/*
 		 * Provide unique random IGTK to each STA to prevent use of
 		 * IGTK in the BSS.
 		 */
-		if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+		if (random_get_bytes(igtk.igtk, len) < 0)
 			return pos;
 	}
 	pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
-			  (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+			  (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
+			  NULL, 0);
 
 	return pos;
 }
@@ -2457,15 +2461,16 @@
 
 #ifdef CONFIG_IEEE80211W
 	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		size_t len;
+		len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
 		os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
 		inc_byte_array(group->Counter, WPA_NONCE_LEN);
 		if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
 				   wpa_auth->addr, group->GNonce,
-				   group->IGTK[group->GN_igtk - 4],
-				   WPA_IGTK_LEN) < 0)
+				   group->IGTK[group->GN_igtk - 4], len) < 0)
 			ret = -1;
 		wpa_hexdump_key(MSG_DEBUG, "IGTK",
-				group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
+				group->IGTK[group->GN_igtk - 4], len);
 	}
 #endif /* CONFIG_IEEE80211W */
 
@@ -2582,26 +2587,27 @@
 {
 	struct wpa_group *gsm = sm->group;
 	u8 *start = pos;
+	size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
 
 	/*
 	 * IGTK subelement:
 	 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
 	 */
 	*pos++ = WNM_SLEEP_SUBELEM_IGTK;
-	*pos++ = 2 + 6 + WPA_IGTK_LEN;
+	*pos++ = 2 + 6 + len;
 	WPA_PUT_LE16(pos, gsm->GN_igtk);
 	pos += 2;
 	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
 		return 0;
 	pos += 6;
 
-	os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
-	pos += WPA_IGTK_LEN;
+	os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+	pos += len;
 
 	wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
 		   gsm->GN_igtk);
 	wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
-			gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+			gsm->IGTK[gsm->GN_igtk - 4], len);
 
 	return pos - start;
 }
@@ -2656,12 +2662,19 @@
 		ret = -1;
 
 #ifdef CONFIG_IEEE80211W
-	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
-	    wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
-			     broadcast_ether_addr, group->GN_igtk,
-			     group->IGTK[group->GN_igtk - 4],
-			     WPA_IGTK_LEN) < 0)
-		ret = -1;
+	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		enum wpa_alg alg;
+		size_t len;
+
+		alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
+		len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+
+		if (ret == 0 &&
+		    wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+				     broadcast_ether_addr, group->GN_igtk,
+				     group->IGTK[group->GN_igtk - 4], len) < 0)
+			ret = -1;
+	}
 #endif /* CONFIG_IEEE80211W */
 
 	return ret;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index d99db69..3ab3e3d 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -142,6 +142,7 @@
 	int tx_status;
 #ifdef CONFIG_IEEE80211W
 	enum mfp_options ieee80211w;
+	int group_mgmt_cipher;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
 #define SSID_LEN 32
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index da5fea7..6ee9a4f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -49,6 +49,7 @@
 	wconf->okc = conf->okc;
 #ifdef CONFIG_IEEE80211W
 	wconf->ieee80211w = conf->ieee80211w;
+	wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
 	wconf->ssid_len = conf->ssid.ssid_len;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index fcd5878..2e1bdcf 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -154,7 +154,7 @@
 	Boolean first_sta_seen;
 	Boolean reject_4way_hs_for_entropy;
 #ifdef CONFIG_IEEE80211W
-	u8 IGTK[2][WPA_IGTK_LEN];
+	u8 IGTK[2][WPA_IGTK_MAX_LEN];
 	int GN_igtk, GM_igtk;
 #endif /* CONFIG_IEEE80211W */
 };
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 7a49751..e957c6e 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -261,7 +261,25 @@
 		}
 
 		/* Management Group Cipher Suite */
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		switch (conf->group_mgmt_cipher) {
+		case WPA_CIPHER_AES_128_CMAC:
+			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+			break;
+		case WPA_CIPHER_BIP_GMAC_128:
+			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
+			break;
+		case WPA_CIPHER_BIP_GMAC_256:
+			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
+			break;
+		case WPA_CIPHER_BIP_CMAC_256:
+			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG,
+				   "Invalid group management cipher (0x%x)",
+				   conf->group_mgmt_cipher);
+			return -1;
+		}
 		pos += RSN_SELECTOR_LEN;
 	}
 #endif /* CONFIG_IEEE80211W */
@@ -586,7 +604,8 @@
 			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
 		}
 
-		if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+		if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
+		{
 			wpa_printf(MSG_DEBUG, "Unsupported management group "
 				   "cipher %d", data.mgmt_group_cipher);
 			return WPA_INVALID_MGMT_GROUP_CIPHER;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 27f58aa..adb22c7 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -368,6 +368,8 @@
 		return WPA_CIPHER_BIP_GMAC_256;
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
 		return WPA_CIPHER_BIP_CMAC_256;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
+		return WPA_CIPHER_GTK_NOT_USED;
 	return 0;
 }
 
@@ -400,6 +402,26 @@
 }
 
 
+static int wpa_cipher_valid_group(int cipher)
+{
+	return wpa_cipher_valid_pairwise(cipher) ||
+		cipher == WPA_CIPHER_WEP104 ||
+		cipher == WPA_CIPHER_WEP40 ||
+		cipher == WPA_CIPHER_GTK_NOT_USED;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_cipher_valid_mgmt_group(int cipher)
+{
+	return cipher == WPA_CIPHER_AES_128_CMAC ||
+		cipher == WPA_CIPHER_BIP_GMAC_128 ||
+		cipher == WPA_CIPHER_BIP_GMAC_256 ||
+		cipher == WPA_CIPHER_BIP_CMAC_256;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
 /**
  * wpa_parse_wpa_ie_rsn - Parse RSN IE
  * @rsn_ie: Buffer containing RSN IE
@@ -455,13 +477,11 @@
 
 	if (left >= RSN_SELECTOR_LEN) {
 		data->group_cipher = rsn_selector_to_bitfield(pos);
-#ifdef CONFIG_IEEE80211W
-		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
-			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
-				   "cipher", __func__);
+		if (!wpa_cipher_valid_group(data->group_cipher)) {
+			wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
+				   __func__, data->group_cipher);
 			return -1;
 		}
-#endif /* CONFIG_IEEE80211W */
 		pos += RSN_SELECTOR_LEN;
 		left -= RSN_SELECTOR_LEN;
 	} else if (left > 0) {
@@ -546,7 +566,7 @@
 #ifdef CONFIG_IEEE80211W
 	if (left >= 4) {
 		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
-		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+		if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
 			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
 				   "group cipher 0x%x", __func__,
 				   data->mgmt_group_cipher);
@@ -1103,9 +1123,13 @@
 	switch (cipher) {
 	case WPA_CIPHER_CCMP_256:
 	case WPA_CIPHER_GCMP_256:
+	case WPA_CIPHER_BIP_GMAC_256:
+	case WPA_CIPHER_BIP_CMAC_256:
 		return 32;
 	case WPA_CIPHER_CCMP:
 	case WPA_CIPHER_GCMP:
+	case WPA_CIPHER_AES_128_CMAC:
+	case WPA_CIPHER_BIP_GMAC_128:
 		return 16;
 	case WPA_CIPHER_TKIP:
 		return 32;
@@ -1153,6 +1177,14 @@
 	case WPA_CIPHER_WEP104:
 	case WPA_CIPHER_WEP40:
 		return WPA_ALG_WEP;
+	case WPA_CIPHER_AES_128_CMAC:
+		return WPA_ALG_IGTK;
+	case WPA_CIPHER_BIP_GMAC_128:
+		return WPA_ALG_BIP_GMAC_128;
+	case WPA_CIPHER_BIP_GMAC_256:
+		return WPA_ALG_BIP_GMAC_256;
+	case WPA_CIPHER_BIP_CMAC_256:
+		return WPA_ALG_BIP_CMAC_256;
 	}
 	return WPA_ALG_NONE;
 }
@@ -1193,6 +1225,14 @@
 			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
 	if (cipher & WPA_CIPHER_GTK_NOT_USED)
 		return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
+	if (cipher & WPA_CIPHER_AES_128_CMAC)
+		return RSN_CIPHER_SUITE_AES_128_CMAC;
+	if (cipher & WPA_CIPHER_BIP_GMAC_128)
+		return RSN_CIPHER_SUITE_BIP_GMAC_128;
+	if (cipher & WPA_CIPHER_BIP_GMAC_256)
+		return RSN_CIPHER_SUITE_BIP_GMAC_256;
+	if (cipher & WPA_CIPHER_BIP_CMAC_256)
+		return RSN_CIPHER_SUITE_BIP_CMAC_256;
 	return 0;
 }
 
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 5684ef3..c0b2caa 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -77,9 +77,7 @@
 #endif
 #define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
 #define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
-#ifdef CONFIG_IEEE80211W
 #define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
-#endif /* CONFIG_IEEE80211W */
 #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
 #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
 #define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
@@ -130,6 +128,7 @@
 
 #ifdef CONFIG_IEEE80211W
 #define WPA_IGTK_LEN 16
+#define WPA_IGTK_MAX_LEN 32
 #endif /* CONFIG_IEEE80211W */
 
 
@@ -285,10 +284,11 @@
 } STRUCT_PACKED;
 
 #ifdef CONFIG_IEEE80211W
+#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
 struct wpa_igtk_kde {
 	u8 keyid[2];
 	u8 pn[6];
-	u8 igtk[WPA_IGTK_LEN];
+	u8 igtk[WPA_IGTK_MAX_LEN];
 } STRUCT_PACKED;
 #endif /* CONFIG_IEEE80211W */
 
@@ -409,6 +409,7 @@
 int wpa_cipher_rsc_len(int cipher);
 int wpa_cipher_to_alg(int cipher);
 int wpa_cipher_valid_pairwise(int cipher);
+int wpa_cipher_valid_mgmt_group(int cipher);
 u32 wpa_cipher_to_suite(int proto, int cipher);
 int rsn_cipher_put_suites(u8 *pos, int ciphers);
 int wpa_cipher_put_suites(u8 *pos, int ciphers);
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 81e588f..65e0f79 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -544,6 +544,11 @@
 #define TLS_BREAK_VERIFY_DATA BIT(0)
 #define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
 #define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
+#define TLS_DHE_PRIME_511B BIT(3)
+#define TLS_DHE_PRIME_767B BIT(4)
+#define TLS_DHE_PRIME_15 BIT(5)
+#define TLS_DHE_PRIME_58B BIT(6)
+#define TLS_DHE_NON_PRIME BIT(7)
 
 void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
 
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 2e40db1..a32cfac 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -618,7 +618,8 @@
 
 	if (dev == NULL)
 		dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg);
-	else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
+	else if ((dev->flags & P2P_DEV_PROBE_REQ_ONLY) ||
+		  !(dev->flags & P2P_DEV_REPORTED))
 		p2p_add_dev_info(p2p, sa, dev, &msg);
 	else if (!dev->listen_freq && !dev->oper_freq) {
 		/*
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index c929fe1..f2ea393 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -554,6 +554,26 @@
 		srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature");
 		eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE;
 		break;
+	case 4:
+		srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime");
+		eap_conf->tls_test_flags = TLS_DHE_PRIME_511B;
+		break;
+	case 5:
+		srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime");
+		eap_conf->tls_test_flags = TLS_DHE_PRIME_767B;
+		break;
+	case 6:
+		srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\"");
+		eap_conf->tls_test_flags = TLS_DHE_PRIME_15;
+		break;
+	case 7:
+		srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container");
+		eap_conf->tls_test_flags = TLS_DHE_PRIME_58B;
+		break;
+	case 8:
+		srv_log(sess, "TLS test - RSA-DHE using a non-prime");
+		eap_conf->tls_test_flags = TLS_DHE_NON_PRIME;
+		break;
 	default:
 		srv_log(sess, "Unrecognized TLS test");
 		break;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8a978f7..9b8ca6b 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1466,6 +1466,29 @@
 }
 
 
+static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde,
+			       struct wpa_tdls_peer *peer)
+{
+	struct wmm_information_element *wmm;
+
+	if (!kde->wmm) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received");
+		return 0;
+	}
+
+	if (kde->wmm_len < sizeof(struct wmm_information_element)) {
+		wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received");
+		return -1;
+	}
+
+	wmm = (struct wmm_information_element *) kde->wmm;
+	peer->qos_info = wmm->qos_info;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info);
+	return 0;
+}
+
+
 static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde,
 				   struct wpa_tdls_peer *peer)
 {
@@ -1638,6 +1661,10 @@
 
 	peer->qos_info = kde.qosinfo;
 
+	/* Overwrite with the qos_info obtained in WMM IE */
+	if (copy_peer_wmm_capab(&kde, peer) < 0)
+		goto error;
+
 	peer->aid = kde.aid;
 
 #ifdef CONFIG_TDLS_TESTING
@@ -2018,6 +2045,10 @@
 
 	peer->qos_info = kde.qosinfo;
 
+	/* Overwrite with the qos_info obtained in WMM IE */
+	if (copy_peer_wmm_capab(&kde, peer) < 0)
+		goto error;
+
 	peer->aid = kde.aid;
 
 	if (!wpa_tdls_get_privacy(sm)) {
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index de86cdf..77d7991 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -742,13 +742,15 @@
 			       struct wpa_eapol_ie_parse *ie)
 {
 #ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+	if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
 		return 0;
 
 	if (ie->igtk) {
+		size_t len;
 		const struct wpa_igtk_kde *igtk;
 		u16 keyidx;
-		if (ie->igtk_len != sizeof(*igtk))
+		len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+		if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
 			return -1;
 		igtk = (const struct wpa_igtk_kde *) ie->igtk;
 		keyidx = WPA_GET_LE16(igtk->keyid);
@@ -756,15 +758,16 @@
 			"pn %02x%02x%02x%02x%02x%02x",
 			keyidx, MAC2STR(igtk->pn));
 		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
-				igtk->igtk, WPA_IGTK_LEN);
+				igtk->igtk, len);
 		if (keyidx > 4095) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Invalid IGTK KeyID %d", keyidx);
 			return -1;
 		}
-		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+				   broadcast_ether_addr,
 				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
-				   igtk->igtk, WPA_IGTK_LEN) < 0) {
+				   igtk->igtk, len) < 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Failed to configure IGTK to the driver");
 			return -1;
@@ -1097,7 +1100,10 @@
 		goto failed;
 	}
 
-	if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
+	if (ie.igtk &&
+	    wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
+	    ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
+	    (unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Invalid IGTK KDE length %lu",
 			(unsigned long) ie.igtk_len);
@@ -2748,17 +2754,19 @@
 		}
 #ifdef CONFIG_IEEE80211W
 	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+		keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
 		os_memcpy(igd.keyid, buf + 2, 2);
 		os_memcpy(igd.pn, buf + 4, 6);
 
 		keyidx = WPA_GET_LE16(igd.keyid);
-		os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
+		os_memcpy(igd.igtk, buf + 10, keylen);
 
 		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
-				igd.igtk, WPA_IGTK_LEN);
-		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+				igd.igtk, keylen);
+		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+				   broadcast_ether_addr,
 				   keyidx, 0, igd.pn, sizeof(igd.pn),
-				   igd.igtk, WPA_IGTK_LEN) < 0) {
+				   igd.igtk, keylen) < 0) {
 			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
 				   "WNM mode");
 			return -1;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 610b65a..2329033 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -201,7 +201,7 @@
 	}
 
 #ifdef CONFIG_IEEE80211W
-	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+	if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
 		if (!sm->cur_pmksa) {
 			/* PMKID Count */
 			WPA_PUT_LE16(pos, 0);
@@ -209,7 +209,8 @@
 		}
 
 		/* Management Group Cipher Suite */
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+							  mgmt_group_cipher));
 		pos += RSN_SELECTOR_LEN;
 	}
 #endif /* CONFIG_IEEE80211W */
@@ -311,6 +312,42 @@
 
 
 /**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+				     struct wpa_eapol_ie_parse *ie)
+{
+	unsigned int oui;
+
+	if (pos[1] < 4) {
+		wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
+			   pos[1]);
+		return 1;
+	}
+
+	oui = WPA_GET_BE24(&pos[2]);
+	if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+		if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+			ie->wmm = &pos[2];
+			ie->wmm_len = pos[1];
+			wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+				    ie->wmm, ie->wmm_len);
+		} else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+			ie->wmm = &pos[2];
+			ie->wmm_len = pos[1];
+			wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+				    ie->wmm, ie->wmm_len);
+		}
+	}
+	return 0;
+}
+
+
+/**
  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
  * @pos: Pointer to the IE header
  * @end: Pointer to the end of the Key Data buffer
@@ -540,6 +577,14 @@
 				ret = 0;
 				break;
 			}
+
+			ret = wpa_parse_vendor_specific(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
 		} else {
 			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
 				    "Key Data IE", pos, 2 + pos[1]);
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 82b6fa3..0fc42cc 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -59,6 +59,8 @@
 	size_t supp_oper_classes_len;
 	u8 qosinfo;
 	u16 aid;
+	const u8 *wmm;
+	size_t wmm_len;
 #ifdef CONFIG_P2P
 	const u8 *ip_addr_req;
 	const u8 *ip_addr_alloc;
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 8367e36..f78921d 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -409,12 +409,37 @@
 }
 
 
+static unsigned int count_bits(const u8 *val, size_t len)
+{
+	size_t i;
+	unsigned int bits;
+	u8 tmp;
+
+	for (i = 0; i < len; i++) {
+		if (val[i])
+			break;
+	}
+	if (i == len)
+		return 0;
+
+	bits = (len - i - 1) * 8;
+	tmp = val[i];
+	while (tmp) {
+		bits++;
+		tmp >>= 1;
+	}
+
+	return bits;
+}
+
+
 static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 					const u8 *buf, size_t len,
 					tls_key_exchange key_exchange)
 {
 	const u8 *pos, *end, *server_params, *server_params_end;
 	u8 alert;
+	unsigned int bits;
 
 	tlsv1_client_free_dh(conn);
 
@@ -431,6 +456,14 @@
 			   (unsigned long) conn->dh_p_len);
 		goto fail;
 	}
+	bits = count_bits(pos, conn->dh_p_len);
+	if (bits < 768) {
+		wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
+			   bits);
+		wpa_hexdump(MSG_DEBUG, "TLSv1: Rejected DH prime",
+			    pos, conn->dh_p_len);
+		goto fail;
+	}
 	conn->dh_p = os_malloc(conn->dh_p_len);
 	if (conn->dh_p == NULL)
 		goto fail;
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 4aeccf6..23d0b81 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -316,7 +316,7 @@
 		}
 
 #ifdef CONFIG_TESTING_OPTIONS
-		if ((conn->test_flags &&
+		if ((conn->test_flags &
 		     (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
 		      TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
 		    !conn->test_failure_reported) {
@@ -673,4 +673,110 @@
 {
 	conn->test_flags = flags;
 }
+
+
+static const u8 test_tls_prime15[1] = {
+	15
+};
+
+static const u8 test_tls_prime511b[64] = {
+	0x50, 0xfb, 0xf1, 0xae, 0x01, 0xf1, 0xfe, 0xe6,
+	0xe1, 0xae, 0xdc, 0x1e, 0xbe, 0xfb, 0x9e, 0x58,
+	0x9a, 0xd7, 0x54, 0x9d, 0x6b, 0xb3, 0x78, 0xe2,
+	0x39, 0x7f, 0x30, 0x01, 0x25, 0xa1, 0xf9, 0x7c,
+	0x55, 0x0e, 0xa1, 0x15, 0xcc, 0x36, 0x34, 0xbb,
+	0x6c, 0x8b, 0x64, 0x45, 0x15, 0x7f, 0xd3, 0xe7,
+	0x31, 0xc8, 0x8e, 0x56, 0x8e, 0x95, 0xdc, 0xea,
+	0x9e, 0xdf, 0xf7, 0x56, 0xdd, 0xb0, 0x34, 0xdb
+};
+
+static const u8 test_tls_prime767b[96] = {
+	0x4c, 0xdc, 0xb8, 0x21, 0x20, 0x9d, 0xe8, 0xa3,
+	0x53, 0xd9, 0x1c, 0x18, 0xc1, 0x3a, 0x58, 0x67,
+	0xa7, 0x85, 0xf9, 0x28, 0x9b, 0xce, 0xc0, 0xd1,
+	0x05, 0x84, 0x61, 0x97, 0xb2, 0x86, 0x1c, 0xd0,
+	0xd1, 0x96, 0x23, 0x29, 0x8c, 0xc5, 0x30, 0x68,
+	0x3e, 0xf9, 0x05, 0xba, 0x60, 0xeb, 0xdb, 0xee,
+	0x2d, 0xdf, 0x84, 0x65, 0x49, 0x87, 0x90, 0x2a,
+	0xc9, 0x8e, 0x34, 0x63, 0x6d, 0x9a, 0x2d, 0x32,
+	0x1c, 0x46, 0xd5, 0x4e, 0x20, 0x20, 0x90, 0xac,
+	0xd5, 0x48, 0x79, 0x99, 0x0c, 0xe6, 0xed, 0xbf,
+	0x79, 0xc2, 0x47, 0x50, 0x95, 0x38, 0x38, 0xbc,
+	0xde, 0xb0, 0xd2, 0xe8, 0x97, 0xcb, 0x22, 0xbb
+};
+
+static const u8 test_tls_prime58[128] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0xc1, 0xba, 0xc8, 0x25, 0xbe, 0x2d, 0xf3
+};
+
+static const u8 test_tls_non_prime[] = {
+	/*
+	 * This is not a prime and the value has the following factors:
+	 * 13736783488716579923 * 16254860191773456563 * 18229434976173670763 *
+	 * 11112313018289079419 * 10260802278580253339 * 12394009491575311499 *
+	 * 12419059668711064739 * 14317973192687985827 * 10498605410533203179 *
+	 * 16338688760390249003 * 11128963991123878883 * 12990532258280301419 *
+	 * 3
+	 */
+	0x0C, 0x8C, 0x36, 0x9C, 0x6F, 0x71, 0x2E, 0xA7,
+	0xAB, 0x32, 0xD3, 0x0F, 0x68, 0x3D, 0xB2, 0x6D,
+	0x81, 0xDD, 0xC4, 0x84, 0x0D, 0x9C, 0x6E, 0x36,
+	0x29, 0x70, 0xF3, 0x1E, 0x9A, 0x42, 0x0B, 0x67,
+	0x82, 0x6B, 0xB1, 0xF2, 0xAF, 0x55, 0x28, 0xE7,
+	0xDB, 0x67, 0x6C, 0xF7, 0x6B, 0xAC, 0xAC, 0xE5,
+	0xF7, 0x9F, 0xD4, 0x63, 0x55, 0x70, 0x32, 0x7C,
+	0x70, 0xFB, 0xAF, 0xB8, 0xEB, 0x37, 0xCF, 0x3F,
+	0xFE, 0x94, 0x73, 0xF9, 0x7A, 0xC7, 0x12, 0x2E,
+	0x9B, 0xB4, 0x7D, 0x08, 0x60, 0x83, 0x43, 0x52,
+	0x83, 0x1E, 0xA5, 0xFC, 0xFA, 0x87, 0x12, 0xF4,
+	0x64, 0xE2, 0xCE, 0x71, 0x17, 0x72, 0xB6, 0xAB
+};
+
 #endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+			   size_t *dh_p_len)
+{
+	*dh_p = conn->cred->dh_p;
+	*dh_p_len = conn->cred->dh_p_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (conn->test_flags & TLS_DHE_PRIME_511B) {
+		tlsv1_server_log(conn, "TESTING: Use short 511-bit prime with DHE");
+		*dh_p = test_tls_prime511b;
+		*dh_p_len = sizeof(test_tls_prime511b);
+	} else if (conn->test_flags & TLS_DHE_PRIME_767B) {
+		tlsv1_server_log(conn, "TESTING: Use short 767-bit prime with DHE");
+		*dh_p = test_tls_prime767b;
+		*dh_p_len = sizeof(test_tls_prime767b);
+	} else if (conn->test_flags & TLS_DHE_PRIME_15) {
+		tlsv1_server_log(conn, "TESTING: Use bogus 15 \"prime\" with DHE");
+		*dh_p = test_tls_prime15;
+		*dh_p_len = sizeof(test_tls_prime15);
+	} else if (conn->test_flags & TLS_DHE_PRIME_58B) {
+		tlsv1_server_log(conn, "TESTING: Use short 58-bit prime in long container with DHE");
+		*dh_p = test_tls_prime58;
+		*dh_p_len = sizeof(test_tls_prime58);
+	} else if (conn->test_flags & TLS_DHE_NON_PRIME) {
+		tlsv1_server_log(conn, "TESTING: Use claim non-prime as the DHE prime");
+		*dh_p = test_tls_non_prime;
+		*dh_p_len = sizeof(test_tls_non_prime);
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+}
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 9a36d8f..96d79b3 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -78,5 +78,7 @@
 			     u8 description, size_t *out_len);
 int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
 				   const u8 *buf, size_t *len);
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+			   size_t *dh_p_len);
 
 #endif /* TLSV1_SERVER_I_H */
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 04622b5..c34545e 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -31,7 +31,9 @@
 {
 #ifdef CONFIG_TESTING_OPTIONS
 	if ((conn->test_flags &
-	     (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+	     (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE |
+	      TLS_DHE_PRIME_511B | TLS_DHE_PRIME_767B | TLS_DHE_PRIME_15 |
+	      TLS_DHE_PRIME_58B | TLS_DHE_NON_PRIME)) &&
 	    suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
 	    suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
 	    suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
@@ -590,6 +592,8 @@
 	u8 *shared;
 	size_t shared_len;
 	int res;
+	const u8 *dh_p;
+	size_t dh_p_len;
 
 	/*
 	 * struct {
@@ -641,7 +645,9 @@
 		return -1;
 	}
 
-	shared_len = conn->cred->dh_p_len;
+	tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
+	shared_len = dh_p_len;
 	shared = os_malloc(shared_len);
 	if (shared == NULL) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
@@ -653,8 +659,7 @@
 
 	/* shared = Yc^secret mod p */
 	if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
-			   conn->dh_secret_len,
-			   conn->cred->dh_p, conn->cred->dh_p_len,
+			   conn->dh_secret_len, dh_p, dh_p_len,
 			   shared, &shared_len)) {
 		os_free(shared);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -994,6 +999,36 @@
 		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
 		conn->test_failure_reported = 1;
 	}
+
+	if ((conn->test_flags & TLS_DHE_PRIME_15) &&
+	    !conn->test_failure_reported) {
+		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after bogus DHE \"prime\" 15");
+		conn->test_failure_reported = 1;
+	}
+
+	if ((conn->test_flags & TLS_DHE_PRIME_58B) &&
+	    !conn->test_failure_reported) {
+		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after short 58-bit DHE prime in long container");
+		conn->test_failure_reported = 1;
+	}
+
+	if ((conn->test_flags & TLS_DHE_PRIME_511B) &&
+	    !conn->test_failure_reported) {
+		tlsv1_server_log(conn, "TEST-WARNING: Client Finished received after short 511-bit DHE prime (insecure)");
+		conn->test_failure_reported = 1;
+	}
+
+	if ((conn->test_flags & TLS_DHE_PRIME_767B) &&
+	    !conn->test_failure_reported) {
+		tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after 767-bit DHE prime (relatively insecure)");
+		conn->test_failure_reported = 1;
+	}
+
+	if ((conn->test_flags & TLS_DHE_NON_PRIME) &&
+	    !conn->test_failure_reported) {
+		tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after non-prime claimed as DHE prime");
+		conn->test_failure_reported = 1;
+	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index 619b9ab..15e6692 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -248,6 +248,8 @@
 	size_t rlen;
 	u8 *dh_ys;
 	size_t dh_ys_len;
+	const u8 *dh_p;
+	size_t dh_p_len;
 
 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
 	if (suite == NULL)
@@ -273,8 +275,10 @@
 		return -1;
 	}
 
+	tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
 	os_free(conn->dh_secret);
-	conn->dh_secret_len = conn->cred->dh_p_len;
+	conn->dh_secret_len = dh_p_len;
 	conn->dh_secret = os_malloc(conn->dh_secret_len);
 	if (conn->dh_secret == NULL) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
@@ -293,8 +297,7 @@
 		return -1;
 	}
 
-	if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
-	    0)
+	if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
 		conn->dh_secret[0] = 0; /* make sure secret < p */
 
 	pos = conn->dh_secret;
@@ -309,7 +312,7 @@
 			conn->dh_secret, conn->dh_secret_len);
 
 	/* Ys = g^secret mod p */
-	dh_ys_len = conn->cred->dh_p_len;
+	dh_ys_len = dh_p_len;
 	dh_ys = os_malloc(dh_ys_len);
 	if (dh_ys == NULL) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
@@ -320,8 +323,7 @@
 	}
 	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
 			   conn->dh_secret, conn->dh_secret_len,
-			   conn->cred->dh_p, conn->cred->dh_p_len,
-			   dh_ys, &dh_ys_len)) {
+			   dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		os_free(dh_ys);
@@ -369,7 +371,7 @@
 	/* body - ServerDHParams */
 	server_params = pos;
 	/* dh_p */
-	if (pos + 2 + conn->cred->dh_p_len > end) {
+	if (pos + 2 + dh_p_len > end) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 			   "dh_p");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -377,10 +379,10 @@
 		os_free(dh_ys);
 		return -1;
 	}
-	WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+	WPA_PUT_BE16(pos, dh_p_len);
 	pos += 2;
-	os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
-	pos += conn->cred->dh_p_len;
+	os_memcpy(pos, dh_p, dh_p_len);
+	pos += dh_p_len;
 
 	/* dh_g */
 	if (pos + 2 + conn->cred->dh_g_len > end) {
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 70d6a17..89f1366 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -265,6 +265,29 @@
 
 static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
 {
+	if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) &&
+	    wps->wps->network_key_len == 0) {
+		char hex[65];
+		u8 psk[32];
+		/* Generate a random per-device PSK */
+		if (random_get_bytes(psk, sizeof(psk)) < 0)
+			return -1;
+		wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
+				psk, sizeof(psk));
+		wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%u)",
+			   (unsigned int) wps->new_psk_len * 2);
+		wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk));
+		wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
+		wpabuf_put_be16(msg, sizeof(psk) * 2);
+		wpabuf_put_data(msg, hex, sizeof(psk) * 2);
+		if (wps->wps->registrar) {
+			wps_cb_new_psk(wps->wps->registrar,
+				       wps->peer_dev.mac_addr,
+				       wps->p2p_dev_addr, psk, sizeof(psk));
+		}
+		return 0;
+	}
+
 	wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%u)",
 		   (unsigned int) wps->wps->network_key_len);
 	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 22070db..f7154f8 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -212,5 +212,7 @@
 			      const u8 *addr, const u8 *uuid_e);
 void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
 				       struct wps_nfc_pw_token *token);
+int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
+		   const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len);
 
 #endif /* WPS_I_H */
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 6d879be..900dd5a 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1170,8 +1170,8 @@
 }
 
 
-static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
-			  const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len)
+int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
+		   const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len)
 {
 	if (reg->new_psk_cb == NULL)
 		return 0;