Cumulative patch from commit 128f6a98b3d4d6ed103db759707309f451db9682

128f6a98b mka: Fix the order of operations in secure channel deletion
213eb1885 dbus: Set mode to mesh in bss properties when mesh is supported
21fda4ee7 RSN: Fix pre-authentication EAPOL-Start startPeriod configuration
3f23260da nl80211: Notify reason for connection timeout failure
ca1ab9db2 hostapd: Get vendor HE capabilities
7785c70bb QCA vendor command for fetching HE capabilities
d512f406f hostapd: Add IEEE 802.11ax HE IEs into Beacon/Probe Response frames
94380cb40 hostapd: Initial IEEE 802.11ax (HE) definitions
5972dc73c mesh: Use correct rate in VHT and HT mixed environment
84ea61cff mesh: Use correct rate in HT and legacy mixed environment
025c6a47f VHT: Remove a redundant check
a7a638c2c hw_features: Move VHT capabilities checks to common
e01cf2afc Define eapol_sm_get_eap_proxy_imsi() only with CONFIG_EAP_PROXY=y
a8e25deeb FT: Merge similar error paths to use common steps
c6c41f6ea FT: Support addition of RIC elements into Reassociation Request frame
ecbdc1a1f Mark RSN msg 1/2 key data debug dump as key material
834c5d681 FILS: Fix PMK length for initial connection with FILS SHA384 AKM
e491389eb FILS: Fix ifdef for PTK derivation with SHA384-based AKM
62944f7d2 Add HMAC-SHA384 with internal crypto
aeecd4eae OpenSSL: Fix hmac_sha384_vector() implementation
5db32adc9 browser-wpadebug: Send HTTP response with HTTP/1.1 header
79329ae0a P2P: Verify local driver preferred frequencies for P2P use cases
3a7819f0a P2P: Add P2P_SET override_pref_op_chan to allow overriding preference
c06fca04f Add wpa_supplicant SET get_pref_freq_list_override
b4d56efb1 Use throughput estimate-based BSS selection with larger SNR difference
142041487 Drop GREAT_SNR definition from 30 to 25 dB
364c064a4 FT: Check key derivation results explicitly in AP operations
b5562a1a6 FILS: Remove CRC32 dependency from build
5cf0930f9 testS: Additional BSS TM error case coverage
885bbd4de WNM: Remove unused code from BSS TM Req generation
e7ddd86a9 WNM: Use a common error path in ieee802_11_send_wnmsleep_resp()
d6d5970e2 WNM: Fix WNM-Sleep Mode Request parsing for WNM-Sleep element
8492cc79c PeerKey: Remove dead code related to STSL negotiation state
e37c0aa5d OSU server: Remove invalid options from documentation
0d6056703 WMM: Fix estimated medium time calculation for some corner cases
ae26d3021 Fix "IEEE 802.11: Ignored Action frame" debug message
4ead4c7ec WMM: Remove obsolete TODO comments
577e794eb Sync android.config with wpa_supplicant defconfig changes
784710b7f Add bgscan options to wpa_supplicant defconfig
212a8f487 Fix wpa_supplicant defconfig copy-paste description
57c3a605c Add support to sched scan to report relatively better BSSs
20c846d9e nl80211: sched_scan relative RSSI parameters
37e9f511e mka: Send MKPDUs forever if mode is PSK
76aa31838 EAP: Call deinit_for_reauth() for Phase 2 EAP methods
02156b98b EAP-AKA: Don't use anonymous identity in phase2
9e2afe10e EAP-SIM: Don't use anonymous identity in phase2
ed9b1c16d EAP peer: Cache decrypted requests for EAP-SIM/AKA/AKA'
5f11880f6 SME: Remove null ie param from CTRL-EVENT-AUTH-REJECT
4d70b2a4e RRM: Fix a memory leak in beacon request handling
401243b73 RRM: Fix range request overriding
fb81c0a3d RRM: Merge similar error returns to a single one
13b30052d RRM: Fix Range Request max age parsing
bd6ec7f7c Fix MAC ACL query freeing on deinit
b4fd1f0ed Allow PNO scan also in connection completed state
4c6f450ca Add radio_work_is_connect() helper
85b6b6b6e Serialize scan/p2p-scan if already scheduled on the same interface
fcb303a57 P2P: Clear driver scan cache after BSS_FLUSH
0d6dc6830 FILS: Clean up HLP resize check
1d9d21f37 GAS: Add support to randomize transmitter address
8331c9b31 nl80211: Add support for mgmt_tx with random TA
14fa723a9 Sync with mac80211-next.git include/uapi/linux/nl80211.h
65ab7eb1f GAS: Fix OSU Providers List response with invalid configuration
f3e157057 VHT: Fill VHT capability with hardware capability
4bb9b674c Add a log message when GTK rekeying failed
41f140d38 Add hostapd options wpa_group_update_count and wpa_pairwise_update_count
e54691106 mka: Some bug fixes for MACsec in PSK mode
7faf403f9 mka: Fix an incorrect update of participant->to_use_sak
00e0f0b01 hs20-osu-client: Hide a trivial compiler warning
276e93654 hw_features: Clean center freq for falling back HT40 channels
f47f93617 P2P: Override P2P_PEER group_capab with 0 if no matching BSS entry found
bcf66493c Fix estimated throughput based skip-roam case
84bb12aa6 FILS: Fix send_assoc_resp() HLP extension to cover sta == NULL
275cc9428 FILS: Stop processing if fils_rmsk_to_pmk() fails
caab23f19 Set EAPOL-Key Key Length field to 0 for group message 1/2 in RSN
b0fb2be77 Do not send GNonce in EAPOL-Key group message 1/2
3bbc47050 Fix EAPOL-Key Install bit in Group Key 1/2 with FT and FILS auth
db5e53cb0 mesh: Fix struct hostapd_data initialization
9b170991a mesh: Fix mesh interface removal fix
945604a35 Update wpaspy.py to be python3 compatible
4d6e79f86 Use defines in hostapd_set_freq_params()
0217b8d87 eloop: Fix comments mismatch eloop_event/timeout_handler definitions
09a97eb27 Update the copyright notice years for QCA vendor definitions
841e9a8c7 QCA vendor command to set the trace levels for the specific QCA module
d77f33041 FILS: Fix AES-SIV AAD for (Re)Association Request frame decryption
7a6c3de23 ERP: Use macro for EMSKname length instead of hardcoded integer value
bb3ea71a2 ERP: Fix rIK derivation
124ddfa19 FILS: Parse and report received FILS HLP Containers from response
91d91abf6 FILS: DHCP relay for HLP requests
54b04d6f3 FILS: Move HLP request handling into a separate file
5a9d50493 ProxyARP: Use more robust DHCP option parsing
e64c13feb Move DHCP definitions into a common file
70407ee5c Add QCA vendor definitions for BSS transition status
53d171440 AP: Check ACL upon association request for 802.11ad
4cc61c386 GAS: Set temporary session timeout bigger than gas_comeback_delay

Test: Wifi Suite

Change-Id: Id597d7cba5d2b3875f2dbbeb9a10fd5e69a6a7c2
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e417a12..9abcab7 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -13,6 +13,7 @@
 #include "radius/radius_client.h"
 #include "common/ieee802_11_defs.h"
 #include "common/eapol_common.h"
+#include "common/dhcp.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eap_server/eap.h"
 #include "wpa_auth.h"
@@ -55,6 +56,8 @@
 
 	bss->wpa_group_rekey = 600;
 	bss->wpa_gmk_rekey = 86400;
+	bss->wpa_group_update_count = 4;
+	bss->wpa_pairwise_update_count = 4;
 	bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
 	bss->wpa_pairwise = WPA_CIPHER_TKIP;
 	bss->wpa_group = WPA_CIPHER_TKIP;
@@ -100,6 +103,9 @@
 
 #ifdef CONFIG_FILS
 	dl_list_init(&bss->fils_realms);
+	bss->fils_hlp_wait_time = 30;
+	bss->dhcp_server_port = DHCP_SERVER_PORT;
+	bss->dhcp_relay_port = DHCP_SERVER_PORT;
 #endif /* CONFIG_FILS */
 }
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 075261c..fdd5a1a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -330,6 +330,8 @@
 	int wpa_strict_rekey;
 	int wpa_gmk_rekey;
 	int wpa_ptk_rekey;
+	u32 wpa_group_update_count;
+	u32 wpa_pairwise_update_count;
 	int rsn_pairwise;
 	int rsn_preauth;
 	char *rsn_preauth_interfaces;
@@ -607,11 +609,34 @@
 	u8 fils_cache_id[FILS_CACHE_ID_LEN];
 	int fils_cache_id_set;
 	struct dl_list fils_realms; /* list of struct fils_realm */
+	struct hostapd_ip_addr dhcp_server;
+	int dhcp_rapid_commit_proxy;
+	unsigned int fils_hlp_wait_time;
+	u16 dhcp_server_port;
+	u16 dhcp_relay_port;
 #endif /* CONFIG_FILS */
 
 	int multicast_to_unicast;
 };
 
+/**
+ * struct he_phy_capabilities_info - HE PHY capabilities
+ */
+struct he_phy_capabilities_info {
+	Boolean he_su_beamformer;
+	Boolean he_su_beamformee;
+	Boolean he_mu_beamformer;
+};
+
+/**
+ * struct he_operation - HE operation
+ */
+struct he_operation {
+	u8 he_bss_color;
+	u8 he_default_pe_duration;
+	u8 he_twt_required;
+	u8 he_rts_threshold;
+};
 
 /**
  * struct hostapd_config - Per-radio interface configuration
@@ -725,6 +750,12 @@
 	struct wpabuf *lci;
 	struct wpabuf *civic;
 	int stationary_ap;
+
+	int ieee80211ax;
+#ifdef CONFIG_IEEE80211AX
+	struct he_phy_capabilities_info he_phy_capab;
+	struct he_operation he_op;
+#endif /* CONFIG_IEEE80211AX */
 };
 
 
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3788a97..c6bbda3 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -392,6 +392,13 @@
 			2 + sizeof(struct ieee80211_vht_operation);
 	}
 
+#ifdef CONFIG_IEEE80211AX
+	if (hapd->iconf->ieee80211ax) {
+		buflen += 4 + sizeof (struct ieee80211_he_capabilities) +
+			4 + sizeof (struct ieee80211_he_operation);
+	}
+#endif
+
 	buflen += hostapd_mbo_ie_len(hapd);
 
 	resp = os_zalloc(buflen);
@@ -500,6 +507,13 @@
 		pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+	if (hapd->iconf->ieee80211ax) {
+		pos = hostapd_eid_vendor_he_capab(hapd, pos);
+		pos = hostapd_eid_vendor_he_operation(hapd, pos);
+	}
+#endif /* CONFIG_IEEE80211AX */
+
 	/* Wi-Fi Alliance WMM */
 	pos = hostapd_eid_wmm(hapd, pos);
 
@@ -1040,6 +1054,13 @@
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+	if (hapd->iconf->ieee80211ax) {
+		tail_len += 4 + sizeof (struct ieee80211_he_capabilities) +
+			4 + sizeof (struct ieee80211_he_operation);
+	}
+#endif
+
 	tail_len += hostapd_mbo_ie_len(hapd);
 
 	tailpos = tail = os_malloc(tail_len);
@@ -1171,6 +1192,13 @@
 		tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+	if (hapd->iconf->ieee80211ax) {
+		tailpos = hostapd_eid_vendor_he_capab(hapd, tailpos);
+		tailpos = hostapd_eid_vendor_he_operation(hapd, tailpos);
+	}
+#endif /* CONFIG_IEEE80211AX */
+
 	/* Wi-Fi Alliance WMM */
 	tailpos = hostapd_eid_wmm(hapd, tailpos);
 
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index f0212fb..b9a36d7 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -7,10 +7,9 @@
  */
 
 #include "utils/includes.h"
-#include <netinet/ip.h>
-#include <netinet/udp.h>
 
 #include "utils/common.h"
+#include "common/dhcp.h"
 #include "l2_packet/l2_packet.h"
 #include "hostapd.h"
 #include "sta_info.h"
@@ -18,29 +17,6 @@
 #include "x_snoop.h"
 #include "dhcp_snoop.h"
 
-struct bootp_pkt {
-	struct iphdr iph;
-	struct udphdr udph;
-	u8 op;
-	u8 htype;
-	u8 hlen;
-	u8 hops;
-	be32 xid;
-	be16 secs;
-	be16 flags;
-	be32 client_ip;
-	be32 your_ip;
-	be32 server_ip;
-	be32 relay_ip;
-	u8 hw_addr[16];
-	u8 serv_name[64];
-	u8 boot_file[128];
-	u8 exten[312];
-} STRUCT_PACKED;
-
-#define DHCPACK	5
-static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
-
 
 static const char * ipaddr_str(u32 addr)
 {
@@ -74,24 +50,26 @@
 	if (tot_len > (unsigned int) (len - ETH_HLEN))
 		return;
 
-	if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+	if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
 		return;
 
 	/* Parse DHCP options */
 	end = (const u8 *) b + tot_len;
 	pos = &b->exten[4];
-	while (pos < end && *pos != 0xff) {
+	while (pos < end && *pos != DHCP_OPT_END) {
 		const u8 *opt = pos++;
 
-		if (*opt == 0) /* padding */
+		if (*opt == DHCP_OPT_PAD)
 			continue;
 
+		if (pos >= end || 1 + *pos > end - pos)
+			break;
 		pos += *pos + 1;
 		if (pos >= end)
 			break;
 
 		switch (*opt) {
-		case 1:  /* subnet mask */
+		case DHCP_OPT_SUBNET_MASK:
 			if (opt[1] == 4)
 				subnet_mask = WPA_GET_BE32(&opt[2]);
 			if (subnet_mask == 0)
@@ -101,7 +79,7 @@
 				prefixlen--;
 			}
 			break;
-		case 53: /* message type */
+		case DHCP_OPT_MSG_TYPE:
 			if (opt[1])
 				msgtype = opt[2];
 			break;
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
new file mode 100644
index 0000000..40d9be1
--- /dev/null
+++ b/src/ap/fils_hlp.c
@@ -0,0 +1,636 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/dhcp.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
+#include "fils_hlp.h"
+
+
+static be16 ip_checksum(const void *buf, size_t len)
+{
+	u32 sum = 0;
+	const u16 *pos;
+
+	for (pos = buf; len >= 2; len -= 2)
+		sum += ntohs(*pos++);
+	if (len)
+		sum += ntohs(*pos << 8);
+
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += sum >> 16;
+	return htons(~sum);
+}
+
+
+static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
+			     struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
+{
+	u8 *pos, *end;
+	struct dhcp_data *dhcp;
+	struct sockaddr_in addr;
+	ssize_t res;
+	const u8 *server_id = NULL;
+
+	if (!sta->hlp_dhcp_discover) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: No pending HLP DHCPDISCOVER available");
+		return -1;
+	}
+
+	/* Convert to DHCPREQUEST, remove rapid commit option, replace requested
+	 * IP address option with yiaddr. */
+	pos = wpabuf_mhead(sta->hlp_dhcp_discover);
+	end = pos + wpabuf_len(sta->hlp_dhcp_discover);
+	dhcp = (struct dhcp_data *) pos;
+	pos = (u8 *) (dhcp + 1);
+	pos += 4; /* skip magic */
+	while (pos < end && *pos != DHCP_OPT_END) {
+		u8 opt, olen;
+
+		opt = *pos++;
+		if (opt == DHCP_OPT_PAD)
+			continue;
+		if (pos >= end)
+			break;
+		olen = *pos++;
+		if (olen > end - pos)
+			break;
+
+		switch (opt) {
+		case DHCP_OPT_MSG_TYPE:
+			if (olen > 0)
+				*pos = DHCPREQUEST;
+			break;
+		case DHCP_OPT_RAPID_COMMIT:
+		case DHCP_OPT_REQUESTED_IP_ADDRESS:
+		case DHCP_OPT_SERVER_ID:
+			/* Remove option */
+			pos -= 2;
+			os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
+			end -= 2 + olen;
+			olen = 0;
+			break;
+		}
+		pos += olen;
+	}
+	if (pos >= end || *pos != DHCP_OPT_END) {
+		wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
+		return -1;
+	}
+	sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
+
+	/* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
+	pos = (u8 *) (dhcpoffer + 1);
+	end = dhcpofferend;
+	pos += 4; /* skip magic */
+	while (pos < end && *pos != DHCP_OPT_END) {
+		u8 opt, olen;
+
+		opt = *pos++;
+		if (opt == DHCP_OPT_PAD)
+			continue;
+		if (pos >= end)
+			break;
+		olen = *pos++;
+		if (olen > end - pos)
+			break;
+
+		switch (opt) {
+		case DHCP_OPT_SERVER_ID:
+			server_id = pos - 2;
+			break;
+		}
+		pos += olen;
+	}
+
+	if (wpabuf_resize(&sta->hlp_dhcp_discover,
+			  6 + 1 + (server_id ? 2 + server_id[1] : 0)))
+		return -1;
+	if (server_id)
+		wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
+				2 + server_id[1]);
+	wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
+	wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
+	wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
+	wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+	addr.sin_port = htons(hapd->conf->dhcp_server_port);
+	res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
+		     wpabuf_len(sta->hlp_dhcp_discover), 0,
+		     (const struct sockaddr *) &addr, sizeof(addr));
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+			   strerror(errno));
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG,
+		   "FILS: Acting as DHCP rapid commit proxy for %s:%d",
+		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+	wpabuf_free(sta->hlp_dhcp_discover);
+	sta->hlp_dhcp_discover = NULL;
+	sta->fils_dhcp_rapid_commit_proxy = 1;
+	return 0;
+}
+
+
+static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+	struct hostapd_data *hapd = sock_ctx;
+	struct sta_info *sta;
+	u8 buf[1500], *pos, *end, *end_opt = NULL;
+	struct dhcp_data *dhcp;
+	struct sockaddr_in addr;
+	socklen_t addr_len;
+	ssize_t res;
+	u8 msgtype = 0;
+	int rapid_commit = 0;
+	struct iphdr *iph;
+	struct udphdr *udph;
+	struct wpabuf *resp;
+	const u8 *rpos;
+	size_t left, len;
+
+	addr_len = sizeof(addr);
+	res = recvfrom(sd, buf, sizeof(buf), 0,
+		       (struct sockaddr *) &addr, &addr_len);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
+			   strerror(errno));
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
+		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
+	wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
+	if ((size_t) res < sizeof(*dhcp))
+		return;
+	dhcp = (struct dhcp_data *) buf;
+	if (dhcp->op != 2)
+		return; /* Not a BOOTREPLY */
+	if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: HLP - DHCP response to unknown relay address 0x%x",
+			   dhcp->relay_ip);
+		return;
+	}
+	dhcp->relay_ip = 0;
+	pos = (u8 *) (dhcp + 1);
+	end = &buf[res];
+
+	if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
+		wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
+		return;
+	}
+	pos += 4;
+
+	wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
+		    pos, end - pos);
+	while (pos < end && *pos != DHCP_OPT_END) {
+		u8 opt, olen;
+
+		opt = *pos++;
+		if (opt == DHCP_OPT_PAD)
+			continue;
+		if (pos >= end)
+			break;
+		olen = *pos++;
+		if (olen > end - pos)
+			break;
+
+		switch (opt) {
+		case DHCP_OPT_MSG_TYPE:
+			if (olen > 0)
+				msgtype = pos[0];
+			break;
+		case DHCP_OPT_RAPID_COMMIT:
+			rapid_commit = 1;
+			break;
+		}
+		pos += olen;
+	}
+	if (pos < end && *pos == DHCP_OPT_END)
+		end_opt = pos;
+
+	wpa_printf(MSG_DEBUG,
+		   "FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
+		   MACSTR ")",
+		   msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
+
+	sta = ap_get_sta(hapd, dhcp->hw_addr);
+	if (!sta || !sta->fils_pending_assoc_req) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: No pending HLP DHCP exchange with hw_addr"
+			   MACSTR, MAC2STR(dhcp->hw_addr));
+		return;
+	}
+
+	if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
+	    !rapid_commit) {
+		/* Use hostapd to take care of 4-message exchange and convert
+		 * the final DHCPACK to rapid commit version. */
+		if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
+			return;
+		/* failed, so send the server response as-is */
+	} else if (msgtype != DHCPACK) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
+	}
+
+	pos = buf;
+	resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
+			    sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
+	if (!resp)
+		return;
+	wpabuf_put_data(resp, sta->addr, ETH_ALEN);
+	wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
+	wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
+	wpabuf_put_be16(resp, ETH_P_IP);
+	iph = wpabuf_put(resp, sizeof(*iph));
+	iph->version = 4;
+	iph->ihl = sizeof(*iph) / 4;
+	iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+	iph->ttl = 1;
+	iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
+	iph->daddr = dhcp->client_ip;
+	iph->check = ip_checksum(iph, sizeof(*iph));
+	udph = wpabuf_put(resp, sizeof(*udph));
+	udph->uh_sport = htons(DHCP_SERVER_PORT);
+	udph->uh_dport = htons(DHCP_CLIENT_PORT);
+	udph->len = htons(sizeof(*udph) + (end - pos));
+	udph->check = htons(0x0000); /* TODO: calculate checksum */
+	if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
+	    !rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
+		/* Add rapid commit option */
+		wpabuf_put_data(resp, pos, end_opt - pos);
+		wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
+		wpabuf_put_u8(resp, 0);
+		wpabuf_put_data(resp, end_opt, end - end_opt);
+	} else {
+		wpabuf_put_data(resp, pos, end - pos);
+	}
+	if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
+			  2 * wpabuf_len(resp) / 255 + 100)) {
+		wpabuf_free(resp);
+		return;
+	}
+
+	rpos = wpabuf_head(resp);
+	left = wpabuf_len(resp);
+
+	wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
+	if (left <= 254)
+		len = 1 + left;
+	else
+		len = 255;
+	wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
+	/* Element ID Extension */
+	wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
+	/* Destination MAC Address, Source MAC Address, HLP Packet.
+	 * HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
+	 * when LPD is used). */
+	wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
+	rpos += len - 1;
+	left -= len - 1;
+	while (left) {
+		wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
+		len = left > 255 ? 255 : left;
+		wpabuf_put_u8(sta->fils_hlp_resp, len);
+		wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
+		rpos += len;
+		left -= len;
+	}
+	wpabuf_free(resp);
+	fils_hlp_finish_assoc(hapd, sta);
+}
+
+
+static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
+				 struct sta_info *sta,
+				 const u8 *msg, size_t len)
+{
+	const struct dhcp_data *dhcp;
+	struct wpabuf *dhcp_buf;
+	struct dhcp_data *dhcp_msg;
+	u8 msgtype = 0;
+	int rapid_commit = 0;
+	const u8 *pos = msg, *end;
+	struct sockaddr_in addr;
+	ssize_t res;
+
+	if (len < sizeof(*dhcp))
+		return 0;
+	dhcp = (const struct dhcp_data *) pos;
+	end = pos + len;
+	wpa_printf(MSG_DEBUG,
+		   "FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
+		   dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
+		   ntohl(dhcp->xid));
+	pos += sizeof(*dhcp);
+	if (dhcp->op != 1)
+		return 0; /* Not a BOOTREQUEST */
+
+	if (end - pos < 4)
+		return 0;
+	if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
+		wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
+		return 0;
+	}
+	pos += 4;
+
+	wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
+	while (pos < end && *pos != DHCP_OPT_END) {
+		u8 opt, olen;
+
+		opt = *pos++;
+		if (opt == DHCP_OPT_PAD)
+			continue;
+		if (pos >= end)
+			break;
+		olen = *pos++;
+		if (olen > end - pos)
+			break;
+
+		switch (opt) {
+		case DHCP_OPT_MSG_TYPE:
+			if (olen > 0)
+				msgtype = pos[0];
+			break;
+		case DHCP_OPT_RAPID_COMMIT:
+			rapid_commit = 1;
+			break;
+		}
+		pos += olen;
+	}
+
+	wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
+	if (msgtype != DHCPDISCOVER)
+		return 0;
+
+	if (hapd->conf->dhcp_server.af != AF_INET ||
+	    hapd->conf->dhcp_server.u.v4.s_addr == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: HLP - no DHCPv4 server configured - drop request");
+		return 0;
+	}
+
+	if (hapd->conf->own_ip_addr.af != AF_INET ||
+	    hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: HLP - no IPv4 own_ip_addr configured - drop request");
+		return 0;
+	}
+
+	if (hapd->dhcp_sock < 0) {
+		int s;
+
+		s = socket(AF_INET, SOCK_DGRAM, 0);
+		if (s < 0) {
+			wpa_printf(MSG_ERROR,
+				   "FILS: Failed to open DHCP socket: %s",
+				   strerror(errno));
+			return 0;
+		}
+
+		if (hapd->conf->dhcp_relay_port) {
+			os_memset(&addr, 0, sizeof(addr));
+			addr.sin_family = AF_INET;
+			addr.sin_addr.s_addr =
+				hapd->conf->own_ip_addr.u.v4.s_addr;
+			addr.sin_port = htons(hapd->conf->dhcp_relay_port);
+			if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
+				wpa_printf(MSG_ERROR,
+					   "FILS: Failed to bind DHCP socket: %s",
+					   strerror(errno));
+				close(s);
+				return 0;
+			}
+		}
+		if (eloop_register_sock(s, EVENT_TYPE_READ,
+					fils_dhcp_handler, NULL, hapd)) {
+			close(s);
+			return 0;
+		}
+
+		hapd->dhcp_sock = s;
+	}
+
+	dhcp_buf = wpabuf_alloc(len);
+	if (!dhcp_buf)
+		return 0;
+	dhcp_msg = wpabuf_put(dhcp_buf, len);
+	os_memcpy(dhcp_msg, msg, len);
+	dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+	addr.sin_port = htons(hapd->conf->dhcp_server_port);
+	res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
+		     (const struct sockaddr *) &addr, sizeof(addr));
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+			   strerror(errno));
+		wpabuf_free(dhcp_buf);
+		/* Close the socket to try to recover from error */
+		eloop_unregister_read_sock(hapd->dhcp_sock);
+		close(hapd->dhcp_sock);
+		hapd->dhcp_sock = -1;
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
+		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+		   rapid_commit);
+	if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
+		/* Store a copy of the DHCPDISCOVER for rapid commit proxying
+		 * purposes if the server does not support the rapid commit
+		 * option. */
+		wpa_printf(MSG_DEBUG,
+			   "FILS: Store DHCPDISCOVER for rapid commit proxy");
+		wpabuf_free(sta->hlp_dhcp_discover);
+		sta->hlp_dhcp_discover = dhcp_buf;
+	} else {
+		wpabuf_free(dhcp_buf);
+	}
+
+	return 1;
+}
+
+
+static int fils_process_hlp_udp(struct hostapd_data *hapd,
+				struct sta_info *sta, const u8 *dst,
+				const u8 *pos, size_t len)
+{
+	const struct iphdr *iph;
+	const struct udphdr *udph;
+	u16 sport, dport, ulen;
+
+	if (len < sizeof(*iph) + sizeof(*udph))
+		return 0;
+	iph = (const struct iphdr *) pos;
+	udph = (const struct udphdr *) (iph + 1);
+	sport = ntohs(udph->uh_sport);
+	dport = ntohs(udph->uh_dport);
+	ulen = ntohs(udph->uh_ulen);
+	wpa_printf(MSG_DEBUG,
+		   "FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
+		   sport, dport, ulen, ntohs(udph->uh_sum));
+	/* TODO: Check UDP checksum */
+	if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
+		return 0;
+
+	if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
+		return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
+					     ulen - sizeof(*udph));
+	}
+
+	return 0;
+}
+
+
+static int fils_process_hlp_ip(struct hostapd_data *hapd,
+			       struct sta_info *sta, const u8 *dst,
+			       const u8 *pos, size_t len)
+{
+	const struct iphdr *iph;
+	u16 tot_len;
+
+	if (len < sizeof(*iph))
+		return 0;
+	iph = (const struct iphdr *) pos;
+	if (ip_checksum(iph, sizeof(*iph)) != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: HLP request IPv4 packet had invalid header checksum - dropped");
+		return 0;
+	}
+	tot_len = ntohs(iph->tot_len);
+	if (tot_len > len)
+		return 0;
+	wpa_printf(MSG_DEBUG,
+		   "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
+		   iph->saddr, iph->daddr, iph->protocol);
+	switch (iph->protocol) {
+	case 17:
+		return fils_process_hlp_udp(hapd, sta, dst, pos, len);
+	}
+
+	return 0;
+}
+
+
+static int fils_process_hlp_req(struct hostapd_data *hapd,
+				struct sta_info *sta,
+				const u8 *pos, size_t len)
+{
+	const u8 *pkt, *end;
+
+	wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
+		   " src=" MACSTR " len=%u)",
+		   MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
+		   (unsigned int) len);
+	if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "FILS: Ignore HLP request with unexpected source address"
+			   MACSTR, MAC2STR(pos + ETH_ALEN));
+		return 0;
+	}
+
+	end = pos + len;
+	pkt = pos + 2 * ETH_ALEN;
+	if (end - pkt >= 6 &&
+	    os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+		pkt += 6; /* Remove SNAP/LLC header */
+	wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
+
+	if (end - pkt < 2)
+		return 0;
+
+	switch (WPA_GET_BE16(pkt)) {
+	case ETH_P_IP:
+		return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
+					   end - pkt - 2);
+	}
+
+	return 0;
+}
+
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+		     const u8 *pos, int left)
+{
+	const u8 *end = pos + left;
+	u8 *tmp, *tmp_pos;
+	int ret = 0;
+
+	/* Old DHCPDISCOVER is not needed anymore, if it was still pending */
+	wpabuf_free(sta->hlp_dhcp_discover);
+	sta->hlp_dhcp_discover = NULL;
+	sta->fils_dhcp_rapid_commit_proxy = 0;
+
+	/* Check if there are any FILS HLP Container elements */
+	while (end - pos >= 2) {
+		if (2 + pos[1] > end - pos)
+			return 0;
+		if (pos[0] == WLAN_EID_EXTENSION &&
+		    pos[1] >= 1 + 2 * ETH_ALEN &&
+		    pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+			break;
+		pos += 2 + pos[1];
+	}
+	if (end - pos < 2)
+		return 0; /* No FILS HLP Container elements */
+
+	tmp = os_malloc(end - pos);
+	if (!tmp)
+		return 0;
+
+	while (end - pos >= 2) {
+		if (2 + pos[1] > end - pos ||
+		    pos[0] != WLAN_EID_EXTENSION ||
+		    pos[1] < 1 + 2 * ETH_ALEN ||
+		    pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+			break;
+		tmp_pos = tmp;
+		os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+		tmp_pos += pos[1] - 1;
+		pos += 2 + pos[1];
+
+		/* Add possible fragments */
+		while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+		       2 + pos[1] <= end - pos) {
+			os_memcpy(tmp_pos, pos + 2, pos[1]);
+			tmp_pos += pos[1];
+			pos += 2 + pos[1];
+		}
+
+		if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
+			ret = 1;
+	}
+
+	os_free(tmp);
+
+	return ret;
+}
+
+
+void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+	if (hapd->dhcp_sock >= 0) {
+		eloop_unregister_read_sock(hapd->dhcp_sock);
+		close(hapd->dhcp_sock);
+		hapd->dhcp_sock = -1;
+	}
+}
diff --git a/src/ap/fils_hlp.h b/src/ap/fils_hlp.h
new file mode 100644
index 0000000..e14a6bf
--- /dev/null
+++ b/src/ap/fils_hlp.h
@@ -0,0 +1,27 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef FILS_HLP_H
+#define FILS_HLP_H
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+		     const u8 *pos, int left);
+
+#ifdef CONFIG_FILS
+
+void fils_hlp_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_FILS */
+
+static inline void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_FILS */
+
+#endif /* FILS_HLP_H */
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 3878ce6..96cd703 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -50,9 +50,12 @@
 		sta->flags |= WLAN_STA_GAS;
 		/*
 		 * The default inactivity is 300 seconds. We don't need
-		 * it to be that long.
+		 * it to be that long. Use five second timeout and increase this
+		 * with the comeback_delay for testing cases.
 		 */
-		ap_sta_session_timeout(hapd, sta, 5);
+		ap_sta_session_timeout(hapd, sta,
+				       hapd->conf->gas_comeback_delay / 1024 +
+				       5);
 	} else {
 		ap_sta_replenish_timeout(hapd, sta, 5);
 	}
@@ -688,7 +691,7 @@
 
 	/* OSU Method List */
 	count = wpabuf_put(buf, 1);
-	for (i = 0; p->method_list[i] >= 0; i++)
+	for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
 		wpabuf_put_u8(buf, p->method_list[i]);
 	*count = i;
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 26ebbb6..cf8a8cb 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -45,6 +45,7 @@
 #include "ndisc_snoop.h"
 #include "neighbor_db.h"
 #include "rrm.h"
+#include "fils_hlp.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -344,6 +345,7 @@
 #endif /* CONFIG_MESH */
 
 	hostapd_clean_rrm(hapd);
+	fils_hlp_deinit(hapd);
 }
 
 
@@ -2002,10 +2004,12 @@
 	hapd->iconf = conf;
 	hapd->conf = bss;
 	hapd->iface = hapd_iface;
-	hapd->driver = hapd->iconf->driver;
+	if (conf)
+		hapd->driver = conf->driver;
 	hapd->ctrl_sock = -1;
 	dl_list_init(&hapd->ctrl_dst);
 	dl_list_init(&hapd->nr_db);
+	hapd->dhcp_sock = -1;
 
 	return hapd;
 }
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bc0ac23..5ab623d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -303,6 +303,8 @@
 	u8 range_req_token;
 	unsigned int lci_req_active:1;
 	unsigned int range_req_active:1;
+
+	int dhcp_sock; /* UDP socket used with the DHCP server */
 };
 
 
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d66ff4b..2d6cef1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -329,6 +329,8 @@
 	res = ieee80211n_allowed_ht40_channel_pair(iface);
 	if (!res) {
 		iface->conf->secondary_channel = 0;
+		iface->conf->vht_oper_centr_freq_seg0_idx = 0;
+		iface->conf->vht_oper_centr_freq_seg1_idx = 0;
 		res = 1;
 		wpa_printf(MSG_INFO, "Fallback to 20 MHz");
 	}
@@ -621,41 +623,6 @@
 
 
 #ifdef CONFIG_IEEE80211AC
-
-static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
-{
-	u32 req_cap = conf & cap;
-
-	/*
-	 * Make sure we support all requested capabilities.
-	 * NOTE: We assume that 'cap' represents a capability mask,
-	 * not a discrete value.
-	 */
-	if ((hw & req_cap) != req_cap) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
-			   name);
-		return 0;
-	}
-	return 1;
-}
-
-
-static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
-				     unsigned int shift,
-				     const char *name)
-{
-	u32 hw_max = hw & mask;
-	u32 conf_val = conf & mask;
-
-	if (conf_val > hw_max) {
-		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
-			   name, conf_val >> shift, hw_max >> shift);
-		return 0;
-	}
-	return 1;
-}
-
-
 static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
 {
 	struct hostapd_hw_modes *mode = iface->current_mode;
@@ -683,45 +650,7 @@
 		}
 	}
 
-#define VHT_CAP_CHECK(cap) \
-	do { \
-		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
-			return 0; \
-	} while (0)
-
-#define VHT_CAP_CHECK_MAX(cap) \
-	do { \
-		if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
-					       #cap)) \
-			return 0; \
-	} while (0)
-
-	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
-	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
-	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
-	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
-	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
-	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
-	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
-	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
-	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
-	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
-	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
-	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
-	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
-	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
-	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
-	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
-	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
-	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
-	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
-	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
-	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
-
-#undef VHT_CAP_CHECK
-#undef VHT_CAP_CHECK_MAX
-
-	return 1;
+	return ieee80211ac_cap_check(hw, conf);
 }
 #endif /* CONFIG_IEEE80211AC */
 
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index cceeee0..e1a6712 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -45,6 +45,7 @@
 #include "mbo_ap.h"
 #include "rrm.h"
 #include "taxonomy.h"
+#include "fils_hlp.h"
 
 
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -1301,6 +1302,89 @@
 #endif /* CONFIG_FILS */
 
 
+static int
+ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+			   const u8 *msg, size_t len, u32 *session_timeout,
+			   u32 *acct_interim_interval,
+			   struct vlan_description *vlan_id,
+			   struct hostapd_sta_wpa_psk_short **psk,
+			   char **identity, char **radius_cui)
+{
+	int res;
+
+	os_memset(vlan_id, 0, sizeof(*vlan_id));
+	res = hostapd_allowed_address(hapd, addr, msg, len,
+				      session_timeout, acct_interim_interval,
+				      vlan_id, psk, identity, radius_cui);
+
+	if (res == HOSTAPD_ACL_REJECT) {
+		wpa_printf(MSG_INFO,
+			   "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(addr));
+		return HOSTAPD_ACL_REJECT;
+	}
+
+	if (res == HOSTAPD_ACL_PENDING) {
+		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+			   " waiting for an external authentication",
+			   MAC2STR(addr));
+		/* Authentication code will re-send the authentication frame
+		 * after it has received (and cached) information from the
+		 * external source. */
+		return HOSTAPD_ACL_PENDING;
+	}
+
+	return res;
+}
+
+
+static int
+ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int res, u32 session_timeout,
+			   u32 acct_interim_interval,
+			   struct vlan_description *vlan_id,
+			   struct hostapd_sta_wpa_psk_short **psk,
+			   char **identity, char **radius_cui)
+{
+	if (vlan_id->notempty &&
+	    !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO,
+			       "Invalid VLAN %d%s received from RADIUS server",
+			       vlan_id->untagged,
+			       vlan_id->tagged[0] ? "+" : "");
+		return -1;
+	}
+	if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
+		return -1;
+	if (sta->vlan_id)
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+	hostapd_free_psk_list(sta->psk);
+	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+		sta->psk = *psk;
+		*psk = NULL;
+	} else {
+		sta->psk = NULL;
+	}
+
+	sta->identity = *identity;
+	*identity = NULL;
+	sta->radius_cui = *radius_cui;
+	*radius_cui = NULL;
+
+	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
+		sta->acct_interim_interval = acct_interim_interval;
+	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+		ap_sta_session_timeout(hapd, sta, session_timeout);
+	else
+		ap_sta_no_session_timeout(hapd, sta);
+
+	return 0;
+}
+
+
 static void handle_auth(struct hostapd_data *hapd,
 			const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -1319,8 +1403,6 @@
 	char *radius_cui = NULL;
 	u16 seq_ctrl;
 
-	os_memset(&vlan_id, 0, sizeof(vlan_id));
-
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
 		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
 			   (unsigned long) len);
@@ -1464,26 +1546,15 @@
 		}
 	}
 
-	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
-				      &session_timeout,
-				      &acct_interim_interval, &vlan_id,
-				      &psk, &identity, &radius_cui);
-
+	res = ieee802_11_allowed_address(
+		hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
+		&acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui);
 	if (res == HOSTAPD_ACL_REJECT) {
-		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
-			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
-	if (res == HOSTAPD_ACL_PENDING) {
-		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
-			   " waiting for an external authentication",
-			   MAC2STR(mgmt->sa));
-		/* Authentication code will re-send the authentication frame
-		 * after it has received (and cached) information from the
-		 * external source. */
+	if (res == HOSTAPD_ACL_PENDING)
 		return;
-	}
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta) {
@@ -1536,47 +1607,17 @@
 	sta->last_seq_ctrl = seq_ctrl;
 	sta->last_subtype = WLAN_FC_STYPE_AUTH;
 
-	if (vlan_id.notempty &&
-	    !hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_INFO,
-			       "Invalid VLAN %d%s received from RADIUS server",
-			       vlan_id.untagged,
-			       vlan_id.tagged[0] ? "+" : "");
+	res = ieee802_11_set_radius_info(
+		hapd, sta, res, session_timeout, acct_interim_interval,
+		&vlan_id, &psk, &identity, &radius_cui);
+	if (res) {
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
-	if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		goto fail;
-	}
-	if (sta->vlan_id)
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
-
-	hostapd_free_psk_list(sta->psk);
-	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
-		sta->psk = psk;
-		psk = NULL;
-	} else {
-		sta->psk = NULL;
-	}
-
-	sta->identity = identity;
-	identity = NULL;
-	sta->radius_cui = radius_cui;
-	radius_cui = NULL;
 
 	sta->flags &= ~WLAN_STA_PREAUTH;
 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
 
-	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
-		sta->acct_interim_interval = acct_interim_interval;
-	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
-		ap_sta_session_timeout(hapd, sta, session_timeout);
-	else
-		ap_sta_no_session_timeout(hapd, sta);
-
 	/*
 	 * If the driver supports full AP client state, add a station to the
 	 * driver before sending authentication reply to make sure the driver
@@ -2225,11 +2266,22 @@
 			   const u8 *ies, size_t ies_len)
 {
 	int send_len;
-	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+	u8 *buf;
+	size_t buflen;
 	struct ieee80211_mgmt *reply;
 	u8 *p;
+	u16 res = WLAN_STATUS_SUCCESS;
 
-	os_memset(buf, 0, sizeof(buf));
+	buflen = sizeof(struct ieee80211_mgmt) + 1024;
+#ifdef CONFIG_FILS
+	if (sta && sta->fils_hlp_resp)
+		buflen += wpabuf_len(sta->fils_hlp_resp);
+#endif /* CONFIG_FILS */
+	buf = os_zalloc(buflen);
+	if (!buf) {
+		res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto done;
+	}
 	reply = (struct ieee80211_mgmt *) buf;
 	reply->frame_control =
 		IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -2257,7 +2309,7 @@
 		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
 		 * Transition Information, RSN, [RIC Response] */
 		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
-						buf + sizeof(buf) - p,
+						buf + buflen - p,
 						sta->auth_alg, ies, ies_len);
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -2359,10 +2411,10 @@
 		p = hostapd_eid_p2p_manage(hapd, p);
 #endif /* CONFIG_P2P_MANAGER */
 
-	p = hostapd_eid_mbo(hapd, p, buf + sizeof(buf) - p);
+	p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
 
 	if (hapd->conf->assocresp_elements &&
-	    (size_t) (buf + sizeof(buf) - p) >=
+	    (size_t) (buf + buflen - p) >=
 	    wpabuf_len(hapd->conf->assocresp_elements)) {
 		os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
 			  wpabuf_len(hapd->conf->assocresp_elements));
@@ -2380,8 +2432,10 @@
 		struct ieee802_11_elems elems;
 
 		if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
-		    ParseFailed || !elems.fils_session)
-			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		    ParseFailed || !elems.fils_session) {
+			res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto done;
+		}
 
 		/* FILS Session */
 		*p++ = WLAN_EID_EXTENSION; /* Element ID */
@@ -2391,96 +2445,70 @@
 		send_len += 2 + 1 + FILS_SESSION_LEN;
 
 		send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
-					      sizeof(buf));
-		if (send_len < 0)
-			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+					      buflen, sta->fils_hlp_resp);
+		if (send_len < 0) {
+			res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto done;
+		}
 	}
 #endif /* CONFIG_FILS */
 
 	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
 		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
 			   strerror(errno));
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		res = WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
 
-	return WLAN_STATUS_SUCCESS;
+done:
+	os_free(buf);
+	return res;
 }
 
 
 #ifdef CONFIG_FILS
 
-static void fils_process_hlp_req(struct hostapd_data *hapd,
-				 struct sta_info *sta,
-				 const u8 *pos, size_t len)
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
 {
-	const u8 *pkt, *end;
+	u16 reply_res;
 
-	wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
-		   " src=" MACSTR " len=%u)",
-		   MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
-		   (unsigned int) len);
-	if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG,
-			   "FILS: Ignore HLP request with unexpected source address"
-			   MACSTR, MAC2STR(pos + ETH_ALEN));
+	wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
+		   MAC2STR(sta->addr));
+	eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+	if (!sta->fils_pending_assoc_req)
 		return;
-	}
+	reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
+				    sta->fils_pending_assoc_is_reassoc,
+				    sta->fils_pending_assoc_req,
+				    sta->fils_pending_assoc_req_len);
+	os_free(sta->fils_pending_assoc_req);
+	sta->fils_pending_assoc_req = NULL;
+	sta->fils_pending_assoc_req_len = 0;
+	wpabuf_free(sta->fils_hlp_resp);
+	sta->fils_hlp_resp = NULL;
+	wpabuf_free(sta->hlp_dhcp_discover);
+	sta->hlp_dhcp_discover = NULL;
 
-	end = pos + len;
-	pkt = pos + 2 * ETH_ALEN;
-	if (end - pkt >= 6 &&
-	    os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
-		pkt += 6; /* Remove SNAP/LLC header */
-	wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
+	/*
+	 * Remove the station in case tranmission of a success response fails
+	 * (the STA was added associated to the driver) or if the station was
+	 * previously added unassociated.
+	 */
+	if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
+		hostapd_drv_sta_remove(hapd, sta->addr);
+		sta->added_unassoc = 0;
+	}
 }
 
 
-static void fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
-			     const u8 *pos, int left)
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
 {
-	const u8 *end = pos + left;
-	u8 *tmp, *tmp_pos;
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = eloop_data;
 
-	/* Check if there are any FILS HLP Container elements */
-	while (end - pos >= 2) {
-		if (2 + pos[1] > end - pos)
-			return;
-		if (pos[0] == WLAN_EID_EXTENSION &&
-		    pos[1] >= 1 + 2 * ETH_ALEN &&
-		    pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
-			break;
-		pos += 2 + pos[1];
-	}
-	if (end - pos < 2)
-		return; /* No FILS HLP Container elements */
-
-	tmp = os_malloc(end - pos);
-	if (!tmp)
-		return;
-
-	while (end - pos >= 2) {
-		if (2 + pos[1] > end - pos ||
-		    pos[0] != WLAN_EID_EXTENSION ||
-		    pos[1] < 1 + 2 * ETH_ALEN ||
-		    pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
-			break;
-		tmp_pos = tmp;
-		os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
-		tmp_pos += pos[1] - 1;
-		pos += 2 + pos[1];
-
-		/* Add possible fragments */
-		while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
-		       2 + pos[1] <= end - pos) {
-			os_memcpy(tmp_pos, pos + 2, pos[1]);
-			tmp_pos += pos[1];
-			pos += 2 + pos[1];
-		}
-
-		fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp);
-	}
-
-	os_free(tmp);
+	wpa_printf(MSG_DEBUG,
+		   "FILS: HLP response timeout - continue with association response for "
+		   MACSTR, MAC2STR(sta->addr));
+	fils_hlp_finish_assoc(hapd, sta);
 }
 
 #endif /* CONFIG_FILS */
@@ -2496,6 +2524,12 @@
 	int left, i;
 	struct sta_info *sta;
 	u8 *tmp = NULL;
+	struct hostapd_sta_wpa_psk_short *psk = NULL;
+	char *identity = NULL;
+	char *radius_cui = NULL;
+#ifdef CONFIG_FILS
+	int delay_assoc = 0;
+#endif /* CONFIG_FILS */
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
 				      sizeof(mgmt->u.assoc_req))) {
@@ -2571,6 +2605,21 @@
 		if (hapd->iface->current_mode &&
 		    hapd->iface->current_mode->mode ==
 			HOSTAPD_MODE_IEEE80211AD) {
+			int acl_res;
+			u32 session_timeout, acct_interim_interval;
+			struct vlan_description vlan_id;
+
+			acl_res = ieee802_11_allowed_address(
+				hapd, mgmt->sa, (const u8 *) mgmt, len,
+				&session_timeout, &acct_interim_interval,
+				&vlan_id, &psk, &identity, &radius_cui);
+			if (acl_res == HOSTAPD_ACL_REJECT) {
+				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto fail;
+			}
+			if (acl_res == HOSTAPD_ACL_PENDING)
+				return;
+
 			/* DMG/IEEE 802.11ad does not use authentication.
 			 * Allocate sta entry upon association. */
 			sta = ap_sta_add(hapd, mgmt->sa);
@@ -2583,6 +2632,15 @@
 				goto fail;
 			}
 
+			acl_res = ieee802_11_set_radius_info(
+				hapd, sta, acl_res, session_timeout,
+				acct_interim_interval, &vlan_id, &psk,
+				&identity, &radius_cui);
+			if (acl_res) {
+				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto fail;
+			}
+
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_DEBUG,
@@ -2760,11 +2818,17 @@
 #ifdef CONFIG_FILS
 	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
 	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
-	    sta->auth_alg == WLAN_AUTH_FILS_PK)
-		fils_process_hlp(hapd, sta, pos, left);
+	    sta->auth_alg == WLAN_AUTH_FILS_PK) {
+		if (fils_process_hlp(hapd, sta, pos, left) > 0)
+			delay_assoc = 1;
+	}
 #endif /* CONFIG_FILS */
 
  fail:
+	os_free(identity);
+	os_free(radius_cui);
+	hostapd_free_psk_list(psk);
+
 	/*
 	 * In case of a successful response, add the station to the driver.
 	 * Otherwise, the kernel may ignore Data frames before we process the
@@ -2786,6 +2850,29 @@
 	if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
 		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 
+#ifdef CONFIG_FILS
+	if (sta) {
+		eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+		os_free(sta->fils_pending_assoc_req);
+		sta->fils_pending_assoc_req = NULL;
+		sta->fils_pending_assoc_req_len = 0;
+		wpabuf_free(sta->fils_hlp_resp);
+		sta->fils_hlp_resp = NULL;
+	}
+	if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
+		sta->fils_pending_assoc_req = tmp;
+		sta->fils_pending_assoc_req_len = left;
+		sta->fils_pending_assoc_is_reassoc = reassoc;
+		wpa_printf(MSG_DEBUG,
+			   "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
+			   MACSTR, MAC2STR(sta->addr));
+		eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+		eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
+				       fils_hlp_timeout, hapd, sta);
+		return;
+	}
+#endif /* CONFIG_FILS */
+
 	reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
 				    left);
 	os_free(tmp);
@@ -2975,7 +3062,7 @@
 	    (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
 		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
 			   "frame (category=%u) from unassociated STA " MACSTR,
-			   MAC2STR(mgmt->sa), mgmt->u.action.category);
+			   mgmt->u.action.category, MAC2STR(mgmt->sa));
 		return 0;
 	}
 
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 46c92b7..ce3abcb 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -55,6 +55,8 @@
 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_he_operation(struct hostapd_data *hapd, u8 *eid);
 
 int hostapd_ht_operation_update(struct hostapd_iface *iface);
 void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -140,5 +142,7 @@
 				 struct sta_info *sta, int success,
 				 struct wpabuf *erp_resp,
 				 const u8 *msk, size_t msk_len);
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
 
 #endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index b890537..1e0358c 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -665,9 +665,11 @@
 
 #ifndef CONFIG_NO_RADIUS
 	hostapd_acl_cache_free(hapd->acl_cache);
+	hapd->acl_cache = NULL;
 #endif /* CONFIG_NO_RADIUS */
 
 	query = hapd->acl_queries;
+	hapd->acl_queries = NULL;
 	while (query) {
 		prev = query;
 		query = query->next;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
new file mode 100644
index 0000000..7d6a84f
--- /dev/null
+++ b/src/ap/ieee802_11_he.c
@@ -0,0 +1,101 @@
+/*
+ * hostapd / IEEE 802.11ax HE
+ * Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/qca-vendor.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+#include "dfs.h"
+
+u8 * hostapd_eid_vendor_he_capab(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_he_capabilities *cap;
+	u8 *pos = eid;
+
+	if (!hapd->iface->current_mode)
+		return eid;
+
+	/* For now, use a vendor specific element since the P802.11ax draft is
+	 * still subject to changes and the contents of this element may change.
+	 * This can be replaced with the actual element once P802.11ax is
+	 * finalized. */
+	/* Vendor HE Capabilities element */
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = 4 /* The Vendor OUI, subtype */ +
+		sizeof(struct ieee80211_he_capabilities);
+
+	WPA_PUT_BE32(pos, (OUI_QCA << 8) | QCA_VENDOR_ELEM_HE_CAPAB);
+	pos += 4;
+	cap = (struct ieee80211_he_capabilities *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+
+	if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
+		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
+			HE_PHYCAP_SU_BEAMFORMER_CAPAB;
+
+	if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
+		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
+			HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
+
+	if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
+		cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
+			HE_PHYCAP_MU_BEAMFORMER_CAPAB;
+
+	pos += sizeof(*cap);
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_vendor_he_operation(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_he_operation *oper;
+	u8 *pos = eid;
+
+	if (!hapd->iface->current_mode)
+		return eid;
+
+	/* For now, use a vendor specific element since the P802.11ax draft is
+	 * still subject to changes and the contents of this element may change.
+	 * This can be replaced with the actual element once P802.11ax is
+	 * finalized. */
+	/* Vendor HE Operation element */
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = 4 /* The Vendor OUI, subtype */ +
+		sizeof(struct ieee80211_he_operation);
+
+	WPA_PUT_BE32(pos, (OUI_QCA << 8) | QCA_VENDOR_ELEM_HE_OPER);
+	pos += 4;
+	oper = (struct ieee80211_he_operation *) pos;
+	os_memset(oper, 0, sizeof(*oper));
+
+	if (hapd->iface->conf->he_op.he_bss_color)
+		oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
+
+	if (hapd->iface->conf->he_op.he_default_pe_duration)
+		oper->he_oper_params |=
+			(hapd->iface->conf->he_op.he_default_pe_duration <<
+			 HE_OPERATION_DFLT_PE_DURATION_OFFSET);
+
+	if (hapd->iface->conf->he_op.he_twt_required)
+		oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
+
+	if (hapd->iface->conf->he_op.he_rts_threshold)
+		oper->he_oper_params |=
+			(hapd->iface->conf->he_op.he_rts_threshold <<
+			 HE_OPERATION_RTS_THRESHOLD_OFFSET);
+
+	pos += sizeof(*oper);
+
+	return pos;
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 5eb1060..146e447 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -340,8 +340,8 @@
 	 * that did not specify a valid WMM IE in the (Re)Association Request
 	 * frame.
 	 */
-	if (!ht_capab ||
-	    !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
+	if (!ht_capab || !(sta->flags & WLAN_STA_WMM) ||
+	    !hapd->iconf->ieee80211n || hapd->conf->disable_11n) {
 		sta->flags &= ~WLAN_STA_HT;
 		os_free(sta->ht_capabilities);
 		sta->ht_capabilities = NULL;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f30f63b..8d06620 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -334,7 +334,7 @@
 {
 	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
 	if (!vht_capab ||
-	    hapd->conf->disable_11ac ||
+	    !hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
 	    !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
 		sta->flags &= ~WLAN_STA_VHT;
 		os_free(sta->vht_capabilities);
diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
index efc1d7e..93e775b 100644
--- a/src/ap/peerkey_auth.c
+++ b/src/ap/peerkey_auth.c
@@ -19,17 +19,6 @@
 
 #ifdef CONFIG_PEERKEY
 
-static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
-	struct wpa_authenticator *wpa_auth = eloop_ctx;
-	struct wpa_stsl_negotiation *neg = timeout_ctx;
-#endif
-
-	/* TODO: ? */
-}
-
-
 struct wpa_stsl_search {
 	const u8 *addr;
 	struct wpa_state_machine *sm;
@@ -110,7 +99,6 @@
 			   MAC2STR(kde.mac_addr));
 		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
 				   STK_ERR_STA_NR);
-		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
 		return;
 	}
 
@@ -285,7 +273,6 @@
 			   MAC2STR(kde.mac_addr));
 		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
 				   STK_ERR_STA_NR);
-		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
 		return;
 	}
 
@@ -365,32 +352,4 @@
 	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
 }
 
-
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
-		    struct wpa_stsl_negotiation *neg)
-{
-	struct wpa_stsl_negotiation *pos, *prev;
-
-	if (wpa_auth == NULL)
-		return -1;
-	pos = wpa_auth->stsl_negotiations;
-	prev = NULL;
-	while (pos) {
-		if (pos == neg) {
-			if (prev)
-				prev->next = pos->next;
-			else
-				wpa_auth->stsl_negotiations = pos->next;
-
-			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
-			os_free(pos);
-			return 0;
-		}
-		prev = pos;
-		pos = pos->next;
-	}
-
-	return -1;
-}
-
 #endif /* CONFIG_PEERKEY */
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index 28e8cc9..56ed29c 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -147,7 +147,7 @@
 	/* Subelements are arranged as IEs */
 	subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
 	if (subelem && subelem[1] == 2)
-		return *(u16 *) (subelem + 2);
+		return WPA_GET_LE16(subelem + 2);
 
 	return 0;
 }
@@ -370,13 +370,7 @@
 	struct sta_info *sta = ap_get_sta(hapd, addr);
 	int ret;
 
-	if (!sta) {
-		wpa_printf(MSG_INFO,
-			   "Request LCI: Destination address is not in station list");
-		return -1;
-	}
-
-	if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
+	if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
 		wpa_printf(MSG_INFO,
 			   "Request LCI: Destination address is not connected");
 		return -1;
@@ -479,9 +473,8 @@
 		wpa_printf(MSG_DEBUG,
 			   "Request range: Range request is already in process; overriding");
 		hapd->range_req_active = 0;
-		eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
-				       hostapd_range_rep_timeout_handler, hapd,
-				       NULL);
+		eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
+				     NULL);
 	}
 
 	/* Action + measurement type + token + reps + EID + len = 7 */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index b87ddea..af8c754 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -339,6 +339,13 @@
 	mbo_ap_sta_free(sta);
 	os_free(sta->supp_op_classes);
 
+#ifdef CONFIG_FILS
+	os_free(sta->fils_pending_assoc_req);
+	wpabuf_free(sta->fils_hlp_resp);
+	wpabuf_free(sta->hlp_dhcp_discover);
+	eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+#endif /* CONFIG_FILS */
+
 	os_free(sta);
 }
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 0b44f7b..6f55403 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -225,6 +225,12 @@
 #ifdef CONFIG_FILS
 	u8 fils_snonce[FILS_NONCE_LEN];
 	u8 fils_session[FILS_SESSION_LEN];
+	u8 *fils_pending_assoc_req;
+	size_t fils_pending_assoc_req_len;
+	unsigned int fils_pending_assoc_is_reassoc:1;
+	unsigned int fils_dhcp_rapid_commit_proxy:1;
+	struct wpabuf *fils_hlp_resp;
+	struct wpabuf *hlp_dhcp_discover;
 #endif /* CONFIG_FILS */
 };
 
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 314e244..8054c5d 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -21,11 +21,6 @@
 #include "wmm.h"
 
 
-/* TODO: maintain separate sequence and fragment numbers for each AC
- * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
- * if only WMM stations are receiving a certain group */
-
-
 static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
 {
 	u8 ret;
@@ -157,8 +152,9 @@
 
 int wmm_process_tspec(struct wmm_tspec_element *tspec)
 {
-	int medium_time, pps, duration;
-	int up, psb, dir, tid;
+	u64 medium_time;
+	unsigned int pps, duration;
+	unsigned int up, psb, dir, tid;
 	u16 val, surplus;
 
 	up = (tspec->ts_info[1] >> 3) & 0x07;
@@ -206,8 +202,9 @@
 		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
 	}
 
-	medium_time = surplus * pps * duration / 0x2000;
-	wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+	medium_time = (u64) surplus * pps * duration / 0x2000;
+	wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %lu",
+		   (unsigned long) medium_time);
 
 	/*
 	 * TODO: store list of granted (and still active) TSPECs and check
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 41d50ce..7c4fde0 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -95,8 +95,8 @@
 	if (mgmt == NULL) {
 		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
 			   "WNM-Sleep Response action frame");
-		os_free(wnmtfs_ie);
-		return -1;
+		res = -1;
+		goto fail;
 	}
 	os_memcpy(mgmt->da, addr, ETH_ALEN);
 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -118,11 +118,8 @@
 			   (int) gtk_elem_len);
 #ifdef CONFIG_IEEE80211W
 		res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
-		if (res < 0) {
-			os_free(wnmtfs_ie);
-			os_free(mgmt);
-			return -1;
-		}
+		if (res < 0)
+			goto fail;
 		igtk_elem_len = res;
 		pos += igtk_elem_len;
 		wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
@@ -184,6 +181,7 @@
 
 #undef MAX_GTK_SUBELEM_LEN
 #undef MAX_IGTK_SUBELEM_LEN
+fail:
 	os_free(wnmtfs_ie);
 	os_free(mgmt);
 	return res;
@@ -207,7 +205,8 @@
 		u8 ie_len = pos[1];
 		if (pos + 2 + ie_len > frm + len)
 			break;
-		if (*pos == WLAN_EID_WNMSLEEP)
+		if (*pos == WLAN_EID_WNMSLEEP &&
+		    ie_len >= (int) sizeof(*wnmsleep_ie) - 2)
 			wnmsleep_ie = (struct wnm_sleep_element *) pos;
 		else if (*pos == WLAN_EID_TFS_REQ) {
 			if (!tfsreq_ie_start)
@@ -251,20 +250,14 @@
 
 static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
 						  const u8 *addr,
-						  u8 dialog_token,
-						  const char *url)
+						  u8 dialog_token)
 {
 	struct ieee80211_mgmt *mgmt;
-	size_t url_len, len;
+	size_t len;
 	u8 *pos;
 	int res;
 
-	if (url)
-		url_len = os_strlen(url);
-	else
-		url_len = 0;
-
-	mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
+	mgmt = os_zalloc(sizeof(*mgmt));
 	if (mgmt == NULL)
 		return -1;
 	os_memcpy(mgmt->da, addr, ETH_ALEN);
@@ -279,11 +272,6 @@
 	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
 	mgmt->u.action.u.bss_tm_req.validity_interval = 1;
 	pos = mgmt->u.action.u.bss_tm_req.variable;
-	if (url) {
-		*pos++ += url_len;
-		os_memcpy(pos, url, url_len);
-		pos += url_len;
-	}
 
 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
 		   MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
@@ -326,7 +314,7 @@
 	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
 		    pos, end - pos);
 
-	ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
+	ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
 }
 
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 69e3a5d..7b26c04 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -60,8 +60,6 @@
 			  struct wpa_group *group);
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
 
-static const u32 dot11RSNAConfigGroupUpdateCount = 4;
-static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
 static const u32 eapol_key_timeout_first = 100; /* ms */
 static const u32 eapol_key_timeout_subseq = 1000; /* ms */
 static const u32 eapol_key_timeout_first_group = 500; /* ms */
@@ -515,11 +513,6 @@
 	eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
 	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
 
-#ifdef CONFIG_PEERKEY
-	while (wpa_auth->stsl_negotiations)
-		wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
-#endif /* CONFIG_PEERKEY */
-
 	pmksa_cache_auth_deinit(wpa_auth->pmksa);
 
 #ifdef CONFIG_IEEE80211R_AP
@@ -615,6 +608,7 @@
 				"start 4-way handshake");
 		/* Go to PTKINITDONE state to allow GTK rekeying */
 		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+		sm->Pair = TRUE;
 		return 0;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -625,6 +619,7 @@
 				"FILS authentication already completed - do not start 4-way handshake");
 		/* Go to PTKINITDONE state to allow GTK rekeying */
 		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+		sm->Pair = TRUE;
 		return 0;
 	}
 #endif /* CONFIG_FILS */
@@ -862,7 +857,8 @@
 			pmk_len = sm->pmk_len;
 		}
 
-		wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
+		if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+			break;
 
 		if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
 		    == 0) {
@@ -1482,9 +1478,11 @@
 	WPA_PUT_BE16(key->key_info, key_info);
 
 	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
-	WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
-	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+	if ((key_info & WPA_KEY_INFO_SMK_MESSAGE) ||
+	    (sm->wpa == WPA_VERSION_WPA2 && !pairwise))
 		WPA_PUT_BE16(key->key_length, 0);
+	else
+		WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
 
 	/* FIX: STSL: what to use as key_replay_counter? */
 	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
@@ -1619,7 +1617,7 @@
 {
 	int timeout_ms;
 	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
-	int ctr;
+	u32 ctr;
 
 	if (sm == NULL)
 		return;
@@ -1636,7 +1634,7 @@
 	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
 		sm->pending_1_of_4_timeout = 1;
 	wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
-		   "counter %d)", timeout_ms, ctr);
+		   "counter %u)", timeout_ms, ctr);
 	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
 			       wpa_send_eapol_timeout, wpa_auth, sm);
 }
@@ -1927,7 +1925,7 @@
 	} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
 		unsigned int pmk_len;
 
-		if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
 			pmk_len = PMK_LEN_SUITE_B_192;
 		else
 			pmk_len = PMK_LEN;
@@ -1998,7 +1996,7 @@
 	sm->alt_snonce_valid = FALSE;
 
 	sm->TimeoutCtr++;
-	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+	if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
 		/* No point in sending the EAPOL-Key - we will disconnect
 		 * immediately following this. */
 		return;
@@ -2230,10 +2228,10 @@
 	 * field to the FILS Session element (both inclusive).
 	 */
 	aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
-	aad_len[4] = crypt - aad[0];
+	aad_len[4] = crypt - aad[4];
 
 	if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
-			    1, aad, aad_len, pos + (crypt - ie_start)) < 0) {
+			    5, aad, aad_len, pos + (crypt - ie_start)) < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "FILS: Invalid AES-SIV data in the frame");
 		return -1;
@@ -2274,7 +2272,8 @@
 
 
 int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
-		       size_t current_len, size_t max_len)
+		       size_t current_len, size_t max_len,
+		       const struct wpabuf *hlp)
 {
 	u8 *end = buf + max_len;
 	u8 *pos = buf + current_len;
@@ -2334,7 +2333,9 @@
 	wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
 	wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
 
-	/* TODO: FILS HLP Container */
+	/* FILS HLP Container */
+	if (hlp)
+		wpabuf_put_buf(plain, hlp);
 
 	/* TODO: FILS IP Address Assignment */
 
@@ -2464,7 +2465,8 @@
 			pmk_len = sm->pmk_len;
 		}
 
-		wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
+		if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+			break;
 
 		if (mic_len &&
 		    wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
@@ -2686,7 +2688,7 @@
 	sm->TimeoutEvt = FALSE;
 
 	sm->TimeoutCtr++;
-	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+	if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
 		/* No point in sending the EAPOL-Key - we will disconnect
 		 * immediately following this. */
 		return;
@@ -2981,11 +2983,12 @@
 		    sm->EAPOLKeyPairwise)
 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
 		else if (sm->TimeoutCtr >
-			 (int) dot11RSNAConfigPairwiseUpdateCount) {
+			 sm->wpa_auth->conf.wpa_pairwise_update_count) {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-					 "PTKSTART: Retry limit %d reached",
-					 dot11RSNAConfigPairwiseUpdateCount);
+			wpa_auth_vlogger(
+				sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"PTKSTART: Retry limit %u reached",
+				sm->wpa_auth->conf.wpa_pairwise_update_count);
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		} else if (sm->TimeoutEvt)
 			SM_ENTER(WPA_PTK, PTKSTART);
@@ -3009,12 +3012,12 @@
 			 sm->EAPOLKeyPairwise && sm->MICVerified)
 			SM_ENTER(WPA_PTK, PTKINITDONE);
 		else if (sm->TimeoutCtr >
-			 (int) dot11RSNAConfigPairwiseUpdateCount) {
+			 sm->wpa_auth->conf.wpa_pairwise_update_count) {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-					 "PTKINITNEGOTIATING: Retry limit %d "
-					 "reached",
-					 dot11RSNAConfigPairwiseUpdateCount);
+			wpa_auth_vlogger(
+				sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"PTKINITNEGOTIATING: Retry limit %u reached",
+				sm->wpa_auth->conf.wpa_pairwise_update_count);
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		} else if (sm->TimeoutEvt)
 			SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3049,7 +3052,7 @@
 	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
 
 	sm->GTimeoutCtr++;
-	if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+	if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
 		/* No point in sending the EAPOL-Key - we will disconnect
 		 * immediately following this. */
 		return;
@@ -3099,7 +3102,7 @@
 		       (wpa_mic_len(sm->wpa_key_mgmt) ? WPA_KEY_INFO_MIC : 0) |
 		       WPA_KEY_INFO_ACK |
 		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
-		       rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+		       rsc, NULL, kde, kde_len, gsm->GN, 1);
 
 	os_free(kde_buf);
 }
@@ -3128,6 +3131,10 @@
 		sm->group->GKeyDoneStations--;
 	sm->GUpdateStationKeys = FALSE;
 	sm->Disconnect = TRUE;
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "group key handshake failed (%s) after %u tries",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
+			 sm->wpa_auth->conf.wpa_group_update_count);
 }
 
 
@@ -3147,7 +3154,7 @@
 		    !sm->EAPOLKeyPairwise && sm->MICVerified)
 			SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
 		else if (sm->GTimeoutCtr >
-			 (int) dot11RSNAConfigGroupUpdateCount)
+			 sm->wpa_auth->conf.wpa_group_update_count)
 			SM_ENTER(WPA_PTK_GROUP, KEYERROR);
 		else if (sm->TimeoutEvt)
 			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
@@ -3607,8 +3614,8 @@
 		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
 		RSN_VERSION,
 		!!wpa_auth->conf.wpa_strict_rekey,
-		dot11RSNAConfigGroupUpdateCount,
-		dot11RSNAConfigPairwiseUpdateCount,
+		wpa_auth->conf.wpa_group_update_count,
+		wpa_auth->conf.wpa_pairwise_update_count,
 		wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
 		dot11RSNAConfigPMKLifetime,
 		dot11RSNAConfigPMKReauthThreshold,
@@ -3768,7 +3775,7 @@
 	    sm->wpa_auth->conf.disable_pmksa_caching)
 		return -1;
 
-	if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+	if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
 		if (pmk_len > PMK_LEN_SUITE_B_192)
 			pmk_len = PMK_LEN_SUITE_B_192;
 	} else if (pmk_len > PMK_LEN) {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index a44b030..0920a16 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -144,6 +144,8 @@
 	int wpa_strict_rekey;
 	int wpa_gmk_rekey;
 	int wpa_ptk_rekey;
+	u32 wpa_group_update_count;
+	u32 wpa_pairwise_update_count;
 	int rsn_pairwise;
 	int rsn_preauth;
 	int eapol_version;
@@ -247,7 +249,7 @@
 	WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
 	WPA_INVALID_MDIE, WPA_INVALID_PROTO
 };
-	
+
 int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 			struct wpa_state_machine *sm,
 			const u8 *wpa_ie, size_t wpa_ie_len,
@@ -361,7 +363,8 @@
 		       const struct ieee80211_mgmt *mgmt, size_t frame_len,
 		       u8 *pos, size_t left);
 int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
-		       size_t current_len, size_t max_len);
+		       size_t current_len, size_t max_len,
+		       const struct wpabuf *hlp);
 int fils_set_tk(struct wpa_state_machine *sm);
 
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 1fe3c2b..c267a17 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -392,16 +392,19 @@
 		return -1;
 	}
 
-	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
-			  r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
+	if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+			      r0kh, r0kh_len, sm->addr,
+			      pmk_r0, pmk_r0_name) < 0)
+		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
 	if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
 		wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
 				    sm->pairwise);
 
-	wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
-			  pmk_r1, sm->pmk_r1_name);
+	if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+			      pmk_r1, sm->pmk_r1_name) < 0)
+		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
 		    WPA_PMK_NAME_LEN);
@@ -834,12 +837,12 @@
 		if (pmk == NULL)
 			break;
 
-		wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
-				  r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
-		wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
-				  pmk_r1, pmk_r1_name);
-
-		if (os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
+		if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
+				      r0kh_len, sm->addr,
+				      pmk_r0, pmk_r0_name) < 0 ||
+		    wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+				      pmk_r1, pmk_r1_name) < 0 ||
+		    os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
 				    WPA_PMK_NAME_LEN) != 0)
 			continue;
 
@@ -958,9 +961,10 @@
 
 	wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
 		    parse.rsn_pmkid, WPA_PMK_NAME_LEN);
-	wpa_derive_pmk_r1_name(parse.rsn_pmkid,
-			       sm->wpa_auth->conf.r1_key_holder, sm->addr,
-			       pmk_r1_name);
+	if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+				   sm->wpa_auth->conf.r1_key_holder, sm->addr,
+				   pmk_r1_name) < 0)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
 		    pmk_r1_name, WPA_PMK_NAME_LEN);
 
@@ -1007,41 +1011,35 @@
 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
 		2 + FT_R1KH_ID_LEN + 200;
 	*resp_ies = os_zalloc(buflen);
-	if (*resp_ies == NULL) {
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
+	if (*resp_ies == NULL)
+		goto fail;
 
 	pos = *resp_ies;
 	end = *resp_ies + buflen;
 
 	ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
-	if (ret < 0) {
-		os_free(*resp_ies);
-		*resp_ies = NULL;
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
+	if (ret < 0)
+		goto fail;
 	pos += ret;
 
 	ret = wpa_write_mdie(conf, pos, end - pos);
-	if (ret < 0) {
-		os_free(*resp_ies);
-		*resp_ies = NULL;
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
+	if (ret < 0)
+		goto fail;
 	pos += ret;
 
 	ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
 			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
-	if (ret < 0) {
-		os_free(*resp_ies);
-		*resp_ies = NULL;
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
+	if (ret < 0)
+		goto fail;
 	pos += ret;
 
 	*resp_ies_len = pos - *resp_ies;
 
 	return WLAN_STATUS_SUCCESS;
+fail:
+	os_free(*resp_ies);
+	*resp_ies = NULL;
+	return WLAN_STATUS_UNSPECIFIED_FAILURE;
 }
 
 
@@ -1483,8 +1481,11 @@
 		return -1;
 	}
 
-	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
-			  r.pmk_r1, r.pmk_r1_name);
+	if (wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+			      r.pmk_r1, r.pmk_r1_name) < 0) {
+		os_memset(pmk_r0, 0, PMK_LEN);
+		return -1;
+	}
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
 		    WPA_PMK_NAME_LEN);
@@ -1536,12 +1537,10 @@
 {
 	struct ft_r0kh_r1kh_resp_frame *frame = ctx;
 
-	if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
-		return 0;
-	if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
-		      FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
-		return 0;
-	if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
+	if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0 ||
+	    os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
+		      FT_R0KH_R1KH_PULL_NONCE_LEN) != 0 ||
+	    sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
 		return 0;
 
 	wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
@@ -1825,10 +1824,10 @@
 }
 
 
-static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
-				   struct wpa_ft_pmk_r0_sa *pmk_r0,
-				   struct ft_remote_r1kh *r1kh,
-				   const u8 *s1kh_id, int pairwise)
+static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+				  struct wpa_ft_pmk_r0_sa *pmk_r0,
+				  struct ft_remote_r1kh *r1kh,
+				  const u8 *s1kh_id, int pairwise)
 {
 	struct ft_r0kh_r1kh_push_frame frame, f;
 	struct os_time now;
@@ -1846,8 +1845,9 @@
 	os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
 	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
 	os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
-	wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
-			  s1kh_id, f.pmk_r1, f.pmk_r1_name);
+	if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
+			      s1kh_id, f.pmk_r1, f.pmk_r1_name) < 0)
+		return -1;
 	wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
@@ -1863,9 +1863,10 @@
 	if (aes_wrap(r1kh->key, sizeof(r1kh->key),
 		     (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
 		     plain, crypt) < 0)
-		return;
+		return -1;
 
 	wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+	return 0;
 }
 
 
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 22518a1..394f77a 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -41,6 +41,8 @@
 	wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
 	wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
 	wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+	wconf->wpa_group_update_count = conf->wpa_group_update_count;
+	wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
 	wconf->rsn_pairwise = conf->rsn_pairwise;
 	wconf->rsn_preauth = conf->rsn_preauth;
 	wconf->eapol_version = conf->eapol_version;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 065a624..90318d8 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -14,13 +14,6 @@
 
 struct wpa_group;
 
-struct wpa_stsl_negotiation {
-	struct wpa_stsl_negotiation *next;
-	u8 initiator[ETH_ALEN];
-	u8 peer[ETH_ALEN];
-};
-
-
 struct wpa_state_machine {
 	struct wpa_authenticator *wpa_auth;
 	struct wpa_group *group;
@@ -48,8 +41,8 @@
 	Boolean AuthenticationRequest;
 	Boolean ReAuthenticationRequest;
 	Boolean Disconnect;
-	int TimeoutCtr;
-	int GTimeoutCtr;
+	u32 TimeoutCtr;
+	u32 GTimeoutCtr;
 	Boolean TimeoutEvt;
 	Boolean EAPOLKeyReceived;
 	Boolean EAPOLKeyPairwise;
@@ -200,8 +193,6 @@
 	unsigned int dot11RSNATKIPCounterMeasuresInvoked;
 	unsigned int dot11RSNA4WayHandshakeFailures;
 
-	struct wpa_stsl_negotiation *stsl_negotiations;
-
 	struct wpa_auth_config conf;
 	const struct wpa_auth_callbacks *cb;
 	void *cb_ctx;
@@ -239,8 +230,6 @@
 			   void *cb_ctx);
 
 #ifdef CONFIG_PEERKEY
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
-		    struct wpa_stsl_negotiation *neg);
 void wpa_smk_error(struct wpa_authenticator *wpa_auth,
 		   struct wpa_state_machine *sm,
 		   const u8 *key_data, size_t key_data_len);
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
new file mode 100644
index 0000000..f2ef61e
--- /dev/null
+++ b/src/common/dhcp.h
@@ -0,0 +1,257 @@
+/*
+ * DHCP definitions
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT 68
+
+struct dhcp_data {
+	u8 op;
+	u8 htype;
+	u8 hlen;
+	u8 hops;
+	be32 xid;
+	be16 secs;
+	be16 flags;
+	be32 client_ip;
+	be32 your_ip;
+	be32 server_ip;
+	be32 relay_ip;
+	u8 hw_addr[16];
+	u8 serv_name[64];
+	u8 boot_file[128];
+} STRUCT_PACKED;
+
+struct bootp_pkt {
+	struct iphdr iph;
+	struct udphdr udph;
+	u8 op;
+	u8 htype;
+	u8 hlen;
+	u8 hops;
+	be32 xid;
+	be16 secs;
+	be16 flags;
+	be32 client_ip;
+	be32 your_ip;
+	be32 server_ip;
+	be32 relay_ip;
+	u8 hw_addr[16];
+	u8 serv_name[64];
+	u8 boot_file[128];
+	u8 exten[312];
+} STRUCT_PACKED;
+
+#define DHCP_MAGIC 0x63825363
+
+/*
+ * IANA DHCP/BOOTP registry
+ * http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
+*/
+enum dhcp_options {
+	DHCP_OPT_PAD = 0,
+	DHCP_OPT_SUBNET_MASK = 1,
+	DHCP_OPT_TIME_OFFSET = 2,
+	DHCP_OPT_ROUTER = 3,
+	DHCP_OPT_TIME_SERVER = 4,
+	DHCP_OPT_NAME_SERVER = 5,
+	DHCP_OPT_DOMAIN_NAME_SERVER = 6,
+	DHCP_OPT_LOG_SERVER = 7,
+	DHCP_OPT_QUOTES_SERVER = 8,
+	DHCP_OPT_LPR_SERVER = 9,
+	DHCP_OPT_IMPRESS_SERVER = 10,
+	DHCP_OPT_RLP_SERVER = 11,
+	DHCP_OPT_HOSTNAME = 12,
+	DHCP_OPT_BOOT_FILE_SIZE = 13,
+	DHCP_OPT_MERIT_DUMP_FILE = 14,
+	DHCP_OPT_DOMAIN_NAME = 15,
+	DHCP_OPT_SWAP_SERVER = 16,
+	DHCP_OPT_ROOT_PATH = 17,
+	DHCP_OPT_EXTENSION_PATH = 18,
+	DHCP_OPT_FORWARD = 19,
+	DHCP_OPT_SRC_RTE = 20,
+	DHCP_OPT_POLICY_FILTER = 21,
+	DHCP_OPT_MAX_DG_ASSEMBLY = 22,
+	DHCP_OPT_DEFAULT_IP_TTL = 23,
+	DHCP_OPT_MTU_TIMEOUT = 24,
+	DHCP_OPT_MTU_PLATEAU = 25,
+	DHCP_OPT_MTU_INTERFACE = 26,
+	DHCP_OPT_ALL_SUBNETS_LOCAL = 27,
+	DHCP_OPT_BROADCAST_ADDRESS = 28,
+	DHCP_OPT_MASK_DISCOVERY = 29,
+	DHCP_OPT_MASK_SUPPLIER = 30,
+	DHCP_OPT_ROUTER_DISCOVERY = 31,
+	DHCP_OPT_ROUTER_SOLICITATION_ADDRESS = 32,
+	DHCP_OPT_STATIC_ROUTE = 33,
+	DHCP_OPT_TRAILERS = 34,
+	DHCP_OPT_ARP_TIMEOUT = 35,
+	DHCP_OPT_ETHERNET = 36,
+	DHCP_OPT_TCP_DEFAULT_TTL = 37,
+	DHCP_OPT_TCP_KEEPALIVE_INTERVAL = 38,
+	DHCP_OPT_TCP_KEEPALIVE_GARBAGE = 39,
+	DHCP_OPT_NIS_DOMAIN = 40,
+	DHCP_OPT_NIS_SERVERS = 41,
+	DHCP_OPT_NTP_SERVERS = 42,
+	DHCP_OPT_VENDOR_SPECIFIC = 43,
+	DHCP_OPT_NETBIOS_NAME_SERVER = 44,
+	DHCP_OPT_NETBIOS_DISTRIBUTION_SERVER = 45,
+	DHCP_OPT_NETBIOS_NODE_TYPE = 46,
+	DHCP_OPT_NETBIOS_SCOPE = 47,
+	DHCP_OPT_FONT_SERVER = 48,
+	DHCP_OPT_DISPLAY_MANAGER = 49,
+	DHCP_OPT_REQUESTED_IP_ADDRESS = 50,
+	DHCP_OPT_IP_ADDRESS_LEASE_TIME = 51,
+	DHCP_OPT_OVERLOAD = 52,
+	DHCP_OPT_MSG_TYPE = 53,
+	DHCP_OPT_SERVER_ID = 54,
+	DHCP_OPT_PARAMETER_REQ_LIST = 55,
+	DHCP_OPT_MESSAGE = 56,
+	DHCP_OPT_MAX_MESSAGE_SIZE = 57,
+	DHCP_OPT_RENEWAL_TIME = 58,
+	DHCP_OPT_REBINDING_TIME = 59,
+	DHCP_OPT_VENDOR_CLASS_ID = 60,
+	DHCP_OPT_CLIENT_ID = 61,
+	DHCP_OPT_NETWARE_IP_DOMAIN = 62,
+	DHCP_OPT_NETWARE_IP_OPTION = 63,
+	DHCP_OPT_NIS_V3_DOMAIN = 64,
+	DHCP_OPT_NIS_V3_SERVERS = 65,
+	DHCP_OPT_TFTP_SERVER_NAME = 66,
+	DHCP_OPT_BOOT_FILE_NAME = 67,
+	DHCP_OPT_HOME_AGENT_ADDRESSES = 68,
+	DHCP_OPT_SMTP_SERVER = 69,
+	DHCP_OPT_POP3_SERVER = 70,
+	DHCP_OPT_NNTP_SERVER = 71,
+	DHCP_OPT_WWW_SERVER = 72,
+	DHCP_OPT_FINGER_SERVER = 73,
+	DHCP_OPT_IRC_SERVER = 74,
+	DHCP_OPT_STREETTALK_SERVER = 75,
+	DHCP_OPT_STDA_SERVER = 76,
+	DHCP_OPT_USER_CLASS = 77,
+	DHCP_OPT_DIRECTORY_AGENT = 78,
+	DHCP_OPT_SERVICE_SCOPE = 79,
+	DHCP_OPT_RAPID_COMMIT = 80,
+	DHCP_OPT_CLIENT_FQDN = 81,
+	DHCP_OPT_RELAY_AGENT_INFO = 82,
+	DHCP_OPT_ISNS = 83,
+	DHCP_OPT_NDS_SERVERS = 85,
+	DHCP_OPT_NDS_TREE_NAME = 86,
+	DHCP_OPT_NDS_CONTEXT = 87,
+	DHCP_OPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88,
+	DHCP_OPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89,
+	DHCP_OPT_AUTHENTICATION = 90,
+	DHCP_OPT_CLIENT_LAST_TRANSACTION_TIME = 91,
+	DHCP_OPT_ASSOCIATED_IP = 92,
+	DHCP_OPT_CLIENT_SYSYEM = 93,
+	DHCP_OPT_CLIENT_NDI = 94,
+	DHCP_OPT_LDAP = 95,
+	DHCP_OPT_UUID_GUID = 97,
+	DHCP_OPT_USER_AUTH = 98,
+	DHCP_OPT_GEOCONF_CIVIC = 99,
+	DHCP_OPT_PCODE = 100,
+	DHCP_OPT_TCODE = 101,
+	DHCP_OPT_NETINFO_ADDRESS = 112,
+	DHCP_OPT_NETINFO_TAG = 113,
+	DHCP_OPT_URL = 114,
+	DHCP_OPT_AUTO_CONFIG = 116,
+	DHCP_OPT_NAME_SERVICE_SEARCH = 117,
+	DHCP_OPT_SUBNET_SELECTION = 118,
+	DHCP_OPT_DOMAIN_SEARCH = 119,
+	DHCP_OPT_SIP_SERVERS_DCP = 120,
+	DHCP_OPT_CLASSLESS_STATIC_ROUTE = 121,
+	DHCP_OPT_CCC = 122,
+	DHCP_OPT_GEOCONF = 123,
+	DHCP_OPT_V_I_VENDOR_CLASS = 124,
+	DHCP_OPT_V_I_VENDOR_SPECIFIC_INFO = 125,
+	DHCP_OPT_PANA_AGENT = 136,
+	DHCP_OPT_V4_LOST = 137,
+	DHCP_OPT_CAPWAP_AC_V4 = 138,
+	DHCP_OPT_IPV4_ADDRESS_MOS = 139,
+	DHCP_OPT_IPV4_FQDN_MOS = 140,
+	DHCP_OPT_SIP_UA_CONF = 141,
+	DHCP_OPT_IPV4_ADDRESS_ANDSF = 142,
+	DHCP_OPT_GEOLOC = 144,
+	DHCP_OPT_FORCERENEW_NONCE_CAPABLE = 145,
+	DHCP_OPT_RDNSS_SELECTION = 146,
+	DHCP_OPT_TFTP_SERVER_ADDRESS = 150,
+	DHCP_OPT_STATUS_CODE = 151,
+	DHCP_OPT_BASE_TIME = 152,
+	DHCP_OPT_START_TIME_OF_STATE = 153,
+	DHCP_OPT_QUERY_START_TIME = 154,
+	DHCP_OPT_QUERY_END_TIME = 155,
+	DHCP_OPT_STATE = 156,
+	DHCP_OPT_DATA_SOURCE = 157,
+	DHCP_OPT_V4_PCP_SERVER = 158,
+	DHCP_OPT_V4_PORTPARAMS = 159,
+	DHCP_OPT_CAPTIVE_PORTAL = 160,
+	DHCP_OPT_CONF_FILE = 209,
+	DHCP_OPT_PATH_PREFIX = 210,
+	DHCP_OPT_REBOOT_TIME = 211,
+	DHCP_OPT_6RD = 212,
+	DHCP_OPT_V4_ACCESS_DOMAIN = 213,
+	DHCP_OPT_SUBNET_ALLOCATION = 220,
+	DHCP_OPT_VSS = 221,
+	DHCP_OPT_END = 255
+};
+
+enum dhcp_message_types {
+	DHCPDISCOVER = 1,
+	DHCPOFFER = 2,
+	DHCPREQUEST = 3,
+	DHCPDECLINE = 4,
+	DHCPACK = 5,
+	DHCPNAK = 6,
+	DHCPRELEASE = 7,
+	DHCPINFORM = 8,
+	DHCPFORCERENEW = 9,
+	DHCPLEASEQUERY = 10,
+	DHCPLEASEUNASSIGNED = 11,
+	DHCPLEASEUNKNOWN = 12,
+	DHCPLEASEACTIVE = 13,
+	DHCPBULKLEASEQUERY = 14,
+	DHCPLEASEQUERYDONE = 15,
+	DHCPACTIVELEASEQUERY = 16,
+	DHCPLEASEQUERYSTATUS = 17,
+	DHCPTLS = 18,
+};
+
+enum dhcp_relay_agent_suboptions {
+	DHCP_RELAY_OPT_AGENT_CIRCUIT_ID = 1,
+	DHCP_RELAY_OPT_AGENT_REMOTE_ID = 2,
+	DHCP_RELAY_OPT_DOCSIS_DEVICE_CLASS = 4,
+	DHCP_RELAY_OPT_LINK_SELECTION = 5,
+	DHCP_RELAY_OPT_SUBSCRIBE_ID = 6,
+	DHCP_RELAY_OPT_RADIUS_ATTRIBUTES = 7,
+	DHCP_RELAY_OPT_AUTHENTICATION = 8,
+	DHCP_RELAY_OPT_VEDOR_SPECIFIC = 9,
+	DHCP_RELAY_OPT_RELAY_AGENT_FLAGS = 10,
+	DHCP_RELAY_OPT_SERVER_ID_OVERRIDE = 11,
+	DHCP_RELAY_OPT_RELAY_AGENT_ID = 12,
+	DHCP_RELAY_OPT_ACCESS_TECHNOLOGY_TYPE = 13,
+	DHCP_RELAY_OPT_ACCESS_NETWORK_NAME = 14,
+	DHCP_RELAY_OPT_ACCESS_POINT_NAME = 15,
+	DHCP_RELAY_OPT_ACCESS_POINT_BSSID = 16,
+	DHCP_RELAY_OPT_OPERATOR_ID = 17,
+	DHCP_RELAY_OPT_OPERATOR_REALM = 18,
+	DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION = 151,
+	DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION_CONTROL = 152,
+};
+
+enum access_technology_types {
+	ACCESS_TECHNOLOGY_VIRTUAL = 1,
+	ACCESS_TECHNOLOGY_PPP = 2,
+	ACCESS_TECHNOLOGY_ETHERNET = 3,
+	ACCESS_TECHNOLOGY_WLAN = 4,
+	ACCESS_TECHNOLOGY_WIMAX = 5,
+};
+
+#endif /* DHCP_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index ef4b59d..7a96f96 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -388,8 +388,10 @@
 		/* fall through */
 	case VHT_CHANWIDTH_80MHZ:
 		data->bandwidth = 80;
-		if ((vht_oper_chwidth == 1 && center_segment1) ||
-		    (vht_oper_chwidth == 3 && !center_segment1) ||
+		if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
+		     center_segment1) ||
+		    (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
+		     !center_segment1) ||
 		    !sec_channel_offset)
 			return -1;
 		if (!center_segment0) {
@@ -467,3 +469,88 @@
 	else
 		htcaps->ht_capabilities_info |= msk;
 }
+
+
+#ifdef CONFIG_IEEE80211AC
+
+static int _ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap,
+				  const char *name)
+{
+	u32 req_cap = conf & cap;
+
+	/*
+	 * Make sure we support all requested capabilities.
+	 * NOTE: We assume that 'cap' represents a capability mask,
+	 * not a discrete value.
+	 */
+	if ((hw & req_cap) != req_cap) {
+		wpa_printf(MSG_ERROR,
+			   "Driver does not support configured VHT capability [%s]",
+			   name);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
+				     unsigned int shift,
+				     const char *name)
+{
+	u32 hw_max = hw & mask;
+	u32 conf_val = conf & mask;
+
+	if (conf_val > hw_max) {
+		wpa_printf(MSG_ERROR,
+			   "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+			   name, conf_val >> shift, hw_max >> shift);
+		return 0;
+	}
+	return 1;
+}
+
+
+int ieee80211ac_cap_check(u32 hw, u32 conf)
+{
+#define VHT_CAP_CHECK(cap) \
+	do { \
+		if (!_ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+	do { \
+		if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
+					       #cap)) \
+			return 0; \
+	} while (0)
+
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+	return 1;
+}
+
+#endif /* CONFIG_IEEE80211AC */
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 234b7bf..9cddbd5 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -37,5 +37,6 @@
 			    int center_segment1, u32 vht_caps);
 void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
 		      int disabled);
+int ieee80211ac_cap_check(u32 hw, u32 conf);
 
 #endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 55eaa82..15f6d42 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1960,4 +1960,53 @@
 	NR_CHAN_WIDTH_80P80 = 4,
 };
 
+struct ieee80211_he_capabilities {
+	u8 he_mac_capab_info[5];
+	u8 he_phy_capab_info[9];
+	u16 he_txrx_mcs_support;
+	/* possibly followed by Tx Rx MCS NSS descriptor */
+	u8 variable[];
+	/* PPE Thresholds (optional) */
+} STRUCT_PACKED;
+
+struct ieee80211_he_operation {
+	u32 he_oper_params;
+	u8 he_mcs_nss_set[3];
+	u8 vht_op_info_chwidth;
+	u8 vht_op_info_chan_center_freq_seg0_idx;
+	u8 vht_op_info_chan_center_freq_seg1_idx;
+} STRUCT_PACKED;
+
+/* HE Capabilities Information defines */
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX	3
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB		((u8) BIT(7))
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX	4
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB		((u8) BIT(0))
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX	4
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB		((u8) BIT(1))
+
+/* HE Operation defines */
+#define HE_OPERATION_BSS_COLOR_MASK		((u32) (BIT(0) | BIT(1) | \
+							BIT(2) | BIT(3) | \
+							BIT(4) | BIT(5)))
+#define HE_OPERATION_DFLT_PE_DURATION_MASK	((u32) (BIT(6) | BIT(7) | \
+							BIT(8)))
+#define HE_OPERATION_DFLT_PE_DURATION_OFFSET	6
+#define HE_OPERATION_TWT_REQUIRED		((u32) BIT(9))
+#define HE_OPERATION_RTS_THRESHOLD_MASK	((u32) (BIT(10) | BIT(11) | \
+						BIT(12) | BIT(13) | \
+						BIT(14) | BIT(15) | \
+						BIT(16) | BIT(17) | \
+						BIT(18) | BIT(19)))
+#define HE_OPERATION_RTS_THRESHOLD_OFFSET	10
+#define HE_OPERATION_PARTIAL_BSS_COLOR		((u32) BIT(20))
+#define HE_OPERATION_MAX_BSSID_INDICATOR_MASK	((u32) (BIT(21) | BIT(22) | \
+							BIT(23) | BIT(24) | \
+							BIT(25) | BIT(26) | \
+							BIT(27) | BIT(28)))
+#define HE_OPERATION_MAX_BSSID_INDICATOR_OFFSET 21
+#define HE_OPERATION_TX_BSSID_INDICATOR		((u32) BIT(29))
+#define HE_OPERATION_BSS_COLOR_DISABLED		((u32) BIT(30))
+#define HE_OPERATION_BSS_DUAL_BEACON		((u32) BIT(31))
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 25800d4..934f09d 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,6 @@
 /*
  * Qualcomm Atheros OUI and vendor specific assignments
- * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -233,6 +233,10 @@
  *	in the host driver. The different TDLS configurations are defined
  *	by the attributes in enum qca_wlan_vendor_attr_tdls_configuration.
  *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES: Query device IEEE 802.11ax HE
+ *	capabilities. The response uses the attributes defined in
+ *	enum qca_wlan_vendor_attr_get_he_capabilities.
+ *
  * @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: Abort an ongoing vendor scan that was
  *	started with QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN. This command
  *	carries the scan cookie of the corresponding scan request. The scan
@@ -267,6 +271,23 @@
  * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET: Get the NUD statistics. These
  *	statistics are represented by the enum qca_attr_nud_stats_get
  *	attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS: Sub-command to fetch
+ *	the BSS transition status, whether accept or reject, for a list of
+ *	candidate BSSIDs provided by the userspace. This uses the vendor
+ *	attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and
+ *	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO. The userspace shall specify
+ *	the attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and an
+ *	array of QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID nested in
+ *	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO in the request. In the response
+ *	the driver shall specify array of
+ *	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID and
+ *	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS pairs nested in
+ *	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL: Set the trace level for a
+ *	specific QCA module. The trace levels are represented by
+ *	enum qca_attr_trace_level attributes.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -385,13 +406,15 @@
 	QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
 	QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
 	QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143,
-	/* 144 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES = 144,
 	QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145,
 	QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146,
 	QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS = 147,
 	QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE = 148,
 	QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149,
 	QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150,
+	QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS = 151,
+	QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL = 152,
 };
 
 
@@ -534,6 +557,22 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM = 34,
 	QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO = 35,
+	/* Unsigned 8-bit value representing MBO transition reason code as
+	 * provided by the AP used by subcommand
+	 * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS. This is
+	 * specified by the userspace in the request to the driver.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON = 36,
+	/* Array of nested attributes, BSSID and status code, used by subcommand
+	 * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, where each
+	 * entry is taken from enum qca_wlan_vendor_attr_btm_candidate_info.
+	 * The userspace space specifies the list/array of candidate BSSIDs in
+	 * the order of preference in the request. The driver specifies the
+	 * status code, for each BSSID in the list, in the response. The
+	 * acceptable candidates are listed in the order preferred by the
+	 * driver.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO = 37,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
@@ -3304,4 +3343,83 @@
 		QCA_ATTR_NUD_STATS_GET_LAST - 1,
 };
 
+enum qca_wlan_btm_candidate_status {
+	QCA_STATUS_ACCEPT = 0,
+	QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED = 1,
+	QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED = 2,
+	QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY = 3,
+	QCA_STATUS_REJECT_LOW_RSSI = 4,
+	QCA_STATUS_REJECT_HIGH_INTERFERENCE = 5,
+	QCA_STATUS_REJECT_UNKNOWN = 6,
+};
+
+enum qca_wlan_vendor_attr_btm_candidate_info {
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_INVALID = 0,
+
+	/* 6-byte MAC address representing the BSSID of transition candidate */
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID = 1,
+	/* Unsigned 32-bit value from enum qca_wlan_btm_candidate_status
+	 * returned by the driver. It says whether the BSSID provided in
+	 * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID is acceptable by
+	 * the driver, if not it specifies the reason for rejection.
+	 * Note that the user-space can overwrite the transition reject reason
+	 * codes provided by driver based on more information.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX =
+	QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST - 1,
+};
+
+enum qca_attr_trace_level {
+	QCA_ATTR_TRACE_LEVEL_INVALID = 0,
+	/*
+	 * Nested array of the following attributes:
+	 * QCA_ATTR_TRACE_LEVEL_MODULE,
+	 * QCA_ATTR_TRACE_LEVEL_MASK.
+	 */
+	QCA_ATTR_TRACE_LEVEL_PARAM = 1,
+	/*
+	 * Specific QCA host driver module. Please refer to the QCA host
+	 * driver implementation to get the specific module ID.
+	 */
+	QCA_ATTR_TRACE_LEVEL_MODULE = 2,
+	/* Different trace level masks represented in the QCA host driver. */
+	QCA_ATTR_TRACE_LEVEL_MASK = 3,
+
+	/* keep last */
+	QCA_ATTR_TRACE_LEVEL_AFTER_LAST,
+	QCA_ATTR_TRACE_LEVEL_MAX =
+		QCA_ATTR_TRACE_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_he_capabilities - IEEE 802.11ax HE capabilities
+ */
+enum qca_wlan_vendor_attr_get_he_capabilities {
+	QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0,
+	/* Whether HE capabilities is supported
+	 * (u8 attribute: 0 = not supported, 1 = supported) */
+	QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED = 1,
+	/* HE PHY capabilities, array of 3 u32 values  */
+	QCA_WLAN_VENDOR_ATTR_PHY_CAPAB = 2,
+	/* HE MAC capabilities (u32 attribute) */
+	QCA_WLAN_VENDOR_ATTR_MAC_CAPAB = 3,
+	/* HE MCS map (u32 attribute) */
+	QCA_WLAN_VENDOR_ATTR_HE_MCS = 4,
+	/* Number of SS (u32 attribute) */
+	QCA_WLAN_VENDOR_ATTR_NUM_SS = 5,
+	/* RU count (u32 attribute) */
+	QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK = 6,
+	/* PPE threshold data, array of 8 u32 values */
+	QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD = 7,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX =
+	QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 79f001b..fd167d6 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -194,12 +194,12 @@
 	ptk->tk_len = wpa_cipher_key_len(cipher);
 	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
 
-#ifdef CONFIG_SUITEB192
+#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
 	if (wpa_key_mgmt_sha384(akmp))
 		sha384_prf(pmk, pmk_len, label, data, sizeof(data),
 			   tmp, ptk_len);
 	else
-#endif /* CONFIG_SUITEB192 */
+#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
 #ifdef CONFIG_IEEE80211W
 	if (wpa_key_mgmt_sha256(akmp))
 		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
@@ -1104,10 +1104,10 @@
  *
  * IEEE Std 802.11r-2008 - 8.5.1.5.3
  */
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
-		       const u8 *ssid, size_t ssid_len,
-		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
-		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		      const u8 *ssid, size_t ssid_len,
+		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
 {
 	u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
 	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
@@ -1124,7 +1124,7 @@
 	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
 	 */
 	if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
-		return;
+		return -1;
 	pos = buf;
 	*pos++ = ssid_len;
 	os_memcpy(pos, ssid, ssid_len);
@@ -1137,8 +1137,9 @@
 	os_memcpy(pos, s0kh_id, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
-		   r0_key_data, sizeof(r0_key_data));
+	if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+		       r0_key_data, sizeof(r0_key_data)) < 0)
+		return -1;
 	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
 
 	/*
@@ -1149,8 +1150,10 @@
 	addr[1] = r0_key_data + PMK_LEN;
 	len[1] = 16;
 
-	sha256_vector(2, addr, len, hash);
+	if (sha256_vector(2, addr, len, hash) < 0)
+		return -1;
 	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+	return 0;
 }
 
 
@@ -1159,8 +1162,8 @@
  *
  * IEEE Std 802.11r-2008 - 8.5.1.5.4
  */
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
-			    const u8 *s1kh_id, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			   const u8 *s1kh_id, u8 *pmk_r1_name)
 {
 	u8 hash[32];
 	const u8 *addr[4];
@@ -1179,8 +1182,10 @@
 	addr[3] = s1kh_id;
 	len[3] = ETH_ALEN;
 
-	sha256_vector(4, addr, len, hash);
+	if (sha256_vector(4, addr, len, hash) < 0)
+		return -1;
 	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+	return 0;
 }
 
 
@@ -1189,9 +1194,9 @@
  *
  * IEEE Std 802.11r-2008 - 8.5.1.5.4
  */
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
-		       const u8 *r1kh_id, const u8 *s1kh_id,
-		       u8 *pmk_r1, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		      const u8 *r1kh_id, const u8 *s1kh_id,
+		      u8 *pmk_r1, u8 *pmk_r1_name)
 {
 	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
 	u8 *pos;
@@ -1203,9 +1208,12 @@
 	os_memcpy(pos, s1kh_id, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+	if (sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf,
+		       pmk_r1, PMK_LEN) < 0)
+		return -1;
 
-	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+	return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
+				      pmk_r1_name);
 }
 
 
@@ -1245,7 +1253,9 @@
 	ptk->tk_len = wpa_cipher_key_len(cipher);
 	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
 
-	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
+	if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf,
+		       tmp, ptk_len) < 0)
+		return -1;
 
 	/*
 	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -1264,7 +1274,8 @@
 	addr[5] = sta_addr;
 	len[5] = ETH_ALEN;
 
-	sha256_vector(6, addr, len, hash);
+	if (sha256_vector(6, addr, len, hash) < 0)
+		return -1;
 	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
 
 	os_memcpy(ptk->kck, tmp, ptk->kck_len);
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 4e465f5..a84cc9b 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -358,15 +358,15 @@
 	       const u8 *ftie, size_t ftie_len,
 	       const u8 *rsnie, size_t rsnie_len,
 	       const u8 *ric, size_t ric_len, u8 *mic);
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
-		       const u8 *ssid, size_t ssid_len,
-		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
-		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
-			    const u8 *s1kh_id, u8 *pmk_r1_name);
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
-		       const u8 *r1kh_id, const u8 *s1kh_id,
-		       u8 *pmk_r1, u8 *pmk_r1_name);
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		      const u8 *ssid, size_t ssid_len,
+		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			   const u8 *s1kh_id, u8 *pmk_r1_name);
+int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		      const u8 *r1kh_id, const u8 *s1kh_id,
+		      u8 *pmk_r1, u8 *pmk_r1_name);
 int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
 		      const u8 *sta_addr, const u8 *bssid,
 		      const u8 *pmk_r1_name,
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 766a3fa..4649eab 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -300,6 +300,10 @@
 /* PMKSA cache entry removed; parameters: <BSSID> <network_id> */
 #define PMKSA_CACHE_REMOVED "PMKSA-CACHE-REMOVED "
 
+/* FILS HLP Container receive; parameters: dst=<addr> src=<addr> frame=<hexdump>
+ */
+#define FILS_HLP_RX "FILS-HLP-RX "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index fb91ab4..0fa06d9 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -17,6 +17,7 @@
 #include "crypto/crypto.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/sha384.h"
 
 
 static int test_siv(void)
@@ -1295,13 +1296,14 @@
 };
 
 static const struct hmac_test {
-	u8 key[80];
+	u8 key[150];
 	size_t key_len;
-	u8 data[128];
+	u8 data[160];
 	size_t data_len;
-	u8 hash[32];
+	u8 hash[32]; /* HMAC-SHA-256 */
+	u8 hash384[48]; /* HMAC-SHA-384 */
 } hmac_tests[] = {
-	/* draft-ietf-ipsec-ciph-sha-256-01.txt */
+	/* draft-ietf-ipsec-ciph-sha-256-01.txt; RFC 4231 */
 	{
 		{
 			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -1316,7 +1318,8 @@
 			0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
 			0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
 			0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
-		}
+		},
+		{ }
 	},
 	{
 		{
@@ -1333,7 +1336,8 @@
 			0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
 			0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
 			0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
-		}
+		},
+		{ }
 	},
 	{
 		{
@@ -1351,7 +1355,8 @@
 			0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
 			0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
 			0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
-		}
+		},
+		{ }
 	},
 	{
 		{
@@ -1368,9 +1373,34 @@
 			0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
 			0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
 			0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+		},
+		{ }
+	},
+	{ /* RFC 4231 - Test Case 1 */
+		{
+			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			0x0b, 0x0b, 0x0b, 0x0b
+		},
+		20,
+		"Hi There",
+		8,
+		{
+			0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+			0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+			0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+			0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+		},
+		{
+			0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+			0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+			0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+			0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+			0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+			0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
 		}
 	},
-	{
+	{ /* RFC 4231 - Test Case 2 */
 		"Jefe",
 		4,
 		"what do ya want for nothing?",
@@ -1380,6 +1410,14 @@
 			0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
 			0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
 			0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+		},
+		{
+			0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+			0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+			0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+			0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+			0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+			0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
 		}
 	},
 	{
@@ -1405,6 +1443,39 @@
 			0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
 			0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
 			0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+		},
+		{ }
+	},
+	{ /* RFC 4231 - Test Case 3 */
+		{
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa
+		},
+		20,
+		{
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd
+		},
+		50,
+		{
+			0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+			0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+			0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+			0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+		},
+		{
+			0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+			0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+			0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+			0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+			0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+			0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
 		}
 	},
 	{
@@ -1431,6 +1502,40 @@
 			0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
 			0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
 			0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+		},
+		{ }
+	},
+	{ /* RFC 4231 - Test Case 4 */
+		{
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+			0x19,
+		},
+		25,
+		{
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd
+		},
+		50,
+		{
+			0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+			0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+			0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+			0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+		},
+		{
+			0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+			0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+			0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+			0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+			0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+			0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
 		}
 	},
 	{
@@ -1448,7 +1553,8 @@
 			0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
 			0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
 			0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
-		}
+		},
+		{ }
 	},
 	{
 		{
@@ -1471,6 +1577,45 @@
 			0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
 			0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
 			0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+		},
+		{ }
+	},
+	{ /* RFC 4231 - Test Case 6 */
+		{
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa
+		},
+		131,
+		"Test Using Larger Than Block-Size Key - Hash Key First",
+		54,
+		{
+			0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+			0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+			0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+			0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+		},
+		{
+			0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+			0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+			0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+			0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+			0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+			0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
 		}
 	},
 	{
@@ -1495,6 +1640,45 @@
 			0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
 			0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
 			0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+		},
+		{ }
+	},
+	{ /* RFC 4231 - Test Case 7 */
+		{
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa
+		},
+		131,
+		"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+		152,
+		{
+			0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+			0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+			0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+			0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+		},
+		{
+			0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+			0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+			0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+			0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+			0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+			0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
 		}
 	}
 };
@@ -1609,6 +1793,96 @@
 }
 
 
+static int test_sha384(void)
+{
+#ifdef CONFIG_SHA384
+	unsigned int i;
+	u8 hash[48];
+	const u8 *addr[2];
+	size_t len[2];
+	int errors = 0;
+	const char *data = "hello";
+	const u8 hash_res[] = {
+		0x59, 0xe1, 0x74, 0x87, 0x77, 0x44, 0x8c, 0x69,
+		0xde, 0x6b, 0x80, 0x0d, 0x7a, 0x33, 0xbb, 0xfb,
+		0x9f, 0xf1, 0xb4, 0x63, 0xe4, 0x43, 0x54, 0xc3,
+		0x55, 0x3b, 0xcd, 0xb9, 0xc6, 0x66, 0xfa, 0x90,
+		0x12, 0x5a, 0x3c, 0x79, 0xf9, 0x03, 0x97, 0xbd,
+		0xf5, 0xf6, 0xa1, 0x3d, 0xe8, 0x28, 0x68, 0x4f
+	};
+
+	addr[0] = (const u8 *) data;
+	len[0] = 5;
+	if (sha384_vector(1, addr, len, hash) < 0 ||
+	    os_memcmp(hash, hash_res, 48) != 0) {
+		wpa_printf(MSG_INFO, "SHA384 test case 1: FAIL");
+		errors++;
+	} else {
+		wpa_printf(MSG_INFO, "SHA384 test case 1: OK");
+	}
+
+	addr[0] = (const u8 *) data;
+	len[0] = 4;
+	addr[1] = (const u8 *) data + 4;
+	len[1] = 1;
+	if (sha384_vector(2, addr, len, hash) < 0 ||
+	    os_memcmp(hash, hash_res, 48) != 0) {
+		wpa_printf(MSG_INFO, "SHA384 test case 2: FAIL");
+		errors++;
+	} else {
+		wpa_printf(MSG_INFO, "SHA384 test case 2: OK");
+	}
+
+	for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+		const struct hmac_test *t = &hmac_tests[i];
+
+		if (t->hash384[0] == 0 && t->hash384[1] == 0 &&
+		    t->hash384[2] == 0 && t->hash384[3] == 0)
+			continue;
+		wpa_printf(MSG_INFO, "HMAC-SHA384 test case %d:", i + 1);
+
+		if (hmac_sha384(t->key, t->key_len, t->data, t->data_len,
+				hash) < 0 ||
+		    os_memcmp(hash, t->hash384, 48) != 0) {
+			wpa_printf(MSG_INFO, " FAIL");
+			errors++;
+		} else
+			wpa_printf(MSG_INFO, " OK");
+
+		addr[0] = t->data;
+		len[0] = t->data_len;
+		if (hmac_sha384_vector(t->key, t->key_len, 1, addr, len,
+				       hash) < 0 ||
+		    os_memcmp(hash, t->hash384, 48) != 0) {
+			wpa_printf(MSG_INFO, " FAIL");
+			errors++;
+		} else
+			wpa_printf(MSG_INFO, " OK");
+
+		if (len[0]) {
+			addr[0] = t->data;
+			len[0] = 1;
+			addr[1] = t->data + 1;
+			len[1] = t->data_len - 1;
+			if (hmac_sha384_vector(t->key, t->key_len, 2, addr, len,
+					       hash) < 0 ||
+			    os_memcmp(hash, t->hash384, 48) != 0) {
+				wpa_printf(MSG_INFO, " FAIL");
+				errors++;
+			} else
+				wpa_printf(MSG_INFO, " OK");
+		}
+	}
+
+	if (!errors)
+		wpa_printf(MSG_INFO, "SHA384 test cases passed");
+	return errors;
+#else /* CONFIG_SHA384 */
+	return 0;
+#endif /* CONFIG_SHA384 */
+}
+
+
 static int test_fips186_2_prf(void)
 {
 	/* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
@@ -1754,6 +2028,7 @@
 	    test_md5() ||
 	    test_sha1() ||
 	    test_sha256() ||
+	    test_sha384() ||
 	    test_fips186_2_prf() ||
 	    test_ms_funcs())
 		ret = -1;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 02cb391..5f7896c 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -383,6 +383,8 @@
 	AES_KEY actx;
 	int res;
 
+	if (TEST_FAIL())
+		return -1;
 	if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
 		return -1;
 	res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
@@ -397,6 +399,8 @@
 	AES_KEY actx;
 	int res;
 
+	if (TEST_FAIL())
+		return -1;
 	if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
 		return -1;
 	res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
@@ -1027,7 +1031,7 @@
 		       const u8 *addr[], const size_t *len, u8 *mac)
 {
 	return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
-				   len, mac, 32);
+				   len, mac, 48);
 }
 
 
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
new file mode 100644
index 0000000..ee136ce
--- /dev/null
+++ b/src/crypto/sha384.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha384_vector - HMAC-SHA384 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+	unsigned char tk[48];
+	const u8 *_addr[6];
+	size_t _len[6], i;
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+	/* if key is longer than 128 bytes reset it to key = SHA384(key) */
+	if (key_len > 128) {
+		if (sha384_vector(1, &key, &key_len, tk) < 0)
+			return -1;
+		key = tk;
+		key_len = 48;
+	}
+
+	/* the HMAC_SHA384 transform looks like:
+	 *
+	 * SHA384(K XOR opad, SHA384(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 128 times
+	 * opad is the byte 0x5c repeated 128 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with ipad values */
+	for (i = 0; i < 128; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner SHA384 */
+	_addr[0] = k_pad;
+	_len[0] = 128;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (sha384_vector(1 + num_elem, _addr, _len, mac) < 0)
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 128; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer SHA384 */
+	_addr[0] = k_pad;
+	_len[0] = 128;
+	_addr[1] = mac;
+	_len[1] = SHA384_MAC_LEN;
+	return sha384_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha384 - HMAC-SHA384 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 92688a3..7b3a6bd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -136,6 +136,29 @@
 	unsigned int dfs_cac_ms;
 };
 
+#define HE_MAX_NUM_SS 		8
+#define HE_MAX_PHY_CAPAB_SIZE	3
+
+/**
+ * struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
+ */
+struct he_ppe_threshold {
+	u32 numss_m1;
+	u32 ru_count;
+	u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
+};
+
+/**
+ * struct he_capabilities - IEEE 802.11ax HE capabilities
+ */
+struct he_capabilities {
+	u8 he_supported;
+	u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
+	u32 mac_cap;
+	u32 mcs;
+	struct he_ppe_threshold ppet;
+};
+
 #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
 #define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
 
@@ -194,6 +217,11 @@
 	u8 vht_mcs_set[8];
 
 	unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+
+	/**
+	 * he_capab - HE (IEEE 802.11ax) capabilities
+	 */
+	struct he_capabilities he_capab;
 };
 
 
@@ -495,6 +523,36 @@
 	  */
 	 unsigned int duration_mandatory:1;
 
+	/**
+	 * relative_rssi_set - Whether relative RSSI parameters are set
+	 */
+	unsigned int relative_rssi_set:1;
+
+	/**
+	 * relative_rssi - Relative RSSI for reporting better BSSs
+	 *
+	 * Amount of RSSI by which a BSS should be better than the current
+	 * connected BSS to report the new BSS to user space.
+	 */
+	s8 relative_rssi;
+
+	/**
+	 * relative_adjust_band - Band to which RSSI should be adjusted
+	 *
+	 * The relative_adjust_rssi should be added to the band specified
+	 * by relative_adjust_band.
+	 */
+	enum set_band relative_adjust_band;
+
+	/**
+	 * relative_adjust_rssi - RSSI to be added to relative_adjust_band
+	 *
+	 * An amount of relative_band_rssi should be added to the BSSs that
+	 * belong to the band specified by relative_adjust_band while comparing
+	 * with other bands for BSS reporting.
+	 */
+	s8 relative_adjust_rssi;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -1393,6 +1451,14 @@
 #define WPA_DRIVER_FLAGS_BEACON_RATE_HT		0x0000100000000000ULL
 /** Driver supports Beacon frame TX rate configuration (VHT rates) */
 #define WPA_DRIVER_FLAGS_BEACON_RATE_VHT	0x0000200000000000ULL
+/** Driver supports mgmt_tx with random TX address in non-connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA	0x0000400000000000ULL
+/** Driver supports mgmt_tx with random TX addr in connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED	0x0000800000000000ULL
+/** Driver supports better BSS reporting with sched_scan in connected mode */
+#define WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI	0x0001000000000000ULL
+/** Driver supports HE capabilities */
+#define WPA_DRIVER_FLAGS_HE_CAPABILITIES	0x0002000000000000ULL
 	u64 flags;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2785,6 +2851,9 @@
 	 * transmitted on that channel; alternatively the frame may be sent on
 	 * the current operational channel (if in associated state in station
 	 * mode or while operating as an AP.)
+	 *
+	 * If @src differs from the device MAC address, use of a random
+	 * transmitter address is requested for this message exchange.
 	 */
 	int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
 			   const u8 *dst, const u8 *src, const u8 *bssid,
@@ -4638,6 +4707,11 @@
 		 * than explicit rejection response from the AP.
 		 */
 		int timed_out;
+
+		/**
+		 * timeout_reason - Reason for the timeout
+		 */
+		const char *timeout_reason;
 	} assoc_reject;
 
 	struct timeout_event {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 27e22c6..e9107b3 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6881,6 +6881,14 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
+	if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
+			   MAC2STR(src));
+		os_memcpy(bss->rand_addr, src, ETH_ALEN);
+	} else {
+		os_memset(bss->rand_addr, 0, ETH_ALEN);
+	}
+
 	if (is_ap_interface(drv->nlmode) &&
 	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
 	     (int) freq == bss->freq || drv->device_ap_sme ||
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 94b8bdf..bdc79c5 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -78,6 +78,7 @@
 
 	struct nl80211_wiphy_data *wiphy_data;
 	struct dl_list wiphy_list;
+	u8 rand_addr[ETH_ALEN];
 };
 
 struct wpa_driver_nl80211_data {
@@ -160,6 +161,7 @@
 	unsigned int scan_vendor_cmd_avail:1;
 	unsigned int connect_reassoc:1;
 	unsigned int set_wifi_conf_vendor_cmd_avail:1;
+	unsigned int he_capab_vendor_cmd_avail:1;
 
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
@@ -208,6 +210,8 @@
 	 * (NL80211_CMD_VENDOR). 0 if no pending scan request.
 	 */
 	int last_scan_cmd;
+
+	struct he_capabilities he_capab;
 };
 
 struct nl_msg;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 3d85316..7064ce1 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -389,6 +389,15 @@
 	    ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_SET_SCAN_DWELL))
 		capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT;
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
+		capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA;
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
+		capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED;
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI))
+		capa->flags |= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI;
 }
 
 
@@ -735,6 +744,9 @@
 				case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
 					drv->set_wifi_conf_vendor_cmd_avail = 1;
 					break;
+				case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES:
+					drv->he_capab_vendor_cmd_avail = 1;
+					break;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 				}
 			}
@@ -904,6 +916,100 @@
 }
 
 
+static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct he_capabilities *he_capab = arg;
+	struct nlattr *nl_vend;
+	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1];
+	size_t len;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb[NL80211_ATTR_VENDOR_DATA])
+		return NL_SKIP;
+
+	nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+	nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX,
+		  nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) {
+		u8 he_supported;
+
+		he_supported = nla_get_u8(
+			tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]);
+		wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u",
+			   he_supported);
+		he_capab->he_supported = he_supported;
+		if (!he_supported)
+			return NL_SKIP;
+	}
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) {
+		len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]);
+
+		if (len > sizeof(he_capab->phy_cap))
+			len = sizeof(he_capab->phy_cap);
+		os_memcpy(he_capab->phy_cap,
+			  nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]),
+			  len);
+	}
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB])
+		he_capab->mac_cap =
+			nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]);
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS])
+		he_capab->mcs =
+			nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]);
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS])
+		he_capab->ppet.numss_m1 =
+			nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]);
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK])
+		he_capab->ppet.ru_count =
+			nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]);
+
+	if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) {
+		len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]);
+
+		if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0))
+			len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0);
+		os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0,
+			  nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]),
+			  len);
+	}
+
+	return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	int ret;
+
+	if (!drv->he_capab_vendor_cmd_avail)
+		return;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+		nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+		nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			    QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES)) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler,
+				 &drv->he_capab);
+	if (!ret && drv->he_capab.he_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES;
+}
+
+
 struct features_info {
 	u8 *flags;
 	size_t flags_len;
@@ -1075,6 +1181,7 @@
 #ifdef CONFIG_DRIVER_NL80211_QCA
 	qca_nl80211_check_dfs_capa(drv);
 	qca_nl80211_get_features(drv);
+	qca_nl80211_check_he_capab(drv);
 
 	/*
 	 * To enable offchannel simultaneous support in wpa_supplicant, the
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index c18fc22..ed2cbe4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -279,6 +279,7 @@
 			       struct nlattr *addr, struct nlattr *req_ie,
 			       struct nlattr *resp_ie,
 			       struct nlattr *timed_out,
+			       struct nlattr *timeout_reason,
 			       struct nlattr *authorized,
 			       struct nlattr *key_replay_ctr,
 			       struct nlattr *ptk_kck,
@@ -338,6 +339,24 @@
 		}
 		event.assoc_reject.status_code = status_code;
 		event.assoc_reject.timed_out = timed_out != NULL;
+		if (timed_out && timeout_reason) {
+			enum nl80211_timeout_reason reason;
+
+			reason = nla_get_u32(timeout_reason);
+			switch (reason) {
+			case NL80211_TIMEOUT_SCAN:
+				event.assoc_reject.timeout_reason = "scan";
+				break;
+			case NL80211_TIMEOUT_AUTH:
+				event.assoc_reject.timeout_reason = "auth";
+				break;
+			case NL80211_TIMEOUT_ASSOC:
+				event.assoc_reject.timeout_reason = "assoc";
+				break;
+			default:
+				break;
+			}
+		}
 		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
 		return;
 	}
@@ -860,6 +879,8 @@
 		   MAC2STR(data + 4 + ETH_ALEN));
 	if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
 	    os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+	    (is_zero_ether_addr(bss->rand_addr) ||
+	     os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
 	    os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
 		wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
 			   "for foreign address", bss->ifname);
@@ -1724,7 +1745,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,
+			   NULL, 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],
@@ -2244,6 +2265,7 @@
 				   tb[NL80211_ATTR_REQ_IE],
 				   tb[NL80211_ATTR_RESP_IE],
 				   tb[NL80211_ATTR_TIMED_OUT],
+				   tb[NL80211_ATTR_TIMEOUT_REASON],
 				   NULL, NULL, NULL, NULL, NULL);
 		break;
 	case NL80211_CMD_CH_SWITCH_NOTIFY:
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index b577531..4417721 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -562,6 +562,39 @@
 		nla_nest_end(msg, match_sets);
 	}
 
+	if (params->relative_rssi_set) {
+		struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+		os_memset(&rssi_adjust, 0, sizeof(rssi_adjust));
+		wpa_printf(MSG_DEBUG, "nl80211: Relative RSSI: %d",
+			   params->relative_rssi);
+		if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+				params->relative_rssi))
+			goto fail;
+
+		if (params->relative_adjust_rssi) {
+			int pref_band_set = 1;
+
+			switch (params->relative_adjust_band) {
+			case WPA_SETBAND_5G:
+				rssi_adjust.band = NL80211_BAND_5GHZ;
+				break;
+			case WPA_SETBAND_2G:
+				rssi_adjust.band = NL80211_BAND_2GHZ;
+				break;
+			default:
+				pref_band_set = 0;
+				break;
+			}
+			rssi_adjust.delta = params->relative_adjust_rssi;
+
+			if (pref_band_set &&
+			    nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+				    sizeof(rssi_adjust), &rssi_adjust))
+				goto fail;
+		}
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 
 	/* TODO: if we get an error here, we should fall back to normal scan */
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 174f4b3..d6c62ee 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1772,7 +1772,9 @@
  *
  * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
  *	Notification Element based on association request when used with
- *	%NL80211_CMD_NEW_STATION; u8 attribute.
+ *	%NL80211_CMD_NEW_STATION or %NL80211_CMD_SET_STATION (only when
+ *	%NL80211_FEATURE_FULL_AP_CLIENT_STATE is supported, or with TDLS);
+ *	u8 attribute.
  *
  * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
  *	%NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
@@ -1982,6 +1984,24 @@
  * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
  *	used in various commands/events for specifying the BSSID.
  *
+ * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which
+ *	other BSSs has to be better or slightly worse than the current
+ *	connected BSS so that they get reported to user space.
+ *	This will give an opportunity to userspace to consider connecting to
+ *	other matching BSSs which have better or slightly worse RSSI than
+ *	the current connected BSS by using an offloaded operation to avoid
+ *	unnecessary wakeups.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
+ *	the specified band is to be adjusted before doing
+ *	%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
+ *	better BSSs. The attribute value is a packed structure
+ *	value as specified by &struct nl80211_bss_select_rssi_adjust.
+ *
+ * @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out.
+ *	u32 attribute with an &enum nl80211_timeout_reason value. This is used,
+ *	e.g., with %NL80211_CMD_CONNECT event.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2388,6 +2408,11 @@
 
 	NL80211_ATTR_BSSID,
 
+	NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+	NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+
+	NL80211_ATTR_TIMEOUT_REASON,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -3080,6 +3105,13 @@
  *	how this API was implemented in the past. Also, due to the same problem,
  *	the only way to create a matchset with only an RSSI filter (with this
  *	attribute) is if there's only a single matchset with the RSSI attribute.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether
+ *	%NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or
+ *	relative to current bss's RSSI.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for
+ *	BSS-es in the specified band is to be adjusted before doing
+ *	RSSI-based BSS selection. The attribute value is a packed structure
+ *	value as specified by &struct nl80211_bss_select_rssi_adjust.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *	attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3089,6 +3121,8 @@
 
 	NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
 	NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+	NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
+	NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
 
 	/* keep last */
 	__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -4699,6 +4733,13 @@
  *	configuration (AP/mesh) with VHT rates.
  * @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
  *	with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA
+ *	in @NL80211_CMD_FRAME while not associated.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports
+ *	randomized TA in @NL80211_CMD_FRAME while associated.
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
+ *	for reporting BSSs with better RSSI than the current connected BSS
+ *	(%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4714,6 +4755,9 @@
 	NL80211_EXT_FEATURE_BEACON_RATE_HT,
 	NL80211_EXT_FEATURE_BEACON_RATE_VHT,
 	NL80211_EXT_FEATURE_FILS_STA,
+	NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
+	NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
+	NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
@@ -4753,6 +4797,21 @@
 };
 
 /**
+ * enum nl80211_timeout_reason - timeout reasons
+ *
+ * @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified.
+ * @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out.
+ * @NL80211_TIMEOUT_AUTH: Authentication timed out.
+ * @NL80211_TIMEOUT_ASSOC: Association timed out.
+ */
+enum nl80211_timeout_reason {
+	NL80211_TIMEOUT_UNSPECIFIED,
+	NL80211_TIMEOUT_SCAN,
+	NL80211_TIMEOUT_AUTH,
+	NL80211_TIMEOUT_ASSOC,
+};
+
+/**
  * enum nl80211_scan_flags -  scan request control flags
  *
  * Scan request control flags are used to control the handling
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 1c6116a..bc90c7a 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -489,7 +489,7 @@
 	u8 *emsk = NULL;
 	size_t emsk_len = 0;
 	u8 EMSKname[EAP_EMSK_NAME_LEN];
-	u8 len[2];
+	u8 len[2], ctx[3];
 	char *realm;
 	size_t realm_len, nai_buf_len;
 	struct eap_erp_key *erp = NULL;
@@ -526,7 +526,7 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
 
-	WPA_PUT_BE16(len, 8);
+	WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
 	if (hmac_sha256_kdf(sm->eapSessionId, sm->eapSessionIdLen, "EMSK",
 			    len, sizeof(len),
 			    EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -550,9 +550,11 @@
 	erp->rRK_len = emsk_len;
 	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
 
+	ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+	WPA_PUT_BE16(&ctx[1], erp->rRK_len);
 	if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
-			    "EAP Re-authentication Integrity Key@ietf.org",
-			    len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+			    "Re-authentication Integrity Key@ietf.org",
+			    ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
 		wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
 		goto fail;
 	}
@@ -2244,6 +2246,7 @@
 		config->pending_req_passphrase++;
 		break;
 	case WPA_CTRL_REQ_SIM:
+		config->pending_req_sim++;
 		txt = msg;
 		break;
 	case WPA_CTRL_REQ_EXT_CERT_CHECK:
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 0bac62d..4188817 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -48,6 +48,7 @@
 	struct wpabuf *id_msgs;
 	int prev_id;
 	int result_ind, use_result_ind;
+	int use_pseudonym;
 	u8 eap_method;
 	u8 *network_name;
 	size_t network_name_len;
@@ -101,7 +102,8 @@
 
 	data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
 
-	if (config && config->anonymous_identity) {
+	data->use_pseudonym = !sm->init_phase2;
+	if (config && config->anonymous_identity && data->use_pseudonym) {
 		data->pseudonym = os_malloc(config->anonymous_identity_len);
 		if (data->pseudonym) {
 			os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -350,7 +352,8 @@
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
-		eap_set_anon_id(sm, NULL, 0);
+		if (data->use_pseudonym)
+			eap_set_anon_id(sm, NULL, 0);
 	}
 	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
@@ -405,7 +408,9 @@
 				  realm, realm_len);
 		}
 		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
-		eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+		if (data->use_pseudonym)
+			eap_set_anon_id(sm, data->pseudonym,
+					data->pseudonym_len);
 	}
 
 	if (attr->next_reauth_id) {
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index f980072..16521c3 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -628,6 +628,15 @@
 	int pending_req_passphrase;
 
 	/**
+	 * pending_req_sim - Pending SIM request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	int pending_req_sim;
+
+	/**
 	 * pending_req_otp - Whether there is a pending OTP request
 	 *
 	 * This field should not be set in configuration step. It is only used
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 964ebe7..e4b0c10 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -484,7 +484,8 @@
 
 	if (*resp == NULL && config &&
 	    (config->pending_req_identity || config->pending_req_password ||
-	     config->pending_req_otp || config->pending_req_new_password)) {
+	     config->pending_req_otp || config->pending_req_new_password ||
+	     config->pending_req_sim)) {
 		wpabuf_free(data->pending_phase2_req);
 		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
 	} else if (*resp == NULL)
@@ -1677,6 +1678,10 @@
 static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
 	struct eap_fast_data *data = priv;
+
+	if (data->phase2_priv && data->phase2_method &&
+	    data->phase2_method->deinit_for_reauth)
+		data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
 	os_free(data->key_block_p);
 	data->key_block_p = NULL;
 	wpabuf_free(data->pending_phase2_req);
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index efeddb8..2ff6076 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -726,7 +726,8 @@
 
 	if (*resp == NULL &&
 	    (config->pending_req_identity || config->pending_req_password ||
-	     config->pending_req_otp || config->pending_req_new_password)) {
+	     config->pending_req_otp || config->pending_req_new_password ||
+	     config->pending_req_sim)) {
 		wpabuf_free(data->pending_phase2_req);
 		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
 	}
@@ -1163,6 +1164,10 @@
 static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
 	struct eap_peap_data *data = priv;
+
+	if (data->phase2_priv && data->phase2_method &&
+	    data->phase2_method->deinit_for_reauth)
+		data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
 	wpabuf_free(data->pending_phase2_req);
 	data->pending_phase2_req = NULL;
 	wpabuf_free(data->pending_resp);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index b97c95d..95ecdf7 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -46,6 +46,7 @@
 		CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
 	} state;
 	int result_ind, use_result_ind;
+	int use_pseudonym;
 };
 
 
@@ -115,7 +116,8 @@
 			NULL;
 	}
 
-	if (config && config->anonymous_identity) {
+	data->use_pseudonym = !sm->init_phase2;
+	if (config && config->anonymous_identity && data->use_pseudonym) {
 		data->pseudonym = os_malloc(config->anonymous_identity_len);
 		if (data->pseudonym) {
 			os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -372,7 +374,8 @@
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
-		eap_set_anon_id(sm, NULL, 0);
+		if (data->use_pseudonym)
+			eap_set_anon_id(sm, NULL, 0);
 	}
 	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
@@ -427,7 +430,9 @@
 				  realm, realm_len);
 		}
 		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
-		eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+		if (data->use_pseudonym)
+			eap_set_anon_id(sm, data->pseudonym,
+					data->pseudonym_len);
 	}
 
 	if (attr->next_reauth_id) {
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e4bc22f..3354b2d 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -458,7 +458,7 @@
 
 	if (*resp == NULL &&
 	    (config->pending_req_identity || config->pending_req_password ||
-	     config->pending_req_otp)) {
+	     config->pending_req_otp || config->pending_req_sim)) {
 		return 0;
 	}
 
@@ -1280,7 +1280,8 @@
 	} else if (config->pending_req_identity ||
 		   config->pending_req_password ||
 		   config->pending_req_otp ||
-		   config->pending_req_new_password) {
+		   config->pending_req_new_password ||
+		   config->pending_req_sim) {
 		wpabuf_free(data->pending_phase2_req);
 		data->pending_phase2_req = wpabuf_dup(in_decrypted);
 	}
@@ -1317,7 +1318,8 @@
 		    (config->pending_req_identity ||
 		     config->pending_req_password ||
 		     config->pending_req_otp ||
-		     config->pending_req_new_password)) {
+		     config->pending_req_new_password ||
+		     config->pending_req_sim)) {
 			/*
 			 * Use empty buffer to force implicit request
 			 * processing when EAP request is re-processed after
@@ -1648,6 +1650,10 @@
 static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
 	struct eap_ttls_data *data = priv;
+
+	if (data->phase2_priv && data->phase2_method &&
+	    data->phase2_method->deinit_for_reauth)
+		data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
 	wpabuf_free(data->pending_phase2_req);
 	data->pending_phase2_req = NULL;
 	wpabuf_free(data->pending_resp);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 08cc171..1b571cf 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -415,7 +415,7 @@
 	u8 *emsk = NULL;
 	size_t emsk_len = 0;
 	u8 EMSKname[EAP_EMSK_NAME_LEN];
-	u8 len[2];
+	u8 len[2], ctx[3];
 	const char *domain;
 	size_t domain_len, nai_buf_len;
 	struct eap_server_erp_key *erp = NULL;
@@ -452,7 +452,7 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
 
-	WPA_PUT_BE16(len, 8);
+	WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
 	if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
 			    "EMSK", len, sizeof(len),
 			    EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -476,9 +476,11 @@
 	erp->rRK_len = emsk_len;
 	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
 
+	ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+	WPA_PUT_BE16(&ctx[1], erp->rRK_len);
 	if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
-			    "EAP Re-authentication Integrity Key@ietf.org",
-			    len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+			    "Re-authentication Integrity Key@ietf.org",
+			    ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
 		wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
 		goto fail;
 	}
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 0dc7ea6..e727005 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -250,6 +250,8 @@
 
 	if (sm->eapTriggerStart)
 		send_start = 1;
+	if (sm->ctx->preauth)
+		send_start = 1;
 	sm->eapTriggerStart = FALSE;
 
 	if (send_start) {
@@ -2155,16 +2157,14 @@
 }
 
 
+#ifdef CONFIG_EAP_PROXY
 int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
 {
-#ifdef CONFIG_EAP_PROXY
 	if (sm->eap_proxy == NULL)
 		return -1;
 	return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
-#else /* CONFIG_EAP_PROXY */
-	return -1;
-#endif /* CONFIG_EAP_PROXY */
 }
+#endif /* CONFIG_EAP_PROXY */
 
 
 void eapol_sm_erp_flush(struct eapol_sm *sm)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 65dd1a3..14d6279 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3034,6 +3034,8 @@
 	p2p->ssid_set = 0;
 	p2ps_prov_free(p2p);
 	p2p_reset_pending_pd(p2p);
+	p2p->override_pref_op_class = 0;
+	p2p->override_pref_channel = 0;
 }
 
 
@@ -5522,6 +5524,14 @@
 }
 
 
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+				   u8 chan)
+{
+	p2p->override_pref_op_class = op_class;
+	p2p->override_pref_channel = chan;
+}
+
+
 struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
 					      unsigned int freq)
 {
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7b18dcf..70d3a90 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -2373,6 +2373,8 @@
 void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
 				const unsigned int *pref_freq_list,
 				unsigned int size);
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+				   u8 chan);
 
 /**
  * p2p_group_get_common_freqs - Get the group common frequencies
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 9f0b3f3..65ab4b8 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -315,7 +315,12 @@
 			       group_capab);
 	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
 	p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
-	if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
+	if (p2p->override_pref_op_class) {
+		p2p_dbg(p2p, "Override operating channel preference");
+		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+					      p2p->override_pref_op_class,
+					      p2p->override_pref_channel);
+	} else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
 		p2p_dbg(p2p, "Omit Operating Channel attribute");
 	} else {
 		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -562,26 +567,11 @@
 	 * also supported by the peer device.
 	 */
 	for (i = 0; i < size && !found; i++) {
-		/*
-		 * Make sure that the common frequency is:
-		 * 1. Supported by peer
-		 * 2. Allowed for P2P use.
-		 */
+		/* Make sure that the common frequency is supported by peer. */
 		oper_freq = freq_list[i];
 		if (p2p_freq_to_channel(oper_freq, &op_class,
-					&op_channel) < 0) {
-			p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq);
-			continue;
-		}
-		if (!p2p_channels_includes(&p2p->cfg->channels,
-					   op_class, op_channel) &&
-		    (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
-						  op_class, op_channel))) {
-			p2p_dbg(p2p,
-				"Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
-				oper_freq, op_class, op_channel);
-			break;
-		}
+					&op_channel) < 0)
+			continue; /* cannot happen due to earlier check */
 		for (j = 0; j < msg->channel_list_len; j++) {
 
 			if (op_channel != msg->channel_list[j])
@@ -602,8 +592,7 @@
 			oper_freq);
 	} else {
 		p2p_dbg(p2p,
-			"None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel",
-			dev->oper_freq);
+			"None of our preferred channels are supported by peer!");
 	}
 }
 
@@ -629,29 +618,9 @@
 				msg->pref_freq_list[2 * j + 1]);
 			if (freq_list[i] != oper_freq)
 				continue;
-
-			/*
-			 * Make sure that the found frequency is:
-			 * 1. Supported
-			 * 2. Allowed for P2P use.
-			 */
 			if (p2p_freq_to_channel(oper_freq, &op_class,
-						&op_channel) < 0) {
-				p2p_dbg(p2p, "Unsupported frequency %u MHz",
-					oper_freq);
-				continue;
-			}
-
-			if (!p2p_channels_includes(&p2p->cfg->channels,
-						   op_class, op_channel) &&
-			    (go ||
-			     !p2p_channels_includes(&p2p->cfg->cli_channels,
-						    op_class, op_channel))) {
-				p2p_dbg(p2p,
-					"Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
-					oper_freq, op_class, op_channel);
-				break;
-			}
+						&op_channel) < 0)
+				continue; /* cannot happen */
 			p2p->op_reg_class = op_class;
 			p2p->op_channel = op_channel;
 			os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -666,9 +635,7 @@
 			"Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel",
 			oper_freq);
 	} else {
-		p2p_dbg(p2p,
-			"No common preferred channels found! Use: %d MHz for oper_channel",
-			dev->oper_freq);
+		p2p_dbg(p2p, "No common preferred channels found!");
 	}
 }
 
@@ -679,6 +646,8 @@
 	unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
 	unsigned int i;
 	u8 op_class, op_channel;
+	char txt[100], *pos, *end;
+	int res;
 
 	/*
 	 * Use the preferred channel list from the driver only if there is no
@@ -694,6 +663,39 @@
 	if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
 					 freq_list))
 		return;
+	/* Filter out frequencies that are not acceptable for P2P use */
+	i = 0;
+	while (i < size) {
+		if (p2p_freq_to_channel(freq_list[i], &op_class,
+					&op_channel) < 0 ||
+		    (!p2p_channels_includes(&p2p->cfg->channels,
+					    op_class, op_channel) &&
+		     (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
+						   op_class, op_channel)))) {
+			p2p_dbg(p2p,
+				"Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
+				freq_list[i], go);
+			if (size - i - 1 > 0)
+				os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
+			size--;
+			continue;
+		}
+
+		/* Preferred frequency is acceptable for P2P use */
+		i++;
+	}
+
+	pos = txt;
+	end = pos + sizeof(txt);
+	for (i = 0; i < size; i++) {
+		res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+		if (os_snprintf_error(end - pos, res))
+			break;
+		pos += res;
+	}
+	*pos = '\0';
+	p2p_dbg(p2p, "Local driver frequency preference (size=%u):%s",
+		size, txt);
 
 	/*
 	 * Check if peer's preference of operating channel is in
@@ -703,20 +705,14 @@
 		if (freq_list[i] == (unsigned int) dev->oper_freq)
 			break;
 	}
-	if (i != size) {
+	if (i != size &&
+	    p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
 		/* Peer operating channel preference matches our preference */
-		if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) <
-		    0) {
-			p2p_dbg(p2p,
-				"Peer operating channel preference is unsupported frequency %u MHz",
-				freq_list[i]);
-		} else {
-			p2p->op_reg_class = op_class;
-			p2p->op_channel = op_channel;
-			os_memcpy(&p2p->channels, &p2p->cfg->channels,
-				  sizeof(struct p2p_channels));
-			return;
-		}
+		p2p->op_reg_class = op_class;
+		p2p->op_channel = op_channel;
+		os_memcpy(&p2p->channels, &p2p->cfg->channels,
+			  sizeof(struct p2p_channels));
+		return;
 	}
 
 	p2p_dbg(p2p,
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 47524d4..ce69932 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -553,6 +553,10 @@
 
 	unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
 	unsigned int num_pref_freq;
+
+	/* Override option for preferred operating channel in GO Negotiation */
+	u8 override_pref_op_class;
+	u8 override_pref_channel;
 };
 
 /**
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 1004b32..3f9e53d 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1559,7 +1559,7 @@
 		ieee802_1x_cp_connect_authenticated(kay->cp);
 		ieee802_1x_cp_sm_step(kay->cp);
 		wpa_printf(MSG_WARNING, "KaY:The Key server advise no MACsec");
-		participant->to_use_sak = TRUE;
+		participant->to_use_sak = FALSE;
 		return 0;
 	}
 
@@ -2361,9 +2361,9 @@
 					      &participant->rxsc_list,
 					      struct receive_sc, list) {
 				if (sci_equal(&rxsc->sci, &peer->sci)) {
-					secy_delete_receive_sc(kay, rxsc);
 					ieee802_1x_kay_deinit_receive_sc(
 						participant, rxsc);
+					secy_delete_receive_sc(kay, rxsc);
 				}
 			}
 			dl_list_del(&peer->list);
@@ -2378,6 +2378,12 @@
 			participant->advised_capability =
 				MACSEC_CAP_NOT_IMPLEMENTED;
 			participant->to_use_sak = FALSE;
+			participant->ltx = FALSE;
+			participant->lrx = FALSE;
+			participant->otx = FALSE;
+			participant->orx = FALSE;
+			participant->is_key_server = FALSE;
+			participant->is_elected = FALSE;
 			kay->authenticated = TRUE;
 			kay->secured = FALSE;
 			kay->failed = FALSE;
@@ -2422,7 +2428,8 @@
 		participant->new_sak = FALSE;
 	}
 
-	if (participant->retry_count < MAX_RETRY_CNT) {
+	if (participant->retry_count < MAX_RETRY_CNT ||
+	    participant->mode == PSK) {
 		ieee802_1x_participant_send_mkpdu(participant);
 		participant->retry_count++;
 	}
@@ -2822,7 +2829,7 @@
 	if (!principal)
 		return -1;
 
-	if (principal->retry_count < MAX_RETRY_CNT) {
+	if (principal->retry_count < MAX_RETRY_CNT || principal->mode == PSK) {
 		ieee802_1x_participant_send_mkpdu(principal);
 		principal->retry_count++;
 	}
@@ -3362,6 +3369,7 @@
 		participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
 			usecs / 1000000;
 	}
+	participant->mode = mode;
 
 	return participant;
 
@@ -3424,11 +3432,11 @@
 	while (!dl_list_empty(&participant->rxsc_list)) {
 		rxsc = dl_list_entry(participant->rxsc_list.next,
 				     struct receive_sc, list);
-		secy_delete_receive_sc(kay, rxsc);
 		ieee802_1x_kay_deinit_receive_sc(participant, rxsc);
+		secy_delete_receive_sc(kay, rxsc);
 	}
-	secy_delete_transmit_sc(kay, participant->txsc);
 	ieee802_1x_kay_deinit_transmit_sc(participant, participant->txsc);
+	secy_delete_transmit_sc(kay, participant->txsc);
 
 	os_memset(&participant->cak, 0, sizeof(participant->cak));
 	os_memset(&participant->kek, 0, sizeof(participant->kek));
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index 0c4bb8e..bc522d8 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -93,6 +93,7 @@
 	Boolean active;
 	Boolean participant;
 	Boolean retain;
+	enum mka_created_mode mode;
 
 	enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
 
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 696ea04..1349873 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -288,7 +288,7 @@
 	} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
 		int res, pmk_len;
 
-		if (sm->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		if (wpa_key_mgmt_sha384(sm->key_mgmt))
 			pmk_len = PMK_LEN_SUITE_B_192;
 		else
 			pmk_len = PMK_LEN;
@@ -1393,7 +1393,8 @@
 	int maxkeylen;
 	struct wpa_eapol_ie_parse ie;
 
-	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+	wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data",
+			keydata, keydatalen);
 	if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
 		return -1;
 	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
@@ -3439,6 +3440,8 @@
 				       sm->fils_nonce, sm->fils_anonce, NULL, 0,
 				       sm->pmk, &sm->pmk_len);
 		os_memset(rmsk, 0, sizeof(rmsk));
+		if (res)
+			return -1;
 
 		if (!sm->fils_erp_pmkid_set) {
 			wpa_printf(MSG_DEBUG, "FILS: PMKID not available");
@@ -3564,6 +3567,71 @@
 }
 
 
+static void fils_process_hlp_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
+{
+	const u8 *pos, *end;
+
+	wpa_hexdump(MSG_MSGDUMP, "FILS: HLP response", resp, len);
+	if (len < 2 * ETH_ALEN)
+		return;
+	pos = resp + 2 * ETH_ALEN;
+	end = resp + len;
+	if (end - pos >= 6 &&
+	    os_memcmp(pos, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+		pos += 6; /* Remove SNAP/LLC header */
+	wpa_sm_fils_hlp_rx(sm, resp, resp + ETH_ALEN, pos, end - pos);
+}
+
+
+static void fils_process_hlp_container(struct wpa_sm *sm, const u8 *pos,
+				       size_t len)
+{
+	const u8 *end = pos + len;
+	u8 *tmp, *tmp_pos;
+
+	/* Check if there are any FILS HLP Container elements */
+	while (end - pos >= 2) {
+		if (2 + pos[1] > end - pos)
+			return;
+		if (pos[0] == WLAN_EID_EXTENSION &&
+		    pos[1] >= 1 + 2 * ETH_ALEN &&
+		    pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+			break;
+		pos += 2 + pos[1];
+	}
+	if (end - pos < 2)
+		return; /* No FILS HLP Container elements */
+
+	tmp = os_malloc(end - pos);
+	if (!tmp)
+		return;
+
+	while (end - pos >= 2) {
+		if (2 + pos[1] > end - pos ||
+		    pos[0] != WLAN_EID_EXTENSION ||
+		    pos[1] < 1 + 2 * ETH_ALEN ||
+		    pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+			break;
+		tmp_pos = tmp;
+		os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+		tmp_pos += pos[1] - 1;
+		pos += 2 + pos[1];
+
+		/* Add possible fragments */
+		while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+		       2 + pos[1] <= end - pos) {
+			os_memcpy(tmp_pos, pos + 2, pos[1]);
+			tmp_pos += pos[1];
+			pos += 2 + pos[1];
+		}
+
+		fils_process_hlp_resp(sm, tmp, tmp_pos - tmp);
+	}
+
+	os_free(tmp);
+}
+
+
 int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
 {
 	const struct ieee80211_mgmt *mgmt;
@@ -3705,7 +3773,8 @@
 	/* TK is not needed anymore in supplicant */
 	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
 
-	/* TODO: FILS HLP Container */
+	/* FILS HLP Container */
+	fils_process_hlp_container(sm, ie_start, end - ie_start);
 
 	/* TODO: FILS IP Address Assignment */
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f0eeec8..bde8c78 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -79,6 +79,8 @@
 				  const u8 *kck, size_t kck_len,
 				  const u8 *replay_ctr);
 	int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
+	void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
+			    const u8 *pkt, size_t pkt_len);
 };
 
 
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 491fc98..ab54a18 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -365,6 +365,15 @@
 	return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
 }
 
+static inline void wpa_sm_fils_hlp_rx(struct wpa_sm *sm,
+				      const u8 *dst, const u8 *src,
+				      const u8 *pkt, size_t pkt_len)
+{
+	if (sm->ctx->fils_hlp_rx)
+		sm->ctx->fils_hlp_rx(sm->ctx->ctx, dst, src, pkt, pkt_len);
+}
+
+
 int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
 		       int ver, const u8 *dest, u16 proto,
 		       u8 *msg, size_t msg_len, u8 *key_mic);
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index 59ba4d1..062e6fe 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -52,7 +52,7 @@
 			eloop_terminate();
 		return;
 	}
-	wpabuf_put_str(resp, "User input completed");
+	wpabuf_put_str(resp, "HTTP/1.1\r\n\r\nUser input completed");
 
 	if (done) {
 		eloop_cancel_timeout(browser_timeout, NULL, NULL);
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 97af16f..04ee6d1 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -45,16 +45,16 @@
 /**
  * eloop_event_handler - eloop generic event callback type
  * @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
  */
-typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_event_handler)(void *eloop_ctx, void *user_ctx);
 
 /**
  * eloop_timeout_handler - eloop timeout event callback type
  * @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
  */
-typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx);
 
 /**
  * eloop_signal_handler - eloop signal event callback type