Cumulative patch from commit a9491695b30a7f750dc45cb563d813b03f1d4b8d

a9491695b QCA vendor command to set/get NUD statistics
f593b6c11 nl80211: Do not reset vendor_scan_cookie after scan timeout
f2bc34480 wpa_supplicant: Fix global control interface for STA/STA-FIRST/STA-NEXT
cc3dae85b hostapd: Add possibility to send debug messages to syslog
0da355235 FST: Remove WPA_ASSERT from wpas_fst_send_action_cb()
968dce9b1 FST: Silence compiler warning on WPA_ASSERT
17e20b1e2 FST: Remove a bogus WPA_ASSERT()
6a5425fd6 Increase delayed EAPOL RX frame timeout
cef8fac04 wpa_auth: Make struct wpa_auth_callbacks const
30eddf352 Fix or supress various sparse warnings
b301f54e5 IBSS/mesh: Skip VHT channel setup with vht_disabled=1
adc6a5d81 mesh: Check remote peer HT Operation element
9eb5757a8 Define helper function set_disable_ht40()
7813b7c34 nl80211: Fix a memory leak on deinit with HT enabled mesh
6b585f420 mesh: Fix crash on removing virtual mesh interface
5208160b4 FILS: Parse received FILS HLP requests
5732b770f FILS: Allow FILS HLP requests to be added
a1aa2aebc Remove unused WLAN_CIPHER_SUITE_* definitions
a042e39ac nl80211: Use RSN_CIPHER_SUITE_* instead of WLAN_CIPHER_SUITE_*
2373a3117 Define all RSN_CIPHER_SUITE_* values
89ba101e1 Remove unused WLAN_AKM_SUITE_* definitions
bf9f8a052 Use RSN_AUTH_KEY_MGMT_* instead of WLAN_AKM_SUITE_* for wpa_akm_to_suite()
3aa24db95 nl80211: Use RSN_AUTH_KEY_MGMT_* instead of WLAN_AKM_SUITE_*
a1343fa6b Remove unnecessary ifdef from RSN_AUTH_KEY_MGMT_* definitions
afe731004 Fix CONFIG_SAE build without CONFIG_SME
34e8bfd7a Skip EVENT_ACS_CHANNEL_SELECTED also without CONFIG_AP
510fc2dfc Fix AKM suite selectors for FILS and Suite B
d7d0f909f QCA vendor command to carry the reason for power save failure
53b38209f GAS: Cancel gas_query_timeout when AP responds with comeback delay
d5bd94133 MBO: Silence a compiler warning when building without CONFIG_MBO
4c4070005 QCA vendor command to enable host driver offload ACS to user space
4d77d80ed mesh: Add MESH_PMKSA_GET/ADD commands
117875db3 D-Bus: Add GroupMgmt entry into the interface Capabilities dict
3cdb4ac07 D-Bus: Add pmf to global capabilities
adf8f45f8 D-Bus: Implement Pmf property
b98706c14 RSN IBSS: Fix TK clearing on Authentication frame RX
fa67debf4 Fix duplicate Reassociation Request frame dropping
6ff92677a wext: Cancel send_rfkill timeout in deinit
fcd3d6ce3 FILS: Fix PMK and PMKID derivation from ERP
ef495c78d OpenSSL: Implement sha384_vector()
a70cd0db8 nl80211: Don't register for Beacon frames for IEEE 802.11ad AP
a2aa21a3b Assign additional vendor specific elements for early HE testing
f09095d57 wpa_supplicant: Clarify group_rekey documentation
c85dfc6f8 nl80211: Set NL80211_ATTR_IFACE_SOCKET_OWNER for connect and associate
d07f450da Sync with mac80211-next.git include/uapi/linux/nl80211.h
8f315d050 Fix country code in wpa_supplicant AP mode Country element
29065686a D-Bus: Fix BSS Mode getter for invalid DMG BSS
b2442f256 nl80211: Debug prints for TDLS_OPER command and result
2901bc272 bgscan: Remove unnecessary NULL check
9d6eaad6b bgscan: Remove unnecessary NULL check
0f9b4a0f1 bgscan: Deliver beacon loss event to bgscan modules
688556722 nl80211: More complete processing of connection quality monitor events
54736d835 Store FST parameters to configuration file
35c78f7b9 Store osu_dir to configuration file
1f539c78f Store autoscan to configuration file
58ed9e31d Store filter_rssi to configuration file
1fb1bf99d Write sec_device_type to configuration file
b4bdeadfa Make "SET" behavior more consistent for dot11RSNA parameters
e3394c0e2 Make "SET non_pref_chan .." behavior more consistent
f8c201862 Fix cert_in_cb parsing in wpa_supplicant.conf
9284418d0 Fix writing of wpa_supplicant sae_groups configuration parameter
167f78a5e Send BEACON-REQ-TX-STATUS event only for beacon reports
7ba94fc4b RRM: Use wpa_hexdump_buf() instead of wpa_hexdump()
e4ec6bbfd nl80211: Register for Link Measurement Report frames in AP mode
33468e532 RRM: Document Link Measurement Report frame construction steps
40e9a3f32 RRM: Fix beacon report scan channels for VHT 80, 80+80, 160 MHz cases
5cda35089 RRM: Move wpabuf_resize() call into wpas_rrm_report_elem()
f2058f4af RRM: Remove unnecessary cb check
89fa633af nl80211: Fix error while enabling AP mode with driver-SME

The last change 89fa633af cherrypicks a later change that resolves
an issue with starting up AP mode.

Bug: 34681709
Test: Wifi Suite
Change-Id: Iba8c5824009d6480fb736b274d69243c77aef7fe
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 5afb772..608d355 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -234,6 +234,7 @@
 		conf->ieee80211d = 1;
 		conf->country[0] = wpa_s->conf->country[0];
 		conf->country[1] = wpa_s->conf->country[1];
+		conf->country[2] = ' ';
 	}
 
 #ifdef CONFIG_P2P
@@ -1436,6 +1437,43 @@
 	if (wpa_s->ifmsh)
 		hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]);
 }
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
+				  char *buf, size_t len)
+{
+	return hostapd_ctrl_iface_pmksa_list_mesh(wpa_s->ifmsh->bss[0], addr,
+						  &buf[0], len);
+}
+
+
+int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	struct external_pmksa_cache *entry;
+	void *pmksa_cache;
+
+	pmksa_cache = hostapd_ctrl_iface_pmksa_create_entry(wpa_s->own_addr,
+							    cmd);
+	if (!pmksa_cache)
+		return -1;
+
+	entry = os_zalloc(sizeof(struct external_pmksa_cache));
+	if (!entry)
+		return -1;
+
+	entry->pmksa_cache = pmksa_cache;
+
+	dl_list_add(&wpa_s->mesh_external_pmksa_cache, &entry->list);
+
+	return 0;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
 #endif /* CONFIG_CTRL_IFACE */
 
 
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 5a59ddc..3fa656f 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -85,6 +85,9 @@
 int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
 			     size_t len);
 void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
+				  char *buf, size_t len);
+int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd);
 
 void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
 				   struct dfs_event *radar);
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 798b43c..1ea6401 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -34,8 +34,6 @@
 	const struct bgscan_ops *ops = NULL;
 
 	bgscan_deinit(wpa_s);
-	if (name == NULL)
-		return -1;
 
 	params = os_strchr(name, ':');
 	if (params == NULL) {
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index a320cc4..cb732f7 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -320,9 +320,6 @@
 {
 	const char *pos;
 
-	if (params == NULL)
-		return 0;
-
 	data->short_interval = atoi(params);
 
 	pos = os_strchr(params, ':');
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index bae72b9..41a26df 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -80,9 +80,6 @@
 {
 	const char *pos;
 
-	if (params == NULL)
-		return 0;
-
 	data->short_interval = atoi(params);
 
 	pos = os_strchr(params, ':');
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2a26d2d..bdaaa54 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4445,6 +4445,7 @@
 	{ INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
 	{ INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
 #endif /* CONFIG_FST */
+	{ INT_RANGE(cert_in_cb, 0, 1), 0 },
 	{ INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
 	{ STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
 #ifdef CONFIG_MBO
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 98e3591..920bdc0 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1119,6 +1119,17 @@
 	}
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
+	{
+		int i;
+		char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+
+		for (i = 0; i < config->num_sec_device_types; i++) {
+			buf = wps_dev_type_bin2str(config->sec_device_type[i],
+						   _buf, sizeof(_buf));
+			if (buf)
+				fprintf(f, "sec_device_type=%s\n", buf);
+		}
+	}
 	if (config->p2p_listen_reg_class)
 		fprintf(f, "p2p_listen_reg_class=%d\n",
 			config->p2p_listen_reg_class);
@@ -1218,6 +1229,8 @@
 			config->bss_expiration_scan_count);
 	if (config->filter_ssids)
 		fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
+	if (config->filter_rssi)
+		fprintf(f, "filter_rssi=%d\n", config->filter_rssi);
 	if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
 		fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
 	if (config->disassoc_low_ack)
@@ -1269,7 +1282,7 @@
 	if (config->sae_groups) {
 		int i;
 		fprintf(f, "sae_groups=");
-		for (i = 0; config->sae_groups[i] >= 0; i++) {
+		for (i = 0; config->sae_groups[i] > 0; i++) {
 			fprintf(f, "%s%d", i > 0 ? " " : "",
 				config->sae_groups[i]);
 		}
@@ -1321,6 +1334,9 @@
 	if (config->bgscan)
 		fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
 
+	if (config->autoscan)
+		fprintf(f, "autoscan=%s\n", config->autoscan);
+
 	if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
 		fprintf(f, "p2p_search_delay=%u\n",
 			config->p2p_search_delay);
@@ -1387,6 +1403,16 @@
 		fprintf(f, "ftm_responder=%d\n", config->ftm_responder);
 	if (config->ftm_initiator)
 		fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator);
+
+	if (config->osu_dir)
+		fprintf(f, "osu_dir=%s\n", config->osu_dir);
+
+	if (config->fst_group_id)
+		fprintf(f, "fst_group_id=%s\n", config->fst_group_id);
+	if (config->fst_priority)
+		fprintf(f, "fst_priority=%d\n", config->fst_priority);
+	if (config->fst_llt)
+		fprintf(f, "fst_llt=%d\n", config->fst_llt);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index be178d7..dff53ad 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -365,16 +365,29 @@
 				   -1, -1, -1, atoi(value));
 	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
 		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
-				     atoi(value)))
+				     atoi(value))) {
 			ret = -1;
+		} else {
+			value[-1] = '=';
+			wpa_config_process_global(wpa_s->conf, cmd, -1);
+		}
 	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
 		   0) {
 		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
-				     atoi(value)))
+				     atoi(value))) {
 			ret = -1;
+		} else {
+			value[-1] = '=';
+			wpa_config_process_global(wpa_s->conf, cmd, -1);
+		}
 	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
-		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
+				     atoi(value))) {
 			ret = -1;
+		} else {
+			value[-1] = '=';
+			wpa_config_process_global(wpa_s->conf, cmd, -1);
+		}
 	} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
 		wpa_s->wps_fragment_size = atoi(value);
 #ifdef CONFIG_WPS_TESTING
@@ -527,6 +540,10 @@
 #ifdef CONFIG_MBO
 	} else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
 		ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
+		if (ret == 0) {
+			value[-1] = '=';
+			wpa_config_process_global(wpa_s->conf, cmd, -1);
+		}
 	} else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
 		wpas_mbo_update_cell_capa(wpa_s, atoi(value));
 #endif /* CONFIG_MBO */
@@ -1916,6 +1933,7 @@
 #endif /* CONFIG_AP */
 		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
 	}
+#ifdef CONFIG_SME
 #ifdef CONFIG_SAE
 	if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
 #ifdef CONFIG_AP
@@ -1929,6 +1947,7 @@
 		pos += ret;
 	}
 #endif /* CONFIG_SAE */
+#endif /* CONFIG_SME */
 	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
 			  wpa_supplicant_state_txt(wpa_s->wpa_state));
 	if (os_snprintf_error(end - pos, ret))
@@ -8020,6 +8039,119 @@
 }
 
 
+static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s,
+					   char *param)
+{
+	struct wpa_scan_res *res;
+	struct os_reltime now;
+	char *pos, *end;
+
+	if (!param)
+		return -1;
+
+	if (os_strcmp(param, "START") == 0) {
+		wpa_bss_update_start(wpa_s);
+		return 0;
+	}
+
+	if (os_strcmp(param, "END") == 0) {
+		wpa_bss_update_end(wpa_s, NULL, 1);
+		return 0;
+	}
+
+	if (os_strncmp(param, "BSS ", 4) != 0)
+		return -1;
+	param += 3;
+
+	res = os_zalloc(sizeof(*res) + os_strlen(param) / 2);
+	if (!res)
+		return -1;
+
+	pos = os_strstr(param, " flags=");
+	if (pos)
+		res->flags = strtol(pos + 7, NULL, 16);
+
+	pos = os_strstr(param, " bssid=");
+	if (pos)
+		hwaddr_aton(pos + 7, res->bssid);
+
+	pos = os_strstr(param, " freq=");
+	if (pos)
+		res->freq = atoi(pos + 6);
+
+	pos = os_strstr(param, " beacon_int=");
+	if (pos)
+		res->beacon_int = atoi(pos + 12);
+
+	pos = os_strstr(param, " caps=");
+	if (pos)
+		res->caps = strtol(pos + 6, NULL, 16);
+
+	pos = os_strstr(param, " qual=");
+	if (pos)
+		res->qual = atoi(pos + 6);
+
+	pos = os_strstr(param, " noise=");
+	if (pos)
+		res->noise = atoi(pos + 7);
+
+	pos = os_strstr(param, " level=");
+	if (pos)
+		res->level = atoi(pos + 7);
+
+	pos = os_strstr(param, " tsf=");
+	if (pos)
+		res->tsf = strtoll(pos + 5, NULL, 16);
+
+	pos = os_strstr(param, " age=");
+	if (pos)
+		res->age = atoi(pos + 5);
+
+	pos = os_strstr(param, " est_throughput=");
+	if (pos)
+		res->est_throughput = atoi(pos + 16);
+
+	pos = os_strstr(param, " snr=");
+	if (pos)
+		res->snr = atoi(pos + 5);
+
+	pos = os_strstr(param, " parent_tsf=");
+	if (pos)
+		res->parent_tsf = strtoll(pos + 7, NULL, 16);
+
+	pos = os_strstr(param, " tsf_bssid=");
+	if (pos)
+		hwaddr_aton(pos + 11, res->tsf_bssid);
+
+	pos = os_strstr(param, " ie=");
+	if (pos) {
+		pos += 4;
+		end = os_strchr(pos, ' ');
+		if (!end)
+			end = pos + os_strlen(pos);
+		res->ie_len = (end - pos) / 2;
+		hexstr2bin(pos, (u8 *) (res + 1), res->ie_len);
+	}
+
+	pos = os_strstr(param, " beacon_ie=");
+	if (pos) {
+		pos += 11;
+		end = os_strchr(pos, ' ');
+		if (!end)
+			end = pos + os_strlen(pos);
+		res->beacon_ie_len = (end - pos) / 2;
+		hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len,
+			   res->beacon_ie_len);
+	}
+
+	os_get_reltime(&now);
+	wpa_bss_update_scan_res(wpa_s, res, &now);
+	os_free(res);
+
+	return 0;
+}
+
+
 static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
 {
 	char *pos, *param;
@@ -8050,6 +8182,8 @@
 		wpa_supplicant_event(wpa_s, ev, &event);
 		os_free(event.freq_range.range);
 		return 0;
+	} else if (os_strcmp(cmd, "SCAN_RES") == 0) {
+		return wpas_ctrl_iface_driver_scan_res(wpa_s, param);
 	} else {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
 			cmd);
@@ -8982,9 +9116,77 @@
 	return ret;
 }
 
+
+#ifdef CONFIG_MESH
+
+static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s,
+					  const char *cmd, char *buf,
+					  size_t buflen)
+{
+	u8 spa[ETH_ALEN];
+
+	if (!wpa_s->ifmsh)
+		return -1;
+
+	if (os_strcasecmp(cmd, "any") == 0)
+		return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen);
+
+	if (hwaddr_aton(cmd, spa))
+		return -1;
+
+	return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen);
+}
+
+
+static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
+					  char *cmd)
+{
+	/*
+	 * We do not check mesh interface existance because PMKSA should be
+	 * stored before wpa_s->ifmsh creation to suppress commit message
+	 * creation.
+	 */
+	return wpas_ap_pmksa_cache_add_external(wpa_s, cmd);
+}
+
+#endif /* CONFIG_MESH */
 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 
 
+#ifdef CONFIG_FILS
+static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s,
+					    const char *cmd)
+{
+	struct fils_hlp_req *req;
+	const char *pos;
+
+	/* format: <dst> <packet starting from ethertype> */
+
+	req = os_zalloc(sizeof(*req));
+	if (!req)
+		return -1;
+
+	if (hwaddr_aton(cmd, req->dst))
+		goto fail;
+
+	pos = os_strchr(cmd, ' ');
+	if (!pos)
+		goto fail;
+	pos++;
+	req->pkt = wpabuf_parse_bin(pos);
+	if (!req->pkt)
+		goto fail;
+
+	dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
+	return 0;
+fail:
+	wpabuf_free(req->pkt);
+	os_free(req);
+	return -1;
+}
+#endif /* CONFIG_FILS */
+
+
 static int wpas_ctrl_cmd_debug_level(const char *cmd)
 {
 	if (os_strcmp(cmd, "PING") == 0 ||
@@ -9066,6 +9268,14 @@
 	} else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
 		if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0)
 			reply_len = -1;
+#ifdef CONFIG_MESH
+	} else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) {
+		reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15,
+							   reply, reply_size);
+	} else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
+		if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0)
+			reply_len = -1;
+#endif /* CONFIG_MESH */
 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 	} else if (os_strncmp(buf, "SET ", 4) == 0) {
 		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
@@ -9705,6 +9915,13 @@
 	} else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
 		reply_len = wpas_ctrl_iface_get_pref_freq_list(
 			wpa_s, buf + 19, reply, reply_size);
+#ifdef CONFIG_FILS
+	} else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) {
+		if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) {
+		wpas_flush_fils_hlp_req(wpa_s);
+#endif /* CONFIG_FILS */
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -10014,6 +10231,9 @@
 		"P2P_CANCEL",
 		"P2P_PRESENCE_REQ",
 		"P2P_EXT_LISTEN",
+#ifdef CONFIG_AP
+		"STA-FIRST",
+#endif /* CONFIG_AP */
 		NULL
 	};
 	static const char * prefix[] = {
@@ -10051,6 +10271,10 @@
 		"NFC_REPORT_HANDOVER ",
 		"P2P_ASP_PROVISION ",
 		"P2P_ASP_PROVISION_RESP ",
+#ifdef CONFIG_AP
+		"STA ",
+		"STA-NEXT ",
+#endif /* CONFIG_AP */
 		NULL
 	};
 	int found = 0;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index a601182..0c355f7 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1987,6 +1987,11 @@
 	case WPAS_DBUS_PROP_AP_SCAN:
 		prop = "ApScan";
 		break;
+#ifdef CONFIG_IEEE80211W
+	case WPAS_DBUS_PROP_PMF:
+		prop = "Pmf";
+		break;
+#endif /* CONFIG_IEEE80211W */
 	case WPAS_DBUS_PROP_SCANNING:
 		prop = "Scanning";
 		break;
@@ -3138,6 +3143,13 @@
 	  wpas_dbus_setter_ap_scan,
 	  NULL
 	},
+#ifdef CONFIG_IEEE80211W
+	{ "Pmf", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_pmf,
+	  wpas_dbus_setter_pmf,
+	  NULL
+	},
+#endif /* CONFIG_IEEE80211W */
 	{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
 	  wpas_dbus_getter_bss_expire_age,
 	  wpas_dbus_setter_bss_expire_age,
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 2b0b775..bd0e074 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -22,6 +22,7 @@
 
 enum wpas_dbus_prop {
 	WPAS_DBUS_PROP_AP_SCAN,
+	WPAS_DBUS_PROP_PMF,
 	WPAS_DBUS_PROP_SCANNING,
 	WPAS_DBUS_PROP_STATE,
 	WPAS_DBUS_PROP_CURRENT_BSS,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 7446f8d..a6548ba 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -991,6 +991,9 @@
 #ifdef CONFIG_INTERWORKING
 	capabilities[num_items++] = "interworking";
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_IEEE80211W
+	capabilities[num_items++] = "pmf";
+#endif /* CONFIG_IEEE80211W */
 
 	return wpas_dbus_simple_array_property_getter(iter,
 						      DBUS_TYPE_STRING,
@@ -2489,6 +2492,28 @@
 			goto nomem;
 	}
 
+	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
+					      &iter_dict_entry,
+					      &iter_dict_val,
+					      &iter_array) ||
+	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "aes-128-cmac")) ||
+	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "bip-gmac-128")) ||
+	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "bip-gmac-256")) ||
+	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "bip-cmac-256")) ||
+	    !wpa_dbus_dict_end_string_array(&iter_dict,
+					    &iter_dict_entry,
+					    &iter_dict_val,
+					    &iter_array))
+		goto nomem;
+
 	/***** key management */
 	if (res < 0) {
 		const char *args[] = {
@@ -2787,6 +2812,61 @@
 }
 
 
+#ifdef CONFIG_IEEE80211W
+
+/**
+ * wpas_dbus_getter_pmf - Control PMF default
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "Pmf" property.
+ */
+dbus_bool_t wpas_dbus_getter_pmf(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_uint32_t pmf = wpa_s->conf->pmf;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&pmf, error);
+}
+
+
+/**
+ * wpas_dbus_setter_pmf - Control PMF default
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "Pmf" property.
+ */
+dbus_bool_t wpas_dbus_setter_pmf(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_uint32_t pmf;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &pmf))
+		return FALSE;
+
+	if (pmf > 2) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "Pmf must be 0, 1, or 2");
+		return FALSE;
+	}
+	wpa_s->conf->pmf = pmf;
+	return TRUE;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
 /**
  * wpas_dbus_getter_fast_reauth - Control fast
  * reauthentication (TLS session resumption)
@@ -3699,6 +3779,9 @@
 		case IEEE80211_CAP_DMG_AP:
 			mode = "infrastructure";
 			break;
+		default:
+			mode = "";
+			break;
 		}
 	} else {
 		if (res->caps & IEEE80211_CAP_IBSS)
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index fe8767a..3b8f096 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -138,6 +138,8 @@
 DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
 DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan);
 DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_getter_pmf);
+DECLARE_ACCESSOR(wpas_dbus_setter_pmf);
 DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth);
 DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth);
 DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index afdda00..76805e0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -2585,7 +2585,7 @@
 		struct os_reltime now, age;
 		os_get_reltime(&now);
 		os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
-		if (age.sec == 0 && age.usec < 100000 &&
+		if (age.sec == 0 && age.usec < 200000 &&
 		    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
 		    0) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
@@ -4319,12 +4319,14 @@
 #endif /* CONFIG_AP */
 		break;
 	case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_AP
 #ifdef CONFIG_ACS
 		if (!wpa_s->ap_iface)
 			break;
 		hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
 					     &data->acs_selected_channels);
 #endif /* CONFIG_ACS */
+#endif /* CONFIG_AP */
 		break;
 	case EVENT_P2P_LO_STOP:
 #ifdef CONFIG_P2P
@@ -4334,6 +4336,12 @@
 			data->p2p_lo_stop.reason_code);
 #endif /* CONFIG_P2P */
 		break;
+	case EVENT_BEACON_LOSS:
+		if (!wpa_s->current_bss || !wpa_s->current_ssid)
+			break;
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
+		bgscan_notify_beacon_loss(wpa_s);
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 691de03..1b57d88 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -407,6 +407,7 @@
 	}
 
 	if (comeback_delay) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
 		query->wait_comeback = 1;
 		gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
 		return;
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 53d7d57..521a692 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -408,7 +408,15 @@
 				    const u8 *own_addr, struct wpa_ssid *ssid)
 {
 	struct wpa_auth_config conf;
-	struct wpa_auth_callbacks cb;
+	static const struct wpa_auth_callbacks cb = {
+		.logger = auth_logger,
+		.set_eapol = auth_set_eapol,
+		.send_eapol = auth_send_eapol,
+		.get_psk = auth_get_psk,
+		.set_key = auth_set_key,
+		.for_each_sta = auth_for_each_sta,
+		.disconnect = ibss_rsn_disconnect,
+	};
 
 	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
 
@@ -421,17 +429,7 @@
 	conf.eapol_version = 2;
 	conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600;
 
-	os_memset(&cb, 0, sizeof(cb));
-	cb.ctx = ibss_rsn;
-	cb.logger = auth_logger;
-	cb.set_eapol = auth_set_eapol;
-	cb.send_eapol = auth_send_eapol;
-	cb.get_psk = auth_get_psk;
-	cb.set_key = auth_set_key;
-	cb.for_each_sta = auth_for_each_sta;
-	cb.disconnect = ibss_rsn_disconnect;
-
-	ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
+	ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb, ibss_rsn);
 	if (ibss_rsn->auth_group == NULL) {
 		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
 		return -1;
@@ -838,6 +836,18 @@
 		   MAC2STR(addr));
 
 	if (peer &&
+	    peer->authentication_status & (IBSS_RSN_SET_PTK_SUPP |
+					   IBSS_RSN_SET_PTK_AUTH)) {
+		/* Clear the TK for this pair to allow recovery from the case
+		 * where the peer STA has restarted and lost its key while we
+		 * still have a pairwise key configured. */
+		wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
+			   MACSTR, MAC2STR(addr));
+		wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
+				NULL, 0, NULL, 0);
+	}
+
+	if (peer &&
 	    peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
 		if (peer->own_auth_tx.sec) {
 			struct os_reltime now, diff;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 6c3fa14..1a0fd5f 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "ap/hostapd.h"
 #include "ap/sta_info.h"
 #include "ap/ieee802_11.h"
@@ -646,6 +647,9 @@
 	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
 	struct hostapd_data *data = wpa_s->ifmsh->bss[0];
 	struct sta_info *sta;
+#ifdef CONFIG_IEEE80211N
+	struct ieee80211_ht_operation *oper;
+#endif /* CONFIG_IEEE80211N */
 	int ret;
 
 	if (elems->mesh_config_len >= 7 &&
@@ -677,6 +681,16 @@
 
 #ifdef CONFIG_IEEE80211N
 	copy_sta_ht_capab(data, sta, elems->ht_capabilities);
+
+	oper = (struct ieee80211_ht_operation *) elems->ht_operation;
+	if (oper &&
+	    !(oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH)) {
+		wpa_msg(wpa_s, MSG_DEBUG, MACSTR
+			" does not support 40 MHz bandwidth",
+			MAC2STR(sta->addr));
+		set_disable_ht40(sta->ht_capabilities, 1);
+	}
+
 	update_ht_state(data, sta);
 #endif /* CONFIG_IEEE80211N */
 
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index b1cf138..33040f3 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -140,7 +140,12 @@
 				enum mfp_options ieee80211w)
 {
 	struct wpa_auth_config conf;
-	struct wpa_auth_callbacks cb;
+	static const struct wpa_auth_callbacks cb = {
+		.logger = auth_logger,
+		.get_psk = auth_get_psk,
+		.set_key = auth_set_key,
+		.start_ampe = auth_start_ampe,
+	};
 	u8 seq[6] = {};
 
 	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
@@ -159,14 +164,7 @@
 		conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
 #endif /* CONFIG_IEEE80211W */
 
-	os_memset(&cb, 0, sizeof(cb));
-	cb.ctx = rsn;
-	cb.logger = auth_logger;
-	cb.get_psk = auth_get_psk;
-	cb.set_key = auth_set_key;
-	cb.start_ampe = auth_start_ampe;
-
-	rsn->auth = wpa_init(addr, &conf, &cb);
+	rsn->auth = wpa_init(addr, &conf, &cb, rsn);
 	if (rsn->auth == NULL) {
 		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
 		return -1;
@@ -224,6 +222,9 @@
 	struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
 	const u8 *ie;
 	size_t ie_len;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+	struct external_pmksa_cache *entry;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 
 	mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
 	if (mesh_rsn == NULL)
@@ -242,6 +243,22 @@
 
 	bss->wpa_auth = mesh_rsn->auth;
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+	while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+				     struct external_pmksa_cache,
+				     list)) != NULL) {
+		int ret;
+
+		ret = wpa_auth_pmksa_add_entry(bss->wpa_auth,
+					       entry->pmksa_cache);
+		dl_list_del(&entry->list);
+		os_free(entry);
+
+		if (ret < 0)
+			return NULL;
+	}
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
 	ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
 	conf->rsn_ie = (u8 *) ie;
 	conf->rsn_ie_len = ie_len;
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 942eea7..36a8336 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -160,12 +160,6 @@
 		return -EOPNOTSUPP;
 	}
 
-	if (!cb) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Neighbor Report request must provide a callback.");
-		return -EINVAL;
-	}
-
 	/* Refuse if there's a live request */
 	if (wpa_s->rrm.notify_neighbor_rep) {
 		wpa_printf(MSG_DEBUG,
@@ -284,20 +278,20 @@
 }
 
 
-static int wpas_rrm_report_elem(struct wpabuf *buf, u8 token, u8 mode, u8 type,
+static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type,
 				const u8 *data, size_t data_len)
 {
-	if (wpabuf_tailroom(buf) < 5 + data_len)
+	if (wpabuf_resize(buf, 5 + data_len))
 		return -1;
 
-	wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
-	wpabuf_put_u8(buf, 3 + data_len);
-	wpabuf_put_u8(buf, token);
-	wpabuf_put_u8(buf, mode);
-	wpabuf_put_u8(buf, type);
+	wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT);
+	wpabuf_put_u8(*buf, 3 + data_len);
+	wpabuf_put_u8(*buf, token);
+	wpabuf_put_u8(*buf, mode);
+	wpabuf_put_u8(*buf, type);
 
 	if (data_len)
-		wpabuf_put_data(buf, data, data_len);
+		wpabuf_put_data(*buf, data, data_len);
 
 	return 0;
 }
@@ -350,10 +344,7 @@
 	if (max_age != 0xffff && max_age < diff_l)
 		goto reject;
 
-	if (wpabuf_resize(buf, 5 + wpabuf_len(wpa_s->lci)))
-		return -1;
-
-	if (wpas_rrm_report_elem(*buf, req->token,
+	if (wpas_rrm_report_elem(buf, req->token,
 				 MEASUREMENT_REPORT_MODE_ACCEPT, req->type,
 				 wpabuf_head_u8(wpa_s->lci),
 				 wpabuf_len(wpa_s->lci)) < 0) {
@@ -364,12 +355,7 @@
 	return 0;
 
 reject:
-	if (wpabuf_resize(buf, sizeof(struct rrm_measurement_report_element))) {
-		wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
-		return -1;
-	}
-
-	if (wpas_rrm_report_elem(*buf, req->token,
+	if (wpas_rrm_report_elem(buf, req->token,
 				 MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
 				 req->type, NULL, 0) < 0) {
 		wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
@@ -438,6 +424,12 @@
 		u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4;
 
 		freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan);
+		/* ieee80211_chan_to_freq() is not really meant for this
+		 * conversion of 20 MHz primary channel numbers for wider VHT
+		 * channels, so handle those as special cases here for now. */
+		if (freqs[i] < 0 &&
+		    (op_class == 128 || op_class == 129 || op_class == 130))
+			freqs[i] = 5000 + 5 * primary_chan;
 		if (freqs[i] < 0) {
 			wpa_printf(MSG_DEBUG,
 				   "Beacon Report: Invalid channel %u",
@@ -641,8 +633,8 @@
 }
 
 
-int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
-			 u8 *op_class, u8 *chan, u8 *phy_type)
+static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+				u8 *op_class, u8 *chan, u8 *phy_type)
 {
 	const u8 *ie;
 	int sec_chan = 0, vht = 0;
@@ -832,14 +824,7 @@
 	if (ret < 0)
 		return -1;
 
-	if (wpabuf_resize(wpa_buf,
-			  sizeof(struct rrm_measurement_report_element) +
-			  sizeof(*rep) + ret)) {
-		wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
-		return -1;
-	}
-
-	return wpas_rrm_report_elem(*wpa_buf, wpa_s->beacon_rep_data.token,
+	return wpas_rrm_report_elem(wpa_buf, wpa_s->beacon_rep_data.token,
 				    MEASUREMENT_REPORT_MODE_ACCEPT,
 				    MEASURE_TYPE_BEACON, buf,
 				    ret + sizeof(*rep));
@@ -849,12 +834,7 @@
 static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
 				      struct wpabuf **buf)
 {
-	if (wpabuf_resize(buf, 5)) {
-		wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
-		return -1;
-	}
-
-	return wpas_rrm_report_elem(*buf, wpa_s->beacon_rep_data.token,
+	return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
 				    MEASUREMENT_REPORT_MODE_ACCEPT,
 				    MEASURE_TYPE_BEACON, NULL, 0);
 }
@@ -880,11 +860,9 @@
 
 static void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
 {
-	struct wpabuf *buf;
+	struct wpabuf *buf = NULL;
 
-	buf = wpabuf_alloc(sizeof(struct rrm_measurement_beacon_report));
-	if (!buf ||
-	    wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
+	if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token,
 				 MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
 				 MEASURE_TYPE_BEACON, NULL, 0)) {
 		wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
@@ -1174,12 +1152,7 @@
 	}
 
 reject:
-	if (wpabuf_resize(buf, sizeof(struct rrm_measurement_report_element))) {
-		wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
-		return -1;
-	}
-
-	if (wpas_rrm_report_elem(*buf, req->token,
+	if (wpas_rrm_report_elem(buf, req->token,
 				 MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
 				 req->type, NULL, 0) < 0) {
 		wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
@@ -1311,10 +1284,14 @@
 	}
 
 	os_memset(&report, 0, sizeof(report));
+	report.dialog_token = req->dialog_token;
 	report.tpc.eid = WLAN_EID_TPC_REPORT;
 	report.tpc.len = 2;
+	/* Note: The driver is expected to update report.tpc.tx_power and
+	 * report.tpc.link_margin subfields when sending out this frame.
+	 * Similarly, the driver would need to update report.rx_ant_id and
+	 * report.tx_ant_id subfields. */
 	report.rsni = 255; /* 255 indicates that RSNI is not available */
-	report.dialog_token = req->dialog_token;
 	report.rcpi = rssi_to_rcpi(rssi);
 
 	/* action_category + action_code */
@@ -1328,8 +1305,7 @@
 	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
 	wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
 	wpabuf_put_data(buf, &report, sizeof(report));
-	wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
-		    wpabuf_head(buf), wpabuf_len(buf));
+	wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf);
 
 	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
 				wpa_s->own_addr, wpa_s->bssid,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index f478836..744bc7b 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -995,10 +995,35 @@
 	if (auth_type == WLAN_AUTH_FILS_SK) {
 		struct wpabuf *buf;
 		const u8 *snonce, *anonce;
+		const unsigned int max_hlp = 20;
+		struct wpabuf *hlp[max_hlp];
+		unsigned int i, num_hlp = 0;
+		struct fils_hlp_req *req;
+
+		dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+				 list) {
+			hlp[num_hlp] = wpabuf_alloc(2 * ETH_ALEN + 6 +
+					      wpabuf_len(req->pkt));
+			if (!hlp[num_hlp])
+				break;
+			wpabuf_put_data(hlp[num_hlp], req->dst, ETH_ALEN);
+			wpabuf_put_data(hlp[num_hlp], wpa_s->own_addr,
+					ETH_ALEN);
+			wpabuf_put_data(hlp[num_hlp],
+					"\xaa\xaa\x03\x00\x00\x00", 6);
+			wpabuf_put_buf(hlp[num_hlp], req->pkt);
+			num_hlp++;
+			if (num_hlp >= max_hlp)
+				break;
+		}
 
 		buf = fils_build_assoc_req(wpa_s->wpa, &params.fils_kek,
 					   &params.fils_kek_len, &snonce,
-					   &anonce);
+					   &anonce,
+					   (const struct wpabuf **) hlp,
+					   num_hlp);
+		for (i = 0; i < num_hlp; i++)
+			wpabuf_free(hlp[i]);
 		if (!buf)
 			return;
 		/* TODO: Make wpa_s->sme.assoc_req_ie use dynamic allocation */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 77038ca..538d5cc 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -348,6 +348,23 @@
 	return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv);
 }
 
+
+#ifdef CONFIG_MESH
+
+static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv);
+}
+
+#endif /* CONFIG_MESH */
 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 
 
@@ -2892,6 +2909,14 @@
 	{ "pmksa_add", wpa_cli_cmd_pmksa_add, NULL,
 	  cli_cmd_flag_sensitive,
 	  "<network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> <expiration in seconds> <akmp> <opportunistic> = store PMKSA cache entry from external storage" },
+#ifdef CONFIG_MESH
+	{ "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL,
+	  cli_cmd_flag_none,
+	  "<peer MAC address | any> = fetch all stored mesh PMKSA cache entries" },
+	{ "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<BSSID> <PMKID> <PMK> <expiration in seconds> = store mesh PMKSA cache entry from external storage" },
+#endif /* CONFIG_MESH */
 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 	{ "reassociate", wpa_cli_cmd_reassociate, NULL,
 	  cli_cmd_flag_none,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index fe14cc8..abb033d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -421,6 +421,19 @@
 }
 
 
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
+{
+	struct fils_hlp_req *req;
+
+	while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
+				    list)) != NULL) {
+		dl_list_del(&req->list);
+		wpabuf_free(req->pkt);
+		os_free(req);
+	}
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
 	int i;
@@ -587,6 +600,24 @@
 	wpabuf_free(wpa_s->lci);
 	wpa_s->lci = NULL;
 	wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+	{
+		struct external_pmksa_cache *entry;
+
+		while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+					     struct external_pmksa_cache,
+					     list)) != NULL) {
+			dl_list_del(&entry->list);
+			os_free(entry->pmksa_cache);
+			os_free(entry);
+		}
+	}
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+	wpas_flush_fils_hlp_req(wpa_s);
 }
 
 
@@ -2041,6 +2072,13 @@
 
 	vht_freq = *freq;
 
+#ifdef CONFIG_VHT_OVERRIDES
+	if (ssid->disable_vht) {
+		freq->vht_enabled = 0;
+		return;
+	}
+#endif /* CONFIG_VHT_OVERRIDES */
+
 	vht_freq.vht_enabled = vht_supported(mode);
 	if (!vht_freq.vht_enabled)
 		return;
@@ -3704,6 +3742,7 @@
 	wpa_s->sched_scanning = 0;
 
 	dl_list_init(&wpa_s->bss_tmp_disallowed);
+	dl_list_init(&wpa_s->fils_hlp_req);
 
 	return wpa_s;
 }
@@ -3731,8 +3770,11 @@
 	wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
 
 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+		long v;
+
 		errno = 0;
-		long v = strtol(tmp, &end, 16);
+		v = strtol(tmp, &end, 16);
+
 		if (errno == 0) {
 			wpa_msg(wpa_s, MSG_DEBUG,
 				"htcap value[%i]: %ld end: %p  tmp: %p",
@@ -3842,18 +3884,10 @@
 				struct ieee80211_ht_capabilities *htcaps_mask,
 				int disabled)
 {
-	/* Masking these out disables HT40 */
-	le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
-				HT_CAP_INFO_SHORT_GI40MHZ);
-
 	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
 
-	if (disabled)
-		htcaps->ht_capabilities_info &= ~msk;
-	else
-		htcaps->ht_capabilities_info |= msk;
-
-	htcaps_mask->ht_capabilities_info |= msk;
+	set_disable_ht40(htcaps, disabled);
+	set_disable_ht40(htcaps_mask, 0);
 
 	return 0;
 }
@@ -4129,10 +4163,14 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+	if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
+			   __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
+		return -1;
+	}
 	return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-					  wpa_s->own_addr, wpa_s->bssid,
-					  wpabuf_head(data), wpabuf_len(data),
+				   wpa_s->own_addr, wpa_s->bssid,
+				   wpabuf_head(data), wpabuf_len(data),
 				   0);
 }
 
@@ -4978,6 +5016,12 @@
 	if (wpa_bss_init(wpa_s) < 0)
 		return -1;
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+	dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
 	/*
 	 * Set Wake-on-WLAN triggers, if configured.
 	 * Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -5316,7 +5360,7 @@
 
 #ifdef CONFIG_MESH
 	if (mesh_if_created) {
-		wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+		wpa_drv_if_remove(wpa_s->parent, WPA_IF_MESH, ifname);
 		os_free(ifname);
 	}
 #endif /* CONFIG_MESH */
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 94cef4a..c90fa62 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -937,7 +937,7 @@
 #
 # group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
 # as the dot11RSNAConfigGroupRekeyTime parameter when operating in
-# Authenticator role in IBSS.
+# Authenticator role in IBSS, or in AP and mesh modes.
 #
 # Following fields are only used with internal EAP implementation.
 # eap: space-separated list of accepted EAP methods
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3c902fa..4375523 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -461,6 +461,17 @@
 };
 
 
+struct external_pmksa_cache {
+	struct dl_list list;
+	void *pmksa_cache;
+};
+
+struct fils_hlp_req {
+	struct dl_list list;
+	u8 dst[ETH_ALEN];
+	struct wpabuf *pkt;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -742,7 +753,7 @@
 		u8 ssid[SSID_MAX_LEN];
 		size_t ssid_len;
 		int freq;
-		u8 assoc_req_ie[300];
+		u8 assoc_req_ie[1500];
 		size_t assoc_req_ie_len;
 		int mfp;
 		int ft_used;
@@ -791,6 +802,10 @@
 	unsigned int mesh_if_created:1;
 	unsigned int mesh_ht_enabled:1;
 	unsigned int mesh_vht_enabled:1;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+	/* struct external_pmksa_cache::list */
+	struct dl_list mesh_external_pmksa_cache;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 #endif /* CONFIG_MESH */
 
 	unsigned int off_channel_freq;
@@ -1094,6 +1109,9 @@
 	struct os_reltime lci_time;
 
 	struct os_reltime beacon_rep_scan;
+
+	/* FILS HLP requests (struct fils_hlp_req) */
+	struct dl_list fils_hlp_req;
 };
 
 
@@ -1218,6 +1236,7 @@
 				 struct wpa_scan_results *scan_res,
 				 struct scan_info *info);
 void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
 
 
 /* MBO functions */