Cumulative patch from commit ee48f48ba

The following commits are merged as well as changes in
./wpa_supplicant/hidl/1.3 to fix compilation errors.

ee48f48ba hostapd: Support showing neighbor list through hostapd_cli
3204795d7 STA OBSS: Add check for overlapping BSSs
3af78a4e0 Extract BSS coex 40 MHz check into a separate function
70755e658 Allow removing neighbor DB entries by BSSID alone
bf3ab50f4 Change some RRM debug messages from wpa_printf() to wpa_dbg()
a737e40b5 drivers: Support of dynamic VLAN requires Linux ioctls
9b391715c mesh: Allow group management cipher to be configured
65d0b67c2 mesh: Increase plink action frame AMPY buffer length for max GTK/IGTK
b1b62a136 WPS: Add WPS-PIN-ACTIVE and WPS-CANCEL events
0b1839405 Add "reconnect" cmdline argument to hostapd_cli/wpa_cli
4318a635a DBus: Update dont_quote[] with new network profile parameters
26a00ba8b DBus: Remove not existing network profile params from dont_quote[]
23d87687c dbus: Move roam metrics to the correct interface
8e111157e nl80211: Relax bridge setup
3626e72c8 l2_packet: Fix bridge workaround for repeater configuration
84972999b FT: More debug prints for RSNE modification for EAPOL-Key msg 2/4
4cfa8b92b Fix wpa_insert_pmkid() when buffer includes extra IEs
32289112c wpa_passphrase: Output errors to stderr
07fe134d9 EAP-SIM peer: Do not accept SIM/Challenge without SIM/Start
b2e2a8588 OpenSSL: Extend key_block size determination to support GCM/CCM ciphers
efaa6256e More detailed documentation on ieee80211w configuration parameter
1730a6a5e nl80211: Fix couple of typos in a comment
307cfc328 Strip trailing zero data in EAPOL-Key msg 1/4 when no PMKID to send
2c5ccfa60 nl80211: Initialize full channel info struct even if channel is not known
e6d3aca9c WPS: Add prefixes to public event_* functions
2ba6aa604 Fix memory leak in case allocation of token fails during JSON parsing
84877f253 wpa_supplicant: Do not try to detect PSK mismatch during PTK rekeying
78d338d1b DPP: Fix a memory leak on an error path
9be30ffc1 DPP: Abort ongoing scan if connection status needs to be sent
3f3876344 SAE: Enable NEED_DH_GROUPS_ALL for CONFIG_TESTING_OPTIONS=y builds
1f1567d2a QCA vendor command for getting STA information
e5620bf02 6 GHz: Select channel width using configured op_class
0bfc04b8d Do not enable HT/VHT when operating in 6 GHz band
da8570f4c Allow non-PCS 6 GHz channels to be excluded from ACS
59bb72642 Allow ACS channel list to be configured as frequencies (in MHz)
5f9b4afdf Use frequency in HT/VHT validation steps done before starting AP
59e33b4a9 ACS: Select current hw_mode based on the selected frequency
bb781c763 AP: Populate iface->freq before starting AP
41cac481a ACS: Use frequency params in ACS (offload) completed event interface
840532aea Search through all hw_features sets in hw_get_channel_freq()
15d356873 ACS: Add channels from all modes matching with configured hw mode
996662250 P2P: Add support for EDMG channels
f86e34168 Update operating classes and channels for the 60 GHz band
a19277a28 Add EDMG bandwidth to channel frequency APIs
5a563a3d3 Avoid compiler warning on shadowing a local variable
e3c476bd8 SAE H2E: Fix RSNXE override in EAPOL-Key msg 2/4 for testing purposes
7fde39fb1 Add sae_rejected_groups to hostapd STA control interface command
5661ebd77 DPP: Configurator netRole for Enrollee
740457445 DPP: Replace ap boolean with netRole enum in Configurator params
f2c4b44b4 SAE H2E: RSNXE override in EAPOL-Key msg 3/4
132565539 SAE H2E: RSNXE override for testing purposes
a889e9a70 SAE: Reject invalid rejected group report in SAE commit explicitly (AP)
c88e01e1b SAE H2E: Fix validation of rejected groups list
b834e9700 SAE H2E: Testing option to report extra rejected groups
918df2227 SAE: Reject unexpected Status Code in SAE commit explicitly (AP)
405946d76 SAE: Testing option to ignore H2E requirement mismatch
23acdd9f3 Fix memory leak in ACS offload operation
e86ba912a ACS: Remove redundant ch_list parameters from do_acs interface
3cf360b8e DFS: Don't handle DFS ops for 6 GHz channels
ee0030e81 6 GHz: Do not check for HT capability on 6 GHz channels
e780b4bf2 DPP: Bootstrapping via NFC URI Record
3c0d6eb8a Sync with mac80211-next.git include/uapi/linux/nl80211.h
38203148e Extend hostapd to support setband to driver via QCA vendor command
3c13af557 hostapd: Register wpa_msg callback even if only global ctrl_iface is used
e92080568 hostapd: Extend global control interface notifications
9f50538e1 SAE H2E: Do not use sae_h2e param in AP mode if SAE is disabled
181bf9336 DPP2: Report received ssid_charset as DPP-CONFOBJ-SSID-CHARSET event
71e2848ea DPP2: ssid64/ssid_charset in Configurator
57a63b131 DPP2: Add parsing of ssid64/ssid_charset in Config Object
590bc64d6 DPP: Use JSON token builder helpers
e75ab5322 JSON: Add helper functions for building tokens
8e5e36a18 Clean up base64_{encode,decode} pointer types
b22608423 Clean up base64_url_{encode,decode} pointer types
a4255a207 Simplify base64_url_encode() prototype
c54227c26 DPP2: Replace connectionStatus object ssid with ssid64
31b6eb417 tests: Update SAE H2E test case to match SSWU parameter z change
0432237a4 SAE H2E: Update SSWU curve-specific parameter z values
5b50265e1 WMM: Do not modify input TSPEC buffer during processing
783a99b73 HS2.0: Skip check for roaming_consortium for NAI realm query
f3c077929 P2P: Fix listen state machine getting stuck in send_action() scheduled case
530b8ee3c hostapd: Update DFS status in VHT80+80 mode
93ba13bcf Fix status code in SAE/DPP association PMKID mismatch (driver-AP-SME)
b90d2f7ff Fix a typo in a comment

Bug: 146900007
Test: Device boots up and connects to wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: Regression test Passed (Bug: 146905211)
Change-Id: Idc3584b491429a2e4935068a293bff572fc9d62e
diff --git a/src/ap/acs.c b/src/ap/acs.c
index f12539f..232afa8 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -862,6 +862,7 @@
 	}
 
 	iface->conf->channel = ideal_chan->chan;
+	iface->freq = ideal_chan->freq;
 
 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
 		acs_adjust_center_freq(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 58fc3e9..68af3c1 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -441,7 +441,7 @@
 	struct hostapd_ssid *ssid = &conf->ssid;
 	struct sae_password_entry *pw;
 
-	if (conf->sae_pwe == 0)
+	if (conf->sae_pwe == 0 || !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
 		return 0; /* PT not needed */
 
 	sae_deinit_pt(ssid->pt);
@@ -880,6 +880,7 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	wpabuf_free(conf->own_ie_override);
 	wpabuf_free(conf->sae_commit_override);
+	wpabuf_free(conf->rsnxe_override_eapol);
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	os_free(conf->no_probe_resp_if_seen_on);
@@ -935,6 +936,7 @@
 	os_free(conf->supported_rates);
 	os_free(conf->basic_rates);
 	os_free(conf->acs_ch_list.range);
+	os_free(conf->acs_freq_list.range);
 	os_free(conf->driver_params);
 #ifdef CONFIG_ACS
 	os_free(conf->acs_chan_bias);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2a0c984..83b8aee 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -664,6 +664,7 @@
 	struct wpabuf *own_ie_override;
 	int sae_reflection_attack;
 	struct wpabuf *sae_commit_override;
+	struct wpabuf *rsnxe_override_eapol;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #define MESH_ENABLED BIT(0)
@@ -881,8 +882,11 @@
 	u8 edmg_channel;
 	u8 acs;
 	struct wpa_freq_range_list acs_ch_list;
+	struct wpa_freq_range_list acs_freq_list;
+	u8 acs_freq_list_present;
 	int acs_exclude_dfs;
 	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+	int acs_exclude_6ghz_non_psc;
 	enum {
 		LONG_PREAMBLE = 0,
 		SHORT_PREAMBLE = 1
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 204274f..7585866 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "common/hw_features_common.h"
 #include "wps/wps.h"
 #include "p2p/p2p.h"
@@ -855,10 +856,24 @@
 	for (i = 0; i < mode->num_channels; i++) {
 		struct hostapd_channel_data *chan = &mode->channels[i];
 
-		if ((acs_ch_list_all ||
-		     freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
-					      chan->chan)) &&
-		    !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+		if (!acs_ch_list_all &&
+		    (hapd->iface->conf->acs_freq_list.num &&
+		     !freq_range_list_includes(
+			     &hapd->iface->conf->acs_freq_list,
+			     chan->freq)))
+			continue;
+		if (!acs_ch_list_all &&
+		    (!hapd->iface->conf->acs_freq_list_present &&
+		     hapd->iface->conf->acs_ch_list.num &&
+		     !freq_range_list_includes(
+			     &hapd->iface->conf->acs_ch_list,
+			     chan->chan)))
+			continue;
+		if (is_6ghz_freq(chan->freq) &&
+		    hapd->iface->conf->acs_exclude_6ghz_non_psc &&
+		    !is_6ghz_psc_frequency(chan->freq))
+			continue;
+		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
 		    !(hapd->iface->conf->acs_exclude_dfs &&
 		      (chan->flag & HOSTAPD_CHAN_RADAR)))
 			int_array_add_unique(freq_list, chan->freq);
@@ -884,10 +899,9 @@
 {
 	struct drv_acs_params params;
 	int ret, i, acs_ch_list_all = 0;
-	u8 *channels = NULL;
-	unsigned int num_channels = 0;
 	struct hostapd_hw_modes *mode;
 	int *freq_list = NULL;
+	enum hostapd_hw_mode selected_mode;
 
 	if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
 		return 0;
@@ -899,41 +913,25 @@
 	 * If no chanlist config parameter is provided, include all enabled
 	 * channels of the selected hw_mode.
 	 */
-	if (!hapd->iface->conf->acs_ch_list.num)
-		acs_ch_list_all = 1;
+	if (hapd->iface->conf->acs_freq_list_present)
+		acs_ch_list_all = !hapd->iface->conf->acs_freq_list.num;
+	else
+		acs_ch_list_all = !hapd->iface->conf->acs_ch_list.num;
 
-	mode = hapd->iface->current_mode;
-	if (mode) {
-		channels = os_malloc(mode->num_channels);
-		if (channels == NULL)
-			return -1;
+	if (hapd->iface->current_mode)
+		selected_mode = hapd->iface->current_mode->mode;
+	else
+		selected_mode = HOSTAPD_MODE_IEEE80211ANY;
 
-		for (i = 0; i < mode->num_channels; i++) {
-			struct hostapd_channel_data *chan = &mode->channels[i];
-			if (!acs_ch_list_all &&
-			    !freq_range_list_includes(
-				    &hapd->iface->conf->acs_ch_list,
-				    chan->chan))
-				continue;
-			if (hapd->iface->conf->acs_exclude_dfs &&
-			    (chan->flag & HOSTAPD_CHAN_RADAR))
-				continue;
-			if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
-				channels[num_channels++] = chan->chan;
-				int_array_add_unique(&freq_list, chan->freq);
-			}
-		}
-	} else {
-		for (i = 0; i < hapd->iface->num_hw_features; i++) {
-			mode = &hapd->iface->hw_features[i];
-			hostapd_get_hw_mode_any_channels(hapd, mode,
-							 acs_ch_list_all,
-							 &freq_list);
-		}
+	for (i = 0; i < hapd->iface->num_hw_features; i++) {
+		mode = &hapd->iface->hw_features[i];
+		if (selected_mode != HOSTAPD_MODE_IEEE80211ANY &&
+		    selected_mode != mode->mode)
+			continue;
+		hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
+						 &freq_list);
 	}
 
-	params.ch_list = channels;
-	params.ch_list_len = num_channels;
 	params.freq_list = freq_list;
 
 	params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
@@ -958,8 +956,11 @@
 			params.ch_width = 160;
 	}
 
+	if (hapd->iface->conf->op_class)
+		params.ch_width = op_class_to_bandwidth(
+			hapd->iface->conf->op_class);
 	ret = hapd->driver->do_acs(hapd->drv_priv, &params);
-	os_free(channels);
+	os_free(freq_list);
 
 	return ret;
 }
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 79b1302..fa413df 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -382,4 +382,12 @@
 	return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
 }
 
+static inline int
+hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
+{
+	if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
+		return -1;
+	return hapd->driver->set_band(hapd->drv_priv, band);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index bde61ee..9fd1b81 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -273,6 +273,36 @@
 		if (!os_snprintf_error(buflen - len, res))
 			len += res;
 	}
+
+	if (sta->sae && sta->sae->tmp) {
+		const u8 *pos;
+		unsigned int j, count;
+		struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
+
+		res = os_snprintf(buf + len, buflen - len,
+				  "sae_rejected_groups=");
+		if (!os_snprintf_error(buflen - len, res))
+			len += res;
+
+		if (groups) {
+			pos = wpabuf_head(groups);
+			count = wpabuf_len(groups) / 2;
+		} else {
+			pos = NULL;
+			count = 0;
+		}
+		for (j = 0; pos && j < count; j++) {
+			res = os_snprintf(buf + len, buflen - len, "%s%d",
+					  j == 0 ? "" : " ", WPA_GET_LE16(pos));
+			if (!os_snprintf_error(buflen - len, res))
+				len += res;
+			pos += 2;
+		}
+
+		res = os_snprintf(buf + len, buflen - len, "\n");
+		if (!os_snprintf_error(buflen - len, res))
+			len += res;
+	}
 #endif /* CONFIG_SAE */
 
 	if (sta->vlan_id > 0) {
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index c4c00fc..f70ecc9 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -515,6 +515,7 @@
 	int n_chans = 1, i;
 	struct hostapd_hw_modes *mode;
 	int frequency = freq;
+	int frequency2 = 0;
 	int ret = 0;
 
 	mode = iface->current_mode;
@@ -542,6 +543,11 @@
 		n_chans = 4;
 		frequency = cf1 - 30;
 		break;
+	case CHAN_WIDTH_80P80:
+		n_chans = 4;
+		frequency = cf1 - 30;
+		frequency2 = cf2 - 30;
+		break;
 	case CHAN_WIDTH_160:
 		n_chans = 8;
 		frequency = cf1 - 70;
@@ -557,6 +563,11 @@
 	for (i = 0; i < n_chans; i++) {
 		ret += set_dfs_state_freq(iface, frequency, state);
 		frequency = frequency + 20;
+
+		if (chan_width == CHAN_WIDTH_80P80) {
+			ret += set_dfs_state_freq(iface, frequency2, state);
+			frequency2 = frequency2 + 20;
+		}
 	}
 
 	return ret;
@@ -662,6 +673,9 @@
 	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
 	int skip_radar = 0;
 
+	if (is_6ghz_freq(iface->freq))
+		return 1;
+
 	if (!iface->current_mode) {
 		/*
 		 * This can happen with drivers that do not provide mode
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 085d423..1a3a815 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1,6 +1,7 @@
 /*
  * hostapd / DPP integration
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -62,6 +63,24 @@
 }
 
 
+/**
+ * hostapd_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @hapd: Pointer to hostapd_data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd)
+{
+	struct dpp_bootstrap_info *bi;
+
+	bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, cmd);
+	if (!bi)
+		return -1;
+
+	return bi->id;
+}
+
+
 static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
 						void *timeout_ctx)
 {
@@ -768,7 +787,8 @@
 	struct wpabuf *buf;
 	int res;
 
-	buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name, 1,
+	buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name,
+					DPP_NETROLE_AP,
 					hapd->conf->dpp_mud_url, NULL);
 	if (!buf) {
 		wpa_printf(MSG_DEBUG,
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index c1ec5d7..e151c2f 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -1,6 +1,7 @@
 /*
  * hostapd / DPP integration
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +11,7 @@
 #define DPP_HOSTAPD_H
 
 int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
 void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3198bd5..8a4b0ef 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -17,6 +17,7 @@
 #include "common/wpa_ctrl.h"
 #include "common/dpp.h"
 #include "common/sae.h"
+#include "common/hw_features_common.h"
 #include "crypto/random.h"
 #include "p2p/p2p.h"
 #include "wps/wps.h"
@@ -344,6 +345,9 @@
 			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
 				reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
 				status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+			} else if (res == WPA_INVALID_PMKID) {
+				reason = WLAN_REASON_INVALID_PMKID;
+				status = WLAN_STATUS_INVALID_PMKID;
 			} else {
 				reason = WLAN_REASON_INVALID_IE;
 				status = WLAN_STATUS_INVALID_IE;
@@ -932,6 +936,7 @@
 {
 	int ret, i;
 	int err = 0;
+	struct hostapd_channel_data *pri_chan;
 
 	if (hapd->iconf->channel) {
 		wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -939,12 +944,20 @@
 		return;
 	}
 
+	hapd->iface->freq = acs_res->pri_freq;
+
 	if (!hapd->iface->current_mode) {
 		for (i = 0; i < hapd->iface->num_hw_features; i++) {
 			struct hostapd_hw_modes *mode =
 				&hapd->iface->hw_features[i];
 
 			if (mode->mode == acs_res->hw_mode) {
+				if (hapd->iface->freq > 0 &&
+				    !hw_get_chan(mode->mode,
+						 hapd->iface->freq,
+						 hapd->iface->hw_features,
+						 hapd->iface->num_hw_features))
+					continue;
 				hapd->iface->current_mode = mode;
 				break;
 			}
@@ -958,24 +971,33 @@
 		}
 	}
 
-	hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
-
-	if (!acs_res->pri_channel) {
+	if (!acs_res->pri_freq) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_WARNING,
 			       "driver switched to bad channel");
 		err = 1;
 		goto out;
 	}
+	pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
+				       acs_res->pri_freq, NULL,
+				       hapd->iface->hw_features,
+				       hapd->iface->num_hw_features);
+	if (!pri_chan) {
+		wpa_printf(MSG_ERROR,
+			   "ACS: Could not determine primary channel number from pri_freq %u",
+			   acs_res->pri_freq);
+		err = 1;
+		goto out;
+	}
 
-	hapd->iconf->channel = acs_res->pri_channel;
+	hapd->iconf->channel = pri_chan->chan;
 	hapd->iconf->acs = 1;
 
-	if (acs_res->sec_channel == 0)
+	if (acs_res->sec_freq == 0)
 		hapd->iconf->secondary_channel = 0;
-	else if (acs_res->sec_channel < acs_res->pri_channel)
+	else if (acs_res->sec_freq < acs_res->pri_freq)
 		hapd->iconf->secondary_channel = -1;
-	else if (acs_res->sec_channel > acs_res->pri_channel)
+	else if (acs_res->sec_freq > acs_res->pri_freq)
 		hapd->iconf->secondary_channel = 1;
 	else {
 		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3686438..e4950e3 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1572,6 +1572,51 @@
 }
 
 
+static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
+{
+	int freq, i, j;
+
+	if (!iface->conf->channel)
+		return 0;
+	if (iface->conf->op_class) {
+		freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
+					      iface->conf->channel);
+		if (freq < 0) {
+			wpa_printf(MSG_INFO,
+				   "Could not convert op_class %u channel %u to operating frequency",
+				   iface->conf->op_class, iface->conf->channel);
+			return -1;
+		}
+		iface->freq = freq;
+		return 0;
+	}
+
+	/* Old configurations using only 2.4/5/60 GHz bands may not specify the
+	 * op_class parameter. Select a matching channel from the configured
+	 * mode using the channel parameter for these cases.
+	 */
+	for (j = 0; j < iface->num_hw_features; j++) {
+		struct hostapd_hw_modes *mode = &iface->hw_features[j];
+
+		if (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
+		    iface->conf->hw_mode != mode->mode)
+			continue;
+		for (i = 0; i < mode->num_channels; i++) {
+			struct hostapd_channel_data *chan = &mode->channels[i];
+
+			if (chan->chan == iface->conf->channel &&
+			    !is_6ghz_freq(chan->freq)) {
+				iface->freq = chan->freq;
+				return 0;
+			}
+		}
+	}
+
+	wpa_printf(MSG_INFO, "Could not determine operating frequency");
+	return -1;
+}
+
+
 static int setup_interface2(struct hostapd_iface *iface)
 {
 	iface->wait_channel_update = 0;
@@ -1580,7 +1625,20 @@
 		/* Not all drivers support this yet, so continue without hw
 		 * feature data. */
 	} else {
-		int ret = hostapd_select_hw_mode(iface);
+		int ret;
+
+		ret = configured_fixed_chan_to_freq(iface);
+		if (ret < 0)
+			goto fail;
+
+		if (iface->conf->op_class) {
+			int ch_width;
+
+			ch_width = op_class_to_ch_width(iface->conf->op_class);
+			hostapd_set_oper_chwidth(iface->conf, ch_width);
+		}
+
+		ret = hostapd_select_hw_mode(iface);
 		if (ret < 0) {
 			wpa_printf(MSG_ERROR, "Could not select hw_mode and "
 				   "channel. (%d)", ret);
@@ -1864,12 +1922,11 @@
 		goto fail;
 
 	wpa_printf(MSG_DEBUG, "Completing interface initialization");
-	if (iface->conf->channel) {
+	if (iface->freq) {
 #ifdef NEED_AP_MLME
 		int res;
 #endif /* NEED_AP_MLME */
 
-		iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
 		wpa_printf(MSG_DEBUG, "Mode: %s  Channel: %d  "
 			   "Frequency: %d MHz",
 			   hostapd_hw_mode_txt(iface->conf->hw_mode),
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 2fefaf8..ba10752 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -227,13 +227,25 @@
 #ifdef CONFIG_IEEE80211N
 static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
 {
-	int pri_chan, sec_chan;
+	int pri_freq, sec_freq;
+	struct hostapd_channel_data *p_chan, *s_chan;
 
-	pri_chan = iface->conf->channel;
-	sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+	pri_freq = iface->freq;
+	sec_freq = pri_freq + iface->conf->secondary_channel * 20;
 
-	return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
-					 sec_chan);
+	if (!iface->current_mode)
+		return 0;
+
+	p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+				     iface->hw_features,
+				     iface->num_hw_features);
+
+	s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+				     iface->hw_features,
+				     iface->num_hw_features);
+
+	return allowed_ht40_channel_pair(iface->current_mode->mode,
+					 p_chan, s_chan);
 }
 
 
@@ -241,9 +253,11 @@
 {
 	if (iface->conf->secondary_channel > 0) {
 		iface->conf->channel += 4;
+		iface->freq += 20;
 		iface->conf->secondary_channel = -1;
 	} else {
 		iface->conf->channel -= 4;
+		iface->freq -= 20;
 		iface->conf->secondary_channel = 1;
 	}
 }
@@ -252,13 +266,23 @@
 static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
 				     struct wpa_scan_results *scan_res)
 {
-	int pri_chan, sec_chan;
+	unsigned int pri_freq, sec_freq;
 	int res;
+	struct hostapd_channel_data *pri_chan, *sec_chan;
 
-	pri_chan = iface->conf->channel;
-	sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+	pri_freq = iface->freq;
+	sec_freq = pri_freq + iface->conf->secondary_channel * 20;
 
-	res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
+	if (!iface->current_mode)
+		return 0;
+	pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+				       NULL, iface->hw_features,
+				       iface->num_hw_features);
+	sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+				       NULL, iface->hw_features,
+				       iface->num_hw_features);
+
+	res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
 
 	if (res == 2) {
 		if (iface->conf->no_pri_sec_switch) {
@@ -352,7 +376,7 @@
 	if (iface->current_mode == NULL)
 		return;
 
-	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	pri_freq = iface->freq;
 	if (iface->conf->secondary_channel > 0)
 		sec_freq = pri_freq + 20;
 	else
@@ -397,7 +421,7 @@
 	if (iface->current_mode == NULL)
 		return;
 
-	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	pri_freq = iface->freq;
 	if (iface->conf->secondary_channel > 0) {
 		affected_start = pri_freq - 10;
 		affected_end = pri_freq + 30;
@@ -670,6 +694,9 @@
 {
 #ifdef CONFIG_IEEE80211N
 	int ret;
+
+	if (is_6ghz_freq(iface->freq))
+		return 0;
 	if (!iface->conf->ieee80211n)
 		return 0;
 
@@ -731,14 +758,15 @@
 
 
 static int hostapd_is_usable_chan(struct hostapd_iface *iface,
-				  int channel, int primary)
+				  int frequency, int primary)
 {
 	struct hostapd_channel_data *chan;
 
 	if (!iface->current_mode)
 		return 0;
 
-	chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+	chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
+				   iface->hw_features, iface->num_hw_features);
 	if (!chan)
 		return 0;
 
@@ -747,8 +775,8 @@
 		return 1;
 
 	wpa_printf(MSG_INFO,
-		   "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
-		   channel, primary ? "primary" : "secondary",
+		   "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+		   frequency, primary ? "primary" : "secondary",
 		   chan->flag,
 		   chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
 		   chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@@ -762,19 +790,28 @@
 	int num_of_enabled = 0;
 	int max_contiguous = 0;
 	struct ieee80211_edmg_config edmg;
+	struct hostapd_channel_data *pri_chan;
 
 	if (!iface->conf->enable_edmg)
 		return 1;
 
+	if (!iface->current_mode)
+		return 0;
+	pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+				       iface->freq, NULL,
+				       iface->hw_features,
+				       iface->num_hw_features);
 	hostapd_encode_edmg_chan(iface->conf->enable_edmg,
 				 iface->conf->edmg_channel,
-				 iface->conf->channel,
+				 pri_chan->chan,
 				 &edmg);
-	if (!(edmg.channels & BIT(iface->conf->channel - 1)))
+	if (!(edmg.channels & BIT(pri_chan->chan - 1)))
 		return 0;
 
 	/* 60 GHz channels 1..6 */
 	for (i = 0; i < 6; i++) {
+		int freq = 56160 + 2160 * i;
+
 		if (edmg.channels & BIT(i)) {
 			contiguous++;
 			num_of_enabled++;
@@ -789,7 +826,7 @@
 		if (num_of_enabled > 4)
 			return 0;
 
-		if (!hostapd_is_usable_chan(iface, i + 1, 1))
+		if (!hostapd_is_usable_chan(iface, freq, 1))
 			return 0;
 
 		if (contiguous > max_contiguous)
@@ -819,17 +856,23 @@
 
 static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 {
-	int secondary_chan;
+	int secondary_freq;
 	struct hostapd_channel_data *pri_chan;
 
-	pri_chan = hw_get_channel_chan(iface->current_mode,
-				       iface->conf->channel, NULL);
-	if (!pri_chan)
+	if (!iface->current_mode)
 		return 0;
-
-	if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
+	pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+				       iface->freq, NULL,
+				       iface->hw_features,
+				       iface->num_hw_features);
+	if (!pri_chan) {
+		wpa_printf(MSG_ERROR, "Primary frequency not present");
 		return 0;
-
+	}
+	if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
+		wpa_printf(MSG_ERROR, "Primary frequency not allowed");
+		return 0;
+	}
 	if (!hostapd_is_usable_edmg(iface))
 		return 0;
 
@@ -838,19 +881,19 @@
 
 	if (!iface->conf->ht40_plus_minus_allowed)
 		return hostapd_is_usable_chan(
-			iface, iface->conf->channel +
-			iface->conf->secondary_channel * 4, 0);
+			iface,
+			iface->freq + iface->conf->secondary_channel * 20, 0);
 
 	/* Both HT40+ and HT40- are set, pick a valid secondary channel */
-	secondary_chan = iface->conf->channel + 4;
-	if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+	secondary_freq = iface->freq + 20;
+	if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
 	    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
 		iface->conf->secondary_channel = 1;
 		return 1;
 	}
 
-	secondary_chan = iface->conf->channel - 4;
-	if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+	secondary_freq = iface->freq - 20;
+	if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
 	    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
 		iface->conf->secondary_channel = -1;
 		return 1;
@@ -863,7 +906,7 @@
 static enum hostapd_chan_status
 hostapd_check_chans(struct hostapd_iface *iface)
 {
-	if (iface->conf->channel) {
+	if (iface->freq) {
 		if (hostapd_is_usable_chans(iface))
 			return HOSTAPD_CHAN_VALID;
 		else
@@ -897,9 +940,9 @@
 	hostapd_logger(iface->bss[0], NULL,
 		       HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_WARNING,
-		       "Configured channel (%d) not found from the "
-		       "channel list of current mode (%d) %s",
+		       "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
 		       iface->conf->channel,
+		       iface->freq,
 		       iface->current_mode->mode,
 		       hostapd_hw_mode_txt(iface->current_mode->mode));
 	hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -919,9 +962,7 @@
 	case HOSTAPD_CHAN_VALID:
 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
 			ACS_EVENT_COMPLETED "freq=%d channel=%d",
-			hostapd_hw_get_freq(iface->bss[0],
-					    iface->conf->channel),
-			iface->conf->channel);
+			iface->freq, iface->conf->channel);
 		break;
 	case HOSTAPD_CHAN_ACS:
 		wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
@@ -961,7 +1002,6 @@
 int hostapd_select_hw_mode(struct hostapd_iface *iface)
 {
 	int i;
-	int freq = -1;
 
 	if (iface->num_hw_features < 1)
 		return -1;
@@ -978,13 +1018,13 @@
 	}
 
 	iface->current_mode = NULL;
-	if (iface->conf->channel && iface->conf->op_class)
-		freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
-					      iface->conf->channel);
 	for (i = 0; i < iface->num_hw_features; i++) {
 		struct hostapd_hw_modes *mode = &iface->hw_features[i];
 		if (mode->mode == iface->conf->hw_mode) {
-			if (freq > 0 && !hw_get_chan(mode, freq))
+			if (iface->freq > 0 &&
+			    !hw_get_chan(mode->mode, iface->freq,
+					 iface->hw_features,
+					 iface->num_hw_features))
 				continue;
 			iface->current_mode = mode;
 			break;
@@ -1048,7 +1088,9 @@
 	struct hostapd_hw_modes *mode;
 
 	if (hapd->iface->current_mode) {
-		channel = hw_get_chan(hapd->iface->current_mode, freq);
+		channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+				      hapd->iface->hw_features,
+				      hapd->iface->num_hw_features);
 		if (channel)
 			return channel;
 	}
@@ -1059,7 +1101,9 @@
 		return 0;
 	for (i = 0; i < hapd->iface->num_hw_features; i++) {
 		mode = &hapd->iface->hw_features[i];
-		channel = hw_get_chan(mode, freq);
+		channel = hw_get_chan(mode->mode, freq,
+				      hapd->iface->hw_features,
+				      hapd->iface->num_hw_features);
 		if (channel)
 			return channel;
 	}
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 4d30bae..5b70425 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -98,7 +98,8 @@
 		num++;
 	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
 		num++;
-	if (hapd->conf->sae_pwe == 1)
+	if (hapd->conf->sae_pwe == 1 &&
+	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
 		num++;
 	if (num > 8) {
 		/* rest of the rates are encoded in Extended supported
@@ -126,7 +127,9 @@
 		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
 	}
 
-	if (hapd->conf->sae_pwe == 1 && count < 8) {
+	if (hapd->conf->sae_pwe == 1 &&
+	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+	    count < 8) {
 		count++;
 		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
 	}
@@ -148,7 +151,8 @@
 		num++;
 	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
 		num++;
-	if (hapd->conf->sae_pwe == 1)
+	if (hapd->conf->sae_pwe == 1 &&
+	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
 		num++;
 	if (num <= 8)
 		return eid;
@@ -179,7 +183,8 @@
 			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
 	}
 
-	if (hapd->conf->sae_pwe == 1) {
+	if (hapd->conf->sae_pwe == 1 &&
+	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
 		count++;
 		if (count > 8)
 			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
@@ -1117,8 +1122,10 @@
 	if (!sta->sae) {
 		if (auth_transaction != 1 ||
 		    !sae_status_success(hapd, status_code)) {
-			resp = -1;
-			goto remove_sta;
+			wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
+				   status_code);
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto reply;
 		}
 		sta->sae = os_zalloc(sizeof(*sta->sae));
 		if (!sta->sae) {
@@ -1273,9 +1280,9 @@
 
 		if (sta->sae->tmp &&
 		    check_sae_rejected_groups(
-			    hapd, sta->sae->tmp->peer_rejected_groups) < 0) {
+			    hapd, sta->sae->tmp->peer_rejected_groups)) {
 			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			goto remove_sta;
+			goto reply;
 		}
 
 		if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 0b828e9..1e1cc38 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -1011,6 +1011,7 @@
 	u8 *pos = eid;
 
 	if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+	    !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
 	    (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) ||
 	    len < 3)
 		return pos;
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 5415443..4012ae4 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -34,6 +34,60 @@
 }
 
 
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+	struct hostapd_neighbor_entry *nr;
+	char *pos, *end;
+
+	pos = buf;
+	end = buf + buflen;
+
+	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+			 list) {
+		int ret;
+		char nrie[2 * 255 + 1];
+		char lci[2 * 255 + 1];
+		char civic[2 * 255 + 1];
+		char ssid[SSID_MAX_LEN * 2 + 1];
+
+		ssid[0] = '\0';
+		wpa_snprintf_hex(ssid, sizeof(ssid), nr->ssid.ssid,
+				 nr->ssid.ssid_len);
+
+		nrie[0] = '\0';
+		if (nr->nr)
+			wpa_snprintf_hex(nrie, sizeof(nrie),
+					 wpabuf_head(nr->nr),
+					 wpabuf_len(nr->nr));
+
+		lci[0] = '\0';
+		if (nr->lci)
+			wpa_snprintf_hex(lci, sizeof(lci),
+					 wpabuf_head(nr->lci),
+					 wpabuf_len(nr->lci));
+
+		civic[0] = '\0';
+		if (nr->civic)
+			wpa_snprintf_hex(civic, sizeof(civic),
+					 wpabuf_head(nr->civic),
+					 wpabuf_len(nr->civic));
+
+		ret = os_snprintf(pos, end - pos, MACSTR
+				  " ssid=%s%s%s%s%s%s%s%s\n",
+				  MAC2STR(nr->bssid), ssid,
+				  nr->nr ? " nr=" : "", nrie,
+				  nr->lci ? " lci=" : "", lci,
+				  nr->civic ? " civic=" : "", civic,
+				  nr->stationary ? " stat" : "");
+		if (os_snprintf_error(end - pos, ret))
+			break;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
 static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
 {
 	wpabuf_free(nr->nr);
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index 9c8f4f2..bed0a2f 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -13,6 +13,7 @@
 struct hostapd_neighbor_entry *
 hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
 		     const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen);
 int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
 			 const struct wpa_ssid_value *ssid,
 			 const struct wpabuf *nr, const struct wpabuf *lci,
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index dc73493..9f52dee 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -291,10 +291,11 @@
 
 static void wmm_addts_req(struct hostapd_data *hapd,
 			  const struct ieee80211_mgmt *mgmt,
-			  struct wmm_tspec_element *tspec, size_t len)
+			  const struct wmm_tspec_element *tspec, size_t len)
 {
 	const u8 *end = ((const u8 *) mgmt) + len;
 	int res;
+	struct wmm_tspec_element tspec_resp;
 
 	if ((const u8 *) (tspec + 1) > end) {
 		wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
@@ -306,10 +307,11 @@
 		   mgmt->u.action.u.wmm_action.dialog_token,
 		   MAC2STR(mgmt->sa));
 
-	res = wmm_process_tspec(tspec);
+	os_memcpy(&tspec_resp, tspec, sizeof(struct wmm_tspec_element));
+	res = wmm_process_tspec(&tspec_resp);
 	wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
 
-	wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+	wmm_send_action(hapd, mgmt->sa, &tspec_resp, WMM_ACTION_CODE_ADDTS_RESP,
 			mgmt->u.action.u.wmm_action.dialog_token, res);
 }
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7b690d7..6611b0e 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -2169,7 +2169,6 @@
 			wpa_printf(MSG_DEBUG,
 				   "FT: No PMKID in message 1/4 when using FT protocol");
 			pmkid = NULL;
-			pmkid_len = 0;
 #endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_SAE
 		} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
@@ -2199,6 +2198,8 @@
 				    &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
 		}
 	}
+	if (!pmkid)
+		pmkid_len = 0;
 	wpa_send_eapol(sm->wpa_auth, sm,
 		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
 		       sm->ANonce, pmkid, pmkid_len, 0, 0);
@@ -3139,11 +3140,12 @@
 
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
-	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
 	size_t gtk_len, kde_len;
 	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
 	int wpa_ie_len, secure, gtkidx, encr = 0;
+	u8 *wpa_ie_buf = NULL;
 
 	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
 	sm->TimeoutEvt = FALSE;
@@ -3177,6 +3179,35 @@
 			wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		wpa_ie_len = wpa_ie[1] + 2;
 	}
+#ifdef CONFIG_TESTING_OPTIONS
+	if (sm->wpa_auth->conf.rsnxe_override_eapol_len) {
+		u8 *obuf = sm->wpa_auth->conf.rsnxe_override_eapol;
+		size_t olen = sm->wpa_auth->conf.rsnxe_override_eapol_len;
+		const u8 *rsnxe;
+
+		wpa_hexdump(MSG_DEBUG,
+			    "TESTING: wpa_ie before RSNXE EAPOL override",
+			    wpa_ie, wpa_ie_len);
+		wpa_ie_buf = os_malloc(wpa_ie_len + olen);
+		if (!wpa_ie_buf)
+			return;
+		os_memcpy(wpa_ie_buf, wpa_ie, wpa_ie_len);
+		wpa_ie = wpa_ie_buf;
+		rsnxe = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_RSNX);
+		if (rsnxe) {
+			u8 rsnxe_len = 2 + rsnxe[1];
+
+			os_memmove((void *) rsnxe, rsnxe + rsnxe_len,
+				   wpa_ie_len - (rsnxe - wpa_ie) - rsnxe_len);
+			wpa_ie_len -= rsnxe_len;
+		}
+		os_memcpy(wpa_ie + wpa_ie_len, obuf, olen);
+		wpa_ie_len += olen;
+		wpa_hexdump(MSG_DEBUG,
+			    "TESTING: wpa_ie after RSNXE EAPOL override",
+			    wpa_ie, wpa_ie_len);
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
 			"sending 3/4 msg of 4-Way Handshake");
 	if (sm->wpa == WPA_VERSION_WPA2) {
@@ -3191,7 +3222,7 @@
 			 * of GTK in the BSS.
 			 */
 			if (random_get_bytes(dummy_gtk, gtk_len) < 0)
-				return;
+				goto done;
 			gtk = dummy_gtk;
 		}
 		gtkidx = gsm->GN;
@@ -3234,7 +3265,7 @@
 #endif /* CONFIG_P2P */
 	kde = os_malloc(kde_len);
 	if (kde == NULL)
-		return;
+		goto done;
 
 	pos = kde;
 	os_memcpy(pos, wpa_ie, wpa_ie_len);
@@ -3249,8 +3280,7 @@
 		if (res < 0) {
 			wpa_printf(MSG_ERROR, "FT: Failed to insert "
 				   "PMKR1Name into RSN IE in EAPOL-Key data");
-			os_free(kde);
-			return;
+			goto done;
 		}
 		pos -= wpa_ie_len;
 		pos += elen;
@@ -3264,10 +3294,8 @@
 				  gtk, gtk_len);
 	}
 	pos = ieee80211w_kde_add(sm, pos);
-	if (ocv_oci_add(sm, &pos) < 0) {
-		os_free(kde);
-		return;
-	}
+	if (ocv_oci_add(sm, &pos) < 0)
+		goto done;
 
 #ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -3293,8 +3321,7 @@
 		if (res < 0) {
 			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
 				   "into EAPOL-Key Key Data");
-			os_free(kde);
-			return;
+			goto done;
 		}
 		pos += res;
 
@@ -3331,7 +3358,9 @@
 		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
 		       WPA_KEY_INFO_KEY_TYPE,
 		       _rsc, sm->ANonce, kde, pos - kde, 0, encr);
+done:
 	os_free(kde);
+	os_free(wpa_ie_buf);
 }
 
 
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index f627838..933a4b8 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -219,6 +219,8 @@
 	double corrupt_gtk_rekey_mic_probability;
 	u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
 	size_t own_ie_override_len;
+	u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
+	size_t rsnxe_override_eapol_len;
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_P2P
 	u8 ip_addr_go[4];
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index ddab950..7fb0923 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -118,6 +118,14 @@
 			  wpabuf_head(conf->own_ie_override),
 			  wconf->own_ie_override_len);
 	}
+	if (conf->rsnxe_override_eapol &&
+	    wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+		wconf->rsnxe_override_eapol_len =
+			wpabuf_len(conf->rsnxe_override_eapol);
+		os_memcpy(wconf->rsnxe_override_eapol,
+			  wpabuf_head(conf->rsnxe_override_eapol),
+			  wconf->rsnxe_override_eapol_len);
+	}
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_P2P
 	os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 33caeaf..175b9fc 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1417,6 +1417,7 @@
 		data->count++;
 		wps_registrar_wps_cancel(hapd->wps->registrar);
 		ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_CANCEL);
 	}
 
 	return 0;