Cumulative patch from commit 3b208346ec56342fda736e62601df485ed002493

3b20834 ctrl_iface: BSS command to skip info items if parsing fails
a9c52e8 HS 2.0R2: No longer use HTTP_RAW_POST_DATA
04c18fa curl: Don't free memory for subjectAltName before calling callback
5a8e48f mesh: Use MESH_CAP_* macros for mesh capability
d70a8ab mesh: Ignore crowded peer
a151b0e mesh: Select pairwise and group cipher based on network profile
3b6deac mesh: Avoid use of hardcoded cipher
f868d56 mesh: Clean up AMPE element encoding and parsing
4367eec mesh: Do not use RX MGTK as RX IGTK
a4eec3c mesh: Use variable length MGTK for RX
fccba2c mesh: Generate a separate TX IGTK if PMF is enabled
696f792 mesh: Support variable length TX MGTK
b02f4d0 mesh: Add variable length MTK support
846201d mesh: Coding style cleanup for MTK derivation
0f76d82 mesh: Fix MTK derivation to use AKM suite selector
f5ba692 mesh: Coding style cleanup for AEK derivation
a59c5e9 mesh: Fix AEK derivation to use AKM suite selector
18aca1a mesh: Use ieee80211w profile parameter
b8b499e mesh: Use WPA_NONCE_LEN macro
bb4e19e hostapd: Skip hostapd ACL check for drivers supporting ACL offload
00ec535 WPS: Fix memory leak with wps_ie in wpa_bss_is_wps_candidate()
d1296da Reserve QCA vendor specific nl80211 command 121
fae7b37 WPS: Do not expire probable BSSes for WPS connection
52a6c9c Add a QCA vendor command to configure AP parameters
31d3692 hostapd: Add comment about '-i' parameter in hostapd.conf
40f6282 hostapd: Accept interface names as a command line parameter
cc27c8e hostapd: Fix early init failure path
976dfb3 FST: Make fst_global_deinit() more robust
7a69fad mesh: Sync max peer links with kernel
f7cb6e9 Update PKCS#11 references in template wpa_supplicant.conf
c3d7fb7 OpenSSL: Initialise PKCS#11 engine even if found with ENGINE_by_id()
fdc1188 nl80211: Fix use-after-free in qca_nl80211_get_features()
8359472 hostapd Make GAS Address3 field selection behavior configurable
6996ff7 hostapd: Fix Public Action frame TX status processing for wildcard BSSID
78a3632 hostapd: Fix Public Action frame addressing (BSSID field)
c86bef2 wpa_supplicant: Make GAS Address3 field selection behavior configurable
a5a187b nl80211: Add TEST_FAIL() to command generation and set_mode
ee854ff mesh: Remove extra newline from the end of an error message
331f077 mesh: Allow 160 MHz channel to be configured
92a515b nl80211: Update drv->assoc_freq on mesh join
d2cc8bb mesh: Remove unreachable code
cc9a257 nl80211: Use extended capabilities per interface type
c6edea0 Sync with mac80211-next.git include/uapi/linux/nl80211.h
9a5160f Report connection timeouts in CTRL-EVENT-ASSOC-REJECT
dad0129 mesh: Support simple SAE group negotiation case
b4c738e mesh: Fix error path handling for RSN (MGTK init)
f4b4ddf D-Bus: Remove unused wpas_dbus_signal_p2p_group_started() parameter
4fe50bb D-Bus: Indicate whether created group is persistent or not
62fc8e6 mesh: Fix MESH_INTERFACE_ADD error path cleanup
9c10be3 mesh: Fix error path handling in init OOM cases
7012e25 Remove dead code from wpas_sched_scan_plans_set()
8e909fa Improve reattach scan OOM failure handling
f37d8a4 Indicate scan failure event on parameter cloning failure
9356823 wpaspy: Fix potentially referencing non existing attribute

Change-Id: I656be560523c206195a5bf8649e73d8aa70bd8f9
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index dbeaa3c..6dc7e8c 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3481,6 +3481,8 @@
 		if (atoi(pos))
 			bss->radio_measurements[0] |=
 				WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+	} else if (os_strcmp(buf, "gas_address3") == 0) {
+		bss->gas_address3 = atoi(pos);
 	} else {
 		wpa_printf(MSG_ERROR,
 			   "Line %d: unknown configuration item '%s'",
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index c62fc7e..c244624 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -3,6 +3,8 @@
 
 # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
 # management frames with the Host AP driver); wlan0 with many nl80211 drivers
+# Note: This attribute can be overridden by the values supplied with the '-i'
+# command line parameter.
 interface=wlan0
 
 # In case of atheros and nl80211 driver interfaces, an additional
@@ -1747,6 +1749,13 @@
 # For example, AP Civic Location ANQP-element with unknown location:
 #anqp_elem=266:000000
 
+# GAS Address 3 behavior
+# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
+#     based on GAS request Address3
+# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
+# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
+#gas_address3=0
+
 # QoS Map Set configuration
 #
 # Comma delimited QoS Map Set in decimal values
diff --git a/hostapd/main.c b/hostapd/main.c
index 1d9e63e..2c8dbd3 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -217,11 +217,20 @@
 		iface->drv_flags = capa.flags;
 		iface->smps_modes = capa.smps_modes;
 		iface->probe_resp_offloads = capa.probe_resp_offloads;
+		/*
+		 * Use default extended capa values from per-radio information
+		 */
 		iface->extended_capa = capa.extended_capa;
 		iface->extended_capa_mask = capa.extended_capa_mask;
 		iface->extended_capa_len = capa.extended_capa_len;
 		iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
 
+		/*
+		 * Override extended capa with per-interface type (AP), if
+		 * available from the driver.
+		 */
+		hostapd_get_ext_capa(iface);
+
 		triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
 		if (triggs && hapd->driver->set_wowlan) {
 			if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
@@ -242,7 +251,7 @@
  * interfaces. No actiual driver operations are started.
  */
 static struct hostapd_iface *
-hostapd_interface_init(struct hapd_interfaces *interfaces,
+hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
 		       const char *config_fname, int debug)
 {
 	struct hostapd_iface *iface;
@@ -252,6 +261,12 @@
 	iface = hostapd_init(interfaces, config_fname);
 	if (!iface)
 		return NULL;
+
+	if (if_name) {
+		os_strlcpy(iface->conf->bss[0]->iface, if_name,
+			   sizeof(iface->conf->bss[0]->iface));
+	}
+
 	iface->interfaces = interfaces;
 
 	for (k = 0; k < debug; k++) {
@@ -261,7 +276,8 @@
 
 	if (iface->conf->bss[0]->iface[0] == '\0' &&
 	    !hostapd_drv_none(iface->bss[0])) {
-		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+		wpa_printf(MSG_ERROR,
+			   "Interface name not specified in %s, nor by '-i' parameter",
 			   config_fname);
 		hostapd_interface_deinit_free(iface);
 		return NULL;
@@ -330,6 +346,7 @@
 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
 		return -1;
 	}
+	interfaces->eloop_initialized = 1;
 
 	random_init(entropy_file);
 
@@ -357,7 +374,7 @@
 }
 
 
-static void hostapd_global_deinit(const char *pid_file)
+static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
 {
 	int i;
 
@@ -375,7 +392,8 @@
 
 	random_deinit();
 
-	eloop_destroy();
+	if (eloop_initialized)
+		eloop_destroy();
 
 #ifndef CONFIG_NATIVE_WINDOWS
 	closelog();
@@ -445,7 +463,8 @@
 		"\n"
 		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
 		"\\\n"
-		"         [-g <global ctrl_iface>] [-G <group>] \\\n"
+		"         [-g <global ctrl_iface>] [-G <group>]\\\n"
+		"         [-i <comma-separated list of interface names>]\\\n"
 		"         <configuration file(s)>\n"
 		"\n"
 		"options:\n"
@@ -464,6 +483,7 @@
 		"   -T = record to Linux tracing in addition to logging\n"
 		"        (records all messages regardless of debug verbosity)\n"
 #endif /* CONFIG_DEBUG_LINUX_TRACING */
+		"   -i   list of interface names to use\n"
 		"   -S   start all the interfaces synchronously\n"
 		"   -t   include timestamps in some debug messages\n"
 		"   -v   show hostapd version\n");
@@ -527,6 +547,43 @@
 }
 
 
+static int hostapd_get_interface_names(char ***if_names,
+				       size_t *if_names_size,
+				       char *optarg)
+{
+	char *if_name, *tmp, **nnames;
+	size_t i;
+
+	if (!optarg)
+		return -1;
+	if_name = strtok_r(optarg, ",", &tmp);
+
+	while (if_name) {
+		nnames = os_realloc_array(*if_names, 1 + *if_names_size,
+					  sizeof(char *));
+		if (!nnames)
+			goto fail;
+		*if_names = nnames;
+
+		(*if_names)[*if_names_size] = os_strdup(if_name);
+		if (!(*if_names)[*if_names_size])
+			goto fail;
+		(*if_names_size)++;
+		if_name = strtok_r(NULL, ",", &tmp);
+	}
+
+	return 0;
+
+fail:
+	for (i = 0; i < *if_names_size; i++)
+		os_free((*if_names)[i]);
+	os_free(*if_names);
+	*if_names = NULL;
+	*if_names_size = 0;
+	return -1;
+}
+
+
 #ifdef CONFIG_WPS
 static int gen_uuid(const char *txt_addr)
 {
@@ -585,6 +642,8 @@
 	int enable_trace_dbg = 0;
 #endif /* CONFIG_DEBUG_LINUX_TRACING */
 	int start_ifaces_in_sync = 0;
+	char **if_names = NULL;
+	size_t if_names_size = 0;
 
 	if (os_program_init())
 		return -1;
@@ -602,7 +661,7 @@
 	dl_list_init(&interfaces.global_ctrl_dst);
 
 	for (;;) {
-		c = getopt(argc, argv, "b:Bde:f:hKP:STtu:vg:G:");
+		c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -666,6 +725,11 @@
 		case 'u':
 			return gen_uuid(optarg);
 #endif /* CONFIG_WPS */
+		case 'i':
+			if (hostapd_get_interface_names(&if_names,
+							&if_names_size, optarg))
+				goto out;
+			break;
 		default:
 			usage();
 			break;
@@ -723,7 +787,13 @@
 
 	/* Allocate and parse configuration for full interface files */
 	for (i = 0; i < interfaces.count; i++) {
+		char *if_name = NULL;
+
+		if (i < if_names_size)
+			if_name = if_names[i];
+
 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
+							     if_name,
 							     argv[optind + i],
 							     debug);
 		if (!interfaces.iface[i]) {
@@ -807,8 +877,9 @@
 	}
 	os_free(interfaces.iface);
 
-	eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
-	hostapd_global_deinit(pid_file);
+	if (interfaces.eloop_initialized)
+		eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
+	hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
 	os_free(pid_file);
 
 	if (log_file)
@@ -817,6 +888,10 @@
 
 	os_free(bss_config);
 
+	for (i = 0; i < if_names_size; i++)
+		os_free(if_names[i]);
+	os_free(if_names);
+
 	fst_global_deinit();
 
 	os_program_deinit();
diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php
index dde4434..002d028 100644
--- a/hs20/server/www/spp.php
+++ b/hs20/server/www/spp.php
@@ -96,7 +96,8 @@
   putenv("HS20USER");
 
 putenv("HS20REALM=$realm");
-putenv("HS20POST=$HTTP_RAW_POST_DATA");
+$postdata = file_get_contents("php://input");
+putenv("HS20POST=$postdata");
 $addr = $_SERVER["REMOTE_ADDR"];
 putenv("HS20ADDR=$addr");
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b263eb0..0ae9a6e 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -41,6 +41,10 @@
 #define MESH_CONF_SEC_AUTH BIT(1)
 #define MESH_CONF_SEC_AMPE BIT(2)
 	unsigned int security;
+	enum mfp_options ieee80211w;
+	unsigned int pairwise_cipher;
+	unsigned int group_cipher;
+	unsigned int mgmt_group_cipher;
 	int dot11MeshMaxRetries;
 	int dot11MeshRetryTimeout; /* msec */
 	int dot11MeshConfirmTimeout; /* msec */
@@ -504,6 +508,7 @@
 
 	u16 gas_comeback_delay;
 	int gas_frag_limit;
+	int gas_address3;
 
 	u8 qos_map_set[16 + 2 * 21];
 	unsigned int qos_map_set_len;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index dca6b8b..532b72f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -675,6 +675,36 @@
 			    unsigned int wait, const u8 *dst, const u8 *data,
 			    size_t len)
 {
+	const u8 *bssid;
+	const u8 wildcard_bssid[ETH_ALEN] = {
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	};
+
+	if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+		return 0;
+	bssid = hapd->own_addr;
+	if (!is_multicast_ether_addr(dst) &&
+	    len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+		struct sta_info *sta;
+
+		/*
+		 * Public Action frames to a STA that is not a member of the BSS
+		 * shall use wildcard BSSID value.
+		 */
+		sta = ap_get_sta(hapd, dst);
+		if (!sta || !(sta->flags & WLAN_STA_ASSOC))
+			bssid = wildcard_bssid;
+	}
+	return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+					 hapd->own_addr, bssid, data, len, 0);
+}
+
+
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+				     unsigned int freq,
+				     unsigned int wait, const u8 *dst,
+				     const u8 *data, size_t len)
+{
 	if (hapd->driver == NULL || hapd->driver->send_action == NULL)
 		return 0;
 	return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
@@ -750,6 +780,20 @@
 }
 
 
+void hostapd_get_ext_capa(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+
+	if (!hapd->driver || !hapd->driver->get_ext_capab)
+		return;
+
+	hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
+				    &iface->extended_capa,
+				    &iface->extended_capa_mask,
+				    &iface->extended_capa_len);
+}
+
+
 int hostapd_drv_do_acs(struct hostapd_data *hapd)
 {
 	struct drv_acs_params params;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 6ea1dab..6406d13 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -99,6 +99,10 @@
 int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
 			    unsigned int wait, const u8 *dst, const u8 *data,
 			    size_t len);
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+				     unsigned int freq,
+				     unsigned int wait, const u8 *dst,
+				     const u8 *data, size_t len);
 int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
 			 u16 auth_alg);
 int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
@@ -124,6 +128,8 @@
 int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
 			    u8 qos_map_set_len);
 
+void hostapd_get_ext_capa(struct hostapd_iface *iface);
+
 static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
 						  int enabled)
 {
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3ab5bf3..3552b3e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -116,8 +116,15 @@
 	}
 	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 
-	res = hostapd_check_acl(hapd, addr, NULL);
-	if (res != HOSTAPD_ACL_ACCEPT) {
+	/*
+	 * ACL configurations to the drivers (implementing AP SME and ACL
+	 * offload) without hostapd's knowledge, can result in a disconnection
+	 * though the driver accepts the connection. Skip the hostapd check for
+	 * ACL if the driver supports ACL offload to avoid potentially
+	 * conflicting ACL rules.
+	 */
+	if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
+	    hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
 		wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
 			   MAC2STR(addr));
 		reason = WLAN_REASON_UNSPECIFIED;
@@ -916,11 +923,24 @@
 			       size_t len, u16 stype, int ok)
 {
 	struct ieee80211_hdr *hdr;
+	struct hostapd_data *orig_hapd = hapd;
 
 	hdr = (struct ieee80211_hdr *) buf;
 	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
-	if (hapd == NULL || hapd == HAPD_BROADCAST)
+	if (!hapd)
 		return;
+	if (hapd == HAPD_BROADCAST) {
+		if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
+		    buf[24] != WLAN_ACTION_PUBLIC)
+			return;
+		hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+		if (!hapd || hapd == HAPD_BROADCAST)
+			return;
+		/*
+		 * Allow processing of TX status for a Public Action frame that
+		 * used wildcard BBSID.
+		 */
+	}
 	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
 }
 
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 179dc7a..6ce178d 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1166,7 +1166,8 @@
 
 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
 					  const u8 *sa, u8 dialog_token,
-					  struct anqp_query_info *qi, int prot)
+					  struct anqp_query_info *qi, int prot,
+					  int std_addr3)
 {
 	struct wpabuf *buf, *tx_buf;
 
@@ -1227,15 +1228,22 @@
 		return;
 	if (prot)
 		convert_to_protected_dual(tx_buf);
-	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
-				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	if (std_addr3)
+		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+					wpabuf_head(tx_buf),
+					wpabuf_len(tx_buf));
+	else
+		hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+						 wpabuf_head(tx_buf),
+						 wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
 }
 
 
 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
 					const u8 *sa,
-					const u8 *data, size_t len, int prot)
+					const u8 *data, size_t len, int prot,
+					int std_addr3)
 {
 	const u8 *pos = data;
 	const u8 *end = data + len;
@@ -1287,8 +1295,15 @@
 		wpabuf_put_le16(buf, 0); /* Query Response Length */
 		if (prot)
 			convert_to_protected_dual(buf);
-		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
-					wpabuf_head(buf), wpabuf_len(buf));
+		if (std_addr3)
+			hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+						wpabuf_head(buf),
+						wpabuf_len(buf));
+		else
+			hostapd_drv_send_action_addr3_ap(hapd,
+							 hapd->iface->freq, 0,
+							 sa, wpabuf_head(buf),
+							 wpabuf_len(buf));
 		wpabuf_free(buf);
 		return;
 	}
@@ -1338,13 +1353,15 @@
 		pos += elen;
 	}
 
-	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
+	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
+				      std_addr3);
 }
 
 
 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
 					 const u8 *sa,
-					 const u8 *data, size_t len, int prot)
+					 const u8 *data, size_t len, int prot,
+					 int std_addr3)
 {
 	struct gas_dialog_info *dialog;
 	struct wpabuf *buf, *tx_buf;
@@ -1420,8 +1437,14 @@
 send_resp:
 	if (prot)
 		convert_to_protected_dual(tx_buf);
-	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
-				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	if (std_addr3)
+		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+					wpabuf_head(tx_buf),
+					wpabuf_len(tx_buf));
+	else
+		hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+						 wpabuf_head(tx_buf),
+						 wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
 }
 
@@ -1432,7 +1455,7 @@
 	struct hostapd_data *hapd = ctx;
 	const struct ieee80211_mgmt *mgmt;
 	const u8 *sa, *data;
-	int prot;
+	int prot, std_addr3;
 
 	mgmt = (const struct ieee80211_mgmt *) buf;
 	if (len < IEEE80211_HDRLEN + 2)
@@ -1447,14 +1470,22 @@
 	 */
 	prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
 	sa = mgmt->sa;
+	if (hapd->conf->gas_address3 == 1)
+		std_addr3 = 1;
+	else if (hapd->conf->gas_address3 == 2)
+		std_addr3 = 0;
+	else
+		std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
 	len -= IEEE80211_HDRLEN + 1;
 	data = buf + IEEE80211_HDRLEN + 1;
 	switch (data[0]) {
 	case WLAN_PA_GAS_INITIAL_REQ:
-		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
+		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
+					    std_addr3);
 		break;
 	case WLAN_PA_GAS_COMEBACK_REQ:
-		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
+		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+					     std_addr3);
 		break;
 	}
 }
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 42c1aaa..30f57f4 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -206,10 +206,12 @@
 
 
 static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
-					      char *ifname)
+					      const char *ifname)
 {
 	int i;
 
+	if (!ifname)
+		return;
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
 		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
 					0, NULL, 0, NULL, 0)) {
@@ -2005,6 +2007,8 @@
 
 static void hostapd_bss_deinit(struct hostapd_data *hapd)
 {
+	if (!hapd)
+		return;
 	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
 		   hapd->conf->iface);
 	hostapd_bss_deinit_no_free(hapd);
@@ -2039,8 +2043,11 @@
 	}
 #endif /* CONFIG_FST */
 
-	for (j = iface->num_bss - 1; j >= 0; j--)
+	for (j = iface->num_bss - 1; j >= 0; j--) {
+		if (!iface->bss)
+			break;
 		hostapd_bss_deinit(iface->bss[j]);
+	}
 }
 
 
@@ -2049,6 +2056,8 @@
 	size_t j;
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	for (j = 0; j < iface->num_bss; j++) {
+		if (!iface->bss)
+			break;
 		wpa_printf(MSG_DEBUG, "%s: free hapd %p",
 			   __func__, iface->bss[j]);
 		os_free(iface->bss[j]);
@@ -2849,8 +2858,8 @@
 void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
 {
 	wpa_printf(MSG_INFO, "%s: interface state %s->%s",
-		   iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
-		   hostapd_state_text(s));
+		   iface->conf ? iface->conf->bss[0]->iface : "N/A",
+		   hostapd_state_text(iface->state), hostapd_state_text(s));
 	iface->state = s;
 }
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 4dba8cb..195679e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -53,6 +53,7 @@
 #ifndef CONFIG_NO_VLAN
 	struct dynamic_iface *vlan_priv;
 #endif /* CONFIG_NO_VLAN */
+	int eloop_initialized;
 };
 
 enum hostapd_chan_status {
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 781afa2..f6fca67 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -518,6 +518,9 @@
 	if (sae_check_big_sync(sta))
 		return;
 	sta->sae->sync++;
+	wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
+		   " (sync=%d state=%d)",
+		   MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
 
 	switch (sta->sae->state) {
 	case SAE_COMMITTED:
@@ -724,6 +727,44 @@
 }
 
 
+static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct sae_data *sae = sta->sae;
+	int i, *groups = hapd->conf->sae_groups;
+
+	if (sae->state != SAE_COMMITTED)
+		return;
+
+	wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
+
+	for (i = 0; groups && groups[i] > 0; i++) {
+		if (sae->group == groups[i])
+			break;
+	}
+
+	if (!groups || groups[i] <= 0) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE: Previously selected group not found from the current configuration");
+		return;
+	}
+
+	for (;;) {
+		i++;
+		if (groups[i] <= 0) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: No alternative group enabled");
+			return;
+		}
+
+		if (sae_set_group(sae, groups[i]) < 0)
+			continue;
+
+		break;
+	}
+	wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
+}
+
+
 static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 			    const struct ieee80211_mgmt *mgmt, size_t len,
 			    u16 auth_transaction, u16 status_code)
@@ -811,6 +852,16 @@
 			return;
 		}
 
+		if ((hapd->conf->mesh & MESH_ENABLED) &&
+		    status_code ==
+		    WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+		    sta->sae->tmp) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: Peer did not accept our SAE group");
+			sae_pick_next_group(hapd, sta);
+			goto remove_sta;
+		}
+
 		if (status_code != WLAN_STATUS_SUCCESS)
 			goto remove_sta;
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index c49402d..5d4d0c8 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -12,6 +12,7 @@
 #ifdef CONFIG_MESH
 /* needed for mesh_plink_state enum */
 #include "common/defs.h"
+#include "common/wpa_common.h"
 #endif /* CONFIG_MESH */
 
 #include "list.h"
@@ -81,11 +82,19 @@
 	u16 my_lid;
 	u16 mpm_close_reason;
 	int mpm_retries;
-	u8 my_nonce[32];
-	u8 peer_nonce[32];
+	u8 my_nonce[WPA_NONCE_LEN];
+	u8 peer_nonce[WPA_NONCE_LEN];
 	u8 aek[32];	/* SHA256 digest length */
-	u8 mtk[16];
-	u8 mgtk[16];
+	u8 mtk[WPA_TK_MAX_LEN];
+	size_t mtk_len;
+	u8 mgtk_rsc[6];
+	u8 mgtk_key_id;
+	u8 mgtk[WPA_TK_MAX_LEN];
+	size_t mgtk_len;
+	u8 igtk_rsc[6];
+	u8 igtk[WPA_TK_MAX_LEN];
+	size_t igtk_len;
+	u16 igtk_key_id;
 	u8 sae_auth_retry;
 #endif /* CONFIG_MESH */
 
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 5be747b..02d2ad7 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -757,9 +757,14 @@
 	u8 selected_pairwise_suite[4];
 	u8 local_nonce[32];
 	u8 peer_nonce[32];
-	u8 mgtk[16];
-	u8 key_rsc[8];
-	u8 key_expiration[4];
+	/* Followed by
+	 * Key Replay Counter[8] (optional)
+	 *	(only in Mesh Group Key Inform/Acknowledge frames)
+	 * GTKdata[variable] (optional)
+	 *	(MGTK[variable] || Key RSC[8] || GTKExpirationTime[4])
+	 * IGTKdata[variable] (optional)
+	 *	(Key ID[2], IPN[6], IGTK[variable] in IGTK KDE format)
+	 */
 } STRUCT_PACKED;
 
 #ifdef _MSC_VER
@@ -1332,6 +1337,14 @@
 #define MESH_PATH_PROTOCOL_VENDOR	255
 #define MESH_PATH_METRIC_AIRTIME	1
 #define MESH_PATH_METRIC_VENDOR		255
+/* IEEE 802.11s - Mesh Capability */
+#define MESH_CAP_ACCEPT_ADDITIONAL_PEER	BIT(0)
+#define MESH_CAP_MCCA_SUPPORTED		BIT(1)
+#define MESH_CAP_MCCA_ENABLED		BIT(2)
+#define MESH_CAP_FORWARDING		BIT(3)
+#define MESH_CAP_MBCA_ENABLED		BIT(4)
+#define MESH_CAP_TBTT_ADJUSTING		BIT(5)
+#define MESH_CAP_MESH_PS_LEVEL		BIT(6)
 
 enum plink_action_field {
 	PLINK_OPEN = 1,
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 7759023..896c66a 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -166,9 +166,11 @@
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
 	/* 110..114 - reserved for QCA */
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
-	/* 116..118 - reserved for QCA */
+	/* 116..117 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
 	QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
 	QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
+	/* 121 - reserved for QCA */
 };
 
 
@@ -565,4 +567,23 @@
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ */
+enum qca_wlan_vendor_attr_sap_config {
+	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
+	/* 1 - reserved for QCA */
+	/* List of frequencies on which AP is expected to operate.
+	 * This is irrespective of ACS configuration. This list is a priority
+	 * based one and is looked for before the AP is created to ensure the
+	 * best concurrency sessions (avoid MCC and use DBS/SCC) co-exist in
+	 * the system.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+
+	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
+	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index c831fba..23ac64b 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -729,10 +729,16 @@
 
 	engine = ENGINE_by_id(id);
 	if (engine) {
-		ENGINE_free(engine);
 		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
 			   "available", id);
-		return 0;
+		/*
+		 * If it was auto-loaded by ENGINE_by_id() we might still
+		 * need to tell it which PKCS#11 module to use in legacy
+		 * (non-p11-kit) environments. Do so now; even if it was
+		 * properly initialised before, setting it again will be
+		 * harmless.
+		 */
+		goto found;
 	}
 	ERR_clear_error();
 
@@ -769,7 +775,7 @@
 			   id, ERR_error_string(ERR_get_error(), NULL));
 		return -1;
 	}
-
+ found:
 	while (post && post[0]) {
 		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
 		if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 4675be2..edb6978 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3560,6 +3560,19 @@
 	 * Returns: 0 on success or -1 on failure
 	 */
 	int (*configure_data_frame_filters)(void *priv, u32 filter_flags);
+
+	/**
+	 * get_ext_capab - Get extended capabilities for the specified interface
+	 * @priv: Private driver interface data
+	 * @type: Interface type for which to get extended capabilities
+	 * @ext_capab: Extended capabilities fetched
+	 * @ext_capab_mask: Extended capabilities mask
+	 * @ext_capab_len: Length of the extended capabilities
+	 * Returns: 0 on success or -1 on failure
+	 */
+	int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
+			     const u8 **ext_capab, const u8 **ext_capab_mask,
+			     unsigned int *ext_capab_len);
 };
 
 
@@ -4429,6 +4442,12 @@
 		 * status_code - Status Code from (Re)association Response
 		 */
 		u16 status_code;
+
+		/**
+		 * timed_out - Whether failure is due to timeout (etc.) rather
+		 * than explicit rejection response from the AP.
+		 */
+		int timed_out;
 	} assoc_reject;
 
 	struct timeout_event {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 12a417b..e7a818a 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -445,6 +445,8 @@
 void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
 		   struct nl_msg *msg, int flags, uint8_t cmd)
 {
+	if (TEST_FAIL())
+		return NULL;
 	return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
 			   0, flags, cmd, 0);
 }
@@ -2412,6 +2414,7 @@
 static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+	unsigned int i;
 
 	wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
 		   bss->ifname, drv->disabled_11b_rates);
@@ -2508,6 +2511,10 @@
 
 	os_free(drv->extended_capa);
 	os_free(drv->extended_capa_mask);
+	for (i = 0; i < drv->num_iface_ext_capa; i++) {
+		os_free(drv->iface_ext_capa[i].ext_capa);
+		os_free(drv->iface_ext_capa[i].ext_capa_mask);
+	}
 	os_free(drv->first_bss);
 	os_free(drv);
 }
@@ -4162,7 +4169,7 @@
 }
 
 
-static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+const char * nl80211_iftype_str(enum nl80211_iftype mode)
 {
 	switch (mode) {
 	case NL80211_IFTYPE_ADHOC:
@@ -5113,6 +5120,9 @@
 	int res;
 	int mode_switch_res;
 
+	if (TEST_FAIL())
+		return -1;
+
 	mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
 	if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
 		mode_switch_res = 0;
@@ -8417,8 +8427,7 @@
 	if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
 	    nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
 		goto fail;
-	if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
-	    nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+	if (nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
 			params->max_peer_links))
 		goto fail;
 
@@ -8442,7 +8451,7 @@
 		goto fail;
 	}
 	ret = 0;
-	bss->freq = params->freq.freq;
+	drv->assoc_freq = bss->freq = params->freq.freq;
 	wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
 
 fail:
@@ -9202,6 +9211,39 @@
 }
 
 
+static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
+				 const u8 **ext_capa, const u8 **ext_capa_mask,
+				 unsigned int *ext_capa_len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	enum nl80211_iftype nlmode;
+	unsigned int i;
+
+	if (!ext_capa || !ext_capa_mask || !ext_capa_len)
+		return -1;
+
+	nlmode = wpa_driver_nl80211_if_type(type);
+
+	/* By default, use the per-radio values */
+	*ext_capa = drv->extended_capa;
+	*ext_capa_mask = drv->extended_capa_mask;
+	*ext_capa_len = drv->extended_capa_len;
+
+	/* Replace the default value if a per-interface type value exists */
+	for (i = 0; i < drv->num_iface_ext_capa; i++) {
+		if (nlmode == drv->iface_ext_capa[i].iftype) {
+			*ext_capa = drv->iface_ext_capa[i].ext_capa;
+			*ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
+			*ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -9319,4 +9361,5 @@
 	.set_prob_oper_freq = nl80211_set_prob_oper_freq,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 	.configure_data_frame_filters = nl80211_configure_data_frame_filters,
+	.get_ext_capab = nl80211_get_ext_capab,
 };
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index b0d2b6d..283dfd9 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -96,6 +96,13 @@
 	struct wpa_driver_capa capa;
 	u8 *extended_capa, *extended_capa_mask;
 	unsigned int extended_capa_len;
+	struct drv_nl80211_ext_capa {
+		enum nl80211_iftype iftype;
+		u8 *ext_capa, *ext_capa_mask;
+		unsigned int ext_capa_len;
+	} iface_ext_capa[NL80211_IFTYPE_MAX];
+	unsigned int num_iface_ext_capa;
+
 	int has_capability;
 
 	int operstate;
@@ -251,6 +258,8 @@
 int process_global_event(struct nl_msg *msg, void *arg);
 int process_bss_event(struct nl_msg *msg, void *arg);
 
+const char * nl80211_iftype_str(enum nl80211_iftype mode);
+
 #ifdef ANDROID
 int android_nl_socket_set_nonblocking(struct nl_handle *handle);
 int android_pno_start(struct i802_bss *bss,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 8f07bcb..1ebbdaa 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -486,6 +486,74 @@
 }
 
 
+static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr *tb)
+{
+	int rem = 0, i;
+	struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr;
+
+	if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+		return;
+
+	nla_for_each_nested(attr, tb, rem) {
+		unsigned int len;
+		struct drv_nl80211_ext_capa *capa;
+
+		nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr),
+			  nla_len(attr), NULL);
+
+		if (!tb1[NL80211_ATTR_IFTYPE] ||
+		    !tb1[NL80211_ATTR_EXT_CAPA] ||
+		    !tb1[NL80211_ATTR_EXT_CAPA_MASK])
+			continue;
+
+		capa = &drv->iface_ext_capa[drv->num_iface_ext_capa];
+		capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Driver-advertised extended capabilities for interface type %s",
+			   nl80211_iftype_str(capa->iftype));
+
+		len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]);
+		capa->ext_capa = os_malloc(len);
+		if (!capa->ext_capa)
+			goto err;
+
+		os_memcpy(capa->ext_capa, nla_data(tb1[NL80211_ATTR_EXT_CAPA]),
+			  len);
+		capa->ext_capa_len = len;
+		wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities",
+			    capa->ext_capa, capa->ext_capa_len);
+
+		len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]);
+		capa->ext_capa_mask = os_malloc(len);
+		if (!capa->ext_capa_mask)
+			goto err;
+
+		os_memcpy(capa->ext_capa_mask,
+			  nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]), len);
+		wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask",
+			    capa->ext_capa_mask, capa->ext_capa_len);
+
+		drv->num_iface_ext_capa++;
+		if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+			break;
+	}
+
+	return;
+
+err:
+	/* Cleanup allocated memory on error */
+	for (i = 0; i < NL80211_IFTYPE_MAX; i++) {
+		os_free(drv->iface_ext_capa[i].ext_capa);
+		drv->iface_ext_capa[i].ext_capa = NULL;
+		os_free(drv->iface_ext_capa[i].ext_capa_mask);
+		drv->iface_ext_capa[i].ext_capa_mask = NULL;
+		drv->iface_ext_capa[i].ext_capa_len = 0;
+	}
+	drv->num_iface_ext_capa = 0;
+}
+
+
 static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 {
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -576,6 +644,9 @@
 				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
 			drv->extended_capa_len =
 				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+			wpa_hexdump(MSG_DEBUG,
+				    "nl80211: Driver-advertised extended capabilities (default)",
+				    drv->extended_capa, drv->extended_capa_len);
 		}
 		drv->extended_capa_mask =
 			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
@@ -583,6 +654,10 @@
 			os_memcpy(drv->extended_capa_mask,
 				  nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
 				  nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+			wpa_hexdump(MSG_DEBUG,
+				    "nl80211: Driver-advertised extended capabilities mask (default)",
+				    drv->extended_capa_mask,
+				    drv->extended_capa_len);
 		} else {
 			os_free(drv->extended_capa);
 			drv->extended_capa = NULL;
@@ -590,6 +665,8 @@
 		}
 	}
 
+	wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
+
 	if (tb[NL80211_ATTR_VENDOR_DATA]) {
 		struct nlattr *nl;
 		int rem;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index bd16edb..961a2e4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -265,6 +265,7 @@
 			       enum nl80211_commands cmd, struct nlattr *status,
 			       struct nlattr *addr, struct nlattr *req_ie,
 			       struct nlattr *resp_ie,
+			       struct nlattr *timed_out,
 			       struct nlattr *authorized,
 			       struct nlattr *key_replay_ctr,
 			       struct nlattr *ptk_kck,
@@ -322,6 +323,7 @@
 			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
 		}
 		event.assoc_reject.status_code = status_code;
+		event.assoc_reject.timed_out = timed_out != NULL;
 		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
 		return;
 	}
@@ -1644,6 +1646,7 @@
 			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
 			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
 			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+			   NULL,
 			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
 			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
 			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
@@ -2132,6 +2135,7 @@
 				   tb[NL80211_ATTR_MAC],
 				   tb[NL80211_ATTR_REQ_IE],
 				   tb[NL80211_ATTR_RESP_IE],
+				   tb[NL80211_ATTR_TIMED_OUT],
 				   NULL, NULL, NULL, NULL, NULL);
 		break;
 	case NL80211_CMD_CH_SWITCH_NOTIFY:
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index b460628..53c8278 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -493,7 +493,12 @@
  *	This attribute is ignored if driver does not support roam scan.
  *	It is also sent as an event, with the BSSID and response IEs when the
  *	connection is established or failed to be established. This can be
- *	determined by the STATUS_CODE attribute.
+ *	determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success,
+ *	non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the
+ *	event, the connection attempt failed due to not being able to initiate
+ *	authentication/association or not receiving a response from the AP.
+ *	Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
+ *	well to remain backwards compatible.
  * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
  *	sent as an event when the card/driver roamed by itself.
  * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
@@ -1817,6 +1822,13 @@
  * @NL80211_ATTR_STA_SUPPORT_P2P_PS: whether P2P PS mechanism supported
  *	or not. u8, one of the values of &enum nl80211_sta_p2p_ps_status
  *
+ * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
+ *
+ * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
+ *	%NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
+ *	%NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
+ *	interface type.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2197,6 +2209,10 @@
 
 	NL80211_ATTR_STA_SUPPORT_P2P_PS,
 
+	NL80211_ATTR_PAD,
+
+	NL80211_ATTR_IFTYPE_EXT_CAPA,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2511,6 +2527,9 @@
  *	TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
  *	each one of those is again nested with &enum nl80211_tid_stats
  *	attributes carrying the actual values.
+ * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
+ *	received from the station (u64, usec)
+ * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2547,6 +2566,8 @@
 	NL80211_STA_INFO_BEACON_RX,
 	NL80211_STA_INFO_BEACON_SIGNAL_AVG,
 	NL80211_STA_INFO_TID_STATS,
+	NL80211_STA_INFO_RX_DURATION,
+	NL80211_STA_INFO_PAD,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -2563,6 +2584,7 @@
  *	transmitted MSDUs (not counting the first attempt; u64)
  * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
  *	MSDUs (u64)
+ * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
  * @NUM_NL80211_TID_STATS: number of attributes here
  * @NL80211_TID_STATS_MAX: highest numbered attribute here
  */
@@ -2572,6 +2594,7 @@
 	NL80211_TID_STATS_TX_MSDU,
 	NL80211_TID_STATS_TX_MSDU_RETRIES,
 	NL80211_TID_STATS_TX_MSDU_FAILED,
+	NL80211_TID_STATS_PAD,
 
 	/* keep last */
 	NUM_NL80211_TID_STATS,
@@ -3008,6 +3031,7 @@
  *	transmitting data (on channel or globally)
  * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
  *	(on this channel or globally)
+ * @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
  * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
  *	currently defined
  * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -3023,6 +3047,7 @@
 	NL80211_SURVEY_INFO_TIME_RX,
 	NL80211_SURVEY_INFO_TIME_TX,
 	NL80211_SURVEY_INFO_TIME_SCAN,
+	NL80211_SURVEY_INFO_PAD,
 
 	/* keep last */
 	__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -3448,6 +3473,7 @@
  * @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry
  *	was last updated by a received frame. The value is expected to be
  *	accurate to about 10ms. (u64, nanoseconds)
+ * @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -3468,6 +3494,7 @@
 	NL80211_BSS_BEACON_TSF,
 	NL80211_BSS_PRESP_DATA,
 	NL80211_BSS_LAST_SEEN_BOOTTIME,
+	NL80211_BSS_PAD,
 
 	/* keep last */
 	__NL80211_BSS_AFTER_LAST,
@@ -3653,11 +3680,15 @@
  * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
  * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
  * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
+ * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
+ *	since newer kernel versions may support more bands
  */
 enum nl80211_band {
 	NL80211_BAND_2GHZ,
 	NL80211_BAND_5GHZ,
 	NL80211_BAND_60GHZ,
+
+	NUM_NL80211_BANDS,
 };
 
 /**
diff --git a/src/fst/fst.c b/src/fst/fst.c
index 40430e2..32cd941 100644
--- a/src/fst/fst.c
+++ b/src/fst/fst.c
@@ -15,6 +15,7 @@
 #include "fst/fst_defs.h"
 #include "fst/fst_ctrl_iface.h"
 
+static int fst_global_initialized = 0;
 struct dl_list fst_global_ctrls_list;
 
 
@@ -106,6 +107,7 @@
 	dl_list_init(&fst_global_groups_list);
 	dl_list_init(&fst_global_ctrls_list);
 	fst_session_global_init();
+	fst_global_initialized = 1;
 	return 0;
 }
 
@@ -115,6 +117,9 @@
 	struct fst_group *group;
 	struct fst_ctrl_handle *h;
 
+	if (!fst_global_initialized)
+		return;
+
 	fst_session_global_deinit();
 	while ((group = fst_first_group()) != NULL)
 		fst_group_delete(group);
@@ -122,6 +127,7 @@
 				  struct fst_ctrl_handle,
 				  global_ctrls_lentry)))
 		fst_global_del_ctrl(h);
+	fst_global_initialized = 0;
 }
 
 
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index d594398..a06aae8 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -857,10 +857,8 @@
 	os_memset(hcert, 0, sizeof(*hcert));
 
 	*names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
-	if (*names) {
+	if (*names)
 		add_alt_names(ctx, hcert, *names);
-		sk_GENERAL_NAME_pop_free(*names, GENERAL_NAME_free);
-	}
 
 	add_logotype_ext(ctx, hcert, cert);
 }
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 1ba2ab3..1e00f35 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -660,6 +660,11 @@
 	if (ieee80211_is_dfs(params.freq.freq))
 		params.freq.freq = 0; /* set channel after CAC */
 
+	if (params.p2p)
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO);
+	else
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS);
+
 	if (wpa_drv_associate(wpa_s, &params) < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
 		return -1;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index a83ca10..3687a2e 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "drivers/driver.h"
+#include "eap_peer/eap.h"
 #include "wpa_supplicant_i.h"
 #include "config.h"
 #include "notify.h"
@@ -303,6 +304,47 @@
 }
 
 
+static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+	struct wpa_ssid *ssid;
+	struct wpabuf *wps_ie;
+	int pbc = 0, ret;
+
+	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+	if (!wps_ie)
+		return 0;
+
+	if (wps_is_selected_pbc_registrar(wps_ie)) {
+		pbc = 1;
+	} else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+		wpabuf_free(wps_ie);
+		return 0;
+	}
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+			continue;
+		if (ssid->ssid_len &&
+		    (ssid->ssid_len != bss->ssid_len ||
+		     os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
+			continue;
+
+		if (pbc)
+			ret = eap_is_wps_pbc_enrollee(&ssid->eap);
+		else
+			ret = eap_is_wps_pin_enrollee(&ssid->eap);
+		wpabuf_free(wps_ie);
+		return ret;
+	}
+	wpabuf_free(wps_ie);
+#endif /* CONFIG_WPS */
+
+	return 0;
+}
+
+
 static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
 	struct wpa_ssid *ssid;
@@ -341,7 +383,8 @@
 	struct wpa_bss *bss;
 
 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (!wpa_bss_known(wpa_s, bss)) {
+		if (!wpa_bss_known(wpa_s, bss) &&
+		    !wpa_bss_is_wps_candidate(wpa_s, bss)) {
 			wpa_bss_remove(wpa_s, bss, __func__);
 			return 0;
 		}
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 674faab..0571c23 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4368,6 +4368,7 @@
 	{ INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
 		    MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
 #endif /*CONFIG_MBO */
+	{ INT(gas_address3), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 786b85a..1535738 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1292,6 +1292,16 @@
 	 */
 	enum mbo_cellular_capa mbo_cell_capa;
 #endif /* CONFIG_MBO */
+
+	/**
+	 * gas_address3 - GAS Address3 field behavior
+	 *
+	 * Values:
+	 * 0 - P2P specification (Address3 = AP BSSID)
+	 * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+	 *	sent to not-associated AP; if associated, AP BSSID)
+	 */
+	int gas_address3;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 939a795..e72f844 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1336,6 +1336,8 @@
 		fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa);
 #endif /* CONFIG_MBO */
 
+	if (config->gas_address3)
+		fprintf(f, "gas_address3=%d\n", config->gas_address3);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e75f1ae..eb1e40a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -4298,9 +4298,10 @@
 	if (mask & WPA_BSS_MASK_P2P_SCAN) {
 		ie = (const u8 *) (bss + 1);
 		ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
-		if (ret < 0 || ret >= end - pos)
+		if (ret >= end - pos)
 			return 0;
-		pos += ret;
+		if (ret > 0)
+			pos += ret;
 	}
 #endif /* CONFIG_P2P */
 
@@ -4381,9 +4382,10 @@
 	if (mask & WPA_BSS_MASK_MESH_SCAN) {
 		ie = (const u8 *) (bss + 1);
 		ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
-		if (ret < 0 || ret >= end - pos)
+		if (ret >= end - pos)
 			return 0;
-		pos += ret;
+		if (ret > 0)
+			pos += ret;
 	}
 #endif /* CONFIG_MESH */
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index d894f6a..0263b2c 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1254,14 +1254,11 @@
  * irrespective of the role (client/GO) of the current device
  *
  * @wpa_s: %wpa_supplicant network interface data
- * @ssid: SSID object
  * @client: this device is P2P client
- * @network_id: network id of the group started, use instead of ssid->id
- *	to account for persistent groups
+ * @persistent: 0 - non persistent group, 1 - persistent group
  */
 void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-					const struct wpa_ssid *ssid,
-					int client, int network_id)
+					int client, int persistent)
 {
 	DBusMessage *msg;
 	DBusMessageIter iter, dict_iter;
@@ -1300,6 +1297,7 @@
 					      wpa_s->dbus_new_path) ||
 	    !wpa_dbus_dict_append_string(&dict_iter, "role",
 					 client ? "client" : "GO") ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
 	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
 					      wpa_s->dbus_groupobj_path) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 3ac66db..d64fcee 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -190,8 +190,7 @@
 				     const u8 *src, u16 dev_passwd_id,
 				     u8 go_intent);
 void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-					const struct wpa_ssid *ssid,
-					int client, int network_id);
+					int client, int persistent);
 void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
 						  const char *reason);
 void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -401,8 +400,7 @@
 
 static inline void
 wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-				   const struct wpa_ssid *ssid,
-				   int client, int network_id)
+				   int client, int persistent)
 {
 }
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 7a213b6..9f104f5 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -158,6 +158,15 @@
 	return -1;
 }
 
+static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s,
+				     const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_s->driver->get_seqnum)
+		return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv,
+						 addr, idx, seq);
+	return -1;
+}
+
 static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
 				     const u8 *addr, int reason_code)
 {
@@ -926,4 +935,15 @@
 							   filters);
 }
 
+static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
+				       enum wpa_driver_if_type type)
+{
+	if (!wpa_s->driver->get_ext_capab)
+		return -1;
+	return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type,
+					    &wpa_s->extended_capa,
+					    &wpa_s->extended_capa_mask,
+					    &wpa_s->extended_capa_len);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index c8d0553..057f630 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3544,13 +3544,15 @@
 	case EVENT_ASSOC_REJECT:
 		if (data->assoc_reject.bssid)
 			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-				"bssid=" MACSTR	" status_code=%u",
+				"bssid=" MACSTR	" status_code=%u%s",
 				MAC2STR(data->assoc_reject.bssid),
-				data->assoc_reject.status_code);
+				data->assoc_reject.status_code,
+				data->assoc_reject.timed_out ? " timeout" : "");
 		else
 			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-				"status_code=%u",
-				data->assoc_reject.status_code);
+				"status_code=%u%s",
+				data->assoc_reject.status_code,
+				data->assoc_reject.timed_out ? " timeout" : "");
 		wpa_s->assoc_status_code = data->assoc_reject.status_code;
 		wpas_notify_assoc_status_code(wpa_s);
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 4f0d0e6..52f50cf 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -17,6 +17,7 @@
 #include "common/wpa_ctrl.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
+#include "config.h"
 #include "driver_i.h"
 #include "offchannel.h"
 #include "gas_query.h"
@@ -273,6 +274,10 @@
 			struct wpabuf *req, unsigned int wait_time)
 {
 	int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+	const u8 *bssid;
+	const u8 wildcard_bssid[ETH_ALEN] = {
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	};
 
 	wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
 		   "freq=%d prot=%d", MAC2STR(query->addr),
@@ -285,8 +290,15 @@
 	if (gas->wpa_s->max_remain_on_chan &&
 	    wait_time > gas->wpa_s->max_remain_on_chan)
 		wait_time = gas->wpa_s->max_remain_on_chan;
+	if (!gas->wpa_s->conf->gas_address3 ||
+	    (gas->wpa_s->current_ssid &&
+	     gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+	     os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))
+		bssid = query->addr;
+	else
+		bssid = wildcard_bssid;
 	res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
-				     gas->wpa_s->own_addr, query->addr,
+				     gas->wpa_s->own_addr, bssid,
 				     wpabuf_head(req), wpabuf_len(req),
 				     wait_time, gas_query_tx_status, 0);
 	if (res == 0)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 89b033b..bf9beb2 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -66,9 +66,11 @@
 }
 
 
-static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
+					     struct wpa_ssid *ssid)
 {
 	struct mesh_conf *conf;
+	int cipher;
 
 	conf = os_zalloc(sizeof(struct mesh_conf));
 	if (!conf)
@@ -82,6 +84,33 @@
 			MESH_CONF_SEC_AMPE;
 	else
 		conf->security |= MESH_CONF_SEC_NONE;
+	conf->ieee80211w = ssid->ieee80211w;
+	if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+		if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
+			conf->ieee80211w = wpa_s->conf->pmf;
+		else
+			conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
+	}
+
+	cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
+	if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
+		wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
+		os_free(conf);
+		return NULL;
+	}
+	conf->pairwise_cipher = cipher;
+
+	cipher = wpa_pick_group_cipher(ssid->group_cipher);
+	if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
+	    cipher == WPA_CIPHER_GTK_NOT_USED) {
+		wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
+		os_free(conf);
+		return NULL;
+	}
+
+	conf->group_cipher = cipher;
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+		conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
 
 	/* defaults */
 	conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -175,19 +204,13 @@
 		wpa_s->conf->dot11RSNASAERetransPeriod;
 	os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
 
-	mconf = mesh_config_create(ssid);
+	mconf = mesh_config_create(wpa_s, ssid);
 	if (!mconf)
 		goto out_free;
 	ifmsh->mconf = mconf;
 
 	/* need conf->hw_mode for supported rates. */
-	if (ssid->frequency == 0) {
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-		conf->channel = 1;
-	} else {
-		conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
-						       &conf->channel);
-	}
+	conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel);
 	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
 		wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
 			   ssid->frequency);
@@ -341,15 +364,9 @@
 
 	wpa_supplicant_mesh_deinit(wpa_s);
 
-	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
-		wpa_s->group_cipher = WPA_CIPHER_CCMP;
-		wpa_s->mgmt_group_cipher = 0;
-	} else {
-		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
-		wpa_s->group_cipher = WPA_CIPHER_NONE;
-		wpa_s->mgmt_group_cipher = 0;
-	}
+	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+	wpa_s->group_cipher = WPA_CIPHER_NONE;
+	wpa_s->mgmt_group_cipher = 0;
 
 	os_memset(&params, 0, sizeof(params));
 	params.meshid = ssid->ssid;
@@ -407,6 +424,12 @@
 		goto out;
 	}
 
+	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+		wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
+		wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
+		wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
+	}
+
 	if (wpa_s->ifmsh) {
 		params.ies = wpa_s->ifmsh->mconf->rsn_ie;
 		params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
@@ -417,7 +440,7 @@
 		wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
 	ret = wpa_drv_join_mesh(wpa_s, &params);
 	if (ret)
-		wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
+		wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
 
 	/* hostapd sets the interface down until we associate */
 	wpa_drv_set_operstate(wpa_s, 1);
@@ -591,7 +614,7 @@
 	if (!mesh_wpa_s) {
 		wpa_printf(MSG_ERROR,
 			   "mesh: Failed to create new wpa_supplicant interface");
-		wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+		wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
 		return -1;
 	}
 	mesh_wpa_s->mesh_if_created = 1;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index a0b7174..8f327d8 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -290,7 +290,8 @@
 		/* TODO: Add Connected to Mesh Gate/AS subfields */
 		wpabuf_put_u8(buf, info);
 		/* always forwarding & accepting plinks for now */
-		wpabuf_put_u8(buf, 0x1 | 0x8);
+		wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
+			      MESH_CAP_FORWARDING);
 	} else {	/* Peer closing frame */
 		/* IE: Mesh ID */
 		wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
@@ -649,6 +650,14 @@
 	struct sta_info *sta;
 	int ret;
 
+	if (elems->mesh_config_len >= 7 &&
+	    !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"mesh: Ignore a crowded peer " MACSTR,
+			MAC2STR(addr));
+		return NULL;
+	}
+
 	sta = ap_get_sta(data, addr);
 	if (!sta) {
 		sta = ap_sta_add(data, addr);
@@ -793,18 +802,32 @@
 		MAC2STR(sta->addr));
 
 	if (conf->security & MESH_CONF_SEC_AMPE) {
-		wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
-				seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
-		wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
-				seq, sizeof(seq),
-				sta->mgtk, sizeof(sta->mgtk));
-		wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
-				seq, sizeof(seq),
-				sta->mgtk, sizeof(sta->mgtk));
+		wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
+		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
+				sta->addr, 0, 0, seq, sizeof(seq),
+				sta->mtk, sta->mtk_len);
 
-		wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
-		wpa_hexdump_key(MSG_DEBUG, "mgtk:",
-				sta->mgtk, sizeof(sta->mgtk));
+		wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
+				sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
+		wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
+				sta->mgtk, sta->mgtk_len);
+		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
+				sta->addr, sta->mgtk_key_id, 0,
+				sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
+				sta->mgtk, sta->mgtk_len);
+
+		if (sta->igtk_len) {
+			wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
+					sta->igtk_rsc, sizeof(sta->igtk_rsc));
+			wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
+					sta->igtk, sta->igtk_len);
+			wpa_drv_set_key(
+				wpa_s,
+				wpa_cipher_to_alg(conf->mgmt_group_cipher),
+				sta->addr, sta->igtk_key_id, 0,
+				sta->igtk_rsc, sizeof(sta->igtk_rsc),
+				sta->igtk, sta->igtk_len);
+		}
 	}
 
 	wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 1994f3f..c5f5d69 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -136,7 +136,8 @@
 }
 
 
-static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
+				enum mfp_options ieee80211w)
 {
 	struct wpa_auth_config conf;
 	struct wpa_auth_callbacks cb;
@@ -145,13 +146,18 @@
 	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
 
 	os_memset(&conf, 0, sizeof(conf));
-	conf.wpa = 2;
+	conf.wpa = WPA_PROTO_RSN;
 	conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
-	conf.wpa_pairwise = WPA_CIPHER_CCMP;
-	conf.rsn_pairwise = WPA_CIPHER_CCMP;
-	conf.wpa_group = WPA_CIPHER_CCMP;
+	conf.wpa_pairwise = rsn->pairwise_cipher;
+	conf.rsn_pairwise = rsn->pairwise_cipher;
+	conf.wpa_group = rsn->group_cipher;
 	conf.eapol_version = 0;
 	conf.wpa_group_rekey = -1;
+#ifdef CONFIG_IEEE80211W
+	conf.ieee80211w = ieee80211w;
+	if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
+		conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
 
 	os_memset(&cb, 0, sizeof(cb));
 	cb.ctx = rsn;
@@ -167,18 +173,34 @@
 	}
 
 	/* TODO: support rekeying */
-	if (random_get_bytes(rsn->mgtk, 16) < 0) {
-		wpa_deinit(rsn->auth);
+	rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group);
+	if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0)
 		return -1;
-	}
+	rsn->mgtk_key_id = 1;
 
-	/* group mgmt */
-	wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
-			seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+#ifdef CONFIG_IEEE80211W
+	if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
+		if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
+			return -1;
+		rsn->igtk_key_id = 4;
+
+		/* group mgmt */
+		wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
+				rsn->igtk, rsn->igtk_len);
+		wpa_drv_set_key(rsn->wpa_s,
+				wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+				rsn->igtk_key_id, 1,
+				seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+	}
+#endif /* CONFIG_IEEE80211W */
 
 	/* group privacy / data frames */
-	wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
-			seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+	wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
+			rsn->mgtk, rsn->mgtk_len);
+	wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+			rsn->mgtk_key_id, 1, seq, sizeof(seq),
+			rsn->mgtk, rsn->mgtk_len);
 
 	return 0;
 }
@@ -187,6 +209,9 @@
 static void mesh_rsn_deinit(struct mesh_rsn *rsn)
 {
 	os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+	rsn->mgtk_len = 0;
+	os_memset(rsn->igtk, 0, sizeof(rsn->igtk));
+	rsn->igtk_len = 0;
 	if (rsn->auth)
 		wpa_deinit(rsn->auth);
 }
@@ -204,8 +229,12 @@
 	if (mesh_rsn == NULL)
 		return NULL;
 	mesh_rsn->wpa_s = wpa_s;
+	mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
+	mesh_rsn->group_cipher = conf->group_cipher;
+	mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
 
-	if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+	if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
+				 conf->ieee80211w) < 0) {
 		mesh_rsn_deinit(mesh_rsn);
 		os_free(mesh_rsn);
 		return NULL;
@@ -358,18 +387,27 @@
 {
 	u8 *myaddr = rsn->wpa_s->own_addr;
 	u8 *peer = sta->addr;
-	u8 *addr1 = peer, *addr2 = myaddr;
-	u8 context[AES_BLOCK_SIZE];
+	u8 *addr1, *addr2;
+	u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context;
 
-	/* SAE */
-	RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+	/*
+	 * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite ||
+	 *       min(localMAC, peerMAC) || max(localMAC, peerMAC))
+	 */
+	/* Selected AKM Suite: SAE */
+	RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+	ptr += RSN_SELECTOR_LEN;
 
 	if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
 		addr1 = myaddr;
 		addr2 = peer;
+	} else {
+		addr1 = peer;
+		addr2 = myaddr;
 	}
-	os_memcpy(context + 4, addr1, ETH_ALEN);
-	os_memcpy(context + 10, addr2, ETH_ALEN);
+	os_memcpy(ptr, addr1, ETH_ALEN);
+	ptr += ETH_ALEN;
+	os_memcpy(ptr, addr2, ETH_ALEN);
 
 	sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
 		   context, sizeof(context), sta->aek, sizeof(sta->aek));
@@ -381,40 +419,44 @@
 {
 	u8 *ptr;
 	u8 *min, *max;
-	u16 min_lid, max_lid;
-	size_t nonce_len = sizeof(sta->my_nonce);
-	size_t lid_len = sizeof(sta->my_lid);
 	u8 *myaddr = wpa_s->own_addr;
 	u8 *peer = sta->addr;
-	/* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
-	u8 context[64 + 4 + 4 + 12];
+	u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN];
 
+	/*
+	 * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce,
+	 *  peerNonce) || max(localNonce, peerNonce) || min(localLinkID,
+	 *  peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite ||
+	 *  min(localMAC, peerMAC) || max(localMAC, peerMAC))
+	 */
 	ptr = context;
-	if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+	if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) {
 		min = sta->my_nonce;
 		max = sta->peer_nonce;
 	} else {
 		min = sta->peer_nonce;
 		max = sta->my_nonce;
 	}
-	os_memcpy(ptr, min, nonce_len);
-	os_memcpy(ptr + nonce_len, max, nonce_len);
-	ptr += 2 * nonce_len;
+	os_memcpy(ptr, min, WPA_NONCE_LEN);
+	ptr += WPA_NONCE_LEN;
+	os_memcpy(ptr, max, WPA_NONCE_LEN);
+	ptr += WPA_NONCE_LEN;
 
 	if (sta->my_lid < sta->peer_lid) {
-		min_lid = host_to_le16(sta->my_lid);
-		max_lid = host_to_le16(sta->peer_lid);
+		WPA_PUT_LE16(ptr, sta->my_lid);
+		ptr += 2;
+		WPA_PUT_LE16(ptr, sta->peer_lid);
+		ptr += 2;
 	} else {
-		min_lid = host_to_le16(sta->peer_lid);
-		max_lid = host_to_le16(sta->my_lid);
+		WPA_PUT_LE16(ptr, sta->peer_lid);
+		ptr += 2;
+		WPA_PUT_LE16(ptr, sta->my_lid);
+		ptr += 2;
 	}
-	os_memcpy(ptr, &min_lid, lid_len);
-	os_memcpy(ptr + lid_len, &max_lid, lid_len);
-	ptr += 2 * lid_len;
 
-	/* SAE */
-	RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
-	ptr += 4;
+	/* Selected AKM Suite: SAE */
+	RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+	ptr += RSN_SELECTOR_LEN;
 
 	if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
 		min = myaddr;
@@ -424,22 +466,24 @@
 		max = myaddr;
 	}
 	os_memcpy(ptr, min, ETH_ALEN);
-	os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+	ptr += ETH_ALEN;
+	os_memcpy(ptr, max, ETH_ALEN);
 
-	sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+	sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher);
+	sha256_prf(sta->sae->pmk, SAE_PMK_LEN,
 		   "Temporal Key Derivation", context, sizeof(context),
-		   sta->mtk, sizeof(sta->mtk));
+		   sta->mtk, sta->mtk_len);
 	return 0;
 }
 
 
 void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
 {
-	if (random_get_bytes(sta->my_nonce, 32) < 0) {
+	if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) {
 		wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
 		/* TODO: How to handle this more cleanly? */
 	}
-	os_memset(sta->peer_nonce, 0, 32);
+	os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN);
 	mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
 }
 
@@ -455,65 +499,89 @@
 {
 	struct ieee80211_ampe_ie *ampe;
 	u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
-	u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+	u8 *ampe_ie, *pos, *mic_payload;
 	const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
 	const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
 	int ret = 0;
+	size_t len;
 
-	if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+	len = sizeof(*ampe) + rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
+#ifdef CONFIG_IEEE80211W
+	if (rsn->igtk_len)
+		len += 2 + 6 + rsn->igtk_len;
+#endif /* CONFIG_IEEE80211W */
+
+	if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
 		wpa_printf(MSG_ERROR, "protect frame: buffer too small");
 		return -EINVAL;
 	}
 
-	ampe_ie = os_zalloc(2 + sizeof(*ampe));
+	ampe_ie = os_zalloc(2 + len);
 	if (!ampe_ie) {
 		wpa_printf(MSG_ERROR, "protect frame: out of memory");
 		return -ENOMEM;
 	}
 
-	mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
-	if (!mic_ie) {
-		wpa_printf(MSG_ERROR, "protect frame: out of memory");
-		ret = -ENOMEM;
-		goto free;
-	}
-
 	/*  IE: AMPE */
 	ampe_ie[0] = WLAN_EID_AMPE;
-	ampe_ie[1] = sizeof(*ampe);
+	ampe_ie[1] = len;
 	ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
 
 	RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
-		     wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
-	os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
-	os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
-	/* incomplete: see 13.5.4 */
+			 RSN_CIPHER_SUITE_CCMP);
+	os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN);
+	os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
+
+	pos = (u8 *) (ampe + 1);
+
+	/* TODO: Key Replay Counter[8] optionally for
+	 * Mesh Group Key Inform/Acknowledge frames */
+
 	/* TODO: static mgtk for now since we don't support rekeying! */
-	os_memcpy(ampe->mgtk, rsn->mgtk, 16);
-	/*  TODO: Populate Key RSC */
-	/*  expire in 13 decades or so */
-	os_memset(ampe->key_expiration, 0xff, 4);
+	/*
+	 * GTKdata[variable]:
+	 * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+	 */
+	os_memcpy(pos, rsn->mgtk, rsn->mgtk_len);
+	pos += rsn->mgtk_len;
+	wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos);
+	pos += WPA_KEY_RSC_LEN;
+	/* Use fixed GTKExpirationTime for now */
+	WPA_PUT_LE32(pos, 0xffffffff);
+	pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+	/*
+	 * IGTKdata[variable]:
+	 * Key ID[2], IPN[6], IGTK[variable]
+	 */
+	if (rsn->igtk_len) {
+		WPA_PUT_LE16(pos, rsn->igtk_key_id);
+		pos += 2;
+		wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos);
+		pos += 6;
+		os_memcpy(pos, rsn->igtk, rsn->igtk_len);
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
+			ampe_ie, 2 + len);
 
 	/* IE: MIC */
-	mic_ie[0] = WLAN_EID_MIC;
-	mic_ie[1] = AES_BLOCK_SIZE;
-	wpabuf_put_data(buf, mic_ie, 2);
+	wpabuf_put_u8(buf, WLAN_EID_MIC);
+	wpabuf_put_u8(buf, AES_BLOCK_SIZE);
 	/* MIC field is output ciphertext */
 
 	/* encrypt after MIC */
-	mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
-					AES_BLOCK_SIZE);
+	mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE);
 
-	if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+	if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3,
 			    aad, aad_len, mic_payload)) {
 		wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
 		ret = -ENOMEM;
-		goto free;
 	}
 
-free:
 	os_free(ampe_ie);
-	os_free(mic_ie);
 
 	return ret;
 }
@@ -526,14 +594,15 @@
 {
 	int ret = 0;
 	struct ieee80211_ampe_ie *ampe;
-	u8 null_nonce[32] = {};
+	u8 null_nonce[WPA_NONCE_LEN] = {};
 	u8 ampe_eid;
 	u8 ampe_ie_len;
-	u8 *ampe_buf, *crypt = NULL;
+	u8 *ampe_buf, *crypt = NULL, *pos, *end;
 	size_t crypt_len;
 	const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
 	const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
 				   (elems->mic - 2) - cat };
+	size_t key_len;
 
 	if (!sta->sae) {
 		struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
@@ -562,7 +631,7 @@
 		return -1;
 
 	crypt_len = elems_len - (elems->mic - start);
-	if (crypt_len < 2) {
+	if (crypt_len < 2 + AES_BLOCK_SIZE) {
 		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
 		return -1;
 	}
@@ -584,10 +653,15 @@
 		goto free;
 	}
 
+	crypt_len -= AES_BLOCK_SIZE;
+	wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element",
+			ampe_buf, crypt_len);
+
 	ampe_eid = *ampe_buf++;
 	ampe_ie_len = *ampe_buf++;
 
 	if (ampe_eid != WLAN_EID_AMPE ||
+	    (size_t) 2 + ampe_ie_len > crypt_len ||
 	    ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
 		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
 		ret = -1;
@@ -595,17 +669,67 @@
 	}
 
 	ampe = (struct ieee80211_ampe_ie *) ampe_buf;
-	if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
-	    os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+	pos = (u8 *) (ampe + 1);
+	end = ampe_buf + ampe_ie_len;
+	if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 &&
+	    os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) {
 		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
 		ret = -1;
 		goto free;
 	}
 	os_memcpy(sta->peer_nonce, ampe->local_nonce,
 		  sizeof(ampe->local_nonce));
-	os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
 
-	/* todo parse mgtk expiration */
+	/* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge
+	 * frames */
+
+	/*
+	 * GTKdata[variable]:
+	 * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+	 */
+	sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */
+	key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher);
+	if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element");
+		ret = -1;
+		goto free;
+	}
+	sta->mgtk_len = key_len;
+	os_memcpy(sta->mgtk, pos, sta->mgtk_len);
+	wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK",
+			sta->mgtk, sta->mgtk_len);
+	pos += sta->mgtk_len;
+	wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC",
+		    pos, WPA_KEY_RSC_LEN);
+	os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc));
+	pos += WPA_KEY_RSC_LEN;
+	wpa_printf(MSG_DEBUG,
+		   "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds",
+		   WPA_GET_LE32(pos));
+	pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+	/*
+	 * IGTKdata[variable]:
+	 * Key ID[2], IPN[6], IGTK[variable]
+	 */
+	key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher);
+	if (end - pos >= (int) (2 + 6 + key_len)) {
+		sta->igtk_key_id = WPA_GET_LE16(pos);
+		wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u",
+			   sta->igtk_key_id);
+		pos += 2;
+		os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc));
+		wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN",
+			    sta->igtk_rsc, sizeof(sta->igtk_rsc));
+		pos += 6;
+		os_memcpy(sta->igtk, pos, key_len);
+		sta->igtk_len = key_len;
+		wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
+				sta->igtk, sta->igtk_len);
+	}
+#endif /* CONFIG_IEEE80211W */
+
 free:
 	os_free(crypt);
 	return ret;
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index 89601d4..8775ced 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -12,7 +12,15 @@
 struct mesh_rsn {
 	struct wpa_supplicant *wpa_s;
 	struct wpa_authenticator *auth;
-	u8 mgtk[16];
+	unsigned int pairwise_cipher;
+	unsigned int group_cipher;
+	u8 mgtk[WPA_TK_MAX_LEN];
+	size_t mgtk_len;
+	u8 mgtk_key_id;
+	unsigned int mgmt_group_cipher;
+	u8 igtk_key_id;
+	u8 igtk[WPA_TK_MAX_LEN];
+	size_t igtk_len;
 #ifdef CONFIG_SAE
 	struct wpabuf *sae_token;
 	int sae_group_index;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index e739363..67e36ae 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -668,13 +668,13 @@
 
 
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
-				   struct wpa_ssid *ssid, int network_id,
+				   struct wpa_ssid *ssid, int persistent,
 				   int client)
 {
 	/* Notify a group has been started */
 	wpas_dbus_register_p2p_group(wpa_s, ssid);
 
-	wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+	wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent);
 }
 
 
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 1b7f04d..8cce0f3 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -113,7 +113,7 @@
 					 u16 config_methods,
 					 unsigned int generated_pin);
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
-				   struct wpa_ssid *ssid, int network_id,
+				   struct wpa_ssid *ssid, int persistent,
 				   int client);
 void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
 					     const char *reason);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 8f6acd6..8c5af5e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1301,7 +1301,6 @@
 	int client;
 	int persistent;
 	u8 go_dev_addr[ETH_ALEN];
-	int network_id = -1;
 
 	/*
 	 * This callback is likely called for the main interface. Update wpa_s
@@ -1376,16 +1375,15 @@
 	}
 
 	if (persistent)
-		network_id = wpas_p2p_store_persistent_group(wpa_s->p2pdev,
-							     ssid, go_dev_addr);
+		wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+						ssid, go_dev_addr);
 	else {
 		os_free(wpa_s->global->add_psk);
 		wpa_s->global->add_psk = NULL;
 	}
-	if (network_id < 0 && ssid)
-		network_id = ssid->id;
+
 	if (!client) {
-		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+		wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0);
 		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 	}
 }
@@ -1750,7 +1748,6 @@
 	struct wpa_supplicant *wpa_s = ctx;
 	struct p2p_go_neg_results *params = data;
 	struct wpa_ssid *ssid;
-	int network_id = -1;
 
 	wpa_s->ap_configured_cb = NULL;
 	wpa_s->ap_configured_cb_ctx = NULL;
@@ -1797,14 +1794,14 @@
 
 		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 		if (params->persistent_group) {
-			network_id = wpas_p2p_store_persistent_group(
+			wpas_p2p_store_persistent_group(
 				wpa_s->p2pdev, ssid,
 				wpa_s->global->p2p_dev_addr);
 			wpas_p2p_add_psk_list(wpa_s, ssid);
 		}
-		if (network_id < 0)
-			network_id = ssid->id;
-		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+
+		wpas_notify_p2p_group_started(wpa_s, ssid,
+					      params->persistent_group, 0);
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
 
@@ -6941,7 +6938,6 @@
 {
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	u8 go_dev_addr[ETH_ALEN];
-	int network_id = -1;
 	int persistent;
 	int freq;
 	u8 ip[3 * 4];
@@ -7000,11 +6996,10 @@
 			       ip_addr);
 
 	if (persistent)
-		network_id = wpas_p2p_store_persistent_group(wpa_s->p2pdev,
-							     ssid, go_dev_addr);
-	if (network_id < 0)
-		network_id = ssid->id;
-	wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+		wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+						ssid, go_dev_addr);
+
+	wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1);
 }
 
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 330679c..6ade9af 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -227,10 +227,8 @@
 	}
 
 	ctx = wpa_scan_clone_params(params);
-	if (ctx == NULL)
-		return -1;
-
-	if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+	if (!ctx ||
+	    radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
 	{
 		wpa_scan_free_params(ctx);
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
@@ -438,6 +436,13 @@
 	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+	else
+#endif /* CONFIG_P2P */
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
 	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
 					     sizeof(ext_capab));
 	if (ext_capab_len > 0 &&
@@ -837,12 +842,10 @@
 		 * slot for the zero-terminator.
 		 */
 		params.freqs = os_malloc(sizeof(int) * 2);
-		if (params.freqs == NULL) {
-			wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed");
-			return;
+		if (params.freqs) {
+			params.freqs[0] = wpa_s->assoc_freq;
+			params.freqs[1] = 0;
 		}
-		params.freqs[0] = wpa_s->assoc_freq;
-		params.freqs[1] = 0;
 
 		/*
 		 * Reset the reattach flag so that we fall back to full scan if
@@ -2611,13 +2614,6 @@
 			goto fail;
 		}
 
-		if (!scan_plan->interval) {
-			wpa_printf(MSG_ERROR,
-				   "scan plan %u: Interval cannot be zero",
-				   num);
-			goto fail;
-		}
-
 		if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
 			wpa_printf(MSG_WARNING,
 				   "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 2fbb2c6..3a8f5b1 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -455,6 +455,11 @@
 	}
 #endif /* CONFIG_MBO */
 
+	if (params.p2p)
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+	else
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
 	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
 					     sizeof(ext_capab));
 	if (ext_capab_len > 0) {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index aa785bd..d3848cb 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2039,6 +2039,16 @@
 			if (chwidth == VHT_CHANWIDTH_80P80MHZ)
 				break;
 		}
+	} else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+		if (freq->freq == 5180) {
+			chwidth = VHT_CHANWIDTH_160MHZ;
+			vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+			seg0 = 50;
+		} else if (freq->freq == 5520) {
+			chwidth = VHT_CHANWIDTH_160MHZ;
+			vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+			seg0 = 114;
+		}
 	}
 
 	if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
@@ -2291,6 +2301,11 @@
 	 * element in all cases, it is justifiable to skip it to avoid
 	 * interoperability issues.
 	 */
+	if (ssid->p2p_group)
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+	else
+		wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
 	if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
 		u8 ext_capab[18];
 		int ext_capab_len;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 2d487c5..1d86a71 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -168,10 +168,13 @@
 fast_reauth=1
 
 # OpenSSL Engine support
-# These options can be used to load OpenSSL engines.
+# These options can be used to load OpenSSL engines in special or legacy
+# modes.
 # The two engines that are supported currently are shown below:
 # They are both from the opensc project (http://www.opensc.org/)
-# By default no engines are loaded.
+# By default the PKCS#11 engine is loaded if the client_cert or
+# private_key option appear to be a PKCS#11 URI, and these options
+# should not need to be used explicitly.
 # make the opensc engine available
 #opensc_engine_path=/usr/lib/opensc/engine_opensc.so
 # make the pkcs11 engine available
@@ -440,6 +443,12 @@
 #     matching network block
 #auto_interworking=0
 
+# GAS Address3 field behavior
+# 0 = P2P specification (Address3 = AP BSSID); default
+# 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+#     sent to not-associated AP; if associated, AP BSSID)
+#gas_address3=0
+
 # credential block
 #
 # Each credential used for automatic network selection is configured as a set
@@ -474,6 +483,10 @@
 #	(EAP-TLS). Full path to the file should be used since working
 #	directory may change when wpa_supplicant is run in the background.
 #
+#	Certificates from PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#
+#	For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
 #	Alternatively, a named configuration blob can be used by setting
 #	this to blob://blob_name.
 #
@@ -484,6 +497,9 @@
 #	used since working directory may change when wpa_supplicant is run
 #	in the background.
 #
+#	Keys in PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#	For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
 #	Windows certificate store can be used by leaving client_cert out and
 #	configuring private_key in one of the following formats:
 #
@@ -1581,22 +1597,10 @@
 	group=CCMP TKIP
 	identity="user@example.com"
 	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
 
-	engine=1
-
-	# The engine configured here must be available. Look at
-	# OpenSSL engine support in the global section.
-	# The key available through the engine must be the private key
-	# matching the client certificate configured above.
-
-	# use the opensc engine
-	#engine_id="opensc"
-	#key_id="45"
-
-	# use the pkcs11 engine
-	engine_id="pkcs11"
-	key_id="id_45"
+	# Certificate and/or key identified by PKCS#11 URI (RFC7512)
+	client_cert="pkcs11:manufacturer=piv_II;id=%01"
+	private_key="pkcs11:manufacturer=piv_II;id=%01"
 
 	# Optional PIN configuration; this can be left out and PIN will be
 	# asked through the control interface