Merge "crypto: Read certificate chain"
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index 76600bc..1dc7547 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -140,7 +140,7 @@
 
 Modified BSD license (no advertisement clause):
 
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 7efce0d..945bdc0 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 
diff --git a/README b/README
index 9685f58..43b684c 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 These programs are licensed under the BSD license (the one with
diff --git a/hostapd/README b/hostapd/README
index 5d5fd36..cb37c8e 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
 	  Authenticator and RADIUS authentication server
 ================================================================
 
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 832ff55..b397034 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -129,9 +129,6 @@
 	struct mac_acl_entry *newacl;
 	int vlan_id;
 
-	if (!fname)
-		return 0;
-
 	f = fopen(fname, "r");
 	if (!f) {
 		wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
@@ -224,9 +221,6 @@
 	int line = 0, ret = 0, num_methods;
 	struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
 
-	if (!fname)
-		return 0;
-
 	if (os_strncmp(fname, "sqlite:", 7) == 0) {
 #ifdef CONFIG_SQLITE
 		os_free(conf->eap_user_sqlite);
@@ -523,15 +517,10 @@
 	fclose(f);
 
 	if (ret == 0) {
-		user = conf->eap_user;
-		while (user) {
-			struct hostapd_eap_user *prev;
-
-			prev = user;
-			user = user->next;
-			hostapd_config_free_eap_user(prev);
-		}
+		hostapd_config_free_eap_users(conf->eap_user);
 		conf->eap_user = new_user;
+	} else {
+		hostapd_config_free_eap_users(new_user);
 	}
 
 	return ret;
@@ -768,7 +757,25 @@
 {
 	size_t len = os_strlen(val);
 
-	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+	if (keyidx < 0 || keyidx > 3)
+		return -1;
+
+	if (len == 0) {
+		int i, set = 0;
+
+		bin_clear_free(wep->key[keyidx], wep->len[keyidx]);
+		wep->key[keyidx] = NULL;
+		wep->len[keyidx] = 0;
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (wep->key[i])
+				set++;
+		}
+		if (!set)
+			wep->keys_set = 0;
+		return 0;
+	}
+
+	if (wep->key[keyidx] != NULL)
 		return -1;
 
 	if (val[0] == '"') {
@@ -1999,6 +2006,29 @@
 }
 
 
+#ifdef CONFIG_FILS
+static int parse_fils_realm(struct hostapd_bss_config *bss, const char *val)
+{
+	struct fils_realm *realm;
+	size_t len;
+
+	len = os_strlen(val);
+	realm = os_zalloc(sizeof(*realm) + len + 1);
+	if (!realm)
+		return -1;
+
+	os_memcpy(realm->realm, val, len);
+	if (fils_domain_name_hash(val, realm->hash) < 0) {
+		os_free(realm);
+		return -1;
+	}
+	dl_list_add_tail(&bss->fils_realms, &realm->list);
+
+	return 0;
+}
+#endif /* CONFIG_FILS */
+
+
 static int hostapd_config_fill(struct hostapd_config *conf,
 			       struct hostapd_bss_config *bss,
 			       const char *buf, char *pos, int line)
@@ -2014,20 +2044,21 @@
 		os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
 	} else if (os_strcmp(buf, "driver") == 0) {
 		int j;
-		/* clear to get error below if setting is invalid */
-		conf->driver = NULL;
+		const struct wpa_driver_ops *driver = NULL;
+
 		for (j = 0; wpa_drivers[j]; j++) {
 			if (os_strcmp(pos, wpa_drivers[j]->name) == 0) {
-				conf->driver = wpa_drivers[j];
+				driver = wpa_drivers[j];
 				break;
 			}
 		}
-		if (conf->driver == NULL) {
+		if (!driver) {
 			wpa_printf(MSG_ERROR,
 				   "Line %d: invalid/unknown driver '%s'",
 				   line, pos);
 			return 1;
 		}
+		conf->driver = driver;
 	} else if (os_strcmp(buf, "driver_params") == 0) {
 		os_free(conf->driver_params);
 		conf->driver_params = os_strdup(pos);
@@ -2071,13 +2102,16 @@
 	} else if (os_strcmp(buf, "utf8_ssid") == 0) {
 		bss->ssid.utf8_ssid = atoi(pos) > 0;
 	} else if (os_strcmp(buf, "macaddr_acl") == 0) {
-		bss->macaddr_acl = atoi(pos);
-		if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
-		    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
-		    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		enum macaddr_acl acl = atoi(pos);
+
+		if (acl != ACCEPT_UNLESS_DENIED &&
+		    acl != DENY_UNLESS_ACCEPTED &&
+		    acl != USE_EXTERNAL_RADIUS_AUTH) {
 			wpa_printf(MSG_ERROR, "Line %d: unknown macaddr_acl %d",
-				   line, bss->macaddr_acl);
+				   line, acl);
+			return 1;
 		}
+		bss->macaddr_acl = acl;
 	} else if (os_strcmp(buf, "accept_mac_file") == 0) {
 		if (hostapd_config_read_maclist(pos, &bss->accept_mac,
 						&bss->num_accept_mac)) {
@@ -2113,13 +2147,15 @@
 	} else if (os_strcmp(buf, "ieee8021x") == 0) {
 		bss->ieee802_1x = atoi(pos);
 	} else if (os_strcmp(buf, "eapol_version") == 0) {
-		bss->eapol_version = atoi(pos);
-		if (bss->eapol_version < 1 || bss->eapol_version > 2) {
+		int eapol_version = atoi(pos);
+
+		if (eapol_version < 1 || eapol_version > 2) {
 			wpa_printf(MSG_ERROR,
 				   "Line %d: invalid EAPOL version (%d): '%s'.",
-				   line, bss->eapol_version, pos);
+				   line, eapol_version, pos);
 			return 1;
 		}
+		bss->eapol_version = eapol_version;
 		wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version);
 #ifdef EAP_SERVER
 	} else if (os_strcmp(buf, "eap_authenticator") == 0) {
@@ -2247,24 +2283,25 @@
 		os_free(bss->erp_domain);
 		bss->erp_domain = os_strdup(pos);
 	} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
-		bss->default_wep_key_len = atoi(pos);
-		if (bss->default_wep_key_len > 13) {
-			wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %lu (= %lu bits)",
-				   line,
-				   (unsigned long) bss->default_wep_key_len,
-				   (unsigned long)
-				   bss->default_wep_key_len * 8);
+		int val = atoi(pos);
+
+		if (val < 0 || val > 13) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid WEP key len %d (= %d bits)",
+				   line, val, val * 8);
 			return 1;
 		}
+		bss->default_wep_key_len = val;
 	} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
-		bss->individual_wep_key_len = atoi(pos);
-		if (bss->individual_wep_key_len < 0 ||
-		    bss->individual_wep_key_len > 13) {
-			wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %d (= %d bits)",
-				   line, bss->individual_wep_key_len,
-				   bss->individual_wep_key_len * 8);
+		int val = atoi(pos);
+
+		if (val < 0 || val > 13) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid WEP key len %d (= %d bits)",
+				   line, val, val * 8);
 			return 1;
 		}
+		bss->individual_wep_key_len = val;
 	} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
 		bss->wep_rekeying_period = atoi(pos);
 		if (bss->wep_rekeying_period < 0) {
@@ -2702,12 +2739,14 @@
 		}
 #endif /* CONFIG_ACS */
 	} else if (os_strcmp(buf, "dtim_period") == 0) {
-		bss->dtim_period = atoi(pos);
-		if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+		int val = atoi(pos);
+
+		if (val < 1 || val > 255) {
 			wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d",
-				   line, bss->dtim_period);
+				   line, val);
 			return 1;
 		}
+		bss->dtim_period = val;
 	} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
 		bss->bss_load_update_period = atoi(pos);
 		if (bss->bss_load_update_period < 0 ||
@@ -3259,7 +3298,15 @@
 		if (parse_anqp_elem(bss, pos, line) < 0)
 			return 1;
 	} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
-		bss->gas_frag_limit = atoi(pos);
+		int val = atoi(pos);
+
+		if (val <= 0) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid gas_frag_limit '%s'",
+				   line, pos);
+			return 1;
+		}
+		bss->gas_frag_limit = val;
 	} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
 		bss->gas_comeback_delay = atoi(pos);
 	} else if (os_strcmp(buf, "qos_map_set") == 0) {
@@ -3542,6 +3589,12 @@
 		if (atoi(pos))
 			bss->radio_measurements[0] |=
 				WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+	} else if (os_strcmp(buf, "rrm_beacon_report") == 0) {
+		if (atoi(pos))
+			bss->radio_measurements[0] |=
+				WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+				WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+				WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
 	} else if (os_strcmp(buf, "gas_address3") == 0) {
 		bss->gas_address3 = atoi(pos);
 	} else if (os_strcmp(buf, "stationary_ap") == 0) {
@@ -3559,6 +3612,9 @@
 			return 1;
 		}
 		bss->fils_cache_id_set = 1;
+	} else if (os_strcmp(buf, "fils_realm") == 0) {
+		if (parse_fils_realm(bss, pos) < 0)
+			return 1;
 #endif /* CONFIG_FILS */
 	} else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
 		bss->multicast_to_unicast = atoi(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index b9d9411..6b4aa05 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1017,14 +1017,16 @@
 		if (ret != 3) {
 			wpa_printf(MSG_DEBUG,
 				   "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
-			return -1;
+			ret = -1;
+			goto fail;
 		}
 
 		if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
 			wpa_printf(MSG_DEBUG,
 				   "Invalid MBO transition reason code %u",
 				   mbo_reason);
-			return -1;
+			ret = -1;
+			goto fail;
 		}
 
 		/* Valid values for Cellular preference are: 0, 1, 255 */
@@ -1032,7 +1034,8 @@
 			wpa_printf(MSG_DEBUG,
 				   "Invalid MBO cellular capability %u",
 				   cell_pref);
-			return -1;
+			ret = -1;
+			goto fail;
 		}
 
 		if (reassoc_delay > 65535 ||
@@ -1040,7 +1043,8 @@
 		     !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
 			wpa_printf(MSG_DEBUG,
 				   "MBO: Assoc retry delay is only valid in disassoc imminent mode");
-			return -1;
+			ret = -1;
+			goto fail;
 		}
 
 		*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
@@ -1066,6 +1070,7 @@
 				  nei_pos > nei_rep ? nei_rep : NULL,
 				  nei_pos - nei_rep, mbo_len ? mbo : NULL,
 				  mbo_len);
+fail:
 	os_free(url);
 	return ret;
 }
@@ -1347,14 +1352,6 @@
 		wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
 			   wps_corrupt_pkhash);
 #endif /* CONFIG_WPS_TESTING */
-#ifdef CONFIG_INTERWORKING
-	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
-		int val = atoi(value);
-		if (val <= 0)
-			ret = -1;
-		else
-			hapd->gas_frag_limit = val;
-#endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
 		hapd->ext_mgmt_frame_handling = atoi(value);
@@ -2239,6 +2236,46 @@
 }
 
 
+static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
+					 const char *cmd, char *reply,
+					 size_t reply_size)
+{
+	u8 addr[ETH_ALEN];
+	const char *pos;
+	struct wpabuf *req;
+	int ret;
+	u8 req_mode = 0;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+	pos = os_strchr(cmd, ' ');
+	if (!pos)
+		return -1;
+	pos++;
+	if (os_strncmp(pos, "req_mode=", 9) == 0) {
+		int val = hex2byte(pos + 9);
+
+		if (val < 0)
+			return -1;
+		req_mode = val;
+		pos += 11;
+		pos = os_strchr(pos, ' ');
+		if (!pos)
+			return -1;
+		pos++;
+	}
+	req = wpabuf_parse_bin(pos);
+	if (!req)
+		return -1;
+
+	ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
+	wpabuf_free(req);
+	if (ret >= 0)
+		ret = os_snprintf(reply, reply_size, "%d", ret);
+	return ret;
+}
+
+
 static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
 {
 	struct wpa_ssid_value ssid;
@@ -2656,9 +2693,14 @@
 	} else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
 		if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
+		reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
+							  reply, reply_size);
 	} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
 		reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
 						      reply_size);
+	} else if (os_strcmp(buf, "TERMINATE") == 0) {
+		eloop_terminate();
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 2117d34..5caa779 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
 /*
  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -973,7 +973,7 @@
 {
 	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
 	       "database/authenticator\n"
-	       "Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
+	       "Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
 	       "\n"
 	       "usage:\n"
 	       "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 1fd4fcc..c9b105a 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -307,7 +307,7 @@
 
 # TX queue parameters (EDCF / bursting)
 # tx_queue_<queue name>_<param>
-# queues: data0, data1, data2, data3, after_beacon, beacon
+# queues: data0, data1, data2, data3
 #		(data0 is the highest priority queue)
 # parameters:
 #   aifs: AIFS (default 2)
@@ -1309,6 +1309,13 @@
 # FILS Cache Identifier (16-bit value in hexdump format)
 #fils_cache_id=0011
 
+# FILS Realm Information
+# One or more FILS realms need to be configured when FILS is enabled. This list
+# of realms is used to define which realms (used in keyName-NAI by the client)
+# can be used with FILS shared key authentication for ERP.
+#fils_realm=example.com
+#fils_realm=example.org
+
 ##### IEEE 802.11r configuration ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -1960,6 +1967,9 @@
 # Enable neighbor report via radio measurements
 #rrm_neighbor_report=1
 
+# Enable beacon report via radio measurements
+#rrm_beacon_report=1
+
 # Publish fine timing measurement (FTM) responder functionality
 # This parameter only controls publishing via Extended Capabilities element.
 # Actual functionality is managed outside hostapd.
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 8b8d7f9..f8d1eda 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -21,7 +21,7 @@
 
 static const char *const hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
 
 static struct wpa_ctrl *ctrl_conn;
 static int hostapd_cli_quit = 0;
@@ -320,7 +320,7 @@
 }
 
 
-static char ** hostapd_complete_sta(const char *str, int pos)
+static char ** hostapd_complete_stations(const char *str, int pos)
 {
 	int arg = get_cmd_arg_num(str, pos);
 	char **res = NULL;
@@ -367,21 +367,6 @@
 }
 
 
-static char ** hostapd_complete_deauthenticate(const char *str, int pos)
-{
-	int arg = get_cmd_arg_num(str, pos);
-	char **res = NULL;
-
-	switch (arg) {
-	case 1:
-		res = cli_txt_list_array(&stations);
-		break;
-	}
-
-	return res;
-}
-
-
 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
 					char *argv[])
 {
@@ -400,21 +385,6 @@
 }
 
 
-static char ** hostapd_complete_disassociate(const char *str, int pos)
-{
-	int arg = get_cmd_arg_num(str, pos);
-	char **res = NULL;
-
-	switch (arg) {
-	case 1:
-		res = cli_txt_list_array(&stations);
-		break;
-	}
-
-	return res;
-}
-
-
 #ifdef CONFIG_TAXONOMY
 static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
 				     char *argv[])
@@ -1072,6 +1042,44 @@
 }
 
 
+static char ** hostapd_complete_set(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	const char *fields[] = {
+#ifdef CONFIG_WPS_TESTING
+		"wps_version_number", "wps_testing_dummy_cred",
+		"wps_corrupt_pkhash",
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+		"gas_frag_limit",
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_TESTING_OPTIONS
+		"ext_mgmt_frame_handling", "ext_eapol_frame_io",
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_MBO
+		"mbo_assoc_disallow",
+#endif /* CONFIG_MBO */
+		"deny_mac_file", "accept_mac_file",
+	};
+	int i, num_fields = ARRAY_SIZE(fields);
+
+	if (arg == 1) {
+		char **res;
+
+		res = os_calloc(num_fields + 1, sizeof(char *));
+		if (!res)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(fields[i]);
+			if (!res[i])
+				return res;
+		}
+		return res;
+	}
+	return NULL;
+}
+
+
 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	char cmd[256];
@@ -1092,6 +1100,31 @@
 }
 
 
+static char ** hostapd_complete_get(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	const char *fields[] = {
+		"version", "tls_library",
+	};
+	int i, num_fields = ARRAY_SIZE(fields);
+
+	if (arg == 1) {
+		char **res;
+
+		res = os_calloc(num_fields + 1, sizeof(char *));
+		if (!res)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(fields[i]);
+			if (!res[i])
+				return res;
+		}
+		return res;
+	}
+	return NULL;
+}
+
+
 #ifdef CONFIG_FST
 static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -1343,9 +1376,11 @@
 	  "= pings hostapd" },
 	{ "mib", hostapd_cli_cmd_mib, NULL,
 	  "= get MIB variables (dot1x, dot11, radius)" },
-	{ "relog", hostapd_cli_cmd_relog, NULL, NULL },
-	{ "status", hostapd_cli_cmd_status, NULL, NULL },
-	{ "sta", hostapd_cli_cmd_sta, hostapd_complete_sta,
+	{ "relog", hostapd_cli_cmd_relog, NULL,
+	  "= reload/truncate debug log output file" },
+	{ "status", hostapd_cli_cmd_status, NULL,
+	  "= show interface status info" },
+	{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
 	  "<addr> = get MIB variables for one station" },
 	{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
 	   "= get MIB variables for all stations" },
@@ -1354,17 +1389,17 @@
 	{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
 	  "<addr> = add a new station" },
 	{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
-	  hostapd_complete_deauthenticate,
+	  hostapd_complete_stations,
 	  "<addr> = deauthenticate a station" },
 	{ "disassociate", hostapd_cli_cmd_disassociate,
-	  hostapd_complete_disassociate,
+	  hostapd_complete_stations,
 	  "<addr> = disassociate a station" },
 #ifdef CONFIG_TAXONOMY
-	{ "signature", hostapd_cli_cmd_signature, NULL,
+	{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
 	  "<addr> = get taxonomy signature for a station" },
 #endif /* CONFIG_TAXONOMY */
 #ifdef CONFIG_IEEE80211W
-	{ "sa_query", hostapd_cli_cmd_sa_query, NULL,
+	{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
 	  "<addr> = send SA Query to a station" },
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
@@ -1393,9 +1428,12 @@
 	{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
 	  "= show current WPS status" },
 #endif /* CONFIG_WPS */
-	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
-	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
-	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
+	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
+	  "= send Disassociation Imminent notification" },
+	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
+	  "= send ESS Dissassociation Imminent notification" },
+	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
+	  "= send BSS Transition Management Request" },
 	{ "get_config", hostapd_cli_cmd_get_config, NULL,
 	  "= show current configuration" },
 	{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
@@ -1403,35 +1441,64 @@
 	{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
 	  "[ifname] = show interfaces/select interface" },
 #ifdef CONFIG_FST
-	{ "fst", hostapd_cli_cmd_fst, NULL, NULL },
+	{ "fst", hostapd_cli_cmd_fst, NULL,
+	  "<params...> = send FST-MANAGER control interface command" },
 #endif /* CONFIG_FST */
-	{ "raw", hostapd_cli_cmd_raw, NULL, NULL },
+	{ "raw", hostapd_cli_cmd_raw, NULL,
+	  "<params..> = send unprocessed command" },
 	{ "level", hostapd_cli_cmd_level, NULL,
 	  "<debug level> = change debug level" },
 	{ "license", hostapd_cli_cmd_license, NULL,
 	  "= show full hostapd_cli license" },
 	{ "quit", hostapd_cli_cmd_quit, NULL,
 	  "= exit hostapd_cli" },
-	{ "set", hostapd_cli_cmd_set, NULL, NULL },
-	{ "get", hostapd_cli_cmd_get, NULL, NULL },
-	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
-	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
-	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
-	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
-	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
-	{ "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
-	{ "enable", hostapd_cli_cmd_enable, NULL, NULL },
-	{ "reload", hostapd_cli_cmd_reload, NULL, NULL },
-	{ "disable", hostapd_cli_cmd_disable, NULL, NULL },
-	{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
-	{ "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
-	{ "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
-	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
-	{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
-	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
-	{ "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
-	{ "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
-	{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
+	{ "set", hostapd_cli_cmd_set, hostapd_complete_set,
+	  "<name> <value> = set runtime variables" },
+	{ "get", hostapd_cli_cmd_get, hostapd_complete_get,
+	  "<name> = get runtime info" },
+	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
+	  "<arg,arg,...> = set QoS Map set element" },
+	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
+	  hostapd_complete_stations,
+	  "<addr> = send QoS Map Configure frame" },
+	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
+	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
+	  "  [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
+	  "  = initiate channel switch announcement" },
+	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
+	  "<addr> <url>\n"
+	  "  = send WNM-Notification Subscription Remediation Request" },
+	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
+	  "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
+	  "  = send WNM-Notification imminent deauthentication indication" },
+	{ "vendor", hostapd_cli_cmd_vendor, NULL,
+	  "<vendor id> <sub command id> [<hex formatted data>]\n"
+	  "  = send vendor driver command" },
+	{ "enable", hostapd_cli_cmd_enable, NULL,
+	  "= enable hostapd on current interface" },
+	{ "reload", hostapd_cli_cmd_reload, NULL,
+	  "= reload configuration for current interface" },
+	{ "disable", hostapd_cli_cmd_disable, NULL,
+	  "= disable hostapd on current interface" },
+	{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
+	  "= drop all ERP keys"},
+	{ "log_level", hostapd_cli_cmd_log_level, NULL,
+	  "[level] = show/change log verbosity level" },
+	{ "pmksa", hostapd_cli_cmd_pmksa, NULL,
+	  " = show PMKSA cache entries" },
+	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
+	  " = flush PMKSA cache" },
+	{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
+	  "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
+	  "  = add AP to neighbor database" },
+	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
+	  "<addr> <ssid=> = remove AP from neighbor database" },
+	{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
+	  "<addr> = send LCI request to a station"},
+	{ "req_range", hostapd_cli_cmd_req_range, NULL,
+	  " = send FTM range request"},
+	{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
+	  " = show supported driver flags"},
 	{ NULL, NULL, NULL, NULL }
 };
 
diff --git a/hostapd/main.c b/hostapd/main.c
index bcc47a4..6911232 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / main()
- * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -451,7 +451,7 @@
 		"hostapd v" VERSION_STR "\n"
 		"User space daemon for IEEE 802.11 AP management,\n"
 		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
-		"Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> "
+		"Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> "
 		"and contributors\n");
 }
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index c986574..e417a12 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -95,6 +95,12 @@
 	bss->radius_das_time_window = 300;
 
 	bss->sae_anti_clogging_threshold = 5;
+
+	bss->gas_frag_limit = 1400;
+
+#ifdef CONFIG_FILS
+	dl_list_init(&bss->fils_realms);
+#endif /* CONFIG_FILS */
 }
 
 
@@ -329,13 +335,7 @@
 		ssid->wpa_psk->group = 1;
 	}
 
-	if (ssid->wpa_psk_file) {
-		if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
-						&conf->ssid))
-			return -1;
-	}
-
-	return 0;
+	return hostapd_config_read_wpa_psk(ssid->wpa_psk_file, &conf->ssid);
 }
 
 
@@ -384,6 +384,18 @@
 }
 
 
+void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
+{
+	struct hostapd_eap_user *prev_user;
+
+	while (user) {
+		prev_user = user;
+		user = user->next;
+		hostapd_config_free_eap_user(prev_user);
+	}
+}
+
+
 static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
 {
 	int i;
@@ -420,10 +432,22 @@
 }
 
 
+static void hostapd_config_free_fils_realms(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_FILS
+	struct fils_realm *realm;
+
+	while ((realm = dl_list_first(&conf->fils_realms, struct fils_realm,
+				      list))) {
+		dl_list_del(&realm->list);
+		os_free(realm);
+	}
+#endif /* CONFIG_FILS */
+}
+
+
 void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
-	struct hostapd_eap_user *user, *prev_user;
-
 	if (conf == NULL)
 		return;
 
@@ -436,12 +460,7 @@
 	os_free(conf->ssid.vlan_tagged_interface);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
-	user = conf->eap_user;
-	while (user) {
-		prev_user = user;
-		user = user->next;
-		hostapd_config_free_eap_user(prev_user);
-	}
+	hostapd_config_free_eap_users(conf->eap_user);
 	os_free(conf->eap_user_sqlite);
 
 	os_free(conf->eap_req_id_text);
@@ -582,6 +601,8 @@
 	os_free(conf->no_probe_resp_if_seen_on);
 	os_free(conf->no_auth_if_seen_on);
 
+	hostapd_config_free_fils_realms(conf);
+
 	os_free(conf);
 }
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 7d8f283..075261c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -224,6 +224,12 @@
 	struct wpabuf *payload;
 };
 
+struct fils_realm {
+	struct dl_list list;
+	u8 hash[2];
+	char realm[];
+};
+
 
 /**
  * struct hostapd_bss_config - Per-BSS configuration
@@ -287,7 +293,7 @@
 	char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
 					* frames */
 
-	enum {
+	enum macaddr_acl {
 		ACCEPT_UNLESS_DENIED = 0,
 		DENY_UNLESS_ACCEPTED = 1,
 		USE_EXTERNAL_RADIUS_AUTH = 2
@@ -509,7 +515,7 @@
 	struct dl_list anqp_elem; /* list of struct anqp_element */
 
 	u16 gas_comeback_delay;
-	int gas_frag_limit;
+	size_t gas_frag_limit;
 	int gas_address3;
 
 	u8 qos_map_set[16 + 2 * 21];
@@ -600,6 +606,7 @@
 #ifdef CONFIG_FILS
 	u8 fils_cache_id[FILS_CACHE_ID_LEN];
 	int fils_cache_id_set;
+	struct dl_list fils_realms; /* list of struct fils_realm */
 #endif /* CONFIG_FILS */
 
 	int multicast_to_unicast;
@@ -725,6 +732,7 @@
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
 void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
+void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
 void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
 void hostapd_config_free_bss(struct hostapd_bss_config *conf);
 void hostapd_config_free(struct hostapd_config *conf);
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index b4306c6..3878ce6 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -261,10 +261,13 @@
 		wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
 	if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
 		wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
-	for (id = 273; id < 277; id++) {
-		if (get_anqp_elem(hapd, id))
-			wpabuf_put_le16(buf, id);
-	}
+#ifdef CONFIG_FILS
+	if (!dl_list_empty(&hapd->conf->fils_realms) ||
+	    get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
+		wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
+#endif /* CONFIG_FILS */
+	if (get_anqp_elem(hapd, ANQP_CAG))
+		wpabuf_put_le16(buf, ANQP_CAG);
 	if (get_anqp_elem(hapd, ANQP_VENUE_URL))
 		wpabuf_put_le16(buf, ANQP_VENUE_URL);
 	if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
@@ -554,6 +557,36 @@
 }
 
 
+#ifdef CONFIG_FILS
+static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
+				     struct wpabuf *buf)
+{
+	size_t count;
+
+	if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
+		return;
+
+	count = dl_list_len(&hapd->conf->fils_realms);
+	if (count > 10000)
+		count = 10000;
+	if (count) {
+		struct fils_realm *realm;
+
+		wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
+		wpabuf_put_le16(buf, 2 * count);
+
+		dl_list_for_each(realm, &hapd->conf->fils_realms,
+				 struct fils_realm, list) {
+			if (count == 0)
+				break;
+			wpabuf_put_data(buf, realm->hash, 2);
+			count--;
+		}
+	}
+}
+#endif /* CONFIG_FILS */
+
+
 #ifdef CONFIG_HS20
 
 static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
@@ -827,6 +860,10 @@
 		len += 1000;
 	if (request & ANQP_REQ_ICON_REQUEST)
 		len += 65536;
+#ifdef CONFIG_FILS
+	if (request & ANQP_FILS_REALM_INFO)
+		len += 2 * dl_list_len(&hapd->conf->fils_realms);
+#endif /* CONFIG_FILS */
 	len += anqp_get_required_len(hapd, extra_req, num_extra_req);
 
 	buf = wpabuf_alloc(len);
@@ -866,8 +903,15 @@
 	if (request & ANQP_REQ_EMERGENCY_NAI)
 		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
 
-	for (i = 0; i < num_extra_req; i++)
+	for (i = 0; i < num_extra_req; i++) {
+#ifdef CONFIG_FILS
+		if (extra_req[i] == ANQP_FILS_REALM_INFO) {
+			anqp_add_fils_realm_info(hapd, buf);
+			continue;
+		}
+#endif /* CONFIG_FILS */
 		anqp_add_elem(hapd, buf, extra_req[i]);
+	}
 
 #ifdef CONFIG_HS20
 	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
@@ -990,6 +1034,13 @@
 			     get_anqp_elem(hapd, info_id) != NULL, qi);
 		break;
 	default:
+#ifdef CONFIG_FILS
+		if (info_id == ANQP_FILS_REALM_INFO &&
+		    !dl_list_empty(&hapd->conf->fils_realms)) {
+			wpa_printf(MSG_DEBUG,
+				   "ANQP: FILS Realm Information (local)");
+		} else
+#endif /* CONFIG_FILS */
 		if (!get_anqp_elem(hapd, info_id)) {
 			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
 				   info_id);
@@ -1195,7 +1246,7 @@
 	}
 #endif /* CONFIG_P2P */
 
-	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+	if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
 	    hapd->conf->gas_comeback_delay) {
 		struct gas_dialog_info *di;
 		u16 comeback_delay = 1;
@@ -1399,8 +1450,8 @@
 	}
 
 	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
-	if (frag_len > hapd->gas_frag_limit) {
-		frag_len = hapd->gas_frag_limit;
+	if (frag_len > hapd->conf->gas_frag_limit) {
+		frag_len = hapd->conf->gas_frag_limit;
 		more = 1;
 	}
 	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
@@ -1501,9 +1552,6 @@
 {
 	hapd->public_action_cb2 = gas_serv_rx_public_action;
 	hapd->public_action_cb2_ctx = hapd;
-	hapd->gas_frag_limit = 1400;
-	if (hapd->conf->gas_frag_limit > 0)
-		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
 	return 0;
 }
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 7c40379..26ebbb6 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -75,6 +75,9 @@
 {
 	struct hostapd_ssid *ssid;
 
+	if (!hapd->started)
+		return;
+
 #ifndef CONFIG_NO_RADIUS
 	radius_client_reconfig(hapd->radius, hapd->conf->radius);
 #endif /* CONFIG_NO_RADIUS */
@@ -210,7 +213,7 @@
 {
 	int i;
 
-	if (!ifname)
+	if (!ifname || !hapd->drv_priv)
 		return;
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
 		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
@@ -357,8 +360,10 @@
 	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
 		   hapd->conf->iface);
 	if (hapd->iface->interfaces &&
-	    hapd->iface->interfaces->ctrl_iface_deinit)
+	    hapd->iface->interfaces->ctrl_iface_deinit) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
 		hapd->iface->interfaces->ctrl_iface_deinit(hapd);
+	}
 	hostapd_free_hapd_data(hapd);
 }
 
@@ -1598,10 +1603,12 @@
 
 	/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
 
-	ieee80211_freq_to_channel_ext(hapd->iface->freq,
-				      hapd->iconf->secondary_channel,
-				      hapd->iconf->vht_oper_chwidth,
-				      &op_class, &channel);
+	if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+					  hapd->iconf->secondary_channel,
+					  hapd->iconf->vht_oper_chwidth,
+					  &op_class, &channel) ==
+	    NUM_HOSTAPD_MODES)
+		return;
 	width = hostapd_get_nr_chan_width(hapd, ht, vht);
 	if (vht) {
 		center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index fd5aaed..bc0ac23 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -260,9 +260,6 @@
 	int noa_start;
 	int noa_duration;
 #endif /* CONFIG_P2P */
-#ifdef CONFIG_INTERWORKING
-	size_t gas_frag_limit;
-#endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_PROXYARP
 	struct l2_packet_data *sock_dhcp;
 	struct l2_packet_data *sock_ndisc;
@@ -301,6 +298,7 @@
 
 	struct dl_list nr_db;
 
+	u8 beacon_req_token;
 	u8 lci_req_token;
 	u8 range_req_token;
 	unsigned int lci_req_active:1;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 16887ac..d66ff4b 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -785,6 +785,8 @@
 			   chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
 	}
 
+	wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
+		   channel, primary ? "primary" : "secondary");
 	return 0;
 }
 
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1cecc80..09850ef 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1789,6 +1789,11 @@
 static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
 			   struct ieee802_11_elems *elems)
 {
+	/* Supported rates not used in IEEE 802.11ad/DMG */
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
+		return WLAN_STATUS_SUCCESS;
+
 	if (!elems->supp_rates) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -2207,8 +2212,8 @@
 
 
 static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
-			   u16 status_code, int reassoc, const u8 *ies,
-			   size_t ies_len)
+			   const u8 *addr, u16 status_code, int reassoc,
+			   const u8 *ies, size_t ies_len)
 {
 	int send_len;
 	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
@@ -2221,7 +2226,7 @@
 		IEEE80211_FC(WLAN_FC_TYPE_MGMT,
 			     (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
 			      WLAN_FC_STYPE_ASSOC_RESP));
-	os_memcpy(reply->da, sta->addr, ETH_ALEN);
+	os_memcpy(reply->da, addr, ETH_ALEN);
 	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
 	os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
 
@@ -2230,14 +2235,16 @@
 	reply->u.assoc_resp.capab_info =
 		host_to_le16(hostapd_own_capab_info(hapd));
 	reply->u.assoc_resp.status_code = host_to_le16(status_code);
-	reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
+
+	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
+					       BIT(14) | BIT(15));
 	/* Supported rates */
 	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
 	/* Extended supported rates */
 	p = hostapd_eid_ext_supp_rates(hapd, p);
 
 #ifdef CONFIG_IEEE80211R_AP
-	if (status_code == WLAN_STATUS_SUCCESS) {
+	if (sta && status_code == WLAN_STATUS_SUCCESS) {
 		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
 		 * Transition Information, RSN, [RIC Response] */
 		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
@@ -2247,7 +2254,7 @@
 #endif /* CONFIG_IEEE80211R_AP */
 
 #ifdef CONFIG_IEEE80211W
-	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
+	if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
 		p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
 #endif /* CONFIG_IEEE80211W */
 
@@ -2260,7 +2267,7 @@
 	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
 		u32 nsts = 0, sta_nsts;
 
-		if (hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+		if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
 			struct ieee80211_vht_capabilities *capa;
 
 			nsts = (hapd->iface->conf->vht_capab >>
@@ -2281,7 +2288,7 @@
 
 	p = hostapd_eid_ext_capab(hapd, p);
 	p = hostapd_eid_bss_max_idle_period(hapd, p);
-	if (sta->qos_map_enabled)
+	if (sta && sta->qos_map_enabled)
 		p = hostapd_eid_qos_map_set(hapd, p);
 
 #ifdef CONFIG_FST
@@ -2293,16 +2300,17 @@
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_IEEE80211AC
-	if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+	if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
 		p = hostapd_eid_vendor_vht(hapd, p);
 #endif /* CONFIG_IEEE80211AC */
 
-	if (sta->flags & WLAN_STA_WMM)
+	if (sta && (sta->flags & WLAN_STA_WMM))
 		p = hostapd_eid_wmm(hapd, p);
 
 #ifdef CONFIG_WPS
-	if ((sta->flags & WLAN_STA_WPS) ||
-	    ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
+	if (sta &&
+	    ((sta->flags & WLAN_STA_WPS) ||
+	     ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
 		struct wpabuf *wps = wps_build_assoc_resp_ie();
 		if (wps) {
 			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -2313,7 +2321,7 @@
 #endif /* CONFIG_WPS */
 
 #ifdef CONFIG_P2P
-	if (sta->p2p_ie && hapd->p2p_group) {
+	if (sta && sta->p2p_ie && hapd->p2p_group) {
 		struct wpabuf *p2p_resp_ie;
 		enum p2p_status_code status;
 		switch (status_code) {
@@ -2355,7 +2363,8 @@
 	send_len += p - reply->u.assoc_resp.variable;
 
 #ifdef CONFIG_FILS
-	if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
+	if (sta &&
+	    (sta->auth_alg == WLAN_AUTH_FILS_SK ||
 	     sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
 	     sta->auth_alg == WLAN_AUTH_FILS_PK) &&
 	    status_code == WLAN_STATUS_SUCCESS) {
@@ -2471,15 +2480,39 @@
 	} else
 #endif /* CONFIG_IEEE80211R_AP */
 	if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "Station tried to "
-			       "associate before authentication "
-			       "(aid=%d flags=0x%x)",
-			       sta ? sta->aid : -1,
-			       sta ? sta->flags : 0);
-		send_deauth(hapd, mgmt->sa,
-			    WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
-		return;
+		if (hapd->iface->current_mode &&
+		    hapd->iface->current_mode->mode ==
+			HOSTAPD_MODE_IEEE80211AD) {
+			/* DMG/IEEE 802.11ad does not use authentication.
+			 * Allocate sta entry upon association. */
+			sta = ap_sta_add(hapd, mgmt->sa);
+			if (!sta) {
+				hostapd_logger(hapd, mgmt->sa,
+					       HOSTAPD_MODULE_IEEE80211,
+					       HOSTAPD_LEVEL_INFO,
+					       "Failed to add STA");
+				resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+				goto fail;
+			}
+
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Skip authentication for DMG/IEEE 802.11ad");
+			sta->flags |= WLAN_STA_AUTH;
+			wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+			sta->auth_alg = WLAN_AUTH_OPEN;
+		} else {
+			hostapd_logger(hapd, mgmt->sa,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_INFO,
+				       "Station tried to associate before authentication (aid=%d flags=0x%x)",
+				       sta ? sta->aid : -1,
+				       sta ? sta->flags : 0);
+			send_deauth(hapd, mgmt->sa,
+				    WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+			return;
+		}
 	}
 
 	if ((fc & WLAN_FC_RETRY) &&
@@ -2634,6 +2667,8 @@
 	taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
 #endif /* CONFIG_TAXONOMY */
 
+	sta->pending_wds_enable = 0;
+
  fail:
 	/*
 	 * In case of a successful response, add the station to the driver.
@@ -2653,10 +2688,11 @@
 	 *    issues with processing other non-Data Class 3 frames during this
 	 *    window.
 	 */
-	if (resp == WLAN_STATUS_SUCCESS && add_associated_sta(hapd, sta))
+	if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
 		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 
-	reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+	reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
+				    left);
 	os_free(tmp);
 
 	/*
@@ -2664,8 +2700,8 @@
 	 * (the STA was added associated to the driver) or if the station was
 	 * previously added unassociated.
 	 */
-	if ((reply_res != WLAN_STATUS_SUCCESS &&
-	     resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc) {
+	if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
+		     resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
 		hostapd_drv_sta_remove(hapd, sta->addr);
 		sta->added_unassoc = 0;
 	}
@@ -2722,6 +2758,17 @@
 
 	mlme_disassociate_indication(
 		hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
+
+	/* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
+	 * disassociation. */
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+		sta->flags &= ~WLAN_STA_AUTH;
+		wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+		ap_free_sta(hapd, sta);
+	}
 }
 
 
@@ -3248,6 +3295,14 @@
 
 	hostapd_set_sta_flags(hapd, sta);
 
+	if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
+		wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
+			   MACSTR " based on pending request",
+			   MAC2STR(sta->addr));
+		sta->pending_wds_enable = 0;
+		sta->flags |= WLAN_STA_WDS;
+	}
+
 	if (sta->flags & WLAN_STA_WDS) {
 		int ret;
 		char ifname_wds[IFNAMSIZ + 1];
@@ -3349,6 +3404,29 @@
 }
 
 
+static void handle_action_cb(struct hostapd_data *hapd,
+			     const struct ieee80211_mgmt *mgmt,
+			     size_t len, int ok)
+{
+	struct sta_info *sta;
+
+	if (is_multicast_ether_addr(mgmt->da))
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+
+	if (len < 24 + 2)
+		return;
+	if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
+	    mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST)
+		hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
+}
+
+
 /**
  * ieee802_11_mgmt_cb - Process management frame TX status callback
  * @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -3398,6 +3476,7 @@
 		break;
 	case WLAN_FC_STYPE_ACTION:
 		wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
+		handle_action_cb(hapd, mgmt, len, ok);
 		break;
 	default:
 		wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
@@ -3512,10 +3591,22 @@
 	struct sta_info *sta;
 
 	sta = ap_get_sta(hapd, src);
-	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+	if (sta &&
+	    ((sta->flags & WLAN_STA_ASSOC) ||
+	     ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
 		if (!hapd->conf->wds_sta)
 			return;
 
+		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
+		    WLAN_STA_ASSOC_REQ_OK) {
+			wpa_printf(MSG_DEBUG,
+				   "Postpone 4-address WDS mode enabling for STA "
+				   MACSTR " since TX status for AssocResp is not yet known",
+				   MAC2STR(sta->addr));
+			sta->pending_wds_enable = 1;
+			return;
+		}
+
 		if (wds && !(sta->flags & WLAN_STA_WDS)) {
 			int ret;
 			char ifname_wds[IFNAMSIZ + 1];
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 97b1d67..daacf7e 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -605,18 +605,23 @@
 #ifdef CONFIG_FILS
 	u8 *len;
 	u16 fils_info = 0;
+	size_t realms;
+	struct fils_realm *realm;
 
 	if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
 	    !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
 		return pos;
 
+	realms = dl_list_len(&hapd->conf->fils_realms);
+	if (realms > 7)
+		realms = 7; /* 3 bit count field limits this to max 7 */
+
 	*pos++ = WLAN_EID_FILS_INDICATION;
 	len = pos++;
 	/* TODO: B0..B2: Number of Public Key Identifiers */
 	if (hapd->conf->erp_domain) {
-		/* TODO: Support for setting multiple domain identifiers */
 		/* B3..B5: Number of Realm Identifiers */
-		fils_info |= BIT(3);
+		fils_info |= realms << 3;
 	}
 	/* TODO: B6: FILS IP Address Configuration */
 	if (hapd->conf->fils_cache_id_set)
@@ -638,11 +643,13 @@
 		os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
 		pos += ETH_ALEN;
 	}
-	if (hapd->conf->erp_domain) {
-		u16 hash;
 
-		hash = fils_domain_name_hash(hapd->conf->erp_domain);
-		WPA_PUT_LE16(pos, hash);
+	dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm,
+			 list) {
+		if (realms == 0)
+			break;
+		realms--;
+		os_memcpy(pos, realm->hash, 2);
 		pos += 2;
 	}
 	*len = pos - len - 1;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 7ac337d..fccdc72 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1962,7 +1962,7 @@
 
 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
 		   eapol->default_wep_key_idx);
-		      
+
 	if (ieee802_1x_rekey_broadcast(hapd)) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_WARNING, "failed to generate a "
@@ -2364,6 +2364,16 @@
 		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
 		   be_to_host16(xhdr->length), ack);
 
+#ifdef CONFIG_WPS
+	if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
+	    (sta->flags & WLAN_STA_WPS) &&
+	    ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Indicate EAP completion on ACK for EAP-Failure");
+		hostapd_wps_eap_completed(hapd);
+	}
+#endif /* CONFIG_WPS */
+
 	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
 		return 0;
 
@@ -2737,15 +2747,6 @@
 		 * EAP-FAST with anonymous provisioning, may require another
 		 * EAPOL authentication to be started to complete connection.
 		 */
-		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
-			"disconnection after EAP-Failure");
-		/* Add a small sleep to increase likelihood of previously
-		 * requested EAP-Failure TX getting out before this should the
-		 * driver reorder operations.
-		 */
-		os_sleep(0, 10000);
-		ap_sta_disconnect(hapd, sta, sta->addr,
-				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
-		hostapd_wps_eap_completed(hapd);
+		ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
 	}
 }
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index 5ca87c0..28e8cc9 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -2,6 +2,7 @@
  * hostapd / Radio Measurement (RRM)
  * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
  * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ * Copyright (c) 2016-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +11,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "common/wpa_ctrl.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
 #include "sta_info.h"
@@ -69,24 +71,47 @@
 }
 
 
+static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
+					 const u8 *addr, u8 token, u8 rep_mode,
+					 const u8 *pos, size_t len)
+{
+	char report[2 * 255 + 1];
+
+	wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR,
+		   token, len, MAC2STR(addr));
+	/* Skip to the beginning of the Beacon report */
+	if (len < 3)
+		return;
+	pos += 3;
+	len -= 3;
+	report[0] = '\0';
+	if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0)
+		return;
+	wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
+		MAC2STR(addr), token, rep_mode, report);
+}
+
+
 static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
 					     const u8 *buf, size_t len)
 {
 	const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
 	const u8 *pos, *ie, *end;
-	u8 token;
+	u8 token, rep_mode;
 
 	end = buf + len;
 	token = mgmt->u.action.u.rrm.dialog_token;
 	pos = mgmt->u.action.u.rrm.variable;
 
 	while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
-		if (ie[1] < 5) {
+		if (ie[1] < 3) {
 			wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
 			break;
 		}
 
-		wpa_printf(MSG_DEBUG, "Measurement report type %u", ie[4]);
+		rep_mode = ie[3];
+		wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u",
+			   rep_mode, ie[4]);
 
 		switch (ie[4]) {
 		case MEASURE_TYPE_LCI:
@@ -95,6 +120,10 @@
 		case MEASURE_TYPE_FTM_RANGE:
 			hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
 			break;
+		case MEASURE_TYPE_BEACON:
+			hostapd_handle_beacon_report(hapd, mgmt->sa, token,
+						     rep_mode, ie + 2, ie[1]);
+			break;
 		default:
 			wpa_printf(MSG_DEBUG,
 				   "Measurement report type %u is not supported",
@@ -542,3 +571,111 @@
 	eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
 	hapd->range_req_active = 0;
 }
+
+
+int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
+			    u8 req_mode, const struct wpabuf *req)
+{
+	struct wpabuf *buf;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	int ret;
+	enum beacon_report_mode mode;
+	const u8 *pos;
+
+	/* Request data:
+	 * Operating Class (1), Channel Number (1), Randomization Interval (2),
+	 * Measurement Duration (2), Measurement Mode (1), BSSID (6),
+	 * Optional Subelements (variable)
+	 */
+	if (wpabuf_len(req) < 13) {
+		wpa_printf(MSG_INFO, "Beacon request: Too short request data");
+		return -1;
+	}
+	pos = wpabuf_head(req);
+	mode = pos[6];
+
+	if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+		wpa_printf(MSG_INFO,
+			   "Beacon request: " MACSTR " is not connected",
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	switch (mode) {
+	case BEACON_REPORT_MODE_PASSIVE:
+		if (!(sta->rrm_enabled_capa[0] &
+		      WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
+			wpa_printf(MSG_INFO,
+				   "Beacon request: " MACSTR
+				   " does not support passive beacon report",
+				   MAC2STR(addr));
+			return -1;
+		}
+		break;
+	case BEACON_REPORT_MODE_ACTIVE:
+		if (!(sta->rrm_enabled_capa[0] &
+		      WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
+			wpa_printf(MSG_INFO,
+				   "Beacon request: " MACSTR
+				   " does not support active beacon report",
+				   MAC2STR(addr));
+			return -1;
+		}
+		break;
+	case BEACON_REPORT_MODE_TABLE:
+		if (!(sta->rrm_enabled_capa[0] &
+		      WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
+			wpa_printf(MSG_INFO,
+				   "Beacon request: " MACSTR
+				   " does not support table beacon report",
+				   MAC2STR(addr));
+			return -1;
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO,
+			   "Beacon request: Unknown measurement mode %d", mode);
+		return -1;
+	}
+
+	buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
+	if (!buf)
+		return -1;
+
+	hapd->beacon_req_token++;
+	if (!hapd->beacon_req_token)
+		hapd->beacon_req_token++;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+	wpabuf_put_u8(buf, hapd->beacon_req_token);
+	wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+	/* Measurement Request element */
+	wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+	wpabuf_put_u8(buf, 3 + wpabuf_len(req));
+	wpabuf_put_u8(buf, 1); /* Measurement Token */
+	wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
+	wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
+	wpabuf_put_buf(buf, req);
+
+	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+				      wpabuf_head(buf), wpabuf_len(buf));
+	wpabuf_free(buf);
+	if (ret < 0)
+		return ret;
+
+	return hapd->beacon_req_token;
+}
+
+
+void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
+				      const struct ieee80211_mgmt *mgmt,
+				      size_t len, int ok)
+{
+	if (len < 24 + 3)
+		return;
+	wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
+		" %u ack=%d", MAC2STR(mgmt->da),
+		mgmt->u.action.u.rrm.dialog_token, ok);
+}
diff --git a/src/ap/rrm.h b/src/ap/rrm.h
index f07fd41..02cd522 100644
--- a/src/ap/rrm.h
+++ b/src/ap/rrm.h
@@ -24,5 +24,10 @@
 			   u16 random_interval, u8 min_ap,
 			   const u8 *responders, unsigned int n_responders);
 void hostapd_clean_rrm(struct hostapd_data *hapd);
+int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
+			    u8 req_mode, const struct wpabuf *req);
+void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
+				      const struct ieee80211_mgmt *mgmt,
+				      size_t len, int ok);
 
 #endif /* RRM_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f12d408..b87ddea 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -36,6 +36,7 @@
 #include "ndisc_snoop.h"
 #include "sta_info.h"
 #include "vlan.h"
+#include "wps_hostapd.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
 				       struct sta_info *sta);
@@ -47,6 +48,7 @@
 static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_IEEE80211W */
 static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
 
 int ap_for_each_sta(struct hostapd_data *hapd,
 		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -745,9 +747,17 @@
 	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
-	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+		/* Skip deauthentication in DMG/IEEE 802.11ad */
+		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+				WLAN_STA_ASSOC_REQ_OK);
+		sta->timeout_next = STA_REMOVE;
+	} else {
+		sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+		sta->timeout_next = STA_DEAUTH;
+	}
 	ap_sta_set_authorized(hapd, sta, 0);
-	sta->timeout_next = STA_DEAUTH;
 	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
 		   "for " MACSTR " (%d seconds - "
 		   "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -783,6 +793,14 @@
 void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
 			   u16 reason)
 {
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+		/* Deauthentication is not used in DMG/IEEE 802.11ad;
+		 * disassociate the STA instead. */
+		ap_sta_disassociate(hapd, sta, reason);
+		return;
+	}
+
 	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
@@ -1229,6 +1247,20 @@
 			       ap_handle_timer, hapd, sta);
 	sta->timeout_next = STA_REMOVE;
 
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+		/* Deauthentication is not used in DMG/IEEE 802.11ad;
+		 * disassociate the STA instead. */
+		sta->disassoc_reason = reason;
+		sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+		eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+		eloop_register_timeout(hapd->iface->drv_flags &
+				       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
+				       2 : 0, 0, ap_sta_disassoc_cb_timeout,
+				       hapd, sta);
+		return;
+	}
+
 	sta->deauth_reason = reason;
 	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
 	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -1275,6 +1307,15 @@
 			   "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
 			   MACSTR,
 			   hapd->conf->iface, MAC2STR(sta->addr));
+	if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
+	{
+		wpa_printf(MSG_DEBUG,
+			   "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
+			   MACSTR,
+			   hapd->conf->iface, MAC2STR(sta->addr));
+		if (sta->flags & WLAN_STA_WPS)
+			hostapd_wps_eap_completed(hapd);
+	}
 }
 
 
@@ -1309,3 +1350,45 @@
 
 	return res;
 }
+
+
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+		"IEEE 802.1X: Scheduled disconnection of " MACSTR
+		" after EAP-Failure", MAC2STR(sta->addr));
+
+	ap_sta_disconnect(hapd, sta, sta->addr,
+			  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+	if (sta->flags & WLAN_STA_WPS)
+		hostapd_wps_eap_completed(hapd);
+}
+
+
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+					    struct sta_info *sta)
+{
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+		"IEEE 802.1X: Force disconnection of " MACSTR
+		" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
+
+	/*
+	 * Add a small sleep to increase likelihood of previously requested
+	 * EAP-Failure TX getting out before this should the driver reorder
+	 * operations.
+	 */
+	eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
+	eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
+			       hapd, sta);
+}
+
+
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+						   struct sta_info *sta)
+{
+	return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
+					   hapd, sta);
+}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index a416337..0b44f7b 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -115,6 +115,7 @@
 	unsigned int radius_das_match:1;
 	unsigned int ecsa_supported:1;
 	unsigned int added_unassoc:1;
+	unsigned int pending_wds_enable:1;
 
 	u16 auth_alg;
 
@@ -296,5 +297,9 @@
 				      struct sta_info *sta);
 
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+					    struct sta_info *sta);
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+						   struct sta_info *sta);
 
 #endif /* STA_INFO_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 637d6d6..7ab371f 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1293,6 +1293,11 @@
 
 	wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
 
+	if (!sm->wpa_auth->conf.ft_over_ds) {
+		wpa_printf(MSG_DEBUG, "FT: Over-DS option disabled - reject");
+		return -1;
+	}
+
 	/* RRB - Forward action frame to the target AP */
 	frame = os_malloc(sizeof(*frame) + len);
 	if (frame == NULL)
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index e0769c0..0b596bb 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -53,12 +53,38 @@
 	  18, ParseOK, 9 },
 	{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
 	{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
+	{ (u8 *) "\xed\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xef\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xef\x01\x11", 3, ParseOK, 1 },
+	{ (u8 *) "\xf0\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xf1\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xf1\x02\x11\x22", 4, ParseOK, 1 },
+	{ (u8 *) "\xf2\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xff\x00", 2, ParseUnknown, 1 },
+	{ (u8 *) "\xff\x01\x00", 3, ParseUnknown, 1 },
+	{ (u8 *) "\xff\x01\x01", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x02\x01\x00", 4, ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x02", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x04\x02\x11\x22\x33", 6, ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x04", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x05", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x0d\x05\x11\x22\x33\x44\x55\x55\x11\x22\x33\x44\x55\x55",
+	  15, ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x06", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x02\x06\x00", 4, ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x07", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x09\x07\x11\x22\x33\x44\x55\x66\x77\x88", 11,
+	  ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x0c", 3, ParseOK, 1 },
+	{ (u8 *) "\xff\x02\x0c\x00", 4, ParseOK, 1 },
+	{ (u8 *) "\xff\x01\x0d", 3, ParseOK, 1 },
 	{ NULL, 0, ParseOK, 0 }
 };
 
 static int ieee802_11_parse_tests(void)
 {
 	int i, ret = 0;
+	struct wpabuf *buf;
 
 	wpa_printf(MSG_INFO, "ieee802_11_parse tests");
 
@@ -84,6 +110,35 @@
 		ret = -1;
 	}
 
+	buf = ieee802_11_vendor_ie_concat((const u8 *) "\xdd\x05\x11\x22\x33\x44\x01\xdd\x05\x11\x22\x33\x44\x02\x00\x01",
+					  16, 0x11223344);
+	do {
+		const u8 *pos;
+
+		if (!buf) {
+			wpa_printf(MSG_ERROR,
+				   "ieee802_11_vendor_ie_concat test 2 failed");
+			ret = -1;
+			break;
+		}
+
+		if (wpabuf_len(buf) != 2) {
+			wpa_printf(MSG_ERROR,
+				   "ieee802_11_vendor_ie_concat test 3 failed");
+			ret = -1;
+			break;
+		}
+
+		pos = wpabuf_head(buf);
+		if (pos[0] != 0x01 || pos[1] != 0x02) {
+			wpa_printf(MSG_ERROR,
+				   "ieee802_11_vendor_ie_concat test 3 failed");
+			ret = -1;
+			break;
+		}
+	} while (0);
+	wpabuf_free(buf);
+
 	return ret;
 }
 
diff --git a/src/common/defs.h b/src/common/defs.h
index 672bdf6..eaccced 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -376,4 +376,8 @@
 	BEACON_RATE_VHT
 };
 
+enum eap_proxy_sim_state {
+	SIM_STATE_ERROR,
+};
+
 #endif /* DEFS_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 26e08b7..a8d68e5 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1449,3 +1449,148 @@
 
 	return 6 + attr_len;
 }
+
+
+static const struct country_op_class us_op_class[] = {
+	{ 1, 115 },
+	{ 2, 118 },
+	{ 3, 124 },
+	{ 4, 121 },
+	{ 5, 125 },
+	{ 12, 81 },
+	{ 22, 116 },
+	{ 23, 119 },
+	{ 24, 122 },
+	{ 25, 126 },
+	{ 26, 126 },
+	{ 27, 117 },
+	{ 28, 120 },
+	{ 29, 123 },
+	{ 30, 127 },
+	{ 31, 127 },
+	{ 32, 83 },
+	{ 33, 84 },
+	{ 34, 180 },
+};
+
+static const struct country_op_class eu_op_class[] = {
+	{ 1, 115 },
+	{ 2, 118 },
+	{ 3, 121 },
+	{ 4, 81 },
+	{ 5, 116 },
+	{ 6, 119 },
+	{ 7, 122 },
+	{ 8, 117 },
+	{ 9, 120 },
+	{ 10, 123 },
+	{ 11, 83 },
+	{ 12, 84 },
+	{ 17, 125 },
+	{ 18, 180 },
+};
+
+static const struct country_op_class jp_op_class[] = {
+	{ 1, 115 },
+	{ 30, 81 },
+	{ 31, 82 },
+	{ 32, 118 },
+	{ 33, 118 },
+	{ 34, 121 },
+	{ 35, 121 },
+	{ 36, 116 },
+	{ 37, 119 },
+	{ 38, 119 },
+	{ 39, 122 },
+	{ 40, 122 },
+	{ 41, 117 },
+	{ 42, 120 },
+	{ 43, 120 },
+	{ 44, 123 },
+	{ 45, 123 },
+	{ 56, 83 },
+	{ 57, 84 },
+	{ 58, 121 },
+	{ 59, 180 },
+};
+
+static const struct country_op_class cn_op_class[] = {
+	{ 1, 115 },
+	{ 2, 118 },
+	{ 3, 125 },
+	{ 4, 116 },
+	{ 5, 119 },
+	{ 6, 126 },
+	{ 7, 81 },
+	{ 8, 83 },
+	{ 9, 84 },
+};
+
+static u8
+global_op_class_from_country_array(u8 op_class, size_t array_size,
+				   const struct country_op_class *country_array)
+{
+	size_t i;
+
+	for (i = 0; i < array_size; i++) {
+		if (country_array[i].country_op_class == op_class)
+			return country_array[i].global_op_class;
+	}
+
+	return 0;
+}
+
+
+u8 country_to_global_op_class(const char *country, u8 op_class)
+{
+	const struct country_op_class *country_array;
+	size_t size;
+	u8 g_op_class;
+
+	if (country_match(us_op_class_cc, country)) {
+		country_array = us_op_class;
+		size = ARRAY_SIZE(us_op_class);
+	} else if (country_match(eu_op_class_cc, country)) {
+		country_array = eu_op_class;
+		size = ARRAY_SIZE(eu_op_class);
+	} else if (country_match(jp_op_class_cc, country)) {
+		country_array = jp_op_class;
+		size = ARRAY_SIZE(jp_op_class);
+	} else if (country_match(cn_op_class_cc, country)) {
+		country_array = cn_op_class;
+		size = ARRAY_SIZE(cn_op_class);
+	} else {
+		/*
+		 * Countries that do not match any of the above countries use
+		 * global operating classes
+		 */
+		return op_class;
+	}
+
+	g_op_class = global_op_class_from_country_array(op_class, size,
+							country_array);
+
+	/*
+	 * If the given operating class did not match any of the country's
+	 * operating classes, assume that global operating class is used.
+	 */
+	return g_op_class ? g_op_class : op_class;
+}
+
+
+const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
+{
+	const struct oper_class_map *op;
+
+	if (country)
+		op_class = country_to_global_op_class(country, op_class);
+
+	op = &global_op_class[0];
+	while (op->op_class && op->op_class != op_class)
+		op++;
+
+	if (!op->op_class)
+		return NULL;
+
+	return op;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2c20ba6..966eeac 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -177,4 +177,13 @@
 
 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
 
+struct country_op_class {
+	u8 country_op_class;
+	u8 global_op_class;
+};
+
+u8 country_to_global_op_class(const char *country, u8 op_class);
+
+const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
+
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index ca808d7..5f6fdc4 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -105,7 +105,7 @@
 #define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
 #define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
 
-/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+/* Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46) */
 #define WLAN_STATUS_SUCCESS 0
 #define WLAN_STATUS_UNSPECIFIED_FAILURE 1
 #define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
@@ -122,27 +122,23 @@
 #define WLAN_STATUS_AUTH_TIMEOUT 16
 #define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
 #define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* IEEE 802.11b */
 #define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
-/* IEEE 802.11h */
 #define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
 #define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
 #define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
-/* IEEE 802.11g */
 #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
 #define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
 #define WLAN_STATUS_R0KH_UNREACHABLE 28
 #define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
-/* IEEE 802.11w */
 #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
 #define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_DENIED_INSUFFICIENT_BANDWIDTH 33
+#define WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS 34
+#define WLAN_STATUS_DENIED_QOS_NOT_SUPPORTED 35
 #define WLAN_STATUS_REQUEST_DECLINED 37
 #define WLAN_STATUS_INVALID_PARAMETERS 38
-/* IEEE 802.11i */
+#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39
 #define WLAN_STATUS_INVALID_IE 40
 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
 #define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
@@ -155,11 +151,13 @@
 #define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
 #define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
 #define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
-/* IEEE 802.11r */
 #define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
 #define WLAN_STATUS_INVALID_PMKID 53
 #define WLAN_STATUS_INVALID_MDIE 54
 #define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_REQUESTED_TCLAS_NOT_SUPPORTED 56
+#define WLAN_STATUS_INSUFFICIENT_TCLAS_PROCESSING_RESOURCES 57
+#define WLAN_STATUS_TRY_ANOTHER_BSS 58
 #define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
 #define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
 #define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
@@ -170,18 +168,43 @@
 #define WLAN_STATUS_REQ_REFUSED_SSPN 67
 #define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
 #define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_U_APSD_COEX_NOT_SUPPORTED 73
+#define WLAN_STATUS_U_APSD_COEX_MODE_NOT_SUPPORTED 74
+#define WLAN_STATUS_BAD_INTERVAL_WITH_U_APSD_COEX 75
 #define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
 #define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
+#define WLAN_STATUS_CANNOT_FIND_ALT_TBTT 78
 #define WLAN_STATUS_TRANSMISSION_FAILURE 79
+#define WLAN_STATUS_REQ_TCLAS_NOT_SUPPORTED 80
+#define WLAN_STATUS_TCLAS_RESOURCES_EXCHAUSTED 81
 #define WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82
+#define WLAN_STATUS_REJECT_WITH_SCHEDULE 83
+#define WLAN_STATUS_REJECT_NO_WAKEUP_SPECIFIED 84
+#define WLAN_STATUS_SUCCESS_POWER_SAVE_MODE 85
 #define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86
+#define WLAN_STATUS_PERFORMING_FST_NOW 87
+#define WLAN_STATUS_PENDING_GAP_IN_BA_WINDOW 88
+#define WLAN_STATUS_REJECT_U_PID_SETTING 89
+#define WLAN_STATUS_REFUSED_EXTERNAL_REASON 92
+#define WLAN_STATUS_REFUSED_AP_OUT_OF_MEMORY 93
+#define WLAN_STATUS_REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED 94
 #define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
+#define WLAN_STATUS_REJECT_DSE_BAND 96
+#define WLAN_STATUS_TCLAS_PROCESSING_TERMINATED 97
+#define WLAN_STATUS_TS_SCHEDULE_CONFLICT 98
 #define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
+#define WLAN_STATUS_MCCAOP_RESERVATION_CONFLICT 100
+#define WLAN_STATUS_MAF_LIMIT_EXCEEDED 101
+#define WLAN_STATUS_MCCA_TRACK_LIMIT_EXCEEDED 102
+#define WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT 103
 #define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
+#define WLAN_STATUS_ENABLEMENT_DENIED 105
+#define WLAN_STATUS_RESTRICTION_FROM_AUTHORIZED_GDB 106
+#define WLAN_STATUS_AUTHORIZATION_DEENABLED 107
 #define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
 #define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
 
-/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
 #define WLAN_REASON_UNSPECIFIED 1
 #define WLAN_REASON_PREV_AUTH_NOT_VALID 2
 #define WLAN_REASON_DEAUTH_LEAVING 3
@@ -191,10 +214,9 @@
 #define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
 #define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
 #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* IEEE 802.11h */
 #define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
 #define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
-/* IEEE 802.11i */
+#define WLAN_REASON_BSS_TRANSITION_DISASSOC 12
 #define WLAN_REASON_INVALID_IE 13
 #define WLAN_REASON_MICHAEL_MIC_FAILURE 14
 #define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
@@ -209,9 +231,26 @@
 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24
 #define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
 #define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
-/* IEEE 802.11e */
+#define WLAN_REASON_SSP_REQUESTED_DISASSOC 27
+#define WLAN_REASON_NO_SSP_ROAMING_AGREEMENT 28
+#define WLAN_REASON_BAD_CIPHER_OR_AKM 29
+#define WLAN_REASON_NOT_AUTHORIZED_THIS_LOCATION 30
+#define WLAN_REASON_SERVICE_CHANGE_PRECLUDES_TS 31
+#define WLAN_REASON_UNSPECIFIED_QOS_REASON 32
+#define WLAN_REASON_NOT_ENOUGH_BANDWIDTH 33
 #define WLAN_REASON_DISASSOC_LOW_ACK 34
-/* IEEE 802.11s */
+#define WLAN_REASON_EXCEEDED_TXOP 35
+#define WLAN_REASON_STA_LEAVING 36
+#define WLAN_REASON_END_TS_BA_DLS 37
+#define WLAN_REASON_UNKNOWN_TS_BA 38
+#define WLAN_REASON_TIMEOUT 39
+#define WLAN_REASON_PEERKEY_MISMATCH 45
+#define WLAN_REASON_AUTHORIZED_ACCESS_LIMIT_REACHED 46
+#define WLAN_REASON_EXTERNAL_SERVICE_REQUIREMENTS 47
+#define WLAN_REASON_INVALID_FT_ACTION_FRAME_COUNT 48
+#define WLAN_REASON_INVALID_PMKID 49
+#define WLAN_REASON_INVALID_MDE 50
+#define WLAN_REASON_INVALID_FTE 51
 #define WLAN_REASON_MESH_PEERING_CANCELLED 52
 #define WLAN_REASON_MESH_MAX_PEERS 53
 #define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
@@ -221,20 +260,29 @@
 #define WLAN_REASON_MESH_INVALID_GTK 58
 #define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
 #define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60
+#define WLAN_REASON_MESH_PATH_ERROR_NO_PROXY_INFO 61
+#define WLAN_REASON_MESH_PATH_ERROR_NO_FORWARDING_INFO 62
+#define WLAN_REASON_MESH_PATH_ERROR_DEST_UNREACHABLE 63
+#define WLAN_REASON_MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS 64
+#define WLAN_REASON_MESH_CHANNEL_SWITCH_REGULATORY_REQ 65
+#define WLAN_REASON_MESH_CHANNEL_SWITCH_UNSPECIFIED 66
 
 
-/* Information Element IDs */
+/* Information Element IDs (IEEE Std 802.11-2016, 9.4.2.1, Table 9-77) */
 #define WLAN_EID_SSID 0
 #define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
 #define WLAN_EID_DS_PARAMS 3
 #define WLAN_EID_CF_PARAMS 4
 #define WLAN_EID_TIM 5
 #define WLAN_EID_IBSS_PARAMS 6
 #define WLAN_EID_COUNTRY 7
+#define WLAN_EID_REQUEST 10
 #define WLAN_EID_BSS_LOAD 11
+#define WLAN_EID_EDCA_PARAM_SET 12
+#define WLAN_EID_TSPEC 13
+#define WLAN_EID_TCLAS 14
+#define WLAN_EID_SCHEDULE 15
 #define WLAN_EID_CHALLENGE 16
-/* EIDs defined by IEEE 802.11h - START */
 #define WLAN_EID_PWR_CONSTRAINT 32
 #define WLAN_EID_PWR_CAPABILITY 33
 #define WLAN_EID_TPC_REQUEST 34
@@ -243,50 +291,139 @@
 #define WLAN_EID_CHANNEL_SWITCH 37
 #define WLAN_EID_MEASURE_REQUEST 38
 #define WLAN_EID_MEASURE_REPORT 39
-#define WLAN_EID_QUITE 40
+#define WLAN_EID_QUIET 40
 #define WLAN_EID_IBSS_DFS 41
-/* EIDs defined by IEEE 802.11h - END */
 #define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_TS_DELAY 43
+#define WLAN_EID_TCLAS_PROCESSING 44
 #define WLAN_EID_HT_CAP 45
 #define WLAN_EID_QOS 46
 #define WLAN_EID_RSN 48
 #define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_AP_CHANNEL_REPORT 51
 #define WLAN_EID_NEIGHBOR_REPORT 52
+#define WLAN_EID_RCPI 53
 #define WLAN_EID_MOBILITY_DOMAIN 54
 #define WLAN_EID_FAST_BSS_TRANSITION 55
 #define WLAN_EID_TIMEOUT_INTERVAL 56
 #define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_DSE_REGISTERED_LOCATION 58
 #define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
 #define WLAN_EID_EXT_CHANSWITCH_ANN 60
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
-#define WLAN_EID_WAPI 68
+#define WLAN_EID_BSS_AVERAGE_ACCESS_DELAY 63
+#define WLAN_EID_ANTENNA 64
+#define WLAN_EID_RSNI 65
+#define WLAN_EID_MEASUREMENT_PILOT_TRANSMISSION 66
+#define WLAN_EID_BSS_AVAILABLE_ADM_CAPA 67
+#define WLAN_EID_BSS_AC_ACCESS_DELAY 68 /* note: also used by WAPI */
 #define WLAN_EID_TIME_ADVERTISEMENT 69
 #define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
+#define WLAN_EID_MULTIPLE_BSSID 71
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_RIC_DESCRIPTOR 75
 #define WLAN_EID_MMIE 76
+#define WLAN_EID_EVENT_REQUEST 78
+#define WLAN_EID_EVENT_REPORT 79
+#define WLAN_EID_DIAGNOSTIC_REQUEST 80
+#define WLAN_EID_DIAGNOSTIC_REPORT 81
+#define WLAN_EID_LOCATION_PARAMETERS 82
+#define WLAN_EID_NONTRANSMITTED_BSSID_CAPA 83
 #define WLAN_EID_SSID_LIST 84
+#define WLAN_EID_MLTIPLE_BSSID_INDEX 85
+#define WLAN_EID_FMS_DESCRIPTOR 86
+#define WLAN_EID_FMS_REQUEST 87
+#define WLAN_EID_FMS_RESPONSE 88
+#define WLAN_EID_QOS_TRAFFIC_CAPABILITY 89
 #define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
 #define WLAN_EID_TFS_REQ 91
 #define WLAN_EID_TFS_RESP 92
 #define WLAN_EID_WNMSLEEP 93
+#define WLAN_EID_TIM_BROADCAST_REQUEST 94
+#define WLAN_EID_TIM_BROADCAST_RESPONSE 95
+#define WLAN_EID_COLLOCATED_INTERFERENCE_REPORT 96
+#define WLAN_EID_CHANNEL_USAGE 97
 #define WLAN_EID_TIME_ZONE 98
+#define WLAN_EID_DMS_REQUEST 99
+#define WLAN_EID_DMS_RESPONSE 100
 #define WLAN_EID_LINK_ID 101
+#define WLAN_EID_WAKEUP_SCHEDULE 102
+#define WLAN_EID_CHANNEL_SWITCH_TIMING 104
+#define WLAN_EID_PTI_CONTROL 105
+#define WLAN_EID_TPU_BUFFER_STATUS 106
 #define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_EXPEDITED_BANDWIDTH_REQ 109
 #define WLAN_EID_QOS_MAP_SET 110
 #define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_EMERGENCY_ALERT_ID 112
 #define WLAN_EID_MESH_CONFIG 113
 #define WLAN_EID_MESH_ID 114
+#define WLAN_EID_MESH_LINK_METRIC_REPORT 115
+#define WLAN_EID_CONGESTION_NOTIFICATION 116
 #define WLAN_EID_PEER_MGMT 117
+#define WLAN_EID_MESH_CHANNEL_SWITCH_PARAMETERS 118
+#define WLAN_EID_MESH_AWAKE_WINDOW 119
+#define WLAN_EID_BEACON_TIMING 120
+#define WLAN_EID_MCCAOP_SETUP_REQUEST 121
+#define WLAN_EID_MCCAOP_SETUP_REPLY 122
+#define WLAN_EID_MCCAOP_ADVERTISEMENT 123
+#define WLAN_EID_MCCAOP_TEARDOWN 124
+#define WLAN_EID_GANN 125
+#define WLAN_EID_RANN 126
 #define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_PREQ 130
+#define WLAN_EID_PREP 131
+#define WLAN_EID_PERR 132
+#define WLAN_EID_PXU 137
+#define WLAN_EID_PXUC 138
 #define WLAN_EID_AMPE 139
 #define WLAN_EID_MIC 140
+#define WLAN_EID_DESTINATION_URI 141
+#define WLAN_EID_U_APSD_COEX 142
+#define WLAN_EID_DMG_WAKEUP_SCHEDULE 143
+#define WLAN_EID_EXTENDED_SCHEDULE 144
+#define WLAN_EID_STA_AVAILABILITY 145
+#define WLAN_EID_DMG_TSPEC 146
+#define WLAN_EID_NEXT_DMG_ATI 147
+#define WLAN_EID_DMG_CAPABILITIES 148
+#define WLAN_EID_DMG_OPERATION 151
+#define WLAN_EID_DMG_BSS_PARAMETER_CHANGE 152
+#define WLAN_EID_DMG_BEAM_REFINEMENT 153
+#define WLAN_EID_CHANNEL_MEASUREMENT_FEEDBACK 154
 #define WLAN_EID_CCKM 156
+#define WLAN_EID_AWAKE_WINDOW 157
 #define WLAN_EID_MULTI_BAND 158
+#define WLAN_EID_ADDBA_EXTENSION 159
+#define WLAN_EID_NEXTPCP_LIST 160
+#define WLAN_EID_PCP_HANDOVER 161
+#define WLAN_EID_DMG_LINK_MARGIN 162
+#define WLAN_EID_SWITCHING_STREAM 163
 #define WLAN_EID_SESSION_TRANSITION 164
+#define WLAN_EID_DYNAMIC_TONE_PAIRING_REPORT 165
+#define WLAN_EID_CLUSTER_REPORT 166
+#define WLAN_EID_REPLAY_CAPABILITIES 167
+#define WLAN_EID_RELAY_TRANSFER_PARAM_SET 168
+#define WLAN_EID_BEAMLINK_MAINTENANCE 169
+#define WLAN_EID_MULTIPLE_MAC_SUBLAYERS 170
+#define WLAN_EID_U_PID 171
+#define WLAN_EID_DMG_LINK_ADAPTATION_ACK 172
+#define WLAN_EID_MCCAOP_ADVERTISEMENT_OVERVIEW 174
+#define WLAN_EID_QUIET_PERIOD_REQUEST 175
+#define WLAN_EID_QUIET_PERIOD_RESPONSE 177
+#define WLAN_EID_QMF_POLICY 181
+#define WLAN_EID_ECAPC_POLICY 182
+#define WLAN_EID_CLUSTER_TIME_OFFSET 183
+#define WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY 184
+#define WLAN_EID_SCS_DESCRIPTOR 185
+#define WLAN_EID_QLOAD_REPORT 186
+#define WLAN_EID_HCCA_TXOP_UPDATE_COUNT 187
+#define WLAN_EID_HIGHER_LAYER_STREAM_ID 188
+#define WLAN_EID_GCR_GROUP_ADDRESS 189
+#define WLAN_EID_ANTENNA_SECTOR_ID_PATTERN 190
 #define WLAN_EID_VHT_CAP 191
 #define WLAN_EID_VHT_OPERATION 192
 #define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@@ -296,6 +433,12 @@
 #define WLAN_EID_VHT_AID 197
 #define WLAN_EID_VHT_QUIET_CHANNEL 198
 #define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_UPSIM 200
+#define WLAN_EID_REDUCED_NEIGHBOR_REPORT 201
+#define WLAN_EID_TVHT_OPERATION 202
+#define WLAN_EID_DEVICE_LOCATION 204
+#define WLAN_EID_WHITE_SPACE_MAP 205
+#define WLAN_EID_FTM_PARAMETERS 206
 #define WLAN_EID_VENDOR_SPECIFIC 221
 #define WLAN_EID_CAG_NUMBER 237
 #define WLAN_EID_AP_CSN 239
@@ -313,11 +456,15 @@
 #define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
 #define WLAN_EID_EXT_KEY_DELIVERY 7
 #define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_FTM_SYNC_INFO 9
+#define WLAN_EID_EXT_EXTENDED_REQUEST 10
+#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
 #define WLAN_EID_EXT_FILS_PUBLIC_KEY 12
 #define WLAN_EID_EXT_FILS_NONCE 13
+#define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14
 
 
-/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
 #define WLAN_ACTION_SPECTRUM_MGMT 0
 #define WLAN_ACTION_QOS 1
 #define WLAN_ACTION_DLS 2
@@ -331,23 +478,59 @@
 #define WLAN_ACTION_WNM 10
 #define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_MESH 13
+#define WLAN_ACTION_MULTIHOP 14
 #define WLAN_ACTION_SELF_PROTECTED 15
+#define WLAN_ACTION_DMG 16
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
 #define WLAN_ACTION_FST 18
+#define WLAN_ACTION_ROBUST_AV_STREAMING 19
+#define WLAN_ACTION_UNPROTECTED_DMG 20
+#define WLAN_ACTION_VHT 21
 #define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
 #define WLAN_ACTION_VENDOR_SPECIFIC 127
+/* Note: 128-255 used to report errors by setting category | 0x80 */
 
-/* Public action codes */
+/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
 #define WLAN_PA_20_40_BSS_COEX 0
+#define WLAN_PA_DSE_ENABLEMENT 1
+#define WLAN_PA_DSE_DEENABLEMENT 2
+#define WLAN_PA_DSE_REG_LOCATION_ANNOUNCE 3
+#define WLAN_PA_EXT_CHANNEL_SWITCH_ANNOUNCE 4
+#define WLAN_PA_DSE_MEASUREMENT_REQ 5
+#define WLAN_PA_DSE_MEASUREMENT_RESP 6
+#define WLAN_PA_MEASUREMENT_PILOT 7
+#define WLAN_PA_DSE_POWER_CONSTRAINT 8
 #define WLAN_PA_VENDOR_SPECIFIC 9
 #define WLAN_PA_GAS_INITIAL_REQ 10
 #define WLAN_PA_GAS_INITIAL_RESP 11
 #define WLAN_PA_GAS_COMEBACK_REQ 12
 #define WLAN_PA_GAS_COMEBACK_RESP 13
 #define WLAN_TDLS_DISCOVERY_RESPONSE 14
+#define WLAN_PA_LOCATION_TRACK_NOTIFICATION 15
+#define WLAN_PA_QAB_REQUEST_FRAME 16
+#define WLAN_PA_QAB_RESPONSE_FRAME 17
+#define WLAN_PA_QMF_POLICY 18
+#define WLAN_PA_QMF_POLICY_CHANGE 19
+#define WLAN_PA_QLOAD_REQUEST 20
+#define WLAN_PA_QLOAD_REPORT 21
+#define WLAN_PA_HCCA_TXOP_ADVERTISEMENT 22
+#define WLAN_PA_HCCA_TXOP_RESPONSE 23
+#define WLAN_PA_PUBLIC_KEY 24
+#define WLAN_PA_CHANNEL_AVAILABILITY_QUERY 25
+#define WLAN_PA_CHANNEL_SCHEDULE_MANAGEMENT 26
+#define WLAN_PA_CONTACT_VERIFICATION_SIGNAL 27
+#define WLAN_PA_GDD_ENABLEMENT_REQ 28
+#define WLAN_PA_GDD_ENABLEMENT_RESP 29
+#define WLAN_PA_NETWORK_CHANNEL_CONTROL 30
+#define WLAN_PA_WHITE_SPACE_MAP_ANNOUNCEMENT 31
+#define WLAN_PA_FTM_REQUEST 32
+#define WLAN_PA_FTM 33
 #define WLAN_PA_FILS_DISCOVERY 34
 
-/* Protected Dual of Public Action frames */
+/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
+ * Table 9-332) */
 #define WLAN_PROT_DSE_ENABLEMENT 1
 #define WLAN_PROT_DSE_DEENABLEMENT 2
 #define WLAN_PROT_EXT_CSA 4
@@ -359,6 +542,21 @@
 #define WLAN_PROT_GAS_INITIAL_RESP 11
 #define WLAN_PROT_GAS_COMEBACK_REQ 12
 #define WLAN_PROT_GAS_COMEBACK_RESP 13
+#define WLAN_PROT_QAB_REQUEST_FRAME 16
+#define WLAN_PROT_QAB_RESPONSE_FRAME 17
+#define WLAN_PROT_QMF_POLICY 18
+#define WLAN_PROT_QMF_POLICY_CHANGE 19
+#define WLAN_PROT_QLOAD_REQUEST 20
+#define WLAN_PROT_QLOAD_REPORT 21
+#define WLAN_PROT_HCCA_TXOP_ADVERTISEMENT 22
+#define WLAN_PROT_HCCA_TXOP_RESPONSE 23
+#define WLAN_PROT_CHANNEL_AVAILABILITY_QUERY 25
+#define WLAN_PROT_CHANNEL_SCHEDULE_MANAGEMENT 26
+#define WLAN_PROT_CONTACT_VERIFICATION_SIGNAL 27
+#define WLAN_PROT_GDD_ENABLEMENT_REQ 28
+#define WLAN_PROT_GDD_ENABLEMENT_RESP 29
+#define WLAN_PROT_NETWORK_CHANNEL_CONTROL 30
+#define WLAN_PROT_WHITE_SPACE_MAP_ANNOUNCEMENT 31
 
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
 #define WLAN_SA_QUERY_REQUEST 0
@@ -387,10 +585,14 @@
 #define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
 #define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
 
-/* Radio Measurement capabilities (from RRM Capabilities IE) */
+/* Radio Measurement capabilities (from RM Enabled Capabilities element)
+ * IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
 /* byte 1 (out of 5) */
 #define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
 #define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+#define WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE BIT(4)
+#define WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE BIT(5)
+#define WLAN_RRM_CAPS_BEACON_REPORT_TABLE BIT(6)
 /* byte 2 (out of 5) */
 #define WLAN_RRM_CAPS_LCI_MEASUREMENT BIT(4)
 /* byte 5 (out of 5) */
@@ -423,16 +625,18 @@
 #define INTERWORKING_ANT_TEST 6
 #define INTERWORKING_ANT_WILDCARD 15
 
-/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+/* Advertisement Protocol ID definitions (IEEE Std 802.11-2016, Table 9-215) */
 enum adv_proto_id {
 	ACCESS_NETWORK_QUERY_PROTOCOL = 0,
 	MIH_INFO_SERVICE = 1,
 	MIH_CMD_AND_EVENT_DISCOVERY = 2,
 	EMERGENCY_ALERT_SYSTEM = 3,
+	REGISTERED_LOCATION_QUERY_PROTO = 4,
 	ADV_PROTO_VENDOR_SPECIFIC = 221
 };
 
-/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11-2016,
+ * Table 9-271; P802.11ai) */
 enum anqp_info_id {
 	ANQP_QUERY_LIST = 256,
 	ANQP_CAPABILITY_LIST = 257,
@@ -453,11 +657,12 @@
 	ANQP_NEIGHBOR_REPORT = 272,
 	ANQP_QUERY_AP_LIST = 273,
 	ANQP_AP_LIST_RESPONSE = 274,
-	AMQP_FILS_REALM_INFO = 275,
+	ANQP_FILS_REALM_INFO = 275,
 	ANQP_CAG = 276,
 	ANQP_VENUE_URL = 277,
 	ANQP_ADVICE_OF_CHARGE = 278,
 	ANQP_LOCAL_CONTENT = 279,
+	ANQP_NETWORK_AUTH_TYPE_TIMESTAMP = 280,
 	ANQP_VENDOR_SPECIFIC = 56797
 };
 
@@ -1597,6 +1802,102 @@
 	u8 variable[0];
 } STRUCT_PACKED;
 
+/* IEEE Std 802.11-2016, 9.4.2.21 - Measurement Request element */
+struct rrm_measurement_request_element {
+	u8 eid; /* Element ID */
+	u8 len; /* Length */
+	u8 token; /* Measurement Token */
+	u8 mode; /* Measurement Request Mode */
+	u8 type; /* Measurement Type */
+	u8 variable[0]; /* Measurement Request */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-148 - Measurement Request Mode field */
+#define MEASUREMENT_REQUEST_MODE_PARALLEL BIT(0)
+#define MEASUREMENT_REQUEST_MODE_ENABLE BIT(1)
+#define MEASUREMENT_REQUEST_MODE_REQUEST BIT(2)
+#define MEASUREMENT_REQUEST_MODE_REPORT BIT(3)
+#define MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY BIT(4)
+
+/* IEEE Std 802.11-2016, 9.4.2.21.7 - Beacon request */
+struct rrm_measurement_beacon_request {
+	u8 oper_class; /* Operating Class */
+	u8 channel; /* Channel Number */
+	le16 rand_interval; /* Randomization Interval (in TUs) */
+	le16 duration; /* Measurement Duration (in TUs) */
+	u8 mode; /* Measurement Mode */
+	u8 bssid[ETH_ALEN]; /* BSSID */
+	u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/*
+ * IEEE Std 802.11-2016, Table 9-87 - Measurement Mode definitions for Beacon
+ * request
+ */
+enum beacon_report_mode {
+	BEACON_REPORT_MODE_PASSIVE = 0,
+	BEACON_REPORT_MODE_ACTIVE = 1,
+	BEACON_REPORT_MODE_TABLE = 2,
+};
+
+/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
+#define WLAN_BEACON_REQUEST_SUBELEM_SSID	0
+#define WLAN_BEACON_REQUEST_SUBELEM_INFO	1 /* Beacon Reporting */
+#define WLAN_BEACON_REQUEST_SUBELEM_DETAIL	2 /* Reporting Detail */
+#define WLAN_BEACON_REQUEST_SUBELEM_REQUEST	10
+#define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL	51 /* AP Channel Report */
+#define WLAN_BEACON_REQUEST_SUBELEM_VENDOR	221
+
+/*
+ * IEEE Std 802.11-2016, Table 9-90 - Reporting Detail values
+ */
+enum beacon_report_detail {
+	/* No fixed-length fields or elements */
+	BEACON_REPORT_DETAIL_NONE = 0,
+	/* All fixed-length fields and any requested elements in the Request
+	 * element if present */
+	BEACON_REPORT_DETAIL_REQUESTED_ONLY = 1,
+	/* All fixed-length fields and elements (default, used when Reporting
+	 * Detail subelement is not included in a Beacon request) */
+	BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS = 2,
+};
+
+/* IEEE Std 802.11-2016, 9.4.2.22 - Measurement Report element */
+struct rrm_measurement_report_element {
+	u8 eid; /* Element ID */
+	u8 len; /* Length */
+	u8 token; /* Measurement Token */
+	u8 mode; /* Measurement Report Mode */
+	u8 type; /* Measurement Type */
+	u8 variable[0]; /* Measurement Report */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-192 - Measurement Report Mode field */
+#define MEASUREMENT_REPORT_MODE_ACCEPT 0
+#define MEASUREMENT_REPORT_MODE_REJECT_LATE BIT(0)
+#define MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE BIT(1)
+#define MEASUREMENT_REPORT_MODE_REJECT_REFUSED BIT(2)
+
+/* IEEE Std 802.11-2016, 9.4.2.22.7 - Beacon report */
+struct rrm_measurement_beacon_report {
+	u8 op_class; /* Operating Class */
+	u8 channel; /* Channel Number */
+	le64 start_time; /* Actual Measurement Start Time
+			  * (in TSF of the BSS requesting the measurement) */
+	le16 duration; /* in TUs */
+	u8 report_info; /* Reported Frame Information */
+	u8 rcpi; /* RCPI */
+	u8 rsni; /* RSNI */
+	u8 bssid[ETH_ALEN]; /* BSSID */
+	u8 antenna_id; /* Antenna ID */
+	le32 parent_tsf; /* Parent TSF */
+	u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
+#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY	1
+#define WLAN_BEACON_REPORT_SUBELEM_VENDOR	221
+
 /* IEEE Std 802.11ad-2012 - Multi-band element */
 struct multi_band_ie {
 	u8 eid; /* WLAN_EID_MULTI_BAND */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 2ce2a89..46fddff 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -237,6 +237,12 @@
  *	started with QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN. This command
  *	carries the scan cookie of the corresponding scan request. The scan
  *	cookie is represented by QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS: Set the Specific
+ *	Absorption Rate (SAR) power limits. A critical regulation for
+ *	FCC compliance, OEMs require methods to set SAR limits on TX
+ *	power of WLAN/WWAN. enum qca_vendor_attr_sar_limits
+ *	attributes are used with this command.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -288,7 +294,19 @@
 	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58,
 	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59,
 	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
-	/* 61-73 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO = 61,
+	QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62,
+	QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP = 63,
+	QCA_NL80211_VENDOR_SUBCMD_ROAM = 64,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SSID_HOTLIST = 65,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SSID_HOTLIST = 66,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_SSID_FOUND = 67,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_SSID_LOST = 68,
+	QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST = 69,
+	QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST = 70,
+	QCA_NL80211_VENDOR_SUBCMD_PNO_RESET_PASSPOINT_LIST = 71,
+	QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND = 72,
+	QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND = 73,
 	/* Wi-Fi configuration subcommands */
 	QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
 	QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
@@ -345,6 +363,7 @@
 	QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143,
 	/* 144 - reserved for QCA */
 	QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145,
+	QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146,
 };
 
 
@@ -802,19 +821,22 @@
  * 	scan flag is set
  * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with
  * 	randomisation
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
+ *	specific BSSID to scan for.
  */
 enum qca_wlan_vendor_attr_scan {
 	QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
-	QCA_WLAN_VENDOR_ATTR_SCAN_IE,
-	QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES,
-	QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS,
-	QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES,
-	QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE,
-	QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS,
-	QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
-	QCA_WLAN_VENDOR_ATTR_SCAN_STATUS,
-	QCA_WLAN_VENDOR_ATTR_SCAN_MAC,
-	QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK,
+	QCA_WLAN_VENDOR_ATTR_SCAN_IE = 1,
+	QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES = 2,
+	QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS = 3,
+	QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES = 4,
+	QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE = 5,
+	QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS = 6,
+	QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE = 7,
+	QCA_WLAN_VENDOR_ATTR_SCAN_STATUS = 8,
+	QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
+	QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
+	QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
 	QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
 	QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -1012,6 +1034,10 @@
 	QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC = 35,
 	/* 32-bit unsigned value to set window size for specific peer */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT = 36,
+	/* 8-bit unsigned value to set the beacon miss threshold in 2.4 GHz */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_24 = 37,
+	/* 8-bit unsigned value to set the beacon miss threshold in 5 GHz */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_5 = 38,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
@@ -2214,4 +2240,676 @@
 	QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = 1 << 2,
 };
 
+/**
+ * enum qca_vendor_attr_sar_limits_selections - Source of SAR power limits
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0: Select SAR profile #0
+ *	that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1: Select SAR profile #1
+ *	that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2: Select SAR profile #2
+ *	that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3: Select SAR profile #3
+ *	that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4: Select SAR profile #4
+ *	that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE: Do not select any
+ *	source of SAR power limits, thereby disabling the SAR power
+ *	limit feature.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power
+ *	limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ *
+ * This enumerates the valid set of values that may be supplied for
+ * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of
+ * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command.
+ */
+enum qca_vendor_attr_sar_limits_selections {
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 = 0,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1 = 1,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2 = 2,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3 = 3,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits_spec_modulations -
+ *	SAR limits specification modulation
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK -
+ *	CCK modulation
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM -
+ *	OFDM modulation
+ *
+ * This enumerates the valid set of values that may be supplied for
+ * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION in an
+ * instance of attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC in an
+ * instance of the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor
+ * command.
+ */
+enum qca_vendor_attr_sar_limits_spec_modulations {
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK = 0,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM = 1,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits - Attributes for SAR power limits
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT: Optional (u32) value to
+ *	select which SAR power limit table should be used. Valid
+ *	values are enumerated in enum
+ *	%qca_vendor_attr_sar_limits_selections. The existing SAR
+ *	power limit selection is unchanged if this attribute is not
+ *	present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS: Optional (u32) value
+ *	which specifies the number of SAR power limit specifications
+ *	which will follow.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC: Nested array of SAR power
+ *	limit specifications. The number of specifications is
+ *	specified by @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS. Each
+ *	specification contains a set of
+ *	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_* attributes. A
+ *	specification is uniquely identified by the attributes
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND,
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always
+ *	contains as a payload the attribute
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to
+ *	indicate for which band this specification applies. Valid
+ *	values are enumerated in enum %nl80211_band (although not all
+ *	bands may be supported by a given device). If the attribute is
+ *	not supplied then the specification will be applied to all
+ *	supported bands.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN: Optional (u32) value
+ *	to indicate for which antenna chain this specification
+ *	applies, i.e. 1 for chain 1, 2 for chain 2, etc. If the
+ *	attribute is not supplied then the specification will be
+ *	applied to all chains.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION: Optional (u32)
+ *	value to indicate for which modulation scheme this
+ *	specification applies. Valid values are enumerated in enum
+ *	%qca_vendor_attr_sar_limits_spec_modulations. If the attribute
+ *	is not supplied then the specification will be applied to all
+ *	modulation schemes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32)
+ *	value to specify the actual power limit value in units of 0.5
+ *	dBm (i.e., a value of 11 represents 5.5 dBm).
+ *
+ * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS.
+ */
+enum qca_vendor_attr_sar_limits {
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE = 1,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS = 2,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC = 3,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND = 4,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7,
+
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX =
+		QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_wifi_info: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO sub command.
+ */
+enum qca_wlan_vendor_attr_get_wifi_info {
+	QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1,
+	QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX =
+	QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_wifi_logger_start: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START sub command.
+ */
+enum qca_wlan_vendor_attr_wifi_logger_start {
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID = 1,
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL = 2,
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS = 3,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_GET_MAX =
+	QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_logger_results {
+	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_INVALID = 0,
+
+	/* Unsigned 32-bit value; must match the request Id supplied by
+	 * Wi-Fi HAL in the corresponding subcmd NL msg.
+	 */
+	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_REQUEST_ID = 1,
+
+	/* Unsigned 32-bit value; used to indicate the size of memory
+	 * dump to be allocated.
+	*/
+	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX =
+	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_roaming_config_params {
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
+
+	QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD = 1,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID = 2,
+
+	/* Attributes for wifi_set_ssid_white_list */
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS = 3,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST = 4,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID = 5,
+
+	/* Attributes for set_roam_params */
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD = 6,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD = 7,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR = 8,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR = 9,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST = 10,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS = 11,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER = 12,
+
+	/* Attribute for set_lazy_roam */
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE = 13,
+
+	/* Attribute for set_lazy_roam with preferences */
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS = 14,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID = 15,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17,
+
+	/* Attribute for set_blacklist bssid params */
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ */
+enum qca_wlan_vendor_attr_roam_subcmd {
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
+	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_gscan_config_params {
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_INVALID = 0,
+
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID = 1,
+
+	/* Attributes for data used by
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS sub command.
+	 */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND
+	= 2,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS
+	= 3,
+
+	/* Attributes for input params used by
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_START sub command.
+	 */
+
+	/* Unsigned 32-bit value; channel frequency */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CHANNEL = 4,
+	/* Unsigned 32-bit value; dwell time in ms. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_DWELL_TIME = 5,
+	/* Unsigned 8-bit value; 0: active; 1: passive; N/A for DFS */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_PASSIVE = 6,
+	/* Unsigned 8-bit value; channel class */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CLASS = 7,
+
+	/* Unsigned 8-bit value; bucket index, 0 based */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_INDEX = 8,
+	/* Unsigned 8-bit value; band. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BAND = 9,
+	/* Unsigned 32-bit value; desired period, in ms. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_PERIOD = 10,
+	/* Unsigned 8-bit value; report events semantics. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_REPORT_EVENTS = 11,
+	/* Unsigned 32-bit value. Followed by a nested array of
+	 * GSCAN_CHANNEL_SPEC_* attributes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS = 12,
+
+	/* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_* attributes.
+	 * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC = 13,
+
+	/* Unsigned 32-bit value; base timer period in ms. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_BASE_PERIOD = 14,
+	/* Unsigned 32-bit value; number of APs to store in each scan in the
+	 * BSSID/RSSI history buffer (keep the highest RSSI APs).
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN = 15,
+	/* Unsigned 8-bit value; in %, when scan buffer is this much full, wake
+	 * up AP.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT
+	= 16,
+
+	/* Unsigned 8-bit value; number of scan bucket specs; followed by a
+	 * nested array of_GSCAN_BUCKET_SPEC_* attributes and values. The size
+	 * of the array is determined by NUM_BUCKETS.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS = 17,
+
+	/* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_* attributes.
+	 * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC = 18,
+
+	/* Unsigned 8-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH
+	= 19,
+	/* Unsigned 32-bit value; maximum number of results to be returned. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX
+	= 20,
+
+	/* An array of 6 x unsigned 8-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID = 21,
+	/* Signed 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW = 22,
+	/* Signed 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH = 23,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_CHANNEL = 24,
+
+	/* Number of hotlist APs as unsigned 32-bit value, followed by a nested
+	 * array of AP_THRESHOLD_PARAM attributes and values. The size of the
+	 * array is determined by NUM_AP.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_NUM_AP = 25,
+
+	/* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_* attributes.
+	 * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM = 26,
+
+	/* Unsigned 32-bit value; number of samples for averaging RSSI. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE
+	= 27,
+	/* Unsigned 32-bit value; number of samples to confirm AP loss. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE
+	= 28,
+	/* Unsigned 32-bit value; number of APs breaching threshold. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING = 29,
+	/* Unsigned 32-bit value; number of APs. Followed by an array of
+	 * AP_THRESHOLD_PARAM attributes. Size of the array is NUM_AP.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP = 30,
+	/* Unsigned 32-bit value; number of samples to confirm AP loss. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE
+	= 31,
+	/* Unsigned 32-bit value. If max_period is non zero or different than
+	 * period, then this bucket is an exponential backoff bucket.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_MAX_PERIOD = 32,
+	/* Unsigned 32-bit value. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BASE = 33,
+	/* Unsigned 32-bit value. For exponential back off bucket, number of
+	 * scans to perform for a given period.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_STEP_COUNT = 34,
+	/* Unsigned 8-bit value; in number of scans, wake up AP after these
+	 * many scans.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS
+	= 35,
+
+	/* Attributes for data used by
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SSID_HOTLIST sub command.
+	 */
+	/* Unsigned 3-2bit value; number of samples to confirm SSID loss. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE
+	= 36,
+	/* Number of hotlist SSIDs as unsigned 32-bit value, followed by a
+	 * nested array of SSID_THRESHOLD_PARAM_* attributes and values. The
+	 * size of the array is determined by NUM_SSID.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_NUM_SSID = 37,
+	/* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_*
+	 * attributes.
+	 * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_NUM_SSID
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM = 38,
+
+	/* An array of 33 x unsigned 8-bit value; NULL terminated SSID */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_SSID = 39,
+	/* Unsigned 8-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_BAND = 40,
+	/* Signed 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW = 41,
+	/* Signed 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH = 42,
+	/* Unsigned 32-bit value; a bitmask with additional gscan config flag.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CONFIGURATION_FLAGS = 43,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_MAX =
+	QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_gscan_results {
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_INVALID = 0,
+
+	/* Unsigned 32-bit value; must match the request Id supplied by
+	 * Wi-Fi HAL in the corresponding subcmd NL msg.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID = 1,
+
+	/* Unsigned 32-bit value; used to indicate the status response from
+	 * firmware/driver for the vendor sub-command.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS = 2,
+
+	/* GSCAN Valid Channels attributes */
+	/* Unsigned 32bit value; followed by a nested array of CHANNELS. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS = 3,
+	/* An array of NUM_CHANNELS x unsigned 32-bit value integers
+	 * representing channel numbers.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS = 4,
+
+	/* GSCAN Capabilities attributes */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE = 5,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS = 6,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
+	= 7,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
+	= 8,
+	/* Signed 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
+	= 9,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS = 10,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
+	= 11,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
+	= 12,
+
+	/* GSCAN Attributes used with
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE sub-command.
+	 */
+
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE = 13,
+
+	/* GSCAN attributes used with
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT sub-command.
+	 */
+
+	/* An array of NUM_RESULTS_AVAILABLE x
+	 * QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_*
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST = 14,
+
+	/* Unsigned 64-bit value; age of sample at the time of retrieval */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP = 15,
+	/* 33 x unsigned 8-bit value; NULL terminated SSID */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID = 16,
+	/* An array of 6 x unsigned 8-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID = 17,
+	/* Unsigned 32-bit value; channel frequency in MHz */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL = 18,
+	/* Signed 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI = 19,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT = 20,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD = 21,
+	/* Unsigned 16-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD = 22,
+	/* Unsigned 16-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY = 23,
+	/* Unsigned 32-bit value; size of the IE DATA blob */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH = 24,
+	/* An array of IE_LENGTH x unsigned 8-bit value; blob of all the
+	 * information elements found in the beacon; this data should be a
+	 * packed list of wifi_information_element objects, one after the
+	 * other.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA = 25,
+
+	/* Unsigned 8-bit value; set by driver to indicate more scan results are
+	 * available.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA = 26,
+
+	/* GSCAN attributes for
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT sub-command.
+	 */
+	/* Unsigned 8-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE = 27,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_STATUS = 28,
+
+	/* GSCAN attributes for
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND sub-command.
+	 */
+	/* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+	 * to indicate number of results.
+	 * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the
+	 * list of results.
+	 */
+
+	/* GSCAN attributes for
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE sub-command.
+	 */
+	/* An array of 6 x unsigned 8-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID = 29,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL
+	= 30,
+	/* Unsigned 32-bit value. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI
+	= 31,
+	/* A nested array of signed 32-bit RSSI values. Size of the array is
+	 * determined by (NUM_RSSI of SIGNIFICANT_CHANGE_RESULT_NUM_RSSI.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST
+	= 32,
+
+	/* GSCAN attributes used with
+	 * QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS sub-command.
+	 */
+	/* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+	 * to indicate number of gscan cached results returned.
+	 * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST to indicate
+	 *  the list of gscan cached results.
+	 */
+
+	/* An array of NUM_RESULTS_AVAILABLE x
+	 * QCA_NL80211_VENDOR_ATTR_GSCAN_CACHED_RESULTS_*
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST = 33,
+	/* Unsigned 32-bit value; a unique identifier for the scan unit. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID = 34,
+	/* Unsigned 32-bit value; a bitmask w/additional information about scan.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS = 35,
+	/* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+	 * to indicate number of wifi scan results/bssids retrieved by the scan.
+	 * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the
+	 * list of wifi scan results returned for each cached result block.
+	 */
+
+	/* GSCAN attributes for
+	 * QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND sub-command.
+	 */
+	/* Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE for
+	 * number of results.
+	 * Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the nested
+	 * list of wifi scan results returned for each
+	 * wifi_passpoint_match_result block.
+	 * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE.
+	 */
+
+	/* GSCAN attributes for
+	 * QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND sub-command.
+	 */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES
+	= 36,
+	/* A nested array of
+	 * QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_*
+	 * attributes. Array size =
+	 * *_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST = 37,
+
+	/* Unsigned 32-bit value; network block id for the matched network */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID = 38,
+	/* Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the nested
+	 * list of wifi scan results returned for each
+	 * wifi_passpoint_match_result block.
+	 */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN = 39,
+	/* An array size of PASSPOINT_MATCH_ANQP_LEN of unsigned 8-bit values;
+	 * ANQP data in the information_element format.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP = 40,
+
+	/* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS = 41,
+	/* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS = 42,
+	/* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID
+	= 43,
+	/* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID
+	= 44,
+
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED = 45,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX =
+	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_pno_config_params {
+	QCA_WLAN_VENDOR_ATTR_PNO_INVALID = 0,
+	/* Attributes for data used by
+	 * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST sub command.
+	 */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM = 1,
+	/* Array of nested QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_*
+	 * attributes. Array size =
+	 * QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY = 2,
+
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID = 3,
+	/* An array of 256 x unsigned 8-bit value; NULL terminated UTF-8 encoded
+	 * realm, 0 if unspecified.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM = 4,
+	/* An array of 16 x unsigned 32-bit value; roaming consortium ids to
+	 * match, 0 if unspecified.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID = 5,
+	/* An array of 6 x unsigned 8-bit value; MCC/MNC combination, 0s if
+	 * unspecified.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN = 6,
+
+	/* Attributes for data used by
+	 * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST sub command.
+	 */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS = 7,
+	/* Array of nested
+	 * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_*
+	 * attributes. Array size =
+	 * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST = 8,
+	/* An array of 33 x unsigned 8-bit value; NULL terminated SSID */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID = 9,
+	/* Signed 8-bit value; threshold for considering this SSID as found,
+	 * required granularity for this threshold is 4 dBm to 8 dBm.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD
+	= 10,
+	/* Unsigned 8-bit value; WIFI_PNO_FLAG_XXX */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS = 11,
+	/* Unsigned 8-bit value; auth bit field for matching WPA IE */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT = 12,
+	/* Unsigned 8-bit to indicate ePNO type;
+	 * It takes values from qca_wlan_epno_type
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE = 13,
+
+	/* Nested attribute to send the channel list */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_CHANNEL_LIST = 14,
+
+	/* Unsigned 32-bit value; indicates the interval between PNO scan
+	 * cycles in msec.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_SCAN_INTERVAL = 15,
+	QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI = 16,
+	QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI = 17,
+	QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX = 18,
+	QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS = 19,
+	QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS = 20,
+	QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS = 21,
+	QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS = 22,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_PNO_MAX =
+	QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a87210e..6eb1e66 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -9,7 +9,6 @@
 #include "includes.h"
 
 #include "common.h"
-#include "utils/crc32.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
@@ -1621,7 +1620,7 @@
 }
 
 
-int wpa_cipher_to_alg(int cipher)
+enum wpa_alg wpa_cipher_to_alg(int cipher)
 {
 	switch (cipher) {
 	case WPA_CIPHER_CCMP_256:
@@ -1908,12 +1907,13 @@
 
 
 #ifdef CONFIG_FILS
-u16 fils_domain_name_hash(const char *domain)
+int fils_domain_name_hash(const char *domain, u8 *hash)
 {
 	char buf[255], *wpos = buf;
 	const char *pos = domain;
 	size_t len;
-	u32 crc;
+	const u8 *addr[1];
+	u8 mac[SHA256_MAC_LEN];
 
 	for (len = 0; len < sizeof(buf) && *pos; len++) {
 		if (isalpha(*pos) && isupper(*pos))
@@ -1923,7 +1923,10 @@
 		pos++;
 	}
 
-	crc = crc32((const u8 *) buf, len);
-	return crc & 0xffff;
+	addr[0] = (const u8 *) buf;
+	if (sha256_vector(1, addr, &len, mac) < 0)
+		return -1;
+	os_memcpy(hash, mac, 2);
+	return 0;
 }
 #endif /* CONFIG_FILS */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 6d28417..4e952c1 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -437,7 +437,7 @@
 
 int wpa_cipher_key_len(int cipher);
 int wpa_cipher_rsc_len(int cipher);
-int wpa_cipher_to_alg(int cipher);
+enum wpa_alg wpa_cipher_to_alg(int cipher);
 int wpa_cipher_valid_group(int cipher);
 int wpa_cipher_valid_pairwise(int cipher);
 int wpa_cipher_valid_mgmt_group(int cipher);
@@ -450,6 +450,6 @@
 int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
 int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
 unsigned int wpa_mic_len(int akmp);
-u16 fils_domain_name_hash(const char *domain);
+int fils_domain_name_hash(const char *domain, u8 *hash);
 
 #endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 4dcba81..ec4e879 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -288,6 +288,16 @@
 /* BSS Transition Management Request received with MBO transition reason */
 #define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON "
 
+/* parameters: <STA address> <dialog token> <ack=0/1> */
+#define BEACON_REQ_TX_STATUS "BEACON-REQ-TX-STATUS "
+/* parameters: <STA address> <dialog token> <report mode> <beacon report> */
+#define BEACON_RESP_RX "BEACON-RESP-RX "
+
+/* PMKSA cache entry added; parameters: <BSSID> <network_id> */
+#define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED "
+/* PMKSA cache entry removed; parameters: <BSSID> <network_id> */
+#define PMKSA_CACHE_REMOVED "PMKSA-CACHE-REMOVED "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
@@ -313,6 +323,9 @@
 #define WPA_BSS_MASK_SNR		BIT(19)
 #define WPA_BSS_MASK_EST_THROUGHPUT	BIT(20)
 #define WPA_BSS_MASK_FST		BIT(21)
+#define WPA_BSS_MASK_UPDATE_IDX		BIT(22)
+#define WPA_BSS_MASK_BEACON_IE		BIT(23)
+#define WPA_BSS_MASK_FILS_INDICATION	BIT(24)
 
 
 /* VENDOR_ELEM_* frame id values */
diff --git a/src/crypto/des-internal.c b/src/crypto/des-internal.c
index dec39ef..ebd9952 100644
--- a/src/crypto/des-internal.c
+++ b/src/crypto/des-internal.c
@@ -48,7 +48,7 @@
 
 static const u32 bytebit[8] =
 {
-	0200, 0100, 040, 020, 010, 04, 02, 01 
+	0200, 0100, 040, 020, 010, 04, 02, 01
 };
 
 static const u32 bigbyte[24] =
@@ -58,22 +58,22 @@
 	0x8000UL,    0x4000UL,    0x2000UL,    0x1000UL,
 	0x800UL,     0x400UL,     0x200UL,     0x100UL,
 	0x80UL,      0x40UL,      0x20UL,      0x10UL,
-	0x8UL,       0x4UL,       0x2UL,       0x1L 
+	0x8UL,       0x4UL,       0x2UL,       0x1L
 };
 
 /* Use the key schedule specific in the standard (ANSI X3.92-1981) */
 
 static const u8 pc1[56] = {
-	56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,  
-	 9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35, 
+	56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35,
 	62, 54, 46, 38, 30, 22, 14,  6, 61, 53, 45, 37, 29, 21,
-	13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3 
+	13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3
 };
 
 static const u8 totrot[16] = {
 	1,   2,  4,  6,
-	8,  10, 12, 14, 
-	15, 17, 19, 21, 
+	8,  10, 12, 14,
+	15, 17, 19, 21,
 	23, 25, 27, 28
 };
 
diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c
index ffcba66..a491707 100644
--- a/src/crypto/sha1-internal.c
+++ b/src/crypto/sha1-internal.c
@@ -53,7 +53,7 @@
 100% Public Domain
 
 -----------------
-Modified 7/98 
+Modified 7/98
 By James H. Brown <jbrown@burgoyne.com>
 Still 100% Public Domain
 
@@ -75,7 +75,7 @@
 be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
 "a"s).
 
-I also changed the declaration of variables i & j in SHA1Update to 
+I also changed the declaration of variables i & j in SHA1Update to
 unsigned long from unsigned int for the same reason.
 
 These changes should make no difference to any 32 bit implementations since
@@ -102,7 +102,7 @@
 Modified 4/01
 By Saul Kravitz <Saul.Kravitz@celera.com>
 Still 100% PD
-Modified to run on Compaq Alpha hardware.  
+Modified to run on Compaq Alpha hardware.
 
 -----------------
 Modified 4/01
@@ -162,7 +162,7 @@
 {
 	printf("%s (%d,%d) %x %x %x %x %x\n",
 	       msg,
-	       context->count[0], context->count[1], 
+	       context->count[0], context->count[1],
 	       context->state[0],
 	       context->state[1],
 	       context->state[2],
diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c
index 86a548e..ff1e2ba 100644
--- a/src/crypto/sha256-internal.c
+++ b/src/crypto/sha256-internal.c
@@ -69,7 +69,7 @@
 ( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
    ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
 #define Ch(x,y,z)       (z ^ (x & (y ^ z)))
-#define Maj(x,y,z)      (((x | y) & z) | (x & y)) 
+#define Maj(x,y,z)      (((x | y) & z) | (x & y))
 #define S(x, n)         RORc((x), (n))
 #define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
 #define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
@@ -100,7 +100,7 @@
 	for (i = 16; i < 64; i++) {
 		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
 			W[i - 16];
-	}        
+	}
 
 	/* Compress */
 #define RND(a,b,c,d,e,f,g,h,i)                          \
@@ -111,7 +111,7 @@
 
 	for (i = 0; i < 64; ++i) {
 		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
-		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; 
+		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
 		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
 	}
 
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 200f0ed..8c76bfa 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -402,7 +402,7 @@
 		return -1;
 	}
 
-	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 
+	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
 	 * to force peer validation(?) */
 
 	if (params->ca_cert) {
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 1abc282..4521891 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -972,6 +972,14 @@
 	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
 	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
 
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+	/* Number of deployed use cases assume the default OpenSSL behavior of
+	 * auto chaining the local certificate is in use. BoringSSL removed this
+	 * functionality by default, so we need to restore it here to avoid
+	 * breaking existing use cases. */
+	SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
+#endif /* SSL_MODE_NO_AUTO_CHAIN */
+
 	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
 	SSL_CTX_set_app_data(ssl, context);
 	if (data->tls_session_lifetime > 0) {
@@ -2254,10 +2262,8 @@
 #ifdef SSL_OP_NO_TICKET
 	if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_set_options(ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
 	else
 		SSL_clear_options(ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
 #endif /* SSL_OP_NO_TICKET */
 
 #ifdef SSL_OP_NO_TLSv1
@@ -4131,10 +4137,8 @@
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
-#ifdef SSL_CTX_clear_options
 	else
 		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
 #ifdef HAVE_OCSP
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 212f16c..291d4d6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -236,6 +236,9 @@
  * @est_throughput: Estimated throughput in kbps (this is calculated during
  * scan result processing if left zero by the driver wrapper)
  * @snr: Signal-to-noise ratio in dB (calculated during scan result processing)
+ * @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
+ * of TSF of the BSS specified by %tsf_bssid.
+ * @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
  * @ie_len: length of the following IE field in octets
  * @beacon_ie_len: length of the following Beacon IE field in octets
  *
@@ -266,6 +269,8 @@
 	unsigned int age;
 	unsigned int est_throughput;
 	int snr;
+	u64 parent_tsf;
+	u8 tsf_bssid[ETH_ALEN];
 	size_t ie_len;
 	size_t beacon_ie_len;
 	/* Followed by ie_len + beacon_ie_len octets of IE data */
@@ -472,6 +477,24 @@
 	 */
 	u64 scan_cookie;
 
+	 /**
+	  * duration - Dwell time on each channel
+	  *
+	  * This optional parameter can be used to set the dwell time on each
+	  * channel. In TUs.
+	  */
+	 u16 duration;
+
+	 /**
+	  * duration_mandatory - Whether the specified duration is mandatory
+	  *
+	  * If this is set, the duration specified by the %duration field is
+	  * mandatory (and the driver should reject the scan request if it is
+	  * unable to comply with the specified duration), otherwise it is the
+	  * maximum duration and the actual duration may be shorter.
+	  */
+	 unsigned int duration_mandatory:1;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -1470,6 +1493,11 @@
  */
 #define WPA_DRIVER_FLAGS_SUPPORT_RRM			0x00000010
 
+/** Driver supports setting the scan dwell time */
+#define WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL		0x00000020
+/** Driver supports Beacon Report Measurement */
+#define WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT		0x00000040
+
 	u32 rrm_flags;
 
 	/* Driver concurrency capabilities */
@@ -4684,6 +4712,11 @@
 	 * @external_scan: Whether the scan info is for an external scan
 	 * @nl_scan_event: 1 if the source of this scan event is a normal scan,
 	 * 	0 if the source of the scan event is a vendor scan
+	 * @scan_start_tsf: Time when the scan started in terms of TSF of the
+	 *	BSS that the interface that requested the scan is connected to
+	 *	(if available).
+	 * @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf
+	 *	is set.
 	 */
 	struct scan_info {
 		int aborted;
@@ -4693,6 +4726,8 @@
 		size_t num_ssids;
 		int external_scan;
 		int nl_scan_event;
+		u64 scan_start_tsf;
+		u8 scan_start_tsf_bssid[ETH_ALEN];
 	} scan_info;
 
 	/**
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 2afd7df..8621aa0 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -726,7 +726,7 @@
 }
 
 
-static int 
+static int
 bsd_flush(void *priv)
 {
 	u8 allsta[IEEE80211_ADDR_LEN];
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d5716db..5f0a277 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -204,6 +204,8 @@
 static int nl80211_put_mesh_config(struct nl_msg *msg,
 				   struct wpa_driver_mesh_bss_params *params);
 #endif /* CONFIG_MESH */
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+			     int reason);
 
 
 /* Converts nl80211_chan_width to a common format */
@@ -6016,6 +6018,14 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct ieee80211_mgmt mgmt;
+	u8 channel;
+
+	if (ieee80211_freq_to_chan(bss->freq, &channel) ==
+	    HOSTAPD_MODE_IEEE80211AD) {
+		/* Deauthentication is not used in DMG/IEEE 802.11ad;
+		 * disassociate the STA instead. */
+		return i802_sta_disassoc(priv, own_addr, addr, reason);
+	}
 
 	if (is_mesh_interface(drv->nlmode))
 		return -1;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 85706ef..cad3970 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -377,6 +377,18 @@
 	if (ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_BEACON_RATE_VHT))
 		capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SET_SCAN_DWELL))
+		capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SCAN_START_TIME) &&
+	    ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_BSS_PARENT_TSF) &&
+	    ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_SET_SCAN_DWELL))
+		capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT;
 }
 
 
@@ -1771,6 +1783,7 @@
 				os_free(result.modes[i].rates);
 			}
 			os_free(result.modes);
+			*num_modes = 0;
 			return NULL;
 		}
 		return wpa_driver_nl80211_postprocess_modes(result.modes,
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 66cfb72..de539b1 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1110,6 +1110,16 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
 			   msg);
 	}
+
+	if (tb[NL80211_ATTR_SCAN_START_TIME_TSF] &&
+	    tb[NL80211_ATTR_SCAN_START_TIME_TSF_BSSID]) {
+		info->scan_start_tsf =
+			nla_get_u64(tb[NL80211_ATTR_SCAN_START_TIME_TSF]);
+		os_memcpy(info->scan_start_tsf_bssid,
+			  nla_data(tb[NL80211_ATTR_SCAN_START_TIME_TSF_BSSID]),
+			  ETH_ALEN);
+	}
+
 	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
 }
 
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 43ed2b7..7dcfae2 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -270,6 +270,19 @@
 		}
 	}
 
+	if (params->duration) {
+		if (!(drv->capa.rrm_flags &
+		      WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) ||
+		    nla_put_u16(msg, NL80211_ATTR_MEASUREMENT_DURATION,
+				params->duration))
+			goto fail;
+
+		if (params->duration_mandatory &&
+		    nla_put_flag(msg,
+				 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY))
+			goto fail;
+	}
+
 	if (scan_flags &&
 	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
 		goto fail;
@@ -645,6 +658,8 @@
 		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
 		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
 		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+		[NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 },
+		[NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC },
 	};
 	struct wpa_scan_res *r;
 	const u8 *ie, *beacon_ie;
@@ -730,6 +745,12 @@
 		}
 	}
 
+	if (bss[NL80211_BSS_PARENT_TSF] && bss[NL80211_BSS_PARENT_BSSID]) {
+		r->parent_tsf = nla_get_u64(bss[NL80211_BSS_PARENT_TSF]);
+		os_memcpy(r->tsf_bssid, nla_data(bss[NL80211_BSS_PARENT_BSSID]),
+			  ETH_ALEN);
+	}
+
 	return r;
 }
 
@@ -1075,7 +1096,7 @@
 	}
 
 	if (scan_flags &&
-	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, scan_flags))
 		goto fail;
 
 	if (params->p2p_probe) {
@@ -1103,6 +1124,14 @@
 			goto fail;
 	}
 
+	if (params->bssid) {
+		wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
+			   MACSTR, MAC2STR(params->bssid));
+		if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_BSSID, ETH_ALEN,
+			    params->bssid))
+			goto fail;
+	}
+
 	nla_nest_end(msg, attr);
 
 	ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 8c93d26..655128a 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -97,7 +97,7 @@
 	return 0;
 }
 
-			     
+
 static int wpa_driver_privsep_scan(void *priv,
 				   struct wpa_driver_scan_params *params)
 {
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 9ef671c..57990d2 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -79,7 +79,7 @@
 
 	/*
 	 * RFC 4851, Section 5.1:
-	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
+	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
 	 *                       server_random + client_random, 48)
 	 */
 	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 7b013ee..932584f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -252,6 +252,14 @@
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
 	 */
 	void (*eap_proxy_cb)(void *ctx);
+
+	/**
+	 * eap_proxy_notify_sim_status - Notification of SIM status change
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @sim_state: One of enum value from sim_state
+	 */
+	void (*eap_proxy_notify_sim_status)(void *ctx,
+					    enum eap_proxy_sim_state sim_state);
 #endif /* CONFIG_EAP_PROXY */
 
 	/**
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 45ba381..efeddb8 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1082,7 +1082,7 @@
 				eap_peer_tls_derive_key(sm, &data->ssl, label,
 							EAP_TLS_KEY_LEN);
 			if (data->key_data) {
-				wpa_hexdump_key(MSG_DEBUG, 
+				wpa_hexdump_key(MSG_DEBUG,
 						"EAP-PEAP: Derived key",
 						data->key_data,
 						EAP_TLS_KEY_LEN);
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
index 23cdbe6..7205fad 100644
--- a/src/eap_peer/eap_proxy.h
+++ b/src/eap_peer/eap_proxy.h
@@ -20,7 +20,7 @@
 };
 
 struct eap_proxy_sm *
-eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
 	       void *msg_ctx);
 
 void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
index d84f012..08009ca 100644
--- a/src/eap_peer/eap_proxy_dummy.c
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -12,7 +12,7 @@
 #include "eap_proxy.h"
 
 struct eap_proxy_sm *
-eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
 	       void *msg_ctx)
 {
 	return NULL;
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 92f94dc..e4bc22f 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1537,7 +1537,7 @@
 }
 
 
-static void eap_ttls_check_auth_status(struct eap_sm *sm, 
+static void eap_ttls_check_auth_status(struct eap_sm *sm,
 				       struct eap_ttls_data *data,
 				       struct eap_method_ret *ret)
 {
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 2049172..f6d7e32 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -561,7 +561,7 @@
 		return -1;
 	}
 	data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
-		    
+
 	if (data->anon_provisioning) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
 		eap_fast_derive_key_provisioning(sm, data);
@@ -789,7 +789,7 @@
 
 	/* A-ID (inside PAC-Info) */
 	eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
-	
+
 	/* Note: headers may be misaligned after A-ID */
 
 	if (sm->identity) {
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 7fdb277..0dc7ea6 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -95,7 +95,7 @@
 		SUPP_BE_RECEIVE = 4,
 		SUPP_BE_RESPONSE = 5,
 		SUPP_BE_FAIL = 6,
-		SUPP_BE_TIMEOUT = 7, 
+		SUPP_BE_TIMEOUT = 7,
 		SUPP_BE_SUCCESS = 8
 	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
 	/* Variables */
@@ -1999,6 +1999,7 @@
 
 
 #ifdef CONFIG_EAP_PROXY
+
 static void eapol_sm_eap_proxy_cb(void *ctx)
 {
 	struct eapol_sm *sm = ctx;
@@ -2006,6 +2007,18 @@
 	if (sm->ctx->eap_proxy_cb)
 		sm->ctx->eap_proxy_cb(sm->ctx->ctx);
 }
+
+
+static void
+eapol_sm_eap_proxy_notify_sim_status(void *ctx,
+				     enum eap_proxy_sim_state sim_state)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->eap_proxy_notify_sim_status)
+		sm->ctx->eap_proxy_notify_sim_status(sm->ctx->ctx, sim_state);
+}
+
 #endif /* CONFIG_EAP_PROXY */
 
 
@@ -2034,6 +2047,7 @@
 	eapol_sm_notify_status,
 #ifdef CONFIG_EAP_PROXY
 	eapol_sm_eap_proxy_cb,
+	eapol_sm_eap_proxy_notify_sim_status,
 #endif /* CONFIG_EAP_PROXY */
 	eapol_sm_set_anon_id
 };
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index b48cab2..cb06e9a 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -277,6 +277,14 @@
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
 	 */
 	void (*eap_proxy_cb)(void *ctx);
+
+	/**
+	 * eap_proxy_notify_sim_status - Notification of SIM status change
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @status: One of enum value from sim_state
+	 */
+	void (*eap_proxy_notify_sim_status)(void *ctx,
+					    enum eap_proxy_sim_state sim_state);
 #endif /* CONFIG_EAP_PROXY */
 
 	/**
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index e26ca20..ce86802 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -51,7 +51,7 @@
 	return 0;
 }
 
-			     
+
 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
 {
 	os_memcpy(addr, l2->own_addr, ETH_ALEN);
@@ -258,7 +258,7 @@
 		unlink(l2->own_socket_path);
 		os_free(l2->own_socket_path);
 	}
-		
+
 	os_free(l2);
 }
 
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index cd2fba3..65dd1a3 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -711,6 +711,7 @@
 	struct p2p_message msg;
 	const u8 *p2p_dev_addr;
 	int wfd_changed;
+	int dev_name_changed;
 	int i;
 	struct os_reltime time_now;
 
@@ -821,6 +822,9 @@
 	}
 	dev->info.level = level;
 
+	dev_name_changed = os_strncmp(dev->info.device_name, msg.device_name,
+				      WPS_DEV_NAME_MAX_LEN) != 0;
+
 	p2p_copy_wps_info(p2p, dev, 0, &msg);
 
 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
@@ -839,9 +843,12 @@
 
 	wfd_changed = p2p_compare_wfd_info(dev, &msg);
 
-	if (msg.wfd_subelems) {
+	if (wfd_changed) {
 		wpabuf_free(dev->info.wfd_subelems);
-		dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+		if (msg.wfd_subelems)
+			dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+		else
+			dev->info.wfd_subelems = NULL;
 	}
 
 	if (scan_res) {
@@ -855,6 +862,7 @@
 	p2p_update_peer_vendor_elems(dev, ies, ies_len);
 
 	if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+	    !dev_name_changed &&
 	    (!msg.adv_service_instance ||
 	     (dev->flags & P2P_DEV_P2PS_REPORTED)))
 		return 0;
@@ -1833,6 +1841,7 @@
 	p2p_clear_timeout(p2p);
 	p2p->ssid_set = 0;
 	peer->go_neg_req_sent = 0;
+	peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
 	peer->wps_method = WPS_NOT_READY;
 	peer->oob_pw_id = 0;
 	wpabuf_free(peer->go_neg_conf);
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index a8bc5ba..d2fb4b5 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -426,6 +426,7 @@
 {
 	struct wpabuf *resp;
 	size_t max_len;
+	unsigned int wait_time = 200;
 
 	/*
 	 * In the 60 GHz, we have a smaller maximum frame length for management
@@ -460,6 +461,7 @@
 					     1, p2p->srv_update_indic, NULL);
 	} else {
 		p2p_dbg(p2p, "SD response fits in initial response");
+		wait_time = 0; /* no more SD frames in the sequence */
 		resp = p2p_build_sd_response(dialog_token,
 					     WLAN_STATUS_SUCCESS, 0,
 					     p2p->srv_update_indic, resp_tlvs);
@@ -470,7 +472,7 @@
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
-			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+			    wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
 		p2p_dbg(p2p, "Failed to send Action frame");
 
 	wpabuf_free(resp);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 1d6d9a9..1004b32 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1641,6 +1641,7 @@
 	ieee802_1x_cp_signal_newsak(kay->cp);
 	ieee802_1x_cp_sm_step(kay->cp);
 
+	kay->rcvd_keys++;
 	participant->to_use_sak = TRUE;
 
 	return 0;
@@ -3082,7 +3083,7 @@
  */
 struct ieee802_1x_kay *
 ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
-		    u16 port, const char *ifname, const u8 *addr)
+		    u16 port, u8 priority, const char *ifname, const u8 *addr)
 {
 	struct ieee802_1x_kay *kay;
 
@@ -3105,7 +3106,7 @@
 	os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
 	os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
 	kay->actor_sci.port = host_to_be16(port ? port : 0x0001);
-	kay->actor_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+	kay->actor_priority = priority;
 
 	/* While actor acts as a key server, shall distribute sakey */
 	kay->dist_kn = 1;
@@ -3519,3 +3520,51 @@
 
 	return 0;
 }
+
+
+#ifdef CONFIG_CTRL_IFACE
+/**
+ * ieee802_1x_kay_get_status - Get IEEE 802.1X KaY status details
+ * @sm: Pointer to KaY allocated with ieee802_1x_kay_init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ *
+ * Query KAY status information. This function fills in a text area with current
+ * status information. If the buffer (buf) is not large enough, status
+ * information will be truncated to fit the buffer.
+ */
+int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
+			      size_t buflen)
+{
+	int len;
+
+	if (!kay)
+		return 0;
+
+	len = os_snprintf(buf, buflen,
+			  "PAE KaY status=%s\n"
+			  "Authenticated=%s\n"
+			  "Secured=%s\n"
+			  "Failed=%s\n"
+			  "Actor Priority=%u\n"
+			  "Key Server Priority=%u\n"
+			  "Is Key Server=%s\n"
+			  "Number of Keys Distributed=%u\n"
+			  "Number of Keys Received=%u\n",
+			  kay->active ? "Active" : "Not-Active",
+			  kay->authenticated ? "Yes" : "No",
+			  kay->secured ? "Yes" : "No",
+			  kay->failed ? "Yes" : "No",
+			  kay->actor_priority,
+			  kay->key_server_priority,
+			  kay->is_key_server ? "Yes" : "No",
+			  kay->dist_kn - 1,
+			  kay->rcvd_keys);
+	if (os_snprintf_error(buflen, len))
+		return 0;
+
+	return len;
+}
+#endif /* CONFIG_CTRL_IFACE */
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 9a92d1c..8f394fd 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -208,6 +208,7 @@
 	int mka_algindex;  /* MKA alg table index */
 
 	u32 dist_kn;
+	u32 rcvd_keys;
 	u8 dist_an;
 	time_t dist_time;
 
@@ -235,7 +236,7 @@
 
 struct ieee802_1x_kay *
 ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
-		    u16 port, const char *ifname, const u8 *addr);
+		    u16 port, u8 priority, const char *ifname, const u8 *addr);
 void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
 
 struct ieee802_1x_mka_participant *
@@ -267,5 +268,7 @@
 int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
 				 struct ieee802_1x_mka_ki *lki);
 int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
+int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
+			      size_t buflen);
 
 #endif /* IEEE802_1X_KAY_H */
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 407e4f8..9ddc19b 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -210,7 +210,7 @@
 	{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
 	  RADIUS_ATTR_TEXT },
 	{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 
+	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
 	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
 	  RADIUS_ATTR_INT32 },
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 744283c..e8bef45 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -26,9 +26,14 @@
 #define RADIUS_SESSION_TIMEOUT 60
 
 /**
+ * RADIUS_SESSION_MAINTAIN - Completed session expiration timeout in seconds
+ */
+#define RADIUS_SESSION_MAINTAIN 5
+
+/**
  * RADIUS_MAX_SESSION - Maximum number of active sessions
  */
-#define RADIUS_MAX_SESSION 100
+#define RADIUS_MAX_SESSION 1000
 
 /**
  * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
@@ -1057,7 +1062,7 @@
 			     "message");
 		return -1;
 	}
-		      
+
 	eap = radius_msg_get_eap(msg);
 	if (eap == NULL && sess->macacl) {
 		reply = radius_server_macacl(data, client, sess, msg);
@@ -1172,7 +1177,7 @@
 			     sess->sess_id);
 		eloop_cancel_timeout(radius_server_session_remove_timeout,
 				     data, sess);
-		eloop_register_timeout(10, 0,
+		eloop_register_timeout(RADIUS_SESSION_MAINTAIN, 0,
 				       radius_server_session_remove_timeout,
 				       data, sess);
 	}
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index f06ed04..ce338f8 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -175,7 +175,8 @@
 
 static int wpa_supplicant_process_smk_m2(
 	struct wpa_sm *sm, const unsigned char *src_addr,
-	const struct wpa_eapol_key *key, size_t extra_len, int ver)
+	const struct wpa_eapol_key *key, const u8 *key_data,
+	size_t key_data_len, int ver)
 {
 	struct wpa_peerkey *peerkey;
 	struct wpa_eapol_ie_parse kde;
@@ -192,8 +193,7 @@
 		return -1;
 	}
 
-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
-	    0) {
+	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
 		return -1;
 	}
@@ -416,7 +416,7 @@
 	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
 
 	WPA_PUT_BE16(mic + mic_len, kde_len);
-	pos = mic + mic_len;
+	pos = mic + mic_len + 2;
 	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
 	lifetime = host_to_be32(peerkey->lifetime);
 	wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
@@ -511,7 +511,8 @@
 
 static int wpa_supplicant_process_smk_m45(
 	struct wpa_sm *sm, const unsigned char *src_addr,
-	const struct wpa_eapol_key *key, size_t extra_len, int ver)
+	const struct wpa_eapol_key *key, const u8 *key_data,
+	size_t key_data_len, int ver)
 {
 	struct wpa_peerkey *peerkey;
 	struct wpa_eapol_ie_parse kde;
@@ -523,8 +524,7 @@
 		return -1;
 	}
 
-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
-	    0) {
+	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
 		return -1;
 	}
@@ -590,7 +590,7 @@
 
 static int wpa_supplicant_process_smk_error(
 	struct wpa_sm *sm, const unsigned char *src_addr,
-	const struct wpa_eapol_key *key, size_t extra_len)
+	const u8 *key_data, size_t key_data_len)
 {
 	struct wpa_eapol_ie_parse kde;
 	struct rsn_error_kde error;
@@ -605,8 +605,7 @@
 		return -1;
 	}
 
-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
-	    0) {
+	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
 		return -1;
 	}
@@ -716,7 +715,8 @@
 
 	if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
 				       peerkey->pnonce, kde_buf, kde_buf_len,
-				       stk)) {
+				       stk) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to send STK message 2/4");
 		os_free(kde_buf);
 		return;
 	}
@@ -844,6 +844,10 @@
 			   "4-Way Handshake differs from 3 of STK 4-Way "
 			   "Handshake - drop packet (src=" MACSTR ")",
 			   MAC2STR(peerkey->addr));
+		wpa_hexdump(MSG_DEBUG, "RSN: INonce from message 1",
+			    peerkey->inonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "RSN: INonce from message 3",
+			    key->key_nonce, WPA_NONCE_LEN);
 		return;
 	}
 
@@ -851,8 +855,10 @@
 
 	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
 				       WPA_GET_BE16(key->key_info),
-				       &peerkey->stk))
+				       &peerkey->stk) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to send STK message 4/4");
 		return;
+	}
 
 	_key = peerkey->stk.tk;
 	if (peerkey->cipher == WPA_CIPHER_TKIP) {
@@ -1138,20 +1144,22 @@
 
 
 void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
-			  struct wpa_eapol_key *key, size_t extra_len,
+			  struct wpa_eapol_key *key, const u8 *key_data,
+			  size_t key_data_len,
 			  u16 key_info, u16 ver)
 {
 	if (key_info & WPA_KEY_INFO_ERROR) {
 		/* SMK Error */
-		wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
+		wpa_supplicant_process_smk_error(sm, src_addr, key_data,
+						 key_data_len);
 	} else if (key_info & WPA_KEY_INFO_ACK) {
 		/* SMK M2 */
-		wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
-					      ver);
+		wpa_supplicant_process_smk_m2(sm, src_addr, key, key_data,
+					      key_data_len, ver);
 	} else {
 		/* SMK M4 or M5 */
-		wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
-					       ver);
+		wpa_supplicant_process_smk_m45(sm, src_addr, key, key_data,
+					       key_data_len, ver);
 	}
 }
 
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index f3d07f3..02e12e9 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -44,8 +44,8 @@
 			   struct wpa_eapol_key *key, u16 key_info, u16 ver,
 			   const u8 *key_data, size_t key_data_len);
 void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
-			  struct wpa_eapol_key *key, size_t extra_len,
-			  u16 key_info, u16 ver);
+			  struct wpa_eapol_key *key, const u8 *key_data,
+			  size_t key_data_len, u16 key_info, u16 ver);
 void peerkey_deinit(struct wpa_sm *sm);
 
 #else /* CONFIG_PEERKEY */
@@ -68,8 +68,8 @@
 
 static inline void
 peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
-		     struct wpa_eapol_key *key, size_t extra_len,
-		     u16 key_info, u16 ver)
+		     struct wpa_eapol_key *key, const u8 *key_data,
+		     size_t key_data_len, u16 key_info, u16 ver)
 {
 }
 
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 3d8d122..f723bb0 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -43,7 +43,8 @@
 				   struct rsn_pmksa_cache_entry *entry,
 				   enum pmksa_free_reason reason)
 {
-	wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+	wpa_sm_remove_pmkid(pmksa->sm, entry->network_ctx, entry->aa,
+			    entry->pmkid);
 	pmksa->pmksa_count--;
 	pmksa->free_cb(entry, pmksa->ctx, reason);
 	_pmksa_cache_free_entry(entry);
@@ -128,7 +129,7 @@
 		const u8 *pmkid, const u8 *kck, size_t kck_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
-	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+	struct rsn_pmksa_cache_entry *entry;
 	struct os_reltime now;
 
 	if (pmk_len > PMK_LEN_MAX)
@@ -159,14 +160,25 @@
 	os_memcpy(entry->aa, aa, ETH_ALEN);
 	entry->network_ctx = network_ctx;
 
+	return pmksa_cache_add_entry(pmksa, entry);
+}
+
+
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+		      struct rsn_pmksa_cache_entry *entry)
+{
+	struct rsn_pmksa_cache_entry *pos, *prev;
+
 	/* Replace an old entry for the same Authenticator (if found) with the
 	 * new entry */
 	pos = pmksa->pmksa;
 	prev = NULL;
 	while (pos) {
-		if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
-			if (pos->pmk_len == pmk_len &&
-			    os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+		if (os_memcmp(entry->aa, pos->aa, ETH_ALEN) == 0) {
+			if (pos->pmk_len == entry->pmk_len &&
+			    os_memcmp_const(pos->pmk, entry->pmk,
+					    entry->pmk_len) == 0 &&
 			    os_memcmp_const(pos->pmkid, entry->pmkid,
 					    PMKID_LEN) == 0) {
 				wpa_printf(MSG_DEBUG, "WPA: reusing previous "
@@ -192,8 +204,8 @@
 				   "the current AP and any PMKSA cache entry "
 				   "that was based on the old PMK");
 			if (!pos->opportunistic)
-				pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
-						  pos->pmk_len);
+				pmksa_cache_flush(pmksa, entry->network_ctx,
+						  pos->pmk, pos->pmk_len);
 			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
 			break;
 		}
@@ -244,8 +256,9 @@
 	}
 	pmksa->pmksa_count++;
 	wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
-		   " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
-	wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+		   " network_ctx=%p", MAC2STR(entry->aa), entry->network_ctx);
+	wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa,
+			 entry->pmkid);
 
 	return entry;
 }
@@ -513,6 +526,12 @@
 }
 
 
+struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
+{
+	return pmksa->pmksa;
+}
+
+
 /**
  * pmksa_cache_init - Initialize PMKSA cache
  * @free_cb: Callback function to be called when a PMKSA cache entry is freed
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index daede6d..adc251a 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -55,10 +55,14 @@
 					       const u8 *aa, const u8 *pmkid,
 					       const void *network_ctx);
 int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		const u8 *pmkid, const u8 *kck, size_t kck_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+		      struct rsn_pmksa_cache_entry *entry);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -104,6 +108,19 @@
 }
 
 static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
+{
+	return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+		      struct rsn_pmksa_cache_entry *entry)
+{
+	return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		const u8 *pmkid, const u8 *kck, size_t kck_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 4c9a4fb..e83d073 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -342,7 +342,7 @@
 		/* Some drivers (e.g., NDIS) expect to get notified about the
 		 * PMKIDs again, so report the existing data now. */
 		if (p) {
-			wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
+			wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid);
 		}
 
 		dl_list_del(&candidate->list);
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 65e257a..365845f 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -79,7 +79,9 @@
 				ver, sm->key_mgmt);
 			goto out;
 		}
-		wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
+		if (ptk)
+			wpa_hexdump_key(MSG_DEBUG, "WPA: KCK",
+					ptk->kck, ptk->kck_len);
 		wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC",
 			    key_mic, mic_len);
 	} else {
@@ -2185,8 +2187,8 @@
 		}
 	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
 		/* PeerKey SMK Handshake */
-		peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
-				     ver);
+		peerkey_rx_eapol_smk(sm, src_addr, key, key_data, key_data_len,
+				     key_info, ver);
 	} else {
 		if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
 		    (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
@@ -3028,6 +3030,20 @@
 }
 
 
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm)
+{
+	return pmksa_cache_head(sm->pmksa);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm,
+			     struct rsn_pmksa_cache_entry * entry)
+{
+	return pmksa_cache_add_entry(sm->pmksa, entry);
+}
+
+
 void wpa_sm_drop_sa(struct wpa_sm *sm)
 {
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 20d5b8e..c9f278a 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -25,7 +25,7 @@
 
 	void (*set_state)(void *ctx, enum wpa_states state);
 	enum wpa_states (*get_state)(void *ctx);
-	void (*deauthenticate)(void * ctx, int reason_code); 
+	void (*deauthenticate)(void * ctx, int reason_code);
 	int (*set_key)(void *ctx, enum wpa_alg alg,
 		       const u8 *addr, int key_idx, int set_tx,
 		       const u8 *seq, size_t seq_len,
@@ -38,8 +38,10 @@
 	void (*cancel_auth_timeout)(void *ctx);
 	u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
 			    size_t *msg_len, void **data_pos);
-	int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
-	int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+	int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
+			 const u8 *pmkid);
+	int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
+			    const u8 *pmkid);
 	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
 	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
 							  const char *name);
@@ -147,6 +149,10 @@
 		    const u8 *buf, size_t len);
 int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
 int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm);
+struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm,
+			     struct rsn_pmksa_cache_entry * entry);
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
 
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 44d5424..180d468 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -219,18 +219,18 @@
 				    msg_len, data_pos);
 }
 
-static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
-				   const u8 *pmkid)
+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
+				   const u8 *bssid, const u8 *pmkid)
 {
 	WPA_ASSERT(sm->ctx->add_pmkid);
-	return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
+	return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid);
 }
 
-static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
-				      const u8 *pmkid)
+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
+				      const u8 *bssid, const u8 *pmkid)
 {
 	WPA_ASSERT(sm->ctx->remove_pmkid);
-	return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
+	return sm->ctx->remove_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid);
 }
 
 static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 8bc824f..4f7a148 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -116,7 +116,7 @@
       #define MP_PREC                 32     /* default digits of precision */
    #else
       #define MP_PREC                 8      /* default digits of precision */
-   #endif   
+   #endif
 #endif
 
 /* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
@@ -274,8 +274,8 @@
       *tmpc++ &= MP_MASK;
     }
 
-    /* now copy higher words if any, that is in A+B 
-     * if A or B has more digits add those in 
+    /* now copy higher words if any, that is in A+B
+     * if A or B has more digits add those in
      */
     if (min != max) {
       for (; i < max; i++) {
@@ -499,29 +499,29 @@
 #ifdef BN_MP_TOOM_MUL_C
   if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
     res = mp_toom_mul(a, b, c);
-  } else 
+  } else
 #endif
 #ifdef BN_MP_KARATSUBA_MUL_C
   /* use Karatsuba? */
   if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
     res = mp_karatsuba_mul (a, b, c);
-  } else 
+  } else
 #endif
   {
     /* can we use the fast multiplier?
      *
-     * The fast multiplier can be used if the output will 
-     * have less than MP_WARRAY digits and the number of 
+     * The fast multiplier can be used if the output will
+     * have less than MP_WARRAY digits and the number of
      * digits won't affect carry propagation
      */
 #ifdef BN_FAST_S_MP_MUL_DIGS_C
     int     digs = a->used + b->used + 1;
 
     if ((digs < MP_WARRAY) &&
-        MIN(a->used, b->used) <= 
+        MIN(a->used, b->used) <=
         (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
       res = fast_s_mp_mul_digs (a, b, c, digs);
-    } else 
+    } else
 #endif
 #ifdef BN_S_MP_MUL_DIGS_C
       res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
@@ -629,7 +629,7 @@
      err = mp_exptmod(&tmpG, &tmpX, P, Y);
      mp_clear_multi(&tmpG, &tmpX, NULL);
      return err;
-#else 
+#else
 #error mp_exptmod would always fail
      /* no invmod */
      return MP_VAL;
@@ -658,7 +658,7 @@
      dr = mp_reduce_is_2k(P) << 1;
   }
 #endif
-    
+
   /* if the modulus is odd or dr != 0 use the montgomery method */
 #ifdef BN_MP_EXPTMOD_FAST_C
   if (mp_isodd (P) == 1 || dr !=  0) {
@@ -693,7 +693,7 @@
         return MP_GT;
      }
   }
-  
+
   /* compare digits */
   if (a->sign == MP_NEG) {
      /* if negative compare opposite direction */
@@ -779,7 +779,7 @@
   }
 
   /* init temps */
-  if ((res = mp_init_multi(&x, &y, &u, &v, 
+  if ((res = mp_init_multi(&x, &y, &u, &v,
                            &A, &B, &C, &D, NULL)) != MP_OKAY) {
      return res;
   }
@@ -906,14 +906,14 @@
          goto LBL_ERR;
       }
   }
-  
+
   /* too big */
   while (mp_cmp_mag(&C, b) != MP_LT) {
       if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
          goto LBL_ERR;
       }
   }
-  
+
   /* C is now the inverse */
   mp_exch (&C, c);
   res = MP_OKAY;
@@ -933,7 +933,7 @@
   if (a->used > b->used) {
     return MP_GT;
   }
-  
+
   if (a->used < b->used) {
     return MP_LT;
   }
@@ -1199,8 +1199,8 @@
     /* top [offset into digits] */
     top = a->dp + b;
 
-    /* this is implemented as a sliding window where 
-     * the window is b-digits long and digits from 
+    /* this is implemented as a sliding window where
+     * the window is b-digits long and digits from
      * the top of the window are copied to the bottom
      *
      * e.g.
@@ -1218,13 +1218,13 @@
       *bottom++ = 0;
     }
   }
-  
+
   /* remove excess digits */
   a->used -= b;
 }
 
 
-/* swap the elements of two integers, for cases where you can't simply swap the 
+/* swap the elements of two integers, for cases where you can't simply swap the
  * mp_int pointers around
  */
 static void mp_exch (mp_int * a, mp_int * b)
@@ -1237,7 +1237,7 @@
 }
 
 
-/* trim unused digits 
+/* trim unused digits
  *
  * This is used to ensure that leading zero digits are
  * trimed and the leading "used" digit will be non-zero
@@ -1298,7 +1298,7 @@
 
 
 #ifdef BN_MP_ABS_C
-/* b = |a| 
+/* b = |a|
  *
  * Simple function copies the input and fixes the sign to positive
  */
@@ -1434,7 +1434,7 @@
       /* set the carry to the carry bits of the current word */
       r = rr;
     }
-    
+
     /* set final carry */
     if (r != 0) {
        c->dp[(c->used)++] = r;
@@ -1446,7 +1446,7 @@
 
 
 #ifdef BN_MP_INIT_MULTI_C
-static int mp_init_multi(mp_int *mp, ...) 
+static int mp_init_multi(mp_int *mp, ...)
 {
     mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
     int n = 0;                 /* Number of ok inits */
@@ -1460,11 +1460,11 @@
                succeeded in init-ing, then return error.
             */
             va_list clean_args;
-            
+
             /* end the current list */
             va_end(args);
-            
-            /* now start cleaning up */            
+
+            /* now start cleaning up */
             cur_arg = mp;
             va_start(clean_args, mp);
             while (n--) {
@@ -1484,7 +1484,7 @@
 
 
 #ifdef BN_MP_CLEAR_MULTI_C
-static void mp_clear_multi(mp_int *mp, ...) 
+static void mp_clear_multi(mp_int *mp, ...)
 {
     mp_int* next_mp = mp;
     va_list args;
@@ -1558,7 +1558,7 @@
 
   /* get number of digits and add that */
   r = (a->used - 1) * DIGIT_BIT;
-  
+
   /* take the last digit and count the bits in it */
   q = a->dp[a->used - 1];
   while (q > ((mp_digit) 0)) {
@@ -1628,7 +1628,7 @@
     }
     return res;
   }
-	
+
   /* init our temps */
   if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
      return res;
@@ -1638,7 +1638,7 @@
   mp_set(&tq, 1);
   n = mp_count_bits(a) - mp_count_bits(b);
   if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
-      ((res = mp_abs(b, &tb)) != MP_OKAY) || 
+      ((res = mp_abs(b, &tb)) != MP_OKAY) ||
       ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
       ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
       goto LBL_ERR;
@@ -1675,17 +1675,17 @@
 
 #else
 
-/* integer signed division. 
+/* integer signed division.
  * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
  * HAC pp.598 Algorithm 14.20
  *
- * Note that the description in HAC is horribly 
- * incomplete.  For example, it doesn't consider 
- * the case where digits are removed from 'x' in 
- * the inner loop.  It also doesn't consider the 
+ * Note that the description in HAC is horribly
+ * incomplete.  For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop.  It also doesn't consider the
  * case that y has fewer than three digits, etc..
  *
- * The overall algorithm is as described as 
+ * The overall algorithm is as described as
  * 14.20 from HAC but fixed to treat these cases.
 */
 static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
@@ -1775,7 +1775,7 @@
       continue;
     }
 
-    /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 
+    /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
      * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
     if (x.dp[i] == y.dp[t]) {
       q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
@@ -1789,10 +1789,10 @@
       q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
     }
 
-    /* while (q{i-t-1} * (yt * b + y{t-1})) > 
-             xi * b**2 + xi-1 * b + xi-2 
-     
-       do q{i-t-1} -= 1; 
+    /* while (q{i-t-1} * (yt * b + y{t-1})) >
+             xi * b**2 + xi-1 * b + xi-2
+
+       do q{i-t-1} -= 1;
     */
     q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
     do {
@@ -1843,10 +1843,10 @@
     }
   }
 
-  /* now q is the quotient and x is the remainder 
-   * [which we have to normalize] 
+  /* now q is the quotient and x is the remainder
+   * [which we have to normalize]
    */
-  
+
   /* get sign before writing to c */
   x.sign = x.used == 0 ? MP_ZPOS : a->sign;
 
@@ -1914,7 +1914,7 @@
   /* init M array */
   /* init first cell */
   if ((err = mp_init(&M[1])) != MP_OKAY) {
-     return err; 
+     return err;
   }
 
   /* now init the second half of the array */
@@ -1932,7 +1932,7 @@
   if ((err = mp_init (&mu)) != MP_OKAY) {
     goto LBL_M;
   }
-  
+
   if (redmode == 0) {
      if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
         goto LBL_MU;
@@ -1943,22 +1943,22 @@
         goto LBL_MU;
      }
      redux = mp_reduce_2k_l;
-  }    
+  }
 
   /* create M table
    *
-   * The M table contains powers of the base, 
+   * The M table contains powers of the base,
    * e.g. M[x] = G**x mod P
    *
-   * The first half of the table is not 
+   * The first half of the table is not
    * computed though accept for M[0] and M[1]
    */
   if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
     goto LBL_MU;
   }
 
-  /* compute the value at M[1<<(winsize-1)] by squaring 
-   * M[1] (winsize-1) times 
+  /* compute the value at M[1<<(winsize-1)] by squaring
+   * M[1] (winsize-1) times
    */
   if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
     goto LBL_MU;
@@ -1966,7 +1966,7 @@
 
   for (x = 0; x < (winsize - 1); x++) {
     /* square it */
-    if ((err = mp_sqr (&M[1 << (winsize - 1)], 
+    if ((err = mp_sqr (&M[1 << (winsize - 1)],
                        &M[1 << (winsize - 1)])) != MP_OKAY) {
       goto LBL_MU;
     }
@@ -2117,18 +2117,18 @@
   if (a->used >= TOOM_SQR_CUTOFF) {
     res = mp_toom_sqr(a, b);
   /* Karatsuba? */
-  } else 
+  } else
 #endif
 #ifdef BN_MP_KARATSUBA_SQR_C
 if (a->used >= KARATSUBA_SQR_CUTOFF) {
     res = mp_karatsuba_sqr (a, b);
-  } else 
+  } else
 #endif
   {
 #ifdef BN_FAST_S_MP_SQR_C
     /* can we use the fast comba multiplier? */
-    if ((a->used * 2 + 1) < MP_WARRAY && 
-         a->used < 
+    if ((a->used * 2 + 1) < MP_WARRAY &&
+         a->used <
          (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
       res = fast_s_mp_sqr (a, b);
     } else
@@ -2145,7 +2145,7 @@
 }
 
 
-/* reduces a modulo n where n is of the form 2**p - d 
+/* reduces a modulo n where n is of the form 2**p - d
    This differs from reduce_2k since "d" can be larger
    than a single digit.
 */
@@ -2153,33 +2153,33 @@
 {
    mp_int q;
    int    p, res;
-   
+
    if ((res = mp_init(&q)) != MP_OKAY) {
       return res;
    }
-   
-   p = mp_count_bits(n);    
+
+   p = mp_count_bits(n);
 top:
    /* q = a/2**p, a = a mod 2**p */
    if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
       goto ERR;
    }
-   
+
    /* q = q * d */
-   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { 
+   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
       goto ERR;
    }
-   
+
    /* a = a + q */
    if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
       goto ERR;
    }
-   
+
    if (mp_cmp_mag(a, n) != MP_LT) {
       s_mp_sub(a, n, a);
       goto top;
    }
-   
+
 ERR:
    mp_clear(&q);
    return res;
@@ -2191,26 +2191,26 @@
 {
    int    res;
    mp_int tmp;
-   
+
    if ((res = mp_init(&tmp)) != MP_OKAY) {
       return res;
    }
-   
+
    if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
       goto ERR;
    }
-   
+
    if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
       goto ERR;
    }
-   
+
 ERR:
    mp_clear(&tmp);
    return res;
 }
 
 
-/* computes a = 2**b 
+/* computes a = 2**b
  *
  * Simple algorithm which zeroes the int, grows it then just sets one bit
  * as required.
@@ -2243,7 +2243,7 @@
 static int mp_reduce_setup (mp_int * a, mp_int * b)
 {
   int     res;
-  
+
   if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
     return res;
   }
@@ -2251,7 +2251,7 @@
 }
 
 
-/* reduces x mod m, assumes 0 < x < m**2, mu is 
+/* reduces x mod m, assumes 0 < x < m**2, mu is
  * precomputed via mp_reduce_setup.
  * From HAC pp.604 Algorithm 14.42
  */
@@ -2266,7 +2266,7 @@
   }
 
   /* q1 = x / b**(k-1)  */
-  mp_rshd (&q, um - 1);         
+  mp_rshd (&q, um - 1);
 
   /* according to HAC this optimization is ok */
   if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
@@ -2282,8 +2282,8 @@
     if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
       goto CLEANUP;
     }
-#else 
-    { 
+#else
+    {
 #error mp_reduce would always fail
       res = MP_VAL;
       goto CLEANUP;
@@ -2292,7 +2292,7 @@
   }
 
   /* q3 = q2 / b**(k+1) */
-  mp_rshd (&q, um + 1);         
+  mp_rshd (&q, um + 1);
 
   /* x = x mod b**(k+1), quick (no division) */
   if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
@@ -2326,7 +2326,7 @@
       goto CLEANUP;
     }
   }
-  
+
 CLEANUP:
   mp_clear (&q);
 
@@ -2335,7 +2335,7 @@
 
 
 /* multiplies |a| * |b| and only computes up to digs digits of result
- * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
+ * HAC pp. 595, Algorithm 14.12  Modified so you can control how
  * many digits of output are created.
  */
 static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
@@ -2349,7 +2349,7 @@
 #ifdef BN_FAST_S_MP_MUL_DIGS_C
   /* can we use the fast multiplier? */
   if (((digs) < MP_WARRAY) &&
-      MIN (a->used, b->used) < 
+      MIN (a->used, b->used) <
           (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
     return fast_s_mp_mul_digs (a, b, c, digs);
   }
@@ -2372,10 +2372,10 @@
     /* setup some aliases */
     /* copy of the digit from a used within the nested loop */
     tmpx = a->dp[ix];
-    
+
     /* an alias for the destination shifted ix places */
     tmpt = t.dp + ix;
-    
+
     /* an alias for the digits of b */
     tmpy = b->dp;
 
@@ -2409,15 +2409,15 @@
 #ifdef BN_FAST_S_MP_MUL_DIGS_C
 /* Fast (comba) multiplier
  *
- * This is the fast column-array [comba] multiplier.  It is 
- * designed to compute the columns of the product first 
- * then handle the carries afterwards.  This has the effect 
+ * This is the fast column-array [comba] multiplier.  It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards.  This has the effect
  * of making the nested loops that compute the columns very
  * simple and schedulable on super-scalar processors.
  *
- * This has been modified to produce a variable number of 
- * digits of output so if say only a half-product is required 
- * you don't have to compute the upper half (a feature 
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
  * required for fast Barrett reduction).
  *
  * Based on Algorithm 14.12 on pp.595 of HAC.
@@ -2441,7 +2441,7 @@
 
   /* clear the carry */
   _W = 0;
-  for (ix = 0; ix < pa; ix++) { 
+  for (ix = 0; ix < pa; ix++) {
       int      tx, ty;
       int      iy;
       mp_digit *tmpx, *tmpy;
@@ -2454,7 +2454,7 @@
       tmpx = a->dp + tx;
       tmpy = b->dp + ty;
 
-      /* this is the number of times the loop will iterrate, essentially 
+      /* this is the number of times the loop will iterrate, essentially
          while (tx++ < a->used && ty-- >= 0) { ... }
        */
       iy = MIN(a->used-tx, ty+1);
@@ -2501,8 +2501,8 @@
   int x;
 
   /* pad size so there are always extra digits */
-  size += (MP_PREC * 2) - (size % MP_PREC);	
-  
+  size += (MP_PREC * 2) - (size % MP_PREC);
+
   /* alloc mem */
   a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
   if (a->dp == NULL) {
@@ -2556,7 +2556,7 @@
 
     /* alias for where to store the results */
     tmpt        = t.dp + (2*ix + 1);
-    
+
     for (iy = ix + 1; iy < pa; iy++) {
       /* first calculate the product */
       r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
@@ -2863,24 +2863,24 @@
 
     /* alias for source */
     tmpa = a->dp;
-    
+
     /* alias for dest */
     tmpb = b->dp;
 
     /* carry */
     r = 0;
     for (x = 0; x < a->used; x++) {
-    
-      /* get what will be the *next* carry bit from the 
-       * MSB of the current digit 
+
+      /* get what will be the *next* carry bit from the
+       * MSB of the current digit
        */
       rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
-      
+
       /* now shift up this digit, add in the carry [from the previous] */
       *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
-      
-      /* copy the carry that would be from the source 
-       * digit into the next iteration 
+
+      /* copy the carry that would be from the source
+       * digit into the next iteration
        */
       r = rr;
     }
@@ -2892,8 +2892,8 @@
       ++(b->used);
     }
 
-    /* now zero any excess digits on the destination 
-     * that we didn't write to 
+    /* now zero any excess digits on the destination
+     * that we didn't write to
      */
     tmpb = b->dp + b->used;
     for (x = b->used; x < oldused; x++) {
@@ -3011,7 +3011,7 @@
 
   /* determine and setup reduction code */
   if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_SETUP_C     
+#ifdef BN_MP_MONTGOMERY_SETUP_C
      /* now setup montgomery  */
      if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
         goto LBL_M;
@@ -3026,7 +3026,7 @@
      if (((P->used * 2 + 1) < MP_WARRAY) &&
           P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
         redux = fast_mp_montgomery_reduce;
-     } else 
+     } else
 #endif
      {
 #ifdef BN_MP_MONTGOMERY_REDUCE_C
@@ -3077,7 +3077,7 @@
      if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
        goto LBL_RES;
      }
-#else 
+#else
      err = MP_VAL;
      goto LBL_RES;
 #endif
@@ -3245,10 +3245,10 @@
 
 #ifdef BN_FAST_S_MP_SQR_C
 /* the jist of squaring...
- * you do like mult except the offset of the tmpx [one that 
- * starts closer to zero] can't equal the offset of tmpy.  
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
  * So basically you set up iy like before then you min it with
- * (ty-tx) so that it never happens.  You double all those 
+ * (ty-tx) so that it never happens.  You double all those
  * you add in the inner loop
 
 After that loop you do the squares and add them in.
@@ -3270,7 +3270,7 @@
 
   /* number of output digits to produce */
   W1 = 0;
-  for (ix = 0; ix < pa; ix++) { 
+  for (ix = 0; ix < pa; ix++) {
       int      tx, ty, iy;
       mp_word  _W;
       mp_digit *tmpy;
@@ -3291,7 +3291,7 @@
        */
       iy = MIN(a->used-tx, ty+1);
 
-      /* now for squaring tx can never equal ty 
+      /* now for squaring tx can never equal ty
        * we halve the distance since they approach at a rate of 2x
        * and we have to round because odd cases need to be executed
        */
diff --git a/src/tls/rsa.c b/src/tls/rsa.c
index 0b7b530..3525eb9 100644
--- a/src/tls/rsa.c
+++ b/src/tls/rsa.c
@@ -80,7 +80,7 @@
 	 * PKCS #1, 7.1:
 	 * RSAPublicKey ::= SEQUENCE {
 	 *     modulus INTEGER, -- n
-	 *     publicExponent INTEGER -- e 
+	 *     publicExponent INTEGER -- e
 	 * }
 	 */
 
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 9bc0d21..76e1974 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -264,7 +264,7 @@
  * @in_data: Pointer to plaintext data to be encrypted
  * @in_len: Input buffer length
  * @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length 
+ * @out_len: Maximum out_data length
  * Returns: Number of bytes written to out_data, -1 on failure
  *
  * This function is used after TLS handshake has been completed successfully to
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 67b55db..e178915 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -21,7 +21,7 @@
  * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
  * Add support for commonly used cipher suites; don't bother with exportable
  * suites.
- */ 
+ */
 
 static const struct tls_cipher_suite tls_cipher_suites[] = {
 	{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index ba47337..5406969 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -216,7 +216,7 @@
  * @in_data: Pointer to plaintext data to be encrypted
  * @in_len: Input buffer length
  * @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length 
+ * @out_len: Maximum out_data length
  * Returns: Number of bytes written to out_data, -1 on failure
  *
  * This function is used after TLS handshake has been completed successfully to
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 75f222c..0d6ee67 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -2039,7 +2039,7 @@
 
 	for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
 		cert->issuer_trusted = 0;
-		x509_name_string(&cert->subject, buf, sizeof(buf)); 
+		x509_name_string(&cert->subject, buf, sizeof(buf));
 		wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
 
 		if (chain_trusted)
@@ -2063,11 +2063,11 @@
 				wpa_printf(MSG_DEBUG, "X509: Certificate "
 					   "chain issuer name mismatch");
 				x509_name_string(&cert->issuer, buf,
-						 sizeof(buf)); 
+						 sizeof(buf));
 				wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
 					   buf);
 				x509_name_string(&cert->next->subject, buf,
-						 sizeof(buf)); 
+						 sizeof(buf));
 				wpa_printf(MSG_DEBUG, "X509: next cert "
 					   "subject: %s", buf);
 				*reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
diff --git a/src/utils/common.c b/src/utils/common.c
index 04a533a..1eb3370 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -1200,3 +1200,24 @@
 {
 	return os_strncmp(str, start, os_strlen(start)) == 0;
 }
+
+
+/**
+ * rssi_to_rcpi - Convert RSSI to RCPI
+ * @rssi: RSSI to convert
+ * Returns: RCPI corresponding to the given RSSI value, or 255 if not available.
+ *
+ * It's possible to estimate RCPI based on RSSI in dBm. This calculation will
+ * not reflect the correct value for high rates, but it's good enough for Action
+ * frames which are transmitted with up to 24 Mbps rates.
+ */
+u8 rssi_to_rcpi(int rssi)
+{
+	if (!rssi)
+		return 255; /* not available */
+	if (rssi < -110)
+		return 0;
+	if (rssi > 0)
+		return 220;
+	return (rssi + 110) * 2;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 7785677..8842864 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -552,6 +552,7 @@
 
 int str_starts(const char *str, const char *start);
 
+u8 rssi_to_rcpi(int rssi);
 
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index ca09ef0..71e08e7 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -92,7 +92,10 @@
 OBJS += src/utils/common.c
 OBJS += src/utils/wpa_debug.c
 OBJS += src/utils/wpabuf.c
+OBJS += src/utils/bitfield.c
 OBJS += wmm_ac.c
+OBJS += op_classes.c
+OBJS += rrm.c
 OBJS_p = wpa_passphrase.c
 OBJS_p += src/utils/common.c
 OBJS_p += src/utils/wpa_debug.c
@@ -269,6 +272,10 @@
 L_CFLAGS += -DCONFIG_PEERKEY
 endif
 
+ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+L_CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL
+endif
+
 ifndef CONFIG_NO_WPA
 OBJS += src/rsn_supp/wpa.c
 OBJS += src/rsn_supp/preauth.c
@@ -305,7 +312,6 @@
 OBJS += src/p2p/p2p_dev_disc.c
 OBJS += src/p2p/p2p_group.c
 OBJS += src/ap/p2p_hostapd.c
-OBJS += src/utils/bitfield.c
 L_CFLAGS += -DCONFIG_P2P
 NEED_GAS=y
 NEED_OFFCHANNEL=y
@@ -1650,10 +1656,7 @@
 LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
 LOCAL_C_INCLUDES = $(INCLUDES)
 LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_COPY_HEADERS_TO := libwpa_client
-LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
-LOCAL_COPY_HEADERS += src/common/qca-vendor.h
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/wpa_client_include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/wpa_client_include $(LOCAL_PATH)/wpa_client_include/libwpa_client
 include $(BUILD_SHARED_LIBRARY)
 
 ifeq ($(WPA_SUPPLICANT_USE_HIDL), y)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index e56ce97..dae6911 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -103,6 +103,9 @@
 OBJS += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
 OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/bitfield.o
+OBJS += op_classes.o
+OBJS += rrm.o
 OBJS_p = wpa_passphrase.o
 OBJS_p += ../src/utils/common.o
 OBJS_p += ../src/utils/wpa_debug.o
@@ -302,6 +305,10 @@
 CFLAGS += -DCONFIG_PEERKEY
 endif
 
+ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL
+endif
+
 ifndef CONFIG_NO_WPA
 OBJS += ../src/rsn_supp/wpa.o
 OBJS += ../src/rsn_supp/preauth.o
@@ -346,7 +353,6 @@
 OBJS += ../src/p2p/p2p_dev_disc.o
 OBJS += ../src/p2p/p2p_group.o
 OBJS += ../src/ap/p2p_hostapd.o
-OBJS += ../src/utils/bitfield.o
 CFLAGS += -DCONFIG_P2P
 NEED_GAS=y
 NEED_OFFCHANNEL=y
@@ -1598,9 +1604,6 @@
 ifdef CONFIG_WPS
 OBJS += ../src/wps/wps_module_tests.o
 endif
-ifndef CONFIG_P2P
-OBJS += ../src/utils/bitfield.o
-endif
 endif
 
 OBJS += ../src/drivers/driver_common.o
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 54564f6..730714b 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
@@ -83,7 +83,7 @@
 	  authentication)
   (following methods are supported, but since they do not generate keying
    material, they cannot be used with WPA or IEEE 802.1X WEP keying)
-  * EAP-MD5-Challenge 
+  * EAP-MD5-Challenge
   * EAP-MSCHAPv2
   * EAP-GTC
   * EAP-OTP
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 2a5c810..f320667 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -489,4 +489,9 @@
 # Support Multi Band Operation
 #CONFIG_MBO=y
 
+# External PMKSA cache control
+# This can be used to enable control interface commands that allow the current
+# PMKSA cache entries to be fetched and new entries to be added.
+#CONFIG_PMKSA_CACHE_EXTERNAL=y
+
 include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index a467cc5..bae72b9 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -56,12 +56,7 @@
 	} else {
 		if (data->scan_interval == data->short_interval) {
 			data->short_scan_count++;
-			/*
-			 * Spend at most the duration of a long scan interval
-			 * scanning at the short scan interval. After that,
-			 * revert to the long scan interval.
-			 */
-			if (data->short_scan_count > data->max_short_scans) {
+			if (data->short_scan_count >= data->max_short_scans) {
 				data->scan_interval = data->long_interval;
 				wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
 					   "off to long scan interval");
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 44a9a7b..914bd5d 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -93,6 +93,7 @@
 	ANQP_DUP(nai_realm);
 	ANQP_DUP(anqp_3gpp);
 	ANQP_DUP(domain_name);
+	ANQP_DUP(fils_realm_info);
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
 	ANQP_DUP(hs20_capability_list);
@@ -168,6 +169,7 @@
 	wpabuf_free(anqp->nai_realm);
 	wpabuf_free(anqp->anqp_3gpp);
 	wpabuf_free(anqp->domain_name);
+	wpabuf_free(anqp->fils_realm_info);
 
 	while ((elem = dl_list_first(&anqp->anqp_elems,
 				     struct wpa_bss_anqp_elem, list))) {
@@ -267,9 +269,9 @@
 }
 
 
-static void calculate_update_time(const struct os_reltime *fetch_time,
-				  unsigned int age_ms,
-				  struct os_reltime *update_time)
+void calculate_update_time(const struct os_reltime *fetch_time,
+			   unsigned int age_ms,
+			   struct os_reltime *update_time)
 {
 	os_time_t usec;
 
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 84e8fb0..84505fa 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -40,6 +40,7 @@
 	struct wpabuf *nai_realm;
 	struct wpabuf *anqp_3gpp;
 	struct wpabuf *domain_name;
+	struct wpabuf *fils_realm_info;
 	struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
@@ -167,4 +168,8 @@
 		bss->level = new_level;
 }
 
+void calculate_update_time(const struct os_reltime *fetch_time,
+			   unsigned int age_ms,
+			   struct os_reltime *update_time);
+
 #endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2120a6e..2a26d2d 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "utils/uuid.h"
 #include "utils/ip_addr.h"
+#include "common/ieee802_1x_defs.h"
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
@@ -2127,6 +2128,7 @@
 	{ INT_RANGE(macsec_policy, 0, 1) },
 	{ INT_RANGE(macsec_integ_only, 0, 1) },
 	{ INT_RANGE(macsec_port, 1, 65534) },
+	{ INT_RANGE(mka_priority, 0, 255) },
 	{ FUNC_KEY(mka_cak) },
 	{ FUNC_KEY(mka_ckn) },
 #endif /* CONFIG_MACSEC */
@@ -2617,6 +2619,9 @@
 #ifdef CONFIG_IEEE80211W
 	ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MACSEC
+	ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+#endif /* CONFIG_MACSEC */
 	ssid->mac_addr = -1;
 }
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 2e3d57e..98e3591 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -19,6 +19,7 @@
 #include "config.h"
 #include "base64.h"
 #include "uuid.h"
+#include "common/ieee802_1x_defs.h"
 #include "p2p/p2p.h"
 #include "eap_peer/eap_methods.h"
 #include "eap_peer/eap.h"
@@ -136,6 +137,9 @@
 		wpa_config_update_psk(ssid);
 	}
 
+	if (ssid->disabled == 2)
+		ssid->p2p_persistent_group = 1;
+
 	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
 	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
 	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
@@ -810,6 +814,7 @@
 	write_mka_ckn(f, ssid);
 	INT(macsec_integ_only);
 	INT(macsec_port);
+	INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	INT(update_identifier);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index fe0f7fa..69ace37 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -751,6 +751,13 @@
 	int macsec_port;
 
 	/**
+	 * mka_priority - Priority of MKA Actor
+	 *
+	 * Range: 0-255 (default: 255)
+	 */
+	int mka_priority;
+
+	/**
 	 * mka_ckn - MKA pre-shared CKN
 	 */
 #define MACSEC_CKN_LEN 32
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a754943..be178d7 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2050,6 +2050,12 @@
 			pos += res;
 	}
 
+#ifdef CONFIG_MACSEC
+	res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos);
+	if (res > 0)
+		pos += res;
+#endif /* CONFIG_MACSEC */
+
 	sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
 	if (sess_id) {
 		char *start = pos;
@@ -4101,13 +4107,85 @@
 #endif /* CONFIG_INTERWORKING */
 
 
+#ifdef CONFIG_FILS
+static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end)
+{
+	char *start = pos;
+	const u8 *ie, *ie_end;
+	u16 info, realms;
+	int ret;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+	if (!ie)
+		return 0;
+	ie_end = ie + 2 + ie[1];
+	ie += 2;
+	if (ie_end - ie < 2)
+		return -1;
+
+	info = WPA_GET_LE16(ie);
+	ie += 2;
+	ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info);
+	if (os_snprintf_error(end - pos, ret))
+		return 0;
+	pos += ret;
+
+	if (info & BIT(7)) {
+		/* Cache Identifier Included */
+		if (ie_end - ie < 2)
+			return -1;
+		ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n",
+				  ie[0], ie[1]);
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+		ie += 2;
+	}
+
+	if (info & BIT(8)) {
+		/* HESSID Included */
+		if (ie_end - ie < ETH_ALEN)
+			return -1;
+		ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n",
+				  MAC2STR(ie));
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+		ie += ETH_ALEN;
+	}
+
+	realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3;
+	if (realms) {
+		if (ie_end - ie < realms * 2)
+			return -1;
+		ret = os_snprintf(pos, end - pos, "fils_realms=");
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+
+		ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2);
+		if (ret <= 0)
+			return 0;
+		pos += ret;
+		ie += realms * 2;
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+	}
+
+	return pos - start;
+}
+#endif /* CONFIG_FILS */
+
+
 static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			  unsigned long mask, char *buf, size_t buflen)
 {
 	size_t i;
 	int ret;
 	char *pos, *end;
-	const u8 *ie, *ie2, *osen_ie;
+	const u8 *ie, *ie2, *osen_ie, *mesh;
 
 	pos = buf;
 	end = buf + buflen;
@@ -4216,13 +4294,16 @@
 			return 0;
 		pos += ret;
 
+		mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
+
 		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
 		if (ie)
 			pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
 						    2 + ie[1]);
 		ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 		if (ie2)
-			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
+			pos = wpa_supplicant_ie_txt(pos, end,
+						    mesh ? "RSN" : "WPA2", ie2,
 						    2 + ie2[1]);
 		osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
 		if (osen_ie)
@@ -4236,6 +4317,14 @@
 				return 0;
 			pos += ret;
 		}
+
+		if (mesh) {
+			ret = os_snprintf(pos, end - pos, "[MESH]");
+			if (os_snprintf_error(end - pos, ret))
+				return 0;
+			pos += ret;
+		}
+
 		if (bss_is_dmg(bss)) {
 			const char *s;
 			ret = os_snprintf(pos, end - pos, "[DMG]");
@@ -4381,6 +4470,8 @@
 		pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
 		pos = anqp_add_hex(pos, end, "anqp_domain_name",
 				   anqp->domain_name);
+		pos = anqp_add_hex(pos, end, "anqp_fils_realm_info",
+				   anqp->fils_realm_info);
 #ifdef CONFIG_HS20
 		pos = anqp_add_hex(pos, end, "hs20_capability_list",
 				   anqp->hs20_capability_list);
@@ -4442,6 +4533,44 @@
 	}
 #endif /* CONFIG_FST */
 
+	if (mask & WPA_BSS_MASK_UPDATE_IDX) {
+		ret = os_snprintf(pos, end - pos, "update_idx=%u\n",
+				  bss->last_update_idx);
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+	}
+
+	if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) {
+		ret = os_snprintf(pos, end - pos, "beacon_ie=");
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+
+		ie = (const u8 *) (bss + 1);
+		ie += bss->ie_len;
+		for (i = 0; i < bss->beacon_ie_len; i++) {
+			ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+			if (os_snprintf_error(end - pos, ret))
+				return 0;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+	}
+
+#ifdef CONFIG_FILS
+	if (mask & WPA_BSS_MASK_FILS_INDICATION) {
+		ret = print_fils_indication(bss, pos, end);
+		if (ret < 0)
+			return 0;
+		pos += ret;
+	}
+#endif /* CONFIG_FILS */
+
 	if (mask & WPA_BSS_MASK_DELIM) {
 		ret = os_snprintf(pos, end - pos, "====\n");
 		if (os_snprintf_error(end - pos, ret))
@@ -4532,6 +4661,8 @@
 				bss = dl_list_entry(next, struct wpa_bss,
 						    list_id);
 		}
+	} else if (os_strncmp(cmd, "CURRENT", 7) == 0) {
+		bss = wpa_s->current_bss;
 #ifdef CONFIG_P2P
 	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
 		if (hwaddr_aton(cmd + 13, bssid) == 0)
@@ -7180,7 +7311,8 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
 
-	wpas_abort_ongoing_scan(wpa_s);
+	if (wpas_abort_ongoing_scan(wpa_s) == 0)
+		wpa_s->ignore_post_flush_scan_res = 1;
 
 	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
 		/*
@@ -8705,6 +8837,154 @@
 }
 
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+
+static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
+				     const char *cmd, char *buf, size_t buflen)
+{
+	struct rsn_pmksa_cache_entry *entry;
+	struct wpa_ssid *ssid;
+	char *pos, *pos2, *end;
+	int ret;
+	struct os_reltime now;
+
+	ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+	if (!ssid)
+		return -1;
+
+	pos = buf;
+	end = buf + buflen;
+
+	os_get_reltime(&now);
+
+	/*
+	 * Entry format:
+	 * <BSSID> <PMKID> <PMK> <reauth_time in seconds>
+	 * <expiration in seconds> <akmp> <opportunistic>
+	 */
+
+	for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry;
+	     entry = entry->next) {
+		if (entry->network_ctx != ssid)
+			continue;
+
+		pos2 = pos;
+		ret = os_snprintf(pos2, end - pos2, MACSTR " ",
+				  MAC2STR(entry->aa));
+		if (os_snprintf_error(end - pos2, ret))
+			break;
+		pos2 += ret;
+
+		pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid,
+					 PMKID_LEN);
+
+		ret = os_snprintf(pos2, end - pos2, " ");
+		if (os_snprintf_error(end - pos2, ret))
+			break;
+		pos2 += ret;
+
+		pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk,
+					 entry->pmk_len);
+
+		ret = os_snprintf(pos2, end - pos2, " %d %d %d %d",
+				  (int) (entry->reauth_time - now.sec),
+				  (int) (entry->expiration - now.sec),
+				  entry->akmp,
+				  entry->opportunistic);
+		if (os_snprintf_error(end - pos2, ret))
+			break;
+		pos2 += ret;
+
+		ret = os_snprintf(pos2, end - pos2, "\n");
+		if (os_snprintf_error(end - pos2, ret))
+			break;
+		pos2 += ret;
+
+		pos = pos2;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
+				     char *cmd)
+{
+	struct rsn_pmksa_cache_entry *entry;
+	struct wpa_ssid *ssid;
+	char *pos, *pos2;
+	int ret = -1;
+	struct os_reltime now;
+	int reauth_time = 0, expiration = 0;
+
+	/*
+	 * Entry format:
+	 * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds>
+	 * <expiration in seconds> <akmp> <opportunistic>
+	 */
+
+	ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+	if (!ssid)
+		return -1;
+
+	pos = os_strchr(cmd, ' ');
+	if (!pos)
+		return -1;
+	pos++;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (!entry)
+		return -1;
+
+	if (hwaddr_aton(pos, entry->aa))
+		goto fail;
+
+	pos = os_strchr(pos, ' ');
+	if (!pos)
+		goto fail;
+	pos++;
+
+	if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0)
+		goto fail;
+
+	pos = os_strchr(pos, ' ');
+	if (!pos)
+		goto fail;
+	pos++;
+
+	pos2 = os_strchr(pos, ' ');
+	if (!pos2)
+		goto fail;
+	entry->pmk_len = (pos2 - pos) / 2;
+	if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX ||
+	    hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0)
+		goto fail;
+
+	pos = os_strchr(pos, ' ');
+	if (!pos)
+		goto fail;
+	pos++;
+
+	if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
+		   &entry->akmp, &entry->opportunistic) != 4)
+		goto fail;
+	os_get_reltime(&now);
+	entry->expiration = now.sec + expiration;
+	entry->reauth_time = now.sec + reauth_time;
+
+	entry->network_ctx = ssid;
+
+	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+	entry = NULL;
+	ret = 0;
+fail:
+	os_free(entry);
+	return ret;
+}
+
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
 static int wpas_ctrl_cmd_debug_level(const char *cmd)
 {
 	if (os_strcmp(cmd, "PING") == 0 ||
@@ -8779,6 +9059,14 @@
 		reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
 	} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
 		wpas_ctrl_iface_pmksa_flush(wpa_s);
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+	} else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) {
+		reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10,
+						      reply, reply_size);
+	} else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
+		if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0)
+			reply_len = -1;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 	} else if (os_strncmp(buf, "SET ", 4) == 0) {
 		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
 			reply_len = -1;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 69fb8f4..a601182 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3234,6 +3234,42 @@
 	  wpas_dbus_setter_config_methods,
 	  NULL
 	},
+	{
+	  "DeviceName", WPAS_DBUS_NEW_IFACE_WPS, "s",
+	  wpas_dbus_getter_wps_device_name,
+	  wpas_dbus_setter_wps_device_name,
+	  NULL
+	},
+	{
+	  "Manufacturer", WPAS_DBUS_NEW_IFACE_WPS, "s",
+	  wpas_dbus_getter_wps_manufacturer,
+	  wpas_dbus_setter_wps_manufacturer,
+	  NULL
+	},
+	{
+	  "ModelName", WPAS_DBUS_NEW_IFACE_WPS, "s",
+	  wpas_dbus_getter_wps_device_model_name,
+	  wpas_dbus_setter_wps_device_model_name,
+	  NULL
+	},
+	{
+	  "ModelNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
+	  wpas_dbus_getter_wps_device_model_number,
+	  wpas_dbus_setter_wps_device_model_number,
+	  NULL
+	},
+	{
+	  "SerialNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
+	  wpas_dbus_getter_wps_device_serial_number,
+	  wpas_dbus_setter_wps_device_serial_number,
+	  NULL
+	},
+	{
+	  "DeviceType", WPAS_DBUS_NEW_IFACE_WPS, "ay",
+	  wpas_dbus_getter_wps_device_device_type,
+	  wpas_dbus_setter_wps_device_device_type,
+	  NULL
+	},
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
 	{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index e11dd36..7446f8d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -517,6 +517,27 @@
 
 
 /**
+ * wpas_dbus_string_property_getter - Get string type property
+ * @iter: Message iter to use when appending arguments
+ * @val: Pointer to place holding property value, can be %NULL
+ * @error: On failure an error describing the failure
+ * Returns: TRUE if the request was successful, FALSE if it failed
+ *
+ * Generic getter for string type properties. %NULL is converted to an empty
+ * string.
+ */
+dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
+					     const void *val,
+					     DBusError *error)
+{
+	if (!val)
+		val = "";
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&val, error);
+}
+
+
+/**
  * wpas_dbus_handler_create_interface - Request registration of a network iface
  * @message: Pointer to incoming dbus message
  * @global: %wpa_supplicant global data structure
@@ -3086,10 +3107,8 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	const char *ifname = wpa_s->ifname;
 
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&ifname, error);
+	return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
 }
 
 
@@ -3107,7 +3126,6 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	const char *driver;
 
 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
 		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
@@ -3117,9 +3135,8 @@
 		return FALSE;
 	}
 
-	driver = wpa_s->driver->name;
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&driver, error);
+	return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
+						error);
 }
 
 
@@ -3232,10 +3249,9 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	const char *bridge_ifname = wpa_s->bridge_ifname;
 
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&bridge_ifname, error);
+	return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
+						error);
 }
 
 
@@ -3253,13 +3269,8 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	char *confname = "";
 
-	if (wpa_s->confname)
-		confname = wpa_s->confname;
-
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&confname, error);
+	return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
 }
 
 
@@ -3399,14 +3410,10 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	const char *pkcs11_engine_path;
 
-	if (wpa_s->conf->pkcs11_engine_path == NULL)
-		pkcs11_engine_path = "";
-	else
-		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&pkcs11_engine_path, error);
+	return wpas_dbus_string_property_getter(iter,
+						wpa_s->conf->pkcs11_engine_path,
+						error);
 }
 
 
@@ -3424,14 +3431,10 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	const char *pkcs11_module_path;
 
-	if (wpa_s->conf->pkcs11_module_path == NULL)
-		pkcs11_module_path = "";
-	else
-		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&pkcs11_module_path, error);
+	return wpas_dbus_string_property_getter(iter,
+						wpa_s->conf->pkcs11_module_path,
+						error);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 1d6235d..fe8767a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -43,6 +43,10 @@
 							 size_t array_len,
 							 DBusError *error);
 
+dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
+					     const void *val,
+					     DBusError *error);
+
 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
 						 struct wpa_global *global);
 
@@ -186,6 +190,18 @@
 DECLARE_ACCESSOR(wpas_dbus_setter_process_credentials);
 DECLARE_ACCESSOR(wpas_dbus_getter_config_methods);
 DECLARE_ACCESSOR(wpas_dbus_setter_config_methods);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_name);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_name);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_number);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_number);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_serial_number);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_serial_number);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_device_type);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_device_type);
 
 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
 					      struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index f50420b..a04783d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -90,6 +90,7 @@
 	int num_req_dev_types = 0;
 	unsigned int i;
 	u8 *req_dev_types = NULL;
+	unsigned int freq = 0;
 
 	dbus_message_iter_init(message, &iter);
 	entry.key = NULL;
@@ -134,6 +135,10 @@
 				type = P2P_FIND_PROGRESSIVE;
 			else
 				goto error_clear;
+		} else if (os_strcmp(entry.key, "freq") == 0 &&
+			   (entry.type == DBUS_TYPE_INT32 ||
+			    entry.type == DBUS_TYPE_UINT32)) {
+			freq = entry.uint32_value;
 		} else
 			goto error_clear;
 		wpa_dbus_dict_entry_clear(&entry);
@@ -142,7 +147,7 @@
 	wpa_s = wpa_s->global->p2p_init_wpa_s;
 
 	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
-		      NULL, 0, 0, NULL, 0);
+		      NULL, 0, 0, NULL, freq);
 	os_free(req_dev_types);
 	return reply;
 
@@ -2347,19 +2352,12 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	char *p_pass;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
 	if (ssid == NULL)
 		return FALSE;
 
-	p_pass = ssid->passphrase;
-	if (!p_pass)
-		p_pass = "";
-
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&p_pass, error);
-
+	return wpas_dbus_string_property_getter(iter, ssid->passphrase, error);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index f16e229..f762b3f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -412,12 +412,10 @@
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	char *methods = wpa_s->conf->config_methods;
 
-	if (methods == NULL)
-		methods = "";
-	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
-						&methods, error);
+	return wpas_dbus_string_property_getter(iter,
+						wpa_s->conf->config_methods,
+						error);
 }
 
 
@@ -454,3 +452,349 @@
 
 	return TRUE;
 }
+
+
+/**
+ * wpas_dbus_getter_wps_device_name - Get current WPS device name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DeviceName" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_name(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+
+	return wpas_dbus_string_property_getter(iter, wpa_s->conf->device_name,
+						error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_name - Set current WPS device name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DeviceName" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_name(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char *methods, *devname;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &methods))
+		return FALSE;
+
+	if (os_strlen(methods) > WPS_DEV_NAME_MAX_LEN)
+		return FALSE;
+
+	devname = os_strdup(methods);
+	if (!devname)
+		return FALSE;
+
+	os_free(wpa_s->conf->device_name);
+	wpa_s->conf->device_name = devname;
+	wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_NAME;
+	wpa_supplicant_update_config(wpa_s);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_manufacturer - Get current manufacturer name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Manufacturer" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_manufacturer(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+
+	return wpas_dbus_string_property_getter(iter, wpa_s->conf->manufacturer,
+						error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_manufacturer - Set current manufacturer name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "Manufacturer" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_manufacturer(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char *methods, *manufacturer;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &methods))
+		return FALSE;
+
+	if (os_strlen(methods) > WPS_MANUFACTURER_MAX_LEN)
+		return FALSE;
+
+	manufacturer = os_strdup(methods);
+	if (!manufacturer)
+		return FALSE;
+
+	os_free(wpa_s->conf->manufacturer);
+	wpa_s->conf->manufacturer = manufacturer;
+	wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+	wpa_supplicant_update_config(wpa_s);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_model_name - Get current device model name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ModelName" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_model_name(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+
+	return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_name,
+						error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_model_name - Set current device model name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "ModelName" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_model_name(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char *methods, *model_name;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &methods))
+		return FALSE;
+
+	if (os_strlen(methods) > WPS_MODEL_NAME_MAX_LEN)
+		return FALSE;
+
+	model_name = os_strdup(methods);
+	if (!model_name)
+		return FALSE;
+	os_free(wpa_s->conf->model_name);
+	wpa_s->conf->model_name = model_name;
+	wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+	wpa_supplicant_update_config(wpa_s);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_model_number - Get current device model number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ModelNumber" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_model_number(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+
+	return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_number,
+						error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_model_number - Set current device model number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "ModelNumber" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_model_number(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char *methods, *model_number;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &methods))
+		return FALSE;
+
+	if (os_strlen(methods) > WPS_MODEL_NUMBER_MAX_LEN)
+		return FALSE;
+
+	model_number = os_strdup(methods);
+	if (!model_number)
+		return FALSE;
+
+	os_free(wpa_s->conf->model_number);
+	wpa_s->conf->model_number = model_number;
+	wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+	wpa_supplicant_update_config(wpa_s);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_serial_number - Get current device serial number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "SerialNumber" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_serial_number(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+
+	return wpas_dbus_string_property_getter(iter,
+						wpa_s->conf->serial_number,
+						error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_serial_number - Set current device serial number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "SerialNumber" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_serial_number(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char *methods, *serial_number;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &methods))
+		return FALSE;
+
+	if (os_strlen(methods) > WPS_SERIAL_NUMBER_MAX_LEN)
+		return FALSE;
+
+	serial_number = os_strdup(methods);
+	if (!serial_number)
+		return FALSE;
+	os_free(wpa_s->conf->serial_number);
+	wpa_s->conf->serial_number = serial_number;
+	wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+	wpa_supplicant_update_config(wpa_s);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_device_type - Get current device type
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DeviceType" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_device_type(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+
+	if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						    (char *)
+						    wpa_s->conf->device_type,
+						    WPS_DEV_TYPE_LEN, error)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: error constructing reply", __func__);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_device_type - Set current device type
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DeviceType" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_device_type(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	u8 *dev_type;
+	int dev_len;
+	DBusMessageIter variant, array_iter;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+		return FALSE;
+
+	dbus_message_iter_recurse(iter, &variant);
+	if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
+		return FALSE;
+
+	dbus_message_iter_recurse(&variant, &array_iter);
+	dbus_message_iter_get_fixed_array(&array_iter, &dev_type, &dev_len);
+
+	if (dev_len != WPS_DEV_TYPE_LEN)
+		return FALSE;
+
+	os_memcpy(wpa_s->conf->device_type, dev_type, WPS_DEV_TYPE_LEN);
+	wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_TYPE;
+	wpa_supplicant_update_config(wpa_s);
+
+	return TRUE;
+}
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index aca9e81..f0ce4a6 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -562,3 +562,11 @@
 # This is needed to be able to use mode=1 network profile with proto=RSN and
 # key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None).
 #CONFIG_IBSS_RSN=y
+
+# External PMKSA cache control
+# This can be used to enable control interface commands that allow the current
+# PMKSA cache entries to be fetched and new entries to be added.
+#CONFIG_PMKSA_CACHE_EXTERNAL=y
+
+# Mesh Networking (IEEE 802.11s)
+#CONFIG_MESH=y
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index 3f22413..25cfd06 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -194,7 +194,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index 13c9f45..fa94ae4 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,7 +90,7 @@
 
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index 15400f0..be3045a 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -345,7 +345,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index 352d3d2..cee9ed6 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -91,7 +91,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index faf1f27..6667a07 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -18,7 +18,7 @@
   </refsynopsisdiv>
 
   <refsect1>
-    <title>Overview</title> 
+    <title>Overview</title>
 
     <para><command>wpa_passphrase</command> pre-computes PSK entries for
     network configuration blocks of a
@@ -62,7 +62,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 403c9b2..3796b93 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,7 +137,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 11e0e90..80b3878 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -565,7 +565,7 @@
 	using ap_scan=0 option in configuration file.</para>
 	</listitem>
       </varlistentry>
-      
+
       <varlistentry>
 	<term>Wired Ethernet drivers</term>
 	<listitem>
@@ -590,7 +590,7 @@
       </varlistentry>
     </variablelist>
 
-	
+
     <para>wpa_supplicant was designed to be portable for different
     drivers and operating systems. Hopefully, support for more wlan
     cards and OSes will be added in the future. See developer.txt for
@@ -729,7 +729,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2016,
+    <para>wpa_supplicant is copyright (c) 2003-2017,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 67438e5..afdda00 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1736,6 +1736,10 @@
 	if (sme_proc_obss_scan(wpa_s) > 0)
 		goto scan_work_done;
 
+	if (own_request &&
+	    wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0)
+		goto scan_work_done;
+
 	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
 		goto scan_work_done;
 
@@ -1966,6 +1970,8 @@
 #else /* CONFIG_NO_SCAN_PROCESSING */
 	struct os_reltime now;
 
+	wpa_s->ignore_post_flush_scan_res = 0;
+
 	if (wpa_s->last_scan_res_used == 0)
 		return -1;
 
diff --git a/wpa_supplicant/hidl/hidl.cpp b/wpa_supplicant/hidl/hidl.cpp
index e38288b..ffc482f 100644
--- a/wpa_supplicant/hidl/hidl.cpp
+++ b/wpa_supplicant/hidl/hidl.cpp
@@ -289,6 +289,20 @@
 	hidl_manager->notifyAssocReject(wpa_s);
 }
 
+void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying auth timeout to hidl control");
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyAuthTimeout(wpa_s);
+}
+
 void wpas_hidl_notify_wps_event_fail(
     struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
     uint16_t error_indication)
@@ -336,3 +350,261 @@
 
 	hidl_manager->notifyWpsEventPbcOverlap(wpa_s);
 }
+
+void wpas_hidl_notify_p2p_device_found(
+    struct wpa_supplicant *wpa_s, const u8 *addr,
+    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+    u8 peer_wfd_device_info_len)
+{
+	if (!wpa_s || !addr || !info || !peer_wfd_device_info)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG, "Notifying P2P device found to hidl control " MACSTR,
+	    MAC2STR(info->p2p_device_addr));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pDeviceFound(
+	    wpa_s, addr, info, peer_wfd_device_info, peer_wfd_device_info_len);
+}
+
+void wpas_hidl_notify_p2p_device_lost(
+    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{
+	if (!wpa_s || !p2p_device_addr)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG, "Notifying P2P device lost to hidl control " MACSTR,
+	    MAC2STR(p2p_device_addr));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pDeviceLost(wpa_s, p2p_device_addr);
+}
+
+void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying P2P find stop to hidl control");
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pFindStopped(wpa_s);
+}
+
+void wpas_hidl_notify_p2p_go_neg_req(
+    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+    u8 go_intent)
+{
+	if (!wpa_s || !src_addr)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P GO negotiation request to hidl control " MACSTR,
+	    MAC2STR(src_addr));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pGoNegReq(
+	    wpa_s, src_addr, dev_passwd_id, go_intent);
+}
+
+void wpas_hidl_notify_p2p_go_neg_completed(
+    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{
+	if (!wpa_s || !res)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P GO negotiation completed to hidl control: %d",
+	    res->status);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pGoNegCompleted(wpa_s, res);
+}
+
+void wpas_hidl_notify_p2p_group_formation_failure(
+    struct wpa_supplicant *wpa_s, const char *reason)
+{
+	if (!wpa_s || !reason)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P Group formation failure to hidl control: %s",
+	    reason);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pGroupFormationFailure(wpa_s, reason);
+}
+
+void wpas_hidl_notify_p2p_group_started(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+    int client, const u8 *ip)
+{
+	if (!wpa_s || !ssid || !ip)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG, "Notifying P2P Group start to hidl control: %d",
+	    ssid->id);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pGroupStarted(
+	    wpa_s, ssid, persistent, client, ip);
+}
+
+void wpas_hidl_notify_p2p_group_removed(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
+{
+	if (!wpa_s || !ssid || !role)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG, "Notifying P2P Group removed to hidl control: %d",
+	    ssid->id);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pGroupRemoved(wpa_s, ssid, role);
+}
+
+void wpas_hidl_notify_p2p_invitation_received(
+    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+    const u8 *bssid, int id, int op_freq)
+{
+	if (!wpa_s || !sa || !go_dev_addr || !bssid)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P invitation received to hidl control: %d " MACSTR, id,
+	    MAC2STR(bssid));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pInvitationReceived(
+	    wpa_s, sa, go_dev_addr, bssid, id, op_freq);
+}
+
+void wpas_hidl_notify_p2p_invitation_result(
+    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{
+	if (!wpa_s || !bssid)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P invitation result to hidl control: " MACSTR,
+	    MAC2STR(bssid));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pInvitationResult(wpa_s, status, bssid);
+}
+
+void wpas_hidl_notify_p2p_provision_discovery(
+    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+    enum p2p_prov_disc_status status, u16 config_methods,
+    unsigned int generated_pin)
+{
+	if (!wpa_s || !dev_addr)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P provision discovery to hidl control " MACSTR,
+	    MAC2STR(dev_addr));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pProvisionDiscovery(
+	    wpa_s, dev_addr, request, status, config_methods, generated_pin);
+}
+
+void wpas_hidl_notify_p2p_sd_response(
+    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+    const u8 *tlvs, size_t tlvs_len)
+{
+	if (!wpa_s || !sa || !tlvs)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P service discovery response to hidl control " MACSTR,
+	    MAC2STR(sa));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyP2pSdResponse(
+	    wpa_s, sa, update_indic, tlvs, tlvs_len);
+}
+
+void wpas_hidl_notify_ap_sta_authorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+	if (!wpa_s || !sta || !p2p_dev_addr)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P AP STA authorized to hidl control " MACSTR,
+	    MAC2STR(sta));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyApStaAuthorized(wpa_s, sta, p2p_dev_addr);
+}
+
+void wpas_hidl_notify_ap_sta_deauthorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+	if (!wpa_s || !sta || !p2p_dev_addr)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying P2P AP STA deauthorized to hidl control " MACSTR,
+	    MAC2STR(sta));
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyApStaDeauthorized(wpa_s, sta, p2p_dev_addr);
+}
diff --git a/wpa_supplicant/hidl/hidl.h b/wpa_supplicant/hidl/hidl.h
index b1e8f11..dbc655e 100644
--- a/wpa_supplicant/hidl/hidl.h
+++ b/wpa_supplicant/hidl/hidl.h
@@ -48,11 +48,48 @@
     struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url);
 void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
 void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpas_hidl_notify_wps_event_fail(
     struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
     uint16_t error_indication);
 void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
 void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_p2p_device_found(
+    struct wpa_supplicant *wpa_s, const u8 *addr,
+    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+    u8 peer_wfd_device_info_len);
+void wpas_hidl_notify_p2p_device_lost(
+    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
+void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_p2p_go_neg_req(
+    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+    u8 go_intent);
+void wpas_hidl_notify_p2p_go_neg_completed(
+    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
+void wpas_hidl_notify_p2p_group_formation_failure(
+    struct wpa_supplicant *wpa_s, const char *reason);
+void wpas_hidl_notify_p2p_group_started(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+    int client, const u8 *ip);
+void wpas_hidl_notify_p2p_group_removed(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
+    const char *role);
+void wpas_hidl_notify_p2p_invitation_received(
+    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+    const u8 *bssid, int id, int op_freq);
+void wpas_hidl_notify_p2p_invitation_result(
+    struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
+void wpas_hidl_notify_p2p_provision_discovery(
+    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+    enum p2p_prov_disc_status status, u16 config_methods,
+    unsigned int generated_pin);
+void wpas_hidl_notify_p2p_sd_response(
+    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+    const u8 *tlvs, size_t tlvs_len);
+void wpas_hidl_notify_ap_sta_authorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
+void wpas_hidl_notify_ap_sta_deauthorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
 #else   // CONFIG_CTRL_IFACE_HIDL
 static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -102,14 +139,77 @@
 }
 static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
 static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
 static void wpas_hidl_notify_wps_event_fail(
-    struct wpa_supplicant *wpa_s, struct wps_event_fail *fail)
+    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+    uint16_t error_indication)
 {
 }
 static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
 static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
 {
 }
+static void wpas_hidl_notify_p2p_device_found(
+    struct wpa_supplicant *wpa_s, const u8 *addr,
+    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+    u8 peer_wfd_device_info_len);
+{
+}
+static void wpas_hidl_notify_p2p_device_lost(
+    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{
+}
+static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_p2p_go_neg_req(
+    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+    u8 go_intent)
+{
+}
+static void wpas_hidl_notify_p2p_go_neg_completed(
+    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{
+}
+static void wpas_hidl_notify_p2p_group_formation_failure(
+    struct wpa_supplicant *wpa_s, const char *reason)
+{
+}
+static void wpas_hidl_notify_p2p_group_started(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+    int client, const u8 *ip)
+{
+}
+static void wpas_hidl_notify_p2p_group_removed(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
+{
+}
+static void wpas_hidl_notify_p2p_invitation_received(
+    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+    const u8 *bssid, int id, int op_freq)
+{
+}
+static void wpas_hidl_notify_p2p_invitation_result(
+    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{
+}
+static void wpas_hidl_notify_p2p_provision_discovery(
+    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+    enum p2p_prov_disc_status status, u16 config_methods,
+    unsigned int generated_pin)
+{
+}
+static void wpas_hidl_notify_p2p_sd_response(
+    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+    const u8 *tlvs, size_t tlvs_len)
+{
+}
+static void wpas_hidl_notify_ap_sta_authorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+}
+static void wpas_hidl_notify_ap_sta_deauthorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+}
 #endif  // CONFIG_CTRL_IFACE_HIDL
 
 #ifdef _cplusplus
diff --git a/wpa_supplicant/hidl/hidl_manager.cpp b/wpa_supplicant/hidl/hidl_manager.cpp
index 2112cc9..ee257ee 100644
--- a/wpa_supplicant/hidl/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/hidl_manager.cpp
@@ -8,10 +8,28 @@
  */
 
 #include <algorithm>
+#include <regex>
 
 #include "hidl_manager.h"
 
+extern "C" {
+#include "src/eap_common/eap_sim_common.h"
+}
+
 namespace {
+using android::hardware::hidl_array;
+
+constexpr uint8_t kWfdDeviceInfoLen = 8;
+// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
+constexpr char kGsmAuthRegex2[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+)";
+constexpr char kGsmAuthRegex3[] =
+    "GSM-AUTH:([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)";
+// UMTS-AUTH:<RAND>:<AUTN>
+constexpr char kUmtsAuthRegex[] = "UMTS-AUTH:([0-9a-f]+):([0-9a-f]+)";
+constexpr size_t kGsmRandLenBytes = GSM_RAND_LEN;
+constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN;
+constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN;
+
 /**
  * Check if the provided |wpa_supplicant| structure represents a P2P iface or
  * not.
@@ -297,6 +315,56 @@
 		return std::vector<uint8_t>();
 	}
 }
+
+int parseGsmAuthNetworkRequest(
+    const std::string &params_str,
+    std::vector<hidl_array<uint8_t, kGsmRandLenBytes>> *out_rands)
+{
+	std::smatch matches;
+	std::regex params_gsm_regex2(kGsmAuthRegex2);
+	std::regex params_gsm_regex3(kGsmAuthRegex3);
+	if (!std::regex_match(params_str, matches, params_gsm_regex3) &&
+	    !std::regex_match(params_str, matches, params_gsm_regex2)) {
+		return 1;
+	}
+	for (uint32_t i = 1; i < matches.size(); i++) {
+		hidl_array<uint8_t, kGsmRandLenBytes> rand;
+		const auto &match = matches[i];
+		WPA_ASSERT(match.size() >= 2 * rand.size());
+		if (hexstr2bin(match.str().c_str(), rand.data(), rand.size())) {
+			wpa_printf(
+			    MSG_ERROR, "Failed to parse GSM auth params");
+			return 1;
+		}
+		out_rands->push_back(rand);
+	}
+	return 0;
+}
+
+int parseUmtsAuthNetworkRequest(
+    const std::string &params_str,
+    hidl_array<uint8_t, kUmtsRandLenBytes> *out_rand,
+    hidl_array<uint8_t, kUmtsAutnLenBytes> *out_autn)
+{
+	std::smatch matches;
+	std::regex params_umts_regex(kUmtsAuthRegex);
+	if (!std::regex_match(params_str, matches, params_umts_regex)) {
+		return 1;
+	}
+	WPA_ASSERT(matches[1].size() >= 2 * out_rand->size());
+	if (hexstr2bin(
+		matches[1].str().c_str(), out_rand->data(), out_rand->size())) {
+		wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
+		return 1;
+	}
+	WPA_ASSERT(matches[2].size() >= 2 * out_autn->size());
+	if (hexstr2bin(
+		matches[2].str().c_str(), out_autn->data(), out_autn->size())) {
+		wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
+		return 1;
+	}
+	return 0;
+}
 }  // namespace
 
 namespace android {
@@ -326,8 +394,7 @@
 {
 	// Create the main hidl service object and register it.
 	supplicant_object_ = new Supplicant(global);
-	if (supplicant_object_->registerAsService() !=
-	    android::NO_ERROR) {
+	if (supplicant_object_->registerAsService() != android::NO_ERROR) {
 		return 1;
 	}
 	return 0;
@@ -345,29 +412,28 @@
 	if (!wpa_s)
 		return 1;
 
-	// Using the corresponding ifname as key to our object map.
-	const std::string ifname(wpa_s->ifname);
-
 	if (isP2pIface(wpa_s)) {
 		if (addHidlObjectToMap<P2pIface>(
-			ifname, new P2pIface(wpa_s->global, wpa_s->ifname),
+			wpa_s->ifname,
+			new P2pIface(wpa_s->global, wpa_s->ifname),
 			p2p_iface_object_map_))
 			return 1;
-		p2p_iface_callbacks_map_[ifname] =
+		p2p_iface_callbacks_map_[wpa_s->ifname] =
 		    std::vector<android::sp<ISupplicantP2pIfaceCallback>>();
 	} else {
 		if (addHidlObjectToMap<StaIface>(
-			ifname, new StaIface(wpa_s->global, wpa_s->ifname),
+			wpa_s->ifname,
+			new StaIface(wpa_s->global, wpa_s->ifname),
 			sta_iface_object_map_))
 			return 1;
-		sta_iface_callbacks_map_[ifname] =
+		sta_iface_callbacks_map_[wpa_s->ifname] =
 		    std::vector<android::sp<ISupplicantStaIfaceCallback>>();
 	}
 
 	// Invoke the |onInterfaceCreated| method on all registered callbacks.
 	callWithEachSupplicantCallback(std::bind(
 	    &ISupplicantCallback::onInterfaceCreated, std::placeholders::_1,
-	    ifname));
+	    wpa_s->ifname));
 	return 0;
 }
 
@@ -383,20 +449,20 @@
 	if (!wpa_s)
 		return 1;
 
-	const std::string ifname(wpa_s->ifname);
-
 	if (isP2pIface(wpa_s)) {
-		if (removeHidlObjectFromMap(ifname, p2p_iface_object_map_))
+		if (removeHidlObjectFromMap(
+			wpa_s->ifname, p2p_iface_object_map_))
 			return 1;
 		if (removeAllIfaceCallbackHidlObjectsFromMap(
-			ifname, p2p_iface_callbacks_map_)) {
+			wpa_s->ifname, p2p_iface_callbacks_map_)) {
 			return 1;
 		}
 	} else {
-		if (removeHidlObjectFromMap(ifname, sta_iface_object_map_))
+		if (removeHidlObjectFromMap(
+			wpa_s->ifname, sta_iface_object_map_))
 			return 1;
 		if (removeAllIfaceCallbackHidlObjectsFromMap(
-			ifname, sta_iface_callbacks_map_)) {
+			wpa_s->ifname, sta_iface_callbacks_map_)) {
 			return 1;
 		}
 	}
@@ -404,7 +470,7 @@
 	// Invoke the |onInterfaceRemoved| method on all registered callbacks.
 	callWithEachSupplicantCallback(std::bind(
 	    &ISupplicantCallback::onInterfaceRemoved, std::placeholders::_1,
-	    ifname));
+	    wpa_s->ifname));
 	return 0;
 }
 
@@ -523,15 +589,11 @@
 	if (!wpa_s)
 		return 1;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return 1;
 
 	// Invoke the |onStateChanged| method on all registered callbacks.
-	ISupplicantStaIfaceCallback::State hidl_state =
-	    static_cast<ISupplicantStaIfaceCallback::State>(wpa_s->wpa_state);
-	std::array<uint8_t, ETH_ALEN> hidl_bssid;
-	os_memcpy(hidl_bssid.data(), wpa_s->bssid, ETH_ALEN);
 	uint32_t hidl_network_id = UINT32_MAX;
 	std::vector<uint8_t> hidl_ssid;
 	if (wpa_s->current_ssid) {
@@ -543,8 +605,10 @@
 	callWithEachStaIfaceCallback(
 	    wpa_s->ifname, std::bind(
 			       &ISupplicantStaIfaceCallback::onStateChanged,
-			       std::placeholders::_1, hidl_state, hidl_bssid,
-			       hidl_network_id, hidl_ssid));
+			       std::placeholders::_1,
+			       static_cast<ISupplicantStaIfaceCallback::State>(
+				   wpa_s->wpa_state),
+			       wpa_s->bssid, hidl_network_id, hidl_ssid));
 	return 0;
 }
 
@@ -570,9 +634,47 @@
 	    sta_network_object_map_.end())
 		return 1;
 
-	// TODO(b/31646740): Parse the param string to find the appropriate
-	// callback.
-	return 0;
+	if (type == WPA_CTRL_REQ_EAP_IDENTITY) {
+		callWithEachStaNetworkCallback(
+		    wpa_s->ifname, ssid->id,
+		    std::bind(
+			&ISupplicantStaNetworkCallback::
+			    onNetworkEapIdentityRequest,
+			std::placeholders::_1));
+		return 0;
+	}
+	if (type == WPA_CTRL_REQ_SIM) {
+		std::vector<hidl_array<uint8_t, 16>> gsm_rands;
+		hidl_array<uint8_t, 16> umts_rand;
+		hidl_array<uint8_t, 16> umts_autn;
+		if (!parseGsmAuthNetworkRequest(param, &gsm_rands)) {
+			ISupplicantStaNetworkCallback::
+			    NetworkRequestEapSimGsmAuthParams hidl_params;
+			hidl_params.rands = gsm_rands;
+			callWithEachStaNetworkCallback(
+			    wpa_s->ifname, ssid->id,
+			    std::bind(
+				&ISupplicantStaNetworkCallback::
+				    onNetworkEapSimGsmAuthRequest,
+				std::placeholders::_1, hidl_params));
+			return 0;
+		}
+		if (!parseUmtsAuthNetworkRequest(
+			param, &umts_rand, &umts_autn)) {
+			ISupplicantStaNetworkCallback::
+			    NetworkRequestEapSimUmtsAuthParams hidl_params;
+			hidl_params.rand = umts_rand;
+			hidl_params.autn = umts_autn;
+			callWithEachStaNetworkCallback(
+			    wpa_s->ifname, ssid->id,
+			    std::bind(
+				&ISupplicantStaNetworkCallback::
+				    onNetworkEapSimUmtsAuthRequest,
+				std::placeholders::_1, hidl_params));
+			return 0;
+		}
+	}
+	return 1;
 }
 
 /**
@@ -590,8 +692,8 @@
 	if (!wpa_s || !bssid || !result || !anqp)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
 	ISupplicantStaIfaceCallback::AnqpData hidl_anqp_data;
@@ -620,13 +722,11 @@
 		    convertWpaBufToVector(anqp->hs20_osu_providers_list);
 	}
 
-	std::array<uint8_t, ETH_ALEN> hidl_bssid;
-	os_memcpy(hidl_bssid.data(), bssid, ETH_ALEN);
 	callWithEachStaIfaceCallback(
 	    wpa_s->ifname, std::bind(
 			       &ISupplicantStaIfaceCallback::onAnqpQueryDone,
-			       std::placeholders::_1, hidl_bssid,
-			       hidl_anqp_data, hidl_hs20_anqp_data));
+			       std::placeholders::_1, bssid, hidl_anqp_data,
+			       hidl_hs20_anqp_data));
 }
 
 /**
@@ -645,18 +745,16 @@
 	if (!wpa_s || !bssid || !file_name || !image)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
-	std::vector<uint8_t> hidl_image(image, image + image_length);
-	std::array<uint8_t, ETH_ALEN> hidl_bssid;
-	os_memcpy(hidl_bssid.data(), bssid, ETH_ALEN);
 	callWithEachStaIfaceCallback(
 	    wpa_s->ifname,
 	    std::bind(
 		&ISupplicantStaIfaceCallback::onHs20IconQueryDone,
-		std::placeholders::_1, hidl_bssid, file_name, hidl_image));
+		std::placeholders::_1, bssid, file_name,
+		std::vector<uint8_t>(image, image + image_length)));
 }
 
 /**
@@ -673,8 +771,8 @@
 	if (!wpa_s || !url)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
 	ISupplicantStaIfaceCallback::OsuMethod hidl_osu_method = {};
@@ -707,8 +805,8 @@
 	if (!wpa_s || !url)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
 	callWithEachStaIfaceCallback(
@@ -730,22 +828,20 @@
 	if (!wpa_s)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
 	const u8 *bssid = wpa_s->bssid;
 	if (is_zero_ether_addr(bssid)) {
 		bssid = wpa_s->pending_bssid;
 	}
-	std::array<uint8_t, ETH_ALEN> hidl_bssid;
-	os_memcpy(hidl_bssid.data(), bssid, ETH_ALEN);
 
 	callWithEachStaIfaceCallback(
 	    wpa_s->ifname,
 	    std::bind(
 		&ISupplicantStaIfaceCallback::onDisconnected,
-		std::placeholders::_1, hidl_bssid, wpa_s->disconnect_reason < 0,
+		std::placeholders::_1, bssid, wpa_s->disconnect_reason < 0,
 		wpa_s->disconnect_reason));
 }
 
@@ -761,6 +857,27 @@
 	if (!wpa_s)
 		return;
 
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
+		return;
+
+	const u8 *bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid)) {
+		bssid = wpa_s->pending_bssid;
+	}
+
+	callWithEachStaIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantStaIfaceCallback::onAssociationRejected,
+		std::placeholders::_1, bssid, wpa_s->assoc_status_code));
+}
+
+void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
 	const std::string ifname(wpa_s->ifname);
 	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
 		return;
@@ -775,8 +892,8 @@
 	callWithEachStaIfaceCallback(
 	    wpa_s->ifname,
 	    std::bind(
-		&ISupplicantStaIfaceCallback::onAssociationRejected,
-		std::placeholders::_1, hidl_bssid, wpa_s->assoc_status_code));
+		&ISupplicantStaIfaceCallback::onAuthenticationTimeout,
+		std::placeholders::_1, hidl_bssid));
 }
 
 void HidlManager::notifyWpsEventFail(
@@ -786,25 +903,19 @@
 	if (!wpa_s || !peer_macaddr)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
-	std::array<uint8_t, ETH_ALEN> hidl_bssid;
-	os_memcpy(hidl_bssid.data(), peer_macaddr, ETH_ALEN);
-
-	ISupplicantStaIfaceCallback::WpsConfigError hidl_config_error =
-	    static_cast<ISupplicantStaIfaceCallback::WpsConfigError>(
-		config_error);
-	ISupplicantStaIfaceCallback::WpsErrorIndication hidl_error_indication =
-	    static_cast<ISupplicantStaIfaceCallback::WpsErrorIndication>(
-		error_indication);
-
 	callWithEachStaIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantStaIfaceCallback::onWpsEventFail,
-			       std::placeholders::_1, hidl_bssid,
-			       hidl_config_error, hidl_error_indication));
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantStaIfaceCallback::onWpsEventFail,
+		std::placeholders::_1, peer_macaddr,
+		static_cast<ISupplicantStaIfaceCallback::WpsConfigError>(
+		    config_error),
+		static_cast<ISupplicantStaIfaceCallback::WpsErrorIndication>(
+		    error_indication)));
 }
 
 void HidlManager::notifyWpsEventSuccess(struct wpa_supplicant *wpa_s)
@@ -812,8 +923,8 @@
 	if (!wpa_s)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
 	callWithEachStaIfaceCallback(
@@ -827,8 +938,8 @@
 	if (!wpa_s)
 		return;
 
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
 		return;
 
 	callWithEachStaIfaceCallback(
@@ -838,6 +949,335 @@
 		std::placeholders::_1));
 }
 
+void HidlManager::notifyP2pDeviceFound(
+    struct wpa_supplicant *wpa_s, const u8 *addr,
+    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+    u8 peer_wfd_device_info_len)
+{
+	if (!wpa_s || !addr || !info || !peer_wfd_device_info)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	if (peer_wfd_device_info_len != kWfdDeviceInfoLen) {
+		wpa_printf(
+		    MSG_ERROR, "Unexpected WFD device info len: %d",
+		    peer_wfd_device_info_len);
+	}
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onDeviceFound,
+		std::placeholders::_1, addr, info->p2p_device_addr,
+		info->pri_dev_type, info->device_name, info->config_methods,
+		info->dev_capab, info->group_capab, peer_wfd_device_info));
+}
+
+void HidlManager::notifyP2pDeviceLost(
+    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{
+	if (!wpa_s || !p2p_device_addr)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname, std::bind(
+			       &ISupplicantP2pIfaceCallback::onDeviceLost,
+			       std::placeholders::_1, p2p_device_addr));
+}
+
+void HidlManager::notifyP2pFindStopped(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname, std::bind(
+			       &ISupplicantP2pIfaceCallback::onFindStopped,
+			       std::placeholders::_1));
+}
+
+void HidlManager::notifyP2pGoNegReq(
+    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+    u8 /* go_intent */)
+{
+	if (!wpa_s || !src_addr)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onGoNegotiationRequest,
+		std::placeholders::_1, src_addr,
+		static_cast<ISupplicantP2pIfaceCallback::WpsDevPasswordId>(
+		    dev_passwd_id)));
+}
+
+void HidlManager::notifyP2pGoNegCompleted(
+    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{
+	if (!wpa_s || !res)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onGoNegotiationCompleted,
+		std::placeholders::_1,
+		static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
+		    res->status)));
+}
+
+void HidlManager::notifyP2pGroupFormationFailure(
+    struct wpa_supplicant *wpa_s, const char *reason)
+{
+	if (!wpa_s || !reason)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onGroupFormationFailure,
+		std::placeholders::_1, reason));
+}
+
+void HidlManager::notifyP2pGroupStarted(
+    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+    int persistent, int client, const u8 *ip)
+{
+	if (!wpa_group_s || !wpa_group_s->parent || !ssid || !ip)
+		return;
+
+	// For group notifications, need to use the parent iface for callbacks.
+	struct wpa_supplicant *wpa_s = wpa_group_s->parent;
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	uint32_t hidl_freq = wpa_group_s->current_bss
+				 ? wpa_group_s->current_bss->freq
+				 : wpa_group_s->assoc_freq;
+	std::array<uint8_t, 32> hidl_psk;
+	if (ssid->psk_set) {
+		os_memcpy(hidl_psk.data(), ssid->psk, 32);
+	}
+	bool hidl_is_go = (client == 0 ? true : false);
+	bool hidl_is_persistent = (persistent == 1 ? true : false);
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onGroupStarted,
+		std::placeholders::_1, wpa_group_s->ifname, hidl_is_go,
+		std::vector<uint8_t>{ssid->ssid, ssid->ssid + ssid->ssid_len},
+		hidl_freq, hidl_psk, ssid->passphrase, wpa_group_s->go_dev_addr,
+		hidl_is_persistent));
+}
+
+void HidlManager::notifyP2pGroupRemoved(
+    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+    const char *role)
+{
+	if (!wpa_group_s || !wpa_group_s->parent || !ssid || !role)
+		return;
+
+	// For group notifications, need to use the parent iface for callbacks.
+	struct wpa_supplicant *wpa_s = wpa_group_s->parent;
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	bool hidl_is_go = (std::string(role) == "GO");
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onGroupRemoved,
+		std::placeholders::_1, wpa_group_s->ifname, hidl_is_go));
+}
+
+void HidlManager::notifyP2pInvitationReceived(
+    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+    const u8 *bssid, int id, int op_freq)
+{
+	if (!wpa_s || !sa || !go_dev_addr || !bssid)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	SupplicantNetworkId hidl_network_id;
+	if (id < 0) {
+		hidl_network_id = UINT32_MAX;
+	}
+	hidl_network_id = id;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onInvitationReceived,
+		std::placeholders::_1, sa, go_dev_addr, bssid, hidl_network_id,
+		op_freq));
+}
+
+void HidlManager::notifyP2pInvitationResult(
+    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{
+	if (!wpa_s || !bssid)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onInvitationResult,
+		std::placeholders::_1, bssid,
+		static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
+		    status)));
+}
+
+void HidlManager::notifyP2pProvisionDiscovery(
+    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+    enum p2p_prov_disc_status status, u16 config_methods,
+    unsigned int generated_pin)
+{
+	if (!wpa_s || !dev_addr)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	std::string hidl_generated_pin;
+	if (generated_pin > 0) {
+		hidl_generated_pin.reserve(9);
+		os_snprintf(
+		    &hidl_generated_pin[0], hidl_generated_pin.size(), "%08d",
+		    generated_pin);
+	}
+	bool hidl_is_request = (request == 1 ? true : false);
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompleted,
+		std::placeholders::_1, dev_addr, hidl_is_request,
+		static_cast<ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode>(
+		    status),
+		config_methods, hidl_generated_pin));
+}
+
+void HidlManager::notifyP2pSdResponse(
+    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+    const u8 *tlvs, size_t tlvs_len)
+{
+	if (!wpa_s || !sa || !tlvs)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onServiceDiscoveryResponse,
+		std::placeholders::_1, sa, update_indic,
+		std::vector<uint8_t>{tlvs, tlvs + tlvs_len}));
+}
+
+void HidlManager::notifyApStaAuthorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+	if (!wpa_s || !sta || !p2p_dev_addr)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname, std::bind(
+			       &ISupplicantP2pIfaceCallback::onStaAuthorized,
+			       std::placeholders::_1, sta, p2p_dev_addr));
+}
+
+void HidlManager::notifyApStaDeauthorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+	if (!wpa_s || !sta || !p2p_dev_addr)
+		return;
+
+	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+	    p2p_iface_object_map_.end())
+		return;
+
+	callWithEachP2pIfaceCallback(
+	    wpa_s->ifname, std::bind(
+			       &ISupplicantP2pIfaceCallback::onStaDeauthorized,
+			       std::placeholders::_1, sta, p2p_dev_addr));
+}
+
+void HidlManager::notifyExtRadioWorkStart(
+    struct wpa_supplicant *wpa_s, uint32_t id)
+{
+	if (!wpa_s)
+		return;
+
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
+		return;
+
+	callWithEachStaIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantStaIfaceCallback::onExtRadioWorkStart,
+		std::placeholders::_1, id));
+}
+
+void HidlManager::notifyExtRadioWorkTimeout(
+    struct wpa_supplicant *wpa_s, uint32_t id)
+{
+	if (!wpa_s)
+		return;
+
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+	    sta_iface_object_map_.end())
+		return;
+
+	callWithEachStaIfaceCallback(
+	    wpa_s->ifname,
+	    std::bind(
+		&ISupplicantStaIfaceCallback::onExtRadioWorkTimeout,
+		std::placeholders::_1, id));
+}
+
 /**
  * Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
  * ifname.
diff --git a/wpa_supplicant/hidl/hidl_manager.h b/wpa_supplicant/hidl/hidl_manager.h
index 5d2ba8c..07680ba 100644
--- a/wpa_supplicant/hidl/hidl_manager.h
+++ b/wpa_supplicant/hidl/hidl_manager.h
@@ -76,13 +76,56 @@
 	    const char *url);
 	void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
 	void notifyAssocReject(struct wpa_supplicant *wpa_s);
+	void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
 	void notifyWpsEventFail(
 	    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr,
 	    uint16_t config_error, uint16_t error_indication);
 	void notifyWpsEventSuccess(struct wpa_supplicant *wpa_s);
 	void notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s);
+	void notifyP2pDeviceFound(
+	    struct wpa_supplicant *wpa_s, const u8 *addr,
+	    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+	    u8 peer_wfd_device_info_len);
+	void notifyP2pDeviceLost(
+	    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
+	void notifyP2pFindStopped(struct wpa_supplicant *wpa_s);
+	void notifyP2pGoNegReq(
+	    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+	    u8 go_intent);
+	void notifyP2pGoNegCompleted(
+	    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
+	void notifyP2pGroupFormationFailure(
+	    struct wpa_supplicant *wpa_s, const char *reason);
+	void notifyP2pGroupStarted(
+	    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+	    int persistent, int client, const u8 *ip);
+	void notifyP2pGroupRemoved(
+	    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+	    const char *role);
+	void notifyP2pInvitationReceived(
+	    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+	    const u8 *bssid, int id, int op_freq);
+	void notifyP2pInvitationResult(
+	    struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
+	void notifyP2pProvisionDiscovery(
+	    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+	    enum p2p_prov_disc_status status, u16 config_methods,
+	    unsigned int generated_pin);
+	void notifyP2pSdResponse(
+	    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+	    const u8 *tlvs, size_t tlvs_len);
+	void notifyApStaAuthorized(
+	    struct wpa_supplicant *wpa_s, const u8 *sta,
+	    const u8 *p2p_dev_addr);
+	void notifyApStaDeauthorized(
+	    struct wpa_supplicant *wpa_s, const u8 *sta,
+	    const u8 *p2p_dev_addr);
 
 	// Methods called from hidl objects.
+	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
+	void notifyExtRadioWorkTimeout(
+	    struct wpa_supplicant *wpa_s, uint32_t id);
+
 	int getP2pIfaceHidlObjectByIfname(
 	    const std::string &ifname,
 	    android::sp<ISupplicantP2pIface> *iface_object);
@@ -321,7 +364,8 @@
 	WPA_CIPHER_CCMP,
     "GroupCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
+    static_cast<uint32_t>(
+	ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
 	WPA_CIPHER_GTK_NOT_USED,
     "GroupCipher value mismatch");
 static_assert(
diff --git a/wpa_supplicant/hidl/iface_config_utils.cpp b/wpa_supplicant/hidl/iface_config_utils.cpp
index 86ed4c1..028eae8 100644
--- a/wpa_supplicant/hidl/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/iface_config_utils.cpp
@@ -20,10 +20,16 @@
 constexpr uint32_t kMaxWpsModelNumberSize = 32;
 constexpr uint32_t kMaxWpsSerialNumberSize = 32;
 
+void processConfigUpdate(struct wpa_supplicant* wpa_s, uint32_t changed_param)
+{
+	wpa_s->conf->changed_parameters |= changed_param;
+	wpa_supplicant_update_config(wpa_s);
+}
+
 // Free any existing pointer stored in |dst| and store the provided string value
 // there.
 int freeAndSetStringConfigParam(
-    wpa_supplicant* wpa_s, const std::string& value, uint32_t max_size,
+    struct wpa_supplicant* wpa_s, const std::string& value, uint32_t max_size,
     uint32_t changed_param, char** dst)
 {
 	if (value.size() > max_size) {
@@ -32,8 +38,7 @@
 	WPA_ASSERT(dst);
 	os_free(static_cast<void*>(*dst));
 	*dst = os_strdup(value.c_str());
-	wpa_s->conf->changed_parameters |= changed_param;
-	wpa_supplicant_update_config(wpa_s);
+	processConfigUpdate(wpa_s, changed_param);
 	return 0;
 }
 
@@ -85,6 +90,16 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus setWpsDeviceType(
+    struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type)
+{
+	WPA_ASSERT(wpa_s);
+	WPA_ASSERT(type.size() == WPS_DEV_TYPE_LEN);
+	os_memcpy(wpa_s->conf->device_type, type.data(), WPS_DEV_TYPE_LEN);
+	processConfigUpdate(wpa_s, CFG_CHANGED_DEVICE_TYPE);
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 SupplicantStatus setWpsManufacturer(
     struct wpa_supplicant* wpa_s, const std::string& manufacturer)
 {
diff --git a/wpa_supplicant/hidl/iface_config_utils.h b/wpa_supplicant/hidl/iface_config_utils.h
index fb72bbc..789cc38 100644
--- a/wpa_supplicant/hidl/iface_config_utils.h
+++ b/wpa_supplicant/hidl/iface_config_utils.h
@@ -34,6 +34,8 @@
 namespace iface_config_utils {
 SupplicantStatus setWpsDeviceName(
     struct wpa_supplicant* wpa_s, const std::string& name);
+SupplicantStatus setWpsDeviceType(
+    struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type);
 SupplicantStatus setWpsManufacturer(
     struct wpa_supplicant* wpa_s, const std::string& manufacturer);
 SupplicantStatus setWpsModelName(
diff --git a/wpa_supplicant/hidl/p2p_iface.cpp b/wpa_supplicant/hidl/p2p_iface.cpp
index 2bcfdfd..4ddb34a 100644
--- a/wpa_supplicant/hidl/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/p2p_iface.cpp
@@ -399,6 +399,14 @@
 	    &P2pIface::setWpsDeviceNameInternal, _hidl_cb, name);
 }
 
+Return<void> P2pIface::setWpsDeviceType(
+    const hidl_array<uint8_t, 8>& type, setWpsDeviceType_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &P2pIface::setWpsDeviceTypeInternal, _hidl_cb, type);
+}
+
 Return<void> P2pIface::setWpsManufacturer(
     const hidl_string& manufacturer, setWpsManufacturer_cb _hidl_cb)
 {
@@ -656,7 +664,7 @@
 	if (provision_method == WpsProvisionMethod::DISPLAY &&
 	    pre_selected_pin.empty()) {
 		pin_ret.reserve(9);
-		snprintf(&pin_ret[0], pin_ret.size(), "%08d", new_pin);
+		os_snprintf(&pin_ret[0], pin_ret.size(), "%08d", new_pin);
 	}
 	return {{SupplicantStatusCode::SUCCESS, ""}, pin_ret};
 }
@@ -1052,6 +1060,12 @@
 	return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
 }
 
+SupplicantStatus P2pIface::setWpsDeviceTypeInternal(
+    const std::array<uint8_t, 8>& type)
+{
+	return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
+}
+
 SupplicantStatus P2pIface::setWpsManufacturerInternal(
     const std::string& manufacturer)
 {
diff --git a/wpa_supplicant/hidl/p2p_iface.h b/wpa_supplicant/hidl/p2p_iface.h
index a0b3aef..07551bd 100644
--- a/wpa_supplicant/hidl/p2p_iface.h
+++ b/wpa_supplicant/hidl/p2p_iface.h
@@ -153,6 +153,9 @@
 	    const hidl_string& groupIfName, cancelWps_cb _hidl_cb) override;
 	Return<void> setWpsDeviceName(
 	    const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
+	Return<void> setWpsDeviceType(
+	    const hidl_array<uint8_t, 8>& type,
+	    setWpsDeviceType_cb _hidl_cb) override;
 	Return<void> setWpsManufacturer(
 	    const hidl_string& manufacturer,
 	    setWpsManufacturer_cb _hidl_cb) override;
@@ -253,6 +256,8 @@
 	    const std::array<uint8_t, 6>& bssid);
 	SupplicantStatus cancelWpsInternal(const std::string& group_ifname);
 	SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
+	SupplicantStatus setWpsDeviceTypeInternal(
+	    const std::array<uint8_t, 8>& type);
 	SupplicantStatus setWpsManufacturerInternal(
 	    const std::string& manufacturer);
 	SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
diff --git a/wpa_supplicant/hidl/sta_iface.cpp b/wpa_supplicant/hidl/sta_iface.cpp
index b7c6ac9..8ce80bb 100644
--- a/wpa_supplicant/hidl/sta_iface.cpp
+++ b/wpa_supplicant/hidl/sta_iface.cpp
@@ -13,6 +13,7 @@
 #include "sta_iface.h"
 
 extern "C" {
+#include "utils/eloop.h"
 #include "gas_query.h"
 #include "interworking.h"
 #include "hs20_supplicant.h"
@@ -20,6 +21,11 @@
 }
 
 namespace {
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
+
 constexpr uint32_t kMaxAnqpElems = 100;
 constexpr char kGetMacAddress[] = "MACADDR";
 constexpr char kStartRxFilter[] = "RXFILTER-START";
@@ -32,10 +38,9 @@
 constexpr char kSetSupendModeEnabled[] = "SETSUSPENDMODE 1";
 constexpr char kSetSupendModeDisabled[] = "SETSUSPENDMODE 0";
 constexpr char kSetCountryCode[] = "COUNTRY ";
-
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+constexpr uint32_t kExtRadioWorkDefaultTimeoutInSec = static_cast<uint32_t>(
+    ISupplicantStaIface::ExtRadioWorkDefaults::TIMEOUT_IN_SECS);
+constexpr char kExtRadioWorkNamePrefix[] = "ext:";
 
 uint8_t convertHidlRxFilterTypeToInternal(
     ISupplicantStaIface::RxFilterType type)
@@ -89,6 +94,60 @@
 	std::string cmd_str = std::string(cmd) + " " + arg;
 	return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
 }
+
+void endExtRadioWork(struct wpa_radio_work *work)
+{
+	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+	work->wpa_s->ext_work_in_progress = 0;
+	radio_work_done(work);
+	os_free(ework);
+}
+
+void extRadioWorkTimeoutCb(void *eloop_ctx, void *timeout_ctx)
+{
+	auto *work = static_cast<struct wpa_radio_work *>(eloop_ctx);
+	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+	wpa_dbg(
+	    work->wpa_s, MSG_DEBUG, "Timing out external radio work %u (%s)",
+	    ework->id, work->type);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	WPA_ASSERT(hidl_manager);
+	hidl_manager->notifyExtRadioWorkTimeout(work->wpa_s, ework->id);
+
+	endExtRadioWork(work);
+}
+
+void startExtRadioWork(struct wpa_radio_work *work)
+{
+	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+	work->wpa_s->ext_work_in_progress = 1;
+	if (!ework->timeout) {
+		ework->timeout = kExtRadioWorkDefaultTimeoutInSec;
+	}
+	eloop_register_timeout(
+	    ework->timeout, 0, extRadioWorkTimeoutCb, work, nullptr);
+}
+
+void extRadioWorkStartCb(struct wpa_radio_work *work, int deinit)
+{
+	// deinit==1 is invoked during interface removal. Since the HIDL
+	// interface does not support interface addition/removal, we don't
+	// need to handle this scenario.
+	WPA_ASSERT(!deinit);
+
+	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+	wpa_dbg(
+	    work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
+	    ework->id, ework->type);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	WPA_ASSERT(hidl_manager);
+	hidl_manager->notifyExtRadioWorkStart(work->wpa_s, ework->id);
+
+	startExtRadioWork(work);
+}
+
 }  // namespace
 
 namespace android {
@@ -355,6 +414,14 @@
 	    &StaIface::setWpsDeviceNameInternal, _hidl_cb, name);
 }
 
+Return<void> StaIface::setWpsDeviceType(
+    const hidl_array<uint8_t, 8> &type, setWpsDeviceType_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::setWpsDeviceTypeInternal, _hidl_cb, type);
+}
+
 Return<void> StaIface::setWpsManufacturer(
     const hidl_string &manufacturer, setWpsManufacturer_cb _hidl_cb)
 {
@@ -403,6 +470,24 @@
 	    &StaIface::setExternalSimInternal, _hidl_cb, useExternalSim);
 }
 
+Return<void> StaIface::addExtRadioWork(
+    const hidl_string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec,
+    addExtRadioWork_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::addExtRadioWorkInternal, _hidl_cb, name, freq_in_mhz,
+	    timeout_in_sec);
+}
+
+Return<void> StaIface::removeExtRadioWork(
+    uint32_t id, removeExtRadioWork_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::removeExtRadioWorkInternal, _hidl_cb, id);
+}
+
 std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -800,6 +885,12 @@
 	return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
 }
 
+SupplicantStatus StaIface::setWpsDeviceTypeInternal(
+    const std::array<uint8_t, 8> &type)
+{
+	return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
+}
+
 SupplicantStatus StaIface::setWpsManufacturerInternal(
     const std::string &manufacturer)
 {
@@ -840,6 +931,63 @@
 	    retrieveIfacePtr(), useExternalSim);
 }
 
+std::pair<SupplicantStatus, uint32_t> StaIface::addExtRadioWorkInternal(
+    const std::string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec)
+{
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	auto *ework = static_cast<struct wpa_external_work *>(
+	    os_zalloc(sizeof(struct wpa_external_work)));
+	if (!ework) {
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
+			UINT32_MAX};
+	}
+
+	std::string radio_work_name = kExtRadioWorkNamePrefix + name;
+	os_strlcpy(ework->type, radio_work_name.c_str(), sizeof(ework->type));
+	ework->timeout = timeout_in_sec;
+	wpa_s->ext_work_id++;
+	if (wpa_s->ext_work_id == 0) {
+		wpa_s->ext_work_id++;
+	}
+	ework->id = wpa_s->ext_work_id;
+
+	if (radio_add_work(
+		wpa_s, freq_in_mhz, ework->type, 0, extRadioWorkStartCb,
+		ework)) {
+		os_free(ework);
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
+			UINT32_MAX};
+	}
+	return {SupplicantStatus{SupplicantStatusCode::SUCCESS, ""}, ework->id};
+}
+
+SupplicantStatus StaIface::removeExtRadioWorkInternal(uint32_t id)
+{
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct wpa_radio_work *work;
+	dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+	{
+		if (os_strncmp(
+			work->type, kExtRadioWorkNamePrefix,
+			sizeof(kExtRadioWorkNamePrefix)) != 0)
+			continue;
+
+		auto *ework =
+		    static_cast<struct wpa_external_work *>(work->ctx);
+		if (ework->id != id)
+			continue;
+
+		wpa_dbg(
+		    wpa_s, MSG_DEBUG, "Completed external radio work %u (%s)",
+		    ework->id, ework->type);
+		eloop_cancel_timeout(extRadioWorkTimeoutCb, work, NULL);
+		endExtRadioWork(work);
+
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
diff --git a/wpa_supplicant/hidl/sta_iface.h b/wpa_supplicant/hidl/sta_iface.h
index cf90d07..32e0e7c 100644
--- a/wpa_supplicant/hidl/sta_iface.h
+++ b/wpa_supplicant/hidl/sta_iface.h
@@ -129,6 +129,9 @@
 	Return<void> cancelWps(cancelWps_cb _hidl_cb) override;
 	Return<void> setWpsDeviceName(
 	    const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
+	Return<void> setWpsDeviceType(
+	    const hidl_array<uint8_t, 8>& type,
+	    setWpsDeviceType_cb _hidl_cb) override;
 	Return<void> setWpsManufacturer(
 	    const hidl_string& manufacturer,
 	    setWpsManufacturer_cb _hidl_cb) override;
@@ -145,6 +148,11 @@
 	    uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
 	Return<void> setExternalSim(
 	    bool useExternalSim, setExternalSim_cb _hidl_cb) override;
+	Return<void> addExtRadioWork(
+	    const hidl_string& name, uint32_t freq_in_mhz,
+	    uint32_t timeout_in_sec, addExtRadioWork_cb _hidl_cb) override;
+	Return<void> removeExtRadioWork(
+	    uint32_t id, removeExtRadioWork_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -200,6 +208,8 @@
 	    const std::array<uint8_t, 6>& bssid);
 	SupplicantStatus cancelWpsInternal();
 	SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
+	SupplicantStatus setWpsDeviceTypeInternal(
+	    const std::array<uint8_t, 8>& type);
 	SupplicantStatus setWpsManufacturerInternal(
 	    const std::string& manufacturer);
 	SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
@@ -209,6 +219,10 @@
 	    const std::string& serial_number);
 	SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
 	SupplicantStatus setExternalSimInternal(bool useExternalSim);
+	std::pair<SupplicantStatus, uint32_t> addExtRadioWorkInternal(
+	    const std::string& name, uint32_t freq_in_mhz,
+	    uint32_t timeout_in_sec);
+	SupplicantStatus removeExtRadioWorkInternal(uint32_t id);
 
 	struct wpa_supplicant* retrieveIfacePtr();
 
diff --git a/wpa_supplicant/hidl/sta_network.cpp b/wpa_supplicant/hidl/sta_network.cpp
index 8ae5cbd..cae61e6 100644
--- a/wpa_supplicant/hidl/sta_network.cpp
+++ b/wpa_supplicant/hidl/sta_network.cpp
@@ -38,7 +38,8 @@
      static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) |
      static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) |
      static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
+     static_cast<uint32_t>(
+	 ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
 constexpr uint32_t kAllowedpairwise_cipher_mask =
     (static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
      static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
@@ -54,6 +55,11 @@
     "NULL", "PAP", "MSCHAP", "MSCHAPV2", "GTC"};
 constexpr char kEapPhase2AuthPrefix[] = "auth=";
 constexpr char kEapPhase2AuthEapPrefix[] = "autheap=";
+constexpr char kNetworkEapSimGsmAuthResponse[] = "GSM-AUTH";
+constexpr char kNetworkEapSimUmtsAuthResponse[] = "UMTS-AUTH";
+constexpr char kNetworkEapSimUmtsAutsResponse[] = "UMTS-AUTS";
+constexpr char kNetworkEapSimGsmAuthFailure[] = "GSM-FAIL";
+constexpr char kNetworkEapSimUmtsAuthFailure[] = "UMTS-FAIL";
 }  // namespace
 
 namespace android {
@@ -316,6 +322,14 @@
 	    &StaNetwork::setEapDomainSuffixMatchInternal, _hidl_cb, match);
 }
 
+Return<void> StaNetwork::setProactiveKeyCaching(
+    bool enable, setProactiveKeyCaching_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setProactiveKeyCachingInternal, _hidl_cb, enable);
+}
+
 Return<void> StaNetwork::setIdStr(
     const hidl_string &id_str, setIdStr_cb _hidl_cb)
 {
@@ -324,6 +338,14 @@
 	    &StaNetwork::setIdStrInternal, _hidl_cb, id_str);
 }
 
+Return<void> StaNetwork::setUpdateIdentifier(
+    uint32_t id, setUpdateIdentifier_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setUpdateIdentifierInternal, _hidl_cb, id);
+}
+
 Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
 {
 	return validateAndCall(
@@ -538,13 +560,22 @@
 }
 
 Return<void> StaNetwork::sendNetworkEapSimGsmAuthResponse(
-    const ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams &params,
+    const hidl_vec<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
+	&vec_params,
     sendNetworkEapSimGsmAuthResponse_cb _hidl_cb)
 {
 	return validateAndCall(
 	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
 	    &StaNetwork::sendNetworkEapSimGsmAuthResponseInternal, _hidl_cb,
-	    params);
+	    vec_params);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimGsmAuthFailure(
+    sendNetworkEapSimGsmAuthFailure_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::sendNetworkEapSimGsmAuthFailureInternal, _hidl_cb);
 }
 
 Return<void> StaNetwork::sendNetworkEapSimUmtsAuthResponse(
@@ -557,6 +588,24 @@
 	    params);
 }
 
+Return<void> StaNetwork::sendNetworkEapSimUmtsAutsResponse(
+    const hidl_array<uint8_t, 14> &auts,
+    sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal, _hidl_cb,
+	    auts);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimUmtsAuthFailure(
+    sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal, _hidl_cb);
+}
+
 Return<void> StaNetwork::sendNetworkEapIdentityResponse(
     const hidl_vec<uint8_t> &identity,
     sendNetworkEapIdentityResponse_cb _hidl_cb)
@@ -1005,6 +1054,14 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus StaNetwork::setProactiveKeyCachingInternal(bool enable)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->proactive_key_caching = enable ? 1 : 0;
+	resetInternalStateAfterParamsUpdate();
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 SupplicantStatus StaNetwork::setIdStrInternal(const std::string &id_str)
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
@@ -1015,6 +1072,16 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus StaNetwork::setUpdateIdentifierInternal(uint32_t id)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->update_identifier = id;
+	wpa_printf(
+	    MSG_MSGDUMP, "update_identifier: %d", wpa_ssid->update_identifier);
+	resetInternalStateAfterParamsUpdate();
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getSsidInternal()
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
@@ -1354,22 +1421,27 @@
 }
 
 SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthResponseInternal(
-    const ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams &params)
+    const std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
+	&vec_params)
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	// Convert the incoming parameters to a string to pass to
 	// wpa_supplicant.
-	uint32_t kc_hex_len = params.kc.size() * 2 + 1;
-	std::vector<char> kc_hex(kc_hex_len);
-	uint32_t sres_hex_len = params.sres.size() * 2 + 1;
-	std::vector<char> sres_hex(sres_hex_len);
-	wpa_snprintf_hex(
-	    kc_hex.data(), kc_hex.size(), params.kc.data(), params.kc.size());
-	wpa_snprintf_hex(
-	    sres_hex.data(), sres_hex.size(), params.sres.data(),
-	    params.sres.size());
-	std::string ctrl_rsp_param = ":" + std::string(kc_hex.data()) + ":" +
-				     std::string(sres_hex.data());
+	std::string ctrl_rsp_param = std::string(kNetworkEapSimGsmAuthResponse);
+	for (const auto &params : vec_params) {
+		uint32_t kc_hex_len = params.kc.size() * 2 + 1;
+		std::vector<char> kc_hex(kc_hex_len);
+		uint32_t sres_hex_len = params.sres.size() * 2 + 1;
+		std::vector<char> sres_hex(sres_hex_len);
+		wpa_snprintf_hex(
+		    kc_hex.data(), kc_hex.size(), params.kc.data(),
+		    params.kc.size());
+		wpa_snprintf_hex(
+		    sres_hex.data(), sres_hex.size(), params.sres.data(),
+		    params.sres.size());
+		ctrl_rsp_param += ":" + std::string(kc_hex.data()) + ":" +
+				  std::string(sres_hex.data());
+	}
 	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	if (wpa_supplicant_ctrl_rsp_handle(
@@ -1383,6 +1455,19 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthFailureInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+	if (wpa_supplicant_ctrl_rsp_handle(
+		wpa_s, wpa_ssid, rtype, kNetworkEapSimGsmAuthFailure)) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal(
     const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams &params)
 {
@@ -1402,9 +1487,10 @@
 	wpa_snprintf_hex(
 	    res_hex.data(), res_hex.size(), params.res.data(),
 	    params.res.size());
-	std::string ctrl_rsp_param = ":" + std::string(ik_hex.data()) + ":" +
-				     std::string(ck_hex.data()) + ":" +
-				     std::string(res_hex.data());
+	std::string ctrl_rsp_param =
+	    std::string(kNetworkEapSimUmtsAuthResponse) + ":" +
+	    std::string(ik_hex.data()) + ":" + std::string(ck_hex.data()) +
+	    ":" + std::string(res_hex.data());
 	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	if (wpa_supplicant_ctrl_rsp_handle(
@@ -1418,6 +1504,43 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal(
+    const std::array<uint8_t, 14> &auts)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	uint32_t auts_hex_len = auts.size() * 2 + 1;
+	std::vector<char> auts_hex(auts_hex_len);
+	wpa_snprintf_hex(
+	    auts_hex.data(), auts_hex.size(), auts.data(), auts.size());
+	std::string ctrl_rsp_param =
+	    std::string(kNetworkEapSimUmtsAutsResponse) + ":" +
+	    std::string(auts_hex.data());
+	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	if (wpa_supplicant_ctrl_rsp_handle(
+		wpa_s, wpa_ssid, rtype, ctrl_rsp_param.c_str())) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+	wpa_hexdump_ascii_key(
+	    MSG_DEBUG, "network sim umts auts response param",
+	    (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+	if (wpa_supplicant_ctrl_rsp_handle(
+		wpa_s, wpa_ssid, rtype, kNetworkEapSimUmtsAuthFailure)) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal(
     const std::vector<uint8_t> &identity)
 {
diff --git a/wpa_supplicant/hidl/sta_network.h b/wpa_supplicant/hidl/sta_network.h
index 9c54e1d..063fa61 100644
--- a/wpa_supplicant/hidl/sta_network.h
+++ b/wpa_supplicant/hidl/sta_network.h
@@ -118,8 +118,12 @@
 	Return<void> setEapDomainSuffixMatch(
 	    const hidl_string& match,
 	    setEapDomainSuffixMatch_cb _hidl_cb) override;
+	Return<void> setProactiveKeyCaching(
+	    bool enable, setProactiveKeyCaching_cb _hidl_cb) override;
 	Return<void> setIdStr(
 	    const hidl_string& id_str, setIdStr_cb _hidl_cb) override;
+	Return<void> setUpdateIdentifier(
+	    uint32_t id, setUpdateIdentifier_cb _hidl_cb) override;
 	Return<void> getSsid(getSsid_cb _hidl_cb) override;
 	Return<void> getBssid(getBssid_cb _hidl_cb) override;
 	Return<void> getScanSsid(getScanSsid_cb _hidl_cb) override;
@@ -157,13 +161,21 @@
 	Return<void> disable(disable_cb _hidl_cb) override;
 	Return<void> select(select_cb _hidl_cb) override;
 	Return<void> sendNetworkEapSimGsmAuthResponse(
-	    const ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams&
-		params,
+	    const hidl_vec<
+		ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
+		vec_params,
 	    sendNetworkEapSimGsmAuthResponse_cb _hidl_cb) override;
+	Return<void> sendNetworkEapSimGsmAuthFailure(
+	    sendNetworkEapSimGsmAuthFailure_cb _hidl_cb) override;
 	Return<void> sendNetworkEapSimUmtsAuthResponse(
 	    const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
 		params,
 	    sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb) override;
+	Return<void> sendNetworkEapSimUmtsAutsResponse(
+	    const hidl_array<uint8_t, 14>& auts,
+	    sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb) override;
+	Return<void> sendNetworkEapSimUmtsAuthFailure(
+	    sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb) override;
 	Return<void> sendNetworkEapIdentityResponse(
 	    const hidl_vec<uint8_t>& identity,
 	    sendNetworkEapIdentityResponse_cb _hidl_cb) override;
@@ -210,7 +222,9 @@
 	SupplicantStatus setEapEngineIDInternal(const std::string& id);
 	SupplicantStatus setEapDomainSuffixMatchInternal(
 	    const std::string& match);
+	SupplicantStatus setProactiveKeyCachingInternal(bool enable);
 	SupplicantStatus setIdStrInternal(const std::string& id_str);
+	SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
 	std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
 	std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
 	std::pair<SupplicantStatus, bool> getScanSsidInternal();
@@ -250,11 +264,16 @@
 	SupplicantStatus disableInternal();
 	SupplicantStatus selectInternal();
 	SupplicantStatus sendNetworkEapSimGsmAuthResponseInternal(
-	    const ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams&
-		params);
+	    const std::vector<
+		ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
+		vec_params);
+	SupplicantStatus sendNetworkEapSimGsmAuthFailureInternal();
 	SupplicantStatus sendNetworkEapSimUmtsAuthResponseInternal(
 	    const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
 		params);
+	SupplicantStatus sendNetworkEapSimUmtsAutsResponseInternal(
+	    const std::array<uint8_t, 14>& auts);
+	SupplicantStatus sendNetworkEapSimUmtsAuthFailureInternal();
 	SupplicantStatus sendNetworkEapIdentityResponseInternal(
 	    const std::vector<uint8_t>& identity);
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index d8368aa..fd2b02e 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -2530,7 +2530,8 @@
 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
 			MAC2STR(selected->bssid));
 		interworking_connect(wpa_s, selected, 0);
-	}
+	} else if (wpa_s->wpa_state == WPA_SCANNING)
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 }
 
 
@@ -2892,6 +2893,18 @@
 			anqp->domain_name = wpabuf_alloc_copy(pos, slen);
 		}
 		break;
+#ifdef CONFIG_FILS
+	case ANQP_FILS_REALM_INFO:
+		wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
+			" FILS Realm Information", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information",
+			pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->fils_realm_info);
+			anqp->fils_realm_info = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+#endif /* CONFIG_FILS */
 	case ANQP_VENDOR_SPECIFIC:
 		if (slen < 3)
 			return;
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 7e049be..d20ae5e 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -380,300 +380,6 @@
 }
 
 
-enum chan_allowed {
-	NOT_ALLOWED, ALLOWED
-};
-
-static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
-				       unsigned int *flags)
-{
-	int i;
-
-	for (i = 0; i < mode->num_channels; i++) {
-		if (mode->channels[i].chan == chan)
-			break;
-	}
-
-	if (i == mode->num_channels ||
-	    (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
-		return NOT_ALLOWED;
-
-	if (flags)
-		*flags = mode->channels[i].flag;
-
-	return ALLOWED;
-}
-
-
-static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
-{
-	u8 center_channels[] = {42, 58, 106, 122, 138, 155};
-	size_t i;
-
-	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
-		return 0;
-
-	for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
-		/*
-		 * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
-		 * so the center channel is 6 channels away from the start/end.
-		 */
-		if (channel >= center_channels[i] - 6 &&
-		    channel <= center_channels[i] + 6)
-			return center_channels[i];
-	}
-
-	return 0;
-}
-
-
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
-{
-	u8 center_chan;
-	unsigned int i;
-
-	center_chan = get_center_80mhz(mode, channel);
-	if (!center_chan)
-		return NOT_ALLOWED;
-
-	/* check all the channels are available */
-	for (i = 0; i < 4; i++) {
-		unsigned int flags;
-		u8 adj_chan = center_chan - 6 + i * 4;
-
-		if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
-			return NOT_ALLOWED;
-
-		if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
-		    (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
-		    (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
-		    (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
-			return NOT_ALLOWED;
-	}
-
-	return ALLOWED;
-}
-
-
-static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
-{
-	u8 center_channels[] = { 50, 114 };
-	unsigned int i;
-
-	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
-		return 0;
-
-	for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
-		/*
-		 * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
-		 * so the center channel is 14 channels away from the start/end.
-		 */
-		if (channel >= center_channels[i] - 14 &&
-		    channel <= center_channels[i] + 14)
-			return center_channels[i];
-	}
-
-	return 0;
-}
-
-
-static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
-				       u8 channel)
-{
-	u8 center_chan;
-	unsigned int i;
-
-	center_chan = get_center_160mhz(mode, channel);
-	if (!center_chan)
-		return NOT_ALLOWED;
-
-	/* Check all the channels are available */
-	for (i = 0; i < 8; i++) {
-		unsigned int flags;
-		u8 adj_chan = center_chan - 14 + i * 4;
-
-		if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
-			return NOT_ALLOWED;
-
-		if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
-		    (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
-		    (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
-		    (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
-		    (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
-		    (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
-		    (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
-		    (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
-			return NOT_ALLOWED;
-	}
-
-	return ALLOWED;
-}
-
-
-static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
-					u8 channel, u8 bw)
-{
-	unsigned int flag = 0;
-	enum chan_allowed res, res2;
-
-	res2 = res = allow_channel(mode, channel, &flag);
-	if (bw == BW40MINUS) {
-		if (!(flag & HOSTAPD_CHAN_HT40MINUS))
-			return NOT_ALLOWED;
-		res2 = allow_channel(mode, channel - 4, NULL);
-	} else if (bw == BW40PLUS) {
-		if (!(flag & HOSTAPD_CHAN_HT40PLUS))
-			return NOT_ALLOWED;
-		res2 = allow_channel(mode, channel + 4, NULL);
-	} else if (bw == BW80) {
-		/*
-		 * channel is a center channel and as such, not necessarily a
-		 * valid 20 MHz channels. Override earlier allow_channel()
-		 * result and use only the 80 MHz specific version.
-		 */
-		res2 = res = verify_80mhz(mode, channel);
-	} else if (bw == BW160) {
-		/*
-		 * channel is a center channel and as such, not necessarily a
-		 * valid 20 MHz channels. Override earlier allow_channel()
-		 * result and use only the 160 MHz specific version.
-		 */
-		res2 = res = verify_160mhz(mode, channel);
-	} else if (bw == BW80P80) {
-		/*
-		 * channel is a center channel and as such, not necessarily a
-		 * valid 20 MHz channels. Override earlier allow_channel()
-		 * result and use only the 80 MHz specific version.
-		 */
-		res2 = res = verify_80mhz(mode, channel);
-	}
-
-	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
-		return NOT_ALLOWED;
-
-	return ALLOWED;
-}
-
-
-static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
-				   const struct oper_class_map *op_class)
-{
-	int chan;
-	size_t i;
-	struct hostapd_hw_modes *mode;
-	int found;
-
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
-	if (!mode)
-		return 0;
-
-	if (op_class->op_class == 128) {
-		u8 channels[] = { 42, 58, 106, 122, 138, 155 };
-
-		for (i = 0; i < ARRAY_SIZE(channels); i++) {
-			if (verify_channel(mode, channels[i], op_class->bw) ==
-			    ALLOWED)
-				return 1;
-		}
-
-		return 0;
-	}
-
-	if (op_class->op_class == 129) {
-		/* Check if either 160 MHz channels is allowed */
-		return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
-			verify_channel(mode, 114, op_class->bw) == ALLOWED;
-	}
-
-	if (op_class->op_class == 130) {
-		/* Need at least two non-contiguous 80 MHz segments */
-		found = 0;
-
-		if (verify_channel(mode, 42, op_class->bw) == ALLOWED ||
-		    verify_channel(mode, 58, op_class->bw) == ALLOWED)
-			found++;
-		if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
-		    verify_channel(mode, 122, op_class->bw) == ALLOWED ||
-		    verify_channel(mode, 138, op_class->bw) == ALLOWED)
-			found++;
-		if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
-		    verify_channel(mode, 138, op_class->bw) == ALLOWED)
-			found++;
-		if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
-			found++;
-
-		if (found >= 2)
-			return 1;
-
-		return 0;
-	}
-
-	found = 0;
-	for (chan = op_class->min_chan; chan <= op_class->max_chan;
-	     chan += op_class->inc) {
-		if (verify_channel(mode, chan, op_class->bw) == ALLOWED) {
-			found = 1;
-			break;
-		}
-	}
-
-	return found;
-}
-
-
-int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
-			      size_t len)
-{
-	struct wpabuf *buf;
-	u8 op, current, chan;
-	u8 *ie_len;
-	int res;
-
-	/*
-	 * Assume 20 MHz channel for now.
-	 * TODO: Use the secondary channel and VHT channel width that will be
-	 * used after association.
-	 */
-	if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
-					  &current, &chan) == NUM_HOSTAPD_MODES)
-		return 0;
-
-	/*
-	 * Need 3 bytes for EID, length, and current operating class, plus
-	 * 1 byte for every other supported operating class.
-	 */
-	buf = wpabuf_alloc(global_op_class_size + 3);
-	if (!buf)
-		return 0;
-
-	wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
-	/* Will set the length later, putting a placeholder */
-	ie_len = wpabuf_put(buf, 1);
-	wpabuf_put_u8(buf, current);
-
-	for (op = 0; global_op_class[op].op_class; op++) {
-		if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
-			wpabuf_put_u8(buf, global_op_class[op].op_class);
-	}
-
-	*ie_len = wpabuf_len(buf) - 2;
-	if (*ie_len < 2 || wpabuf_len(buf) > len) {
-		wpa_printf(MSG_ERROR,
-			   "Failed to add supported operating classes IE");
-		res = 0;
-	} else {
-		os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
-		res = wpabuf_len(buf);
-		wpa_hexdump_buf(MSG_DEBUG,
-				"MBO: Added supported operating classes IE",
-				buf);
-	}
-
-	wpabuf_free(buf);
-	return res;
-}
-
-
 void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
 			   size_t len)
 {
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index d67d3b2..602ed2e 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -146,7 +146,8 @@
 
 
 static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
-				    struct wpa_ssid *ssid)
+				    struct wpa_ssid *ssid,
+				    struct hostapd_freq_params *freq)
 {
 	struct hostapd_iface *ifmsh;
 	struct hostapd_data *bss;
@@ -156,6 +157,7 @@
 	static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
 	size_t len;
 	int rate_len;
+	int frequency;
 
 	if (!wpa_s->conf->user_mpm) {
 		/* not much for us to do here */
@@ -185,7 +187,13 @@
 	bss->drv_priv = wpa_s->drv_priv;
 	bss->iface = ifmsh;
 	bss->mesh_sta_free_cb = mesh_mpm_free_sta;
-	wpa_s->assoc_freq = ssid->frequency;
+	frequency = ssid->frequency;
+	if (frequency != freq->freq &&
+	    frequency == freq->freq + freq->sec_channel_offset * 20) {
+		wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
+		frequency = freq->freq;
+	}
+	wpa_s->assoc_freq = frequency;
 	wpa_s->current_ssid = ssid;
 
 	/* setup an AP config for auth processing */
@@ -211,10 +219,10 @@
 	ifmsh->mconf = mconf;
 
 	/* need conf->hw_mode for supported rates. */
-	conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel);
+	conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel);
 	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
 		wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
-			   ssid->frequency);
+			   frequency);
 		goto out_free;
 	}
 	if (ssid->ht40)
@@ -225,13 +233,13 @@
 		case VHT_CHANWIDTH_80MHZ:
 		case VHT_CHANWIDTH_80P80MHZ:
 			ieee80211_freq_to_chan(
-				ssid->frequency,
+				frequency,
 				&conf->vht_oper_centr_freq_seg0_idx);
 			conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
 			break;
 		case VHT_CHANWIDTH_160MHZ:
 			ieee80211_freq_to_chan(
-				ssid->frequency,
+				frequency,
 				&conf->vht_oper_centr_freq_seg0_idx);
 			conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
 			conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
@@ -422,7 +430,7 @@
 	}
 	params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
 
-	if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+	if (wpa_supplicant_mesh_init(wpa_s, ssid, &params.freq)) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
 		wpa_drv_leave_mesh(wpa_s);
 		ret = -1;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 3fdb36f..1f5b42d 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -159,6 +159,12 @@
 	wpas_hidl_notify_assoc_reject(wpa_s);
 }
 
+void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s) {
+	if (wpa_s->p2p_mgmt)
+		return;
+
+	wpas_hidl_notify_auth_timeout(wpa_s);
+}
 
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
 {
@@ -591,19 +597,27 @@
 {
 	/* Notify P2P find has stopped */
 	wpas_dbus_signal_p2p_find_stopped(wpa_s);
+
+	wpas_hidl_notify_p2p_find_stopped(wpa_s);
 }
 
 
 void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
-				  const u8 *dev_addr, int new_device)
+				  const u8 *addr, const struct p2p_peer_info *info,
+				  const u8* peer_wfd_device_info, u8 peer_wfd_device_info_len,
+				  int new_device)
 {
 	if (new_device) {
 		/* Create the new peer object */
-		wpas_dbus_register_peer(wpa_s, dev_addr);
+		wpas_dbus_register_peer(wpa_s, info->p2p_device_addr);
 	}
 
 	/* Notify a new peer has been detected*/
-	wpas_dbus_signal_peer_device_found(wpa_s, dev_addr);
+	wpas_dbus_signal_peer_device_found(wpa_s, info->p2p_device_addr);
+
+	wpas_hidl_notify_p2p_device_found(wpa_s, addr, info,
+					  peer_wfd_device_info,
+					  peer_wfd_device_info_len);
 }
 
 
@@ -614,6 +628,8 @@
 
 	/* Create signal on interface object*/
 	wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr);
+
+	wpas_hidl_notify_p2p_device_lost(wpa_s, dev_addr);
 }
 
 
@@ -624,6 +640,8 @@
 	wpas_dbus_signal_p2p_group_removed(wpa_s, role);
 
 	wpas_dbus_unregister_p2p_group(wpa_s, ssid);
+
+	wpas_hidl_notify_p2p_group_removed(wpa_s, ssid, role);
 }
 
 
@@ -631,6 +649,8 @@
 				const u8 *src, u16 dev_passwd_id, u8 go_intent)
 {
 	wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id, go_intent);
+
+	wpas_hidl_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id, go_intent);
 }
 
 
@@ -638,6 +658,8 @@
 				      struct p2p_go_neg_results *res)
 {
 	wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res);
+
+	wpas_hidl_notify_p2p_go_neg_completed(wpa_s, res);
 }
 
 
@@ -645,6 +667,8 @@
 				       int status, const u8 *bssid)
 {
 	wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid);
+
+	wpas_hidl_notify_p2p_invitation_result(wpa_s, status, bssid);
 }
 
 
@@ -664,6 +688,9 @@
 {
 	wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic,
 					 tlvs, tlvs_len);
+
+	wpas_hidl_notify_p2p_sd_response(wpa_s, sa, update_indic,
+					 tlvs, tlvs_len);
 }
 
 
@@ -689,6 +716,11 @@
 	wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
 						 status, config_methods,
 						 generated_pin);
+
+	wpas_hidl_notify_p2p_provision_discovery(wpa_s, dev_addr, request,
+						 status, config_methods,
+						 generated_pin);
+
 }
 
 
@@ -700,6 +732,8 @@
 	wpas_dbus_register_p2p_group(wpa_s, ssid);
 
 	wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent, ip);
+
+	wpas_hidl_notify_p2p_group_started(wpa_s, ssid, persistent, client, ip);
 }
 
 
@@ -708,6 +742,8 @@
 {
 	/* Notify a group formation failed */
 	wpas_dbus_signal_p2p_group_formation_failure(wpa_s, reason);
+
+	wpas_hidl_notify_p2p_group_formation_failure(wpa_s, reason);
 }
 
 
@@ -725,6 +761,9 @@
 	/* Notify a P2P Invitation Request */
 	wpas_dbus_signal_p2p_invitation_received(wpa_s, sa, go_dev_addr, bssid,
 						 id, op_freq);
+
+	wpas_hidl_notify_p2p_invitation_received(wpa_s, sa, go_dev_addr, bssid,
+						 id, op_freq);
 }
 
 #endif /* CONFIG_P2P */
@@ -747,6 +786,8 @@
 
 	/* Notify listeners a new station has been authorized */
 	wpas_dbus_signal_sta_authorized(wpa_s, sta);
+
+	wpas_hidl_notify_ap_sta_authorized(wpa_s, sta, p2p_dev_addr);
 }
 
 
@@ -765,6 +806,8 @@
 
 	/* Notify listeners a station has been deauthorized */
 	wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
+
+	wpas_hidl_notify_ap_sta_deauthorized(wpa_s, sta, p2p_dev_addr);
 }
 
 
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 2590e9a..9c98524 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -25,6 +25,7 @@
 			       enum wpa_states old_state);
 void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
 void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
+void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -89,7 +90,9 @@
 				const u8 *p2p_dev_addr);
 void wpas_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
 void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
-				  const u8 *dev_addr, int new_device);
+				 const u8 *addr, const struct p2p_peer_info *info,
+				 const u8* peer_wfd_device_info, u8 peer_wfd_device_info_len,
+				 int new_device);
 void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
 				 const u8 *dev_addr);
 void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
new file mode 100644
index 0000000..d23b009
--- /dev/null
+++ b/wpa_supplicant/op_classes.c
@@ -0,0 +1,325 @@
+/*
+ * Operating classes
+ * Copyright(c) 2015 Intel Deutschland GmbH
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * 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_common.h"
+#include "wpa_supplicant_i.h"
+
+
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+				       unsigned int *flags)
+{
+	int i;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].chan == chan)
+			break;
+	}
+
+	if (i == mode->num_channels ||
+	    (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
+		return NOT_ALLOWED;
+
+	if (flags)
+		*flags = mode->channels[i].flag;
+
+	if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+		return NO_IR;
+
+	return ALLOWED;
+}
+
+
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+	u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+	size_t i;
+
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+		/*
+		 * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+		 * so the center channel is 6 channels away from the start/end.
+		 */
+		if (channel >= center_channels[i] - 6 &&
+		    channel <= center_channels[i] + 6)
+			return center_channels[i];
+	}
+
+	return 0;
+}
+
+
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+	u8 center_chan;
+	unsigned int i;
+	unsigned int no_ir = 0;
+
+	center_chan = get_center_80mhz(mode, channel);
+	if (!center_chan)
+		return NOT_ALLOWED;
+
+	/* check all the channels are available */
+	for (i = 0; i < 4; i++) {
+		unsigned int flags;
+		u8 adj_chan = center_chan - 6 + i * 4;
+
+		if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+			return NOT_ALLOWED;
+
+		if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
+		    (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
+		    (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
+		    (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
+			return NOT_ALLOWED;
+
+		if (flags & HOSTAPD_CHAN_NO_IR)
+			no_ir = 1;
+	}
+
+	if (no_ir)
+		return NO_IR;
+
+	return ALLOWED;
+}
+
+
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+	u8 center_channels[] = { 50, 114 };
+	unsigned int i;
+
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+		/*
+		 * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+		 * so the center channel is 14 channels away from the start/end.
+		 */
+		if (channel >= center_channels[i] - 14 &&
+		    channel <= center_channels[i] + 14)
+			return center_channels[i];
+	}
+
+	return 0;
+}
+
+
+static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
+				       u8 channel)
+{
+	u8 center_chan;
+	unsigned int i;
+	unsigned int no_ir = 0;
+
+	center_chan = get_center_160mhz(mode, channel);
+	if (!center_chan)
+		return NOT_ALLOWED;
+
+	/* Check all the channels are available */
+	for (i = 0; i < 8; i++) {
+		unsigned int flags;
+		u8 adj_chan = center_chan - 14 + i * 4;
+
+		if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+			return NOT_ALLOWED;
+
+		if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
+		    (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
+		    (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
+		    (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
+		    (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
+		    (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
+		    (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
+		    (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
+			return NOT_ALLOWED;
+
+		if (flags & HOSTAPD_CHAN_NO_IR)
+			no_ir = 1;
+	}
+
+	if (no_ir)
+		return NO_IR;
+
+	return ALLOWED;
+}
+
+
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
+				 u8 bw)
+{
+	unsigned int flag = 0;
+	enum chan_allowed res, res2;
+
+	res2 = res = allow_channel(mode, channel, &flag);
+	if (bw == BW40MINUS) {
+		if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+			return NOT_ALLOWED;
+		res2 = allow_channel(mode, channel - 4, NULL);
+	} else if (bw == BW40PLUS) {
+		if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+			return NOT_ALLOWED;
+		res2 = allow_channel(mode, channel + 4, NULL);
+	} else if (bw == BW80) {
+		/*
+		 * channel is a center channel and as such, not necessarily a
+		 * valid 20 MHz channels. Override earlier allow_channel()
+		 * result and use only the 80 MHz specific version.
+		 */
+		res2 = res = verify_80mhz(mode, channel);
+	} else if (bw == BW160) {
+		/*
+		 * channel is a center channel and as such, not necessarily a
+		 * valid 20 MHz channels. Override earlier allow_channel()
+		 * result and use only the 160 MHz specific version.
+		 */
+		res2 = res = verify_160mhz(mode, channel);
+	} else if (bw == BW80P80) {
+		/*
+		 * channel is a center channel and as such, not necessarily a
+		 * valid 20 MHz channels. Override earlier allow_channel()
+		 * result and use only the 80 MHz specific version.
+		 */
+		res2 = res = verify_80mhz(mode, channel);
+	}
+
+	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+		return NOT_ALLOWED;
+
+	if (res == NO_IR || res2 == NO_IR)
+		return NO_IR;
+
+	return ALLOWED;
+}
+
+
+static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+				   const struct oper_class_map *op_class)
+{
+	int chan;
+	size_t i;
+	struct hostapd_hw_modes *mode;
+	int found;
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+	if (!mode)
+		return 0;
+
+	if (op_class->op_class == 128) {
+		u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+
+		for (i = 0; i < ARRAY_SIZE(channels); i++) {
+			if (verify_channel(mode, channels[i], op_class->bw) !=
+			    NOT_ALLOWED)
+				return 1;
+		}
+
+		return 0;
+	}
+
+	if (op_class->op_class == 129) {
+		/* Check if either 160 MHz channels is allowed */
+		return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
+			verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+	}
+
+	if (op_class->op_class == 130) {
+		/* Need at least two non-contiguous 80 MHz segments */
+		found = 0;
+
+		if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
+		    verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+			found++;
+		if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
+		    verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
+		    verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+			found++;
+		if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
+		    verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+			found++;
+		if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+			found++;
+
+		if (found >= 2)
+			return 1;
+
+		return 0;
+	}
+
+	found = 0;
+	for (chan = op_class->min_chan; chan <= op_class->max_chan;
+	     chan += op_class->inc) {
+		if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+			found = 1;
+			break;
+		}
+	}
+
+	return found;
+}
+
+
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+			      size_t len)
+{
+	struct wpabuf *buf;
+	u8 op, current, chan;
+	u8 *ie_len;
+	size_t res;
+
+	/*
+	 * Assume 20 MHz channel for now.
+	 * TODO: Use the secondary channel and VHT channel width that will be
+	 * used after association.
+	 */
+	if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+					  &current, &chan) == NUM_HOSTAPD_MODES)
+		return 0;
+
+	/*
+	 * Need 3 bytes for EID, length, and current operating class, plus
+	 * 1 byte for every other supported operating class.
+	 */
+	buf = wpabuf_alloc(global_op_class_size + 3);
+	if (!buf)
+		return 0;
+
+	wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
+	/* Will set the length later, putting a placeholder */
+	ie_len = wpabuf_put(buf, 1);
+	wpabuf_put_u8(buf, current);
+
+	for (op = 0; global_op_class[op].op_class; op++) {
+		if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
+			wpabuf_put_u8(buf, global_op_class[op].op_class);
+	}
+
+	*ie_len = wpabuf_len(buf) - 2;
+	if (*ie_len < 2 || wpabuf_len(buf) > len) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to add supported operating classes IE");
+		res = 0;
+	} else {
+		os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
+		res = wpabuf_len(buf);
+		wpa_hexdump_buf(MSG_DEBUG,
+				"Added supported operating classes IE", buf);
+	}
+
+	wpabuf_free(buf);
+	return res;
+}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 2da92bf..a24505f 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2289,6 +2289,8 @@
 			   const struct p2p_peer_info *info,
 			   int new_device)
 {
+	u8 *wfd_dev_info = NULL;
+	u8 wfd_dev_info_len = 0;
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	struct wpa_supplicant *wpa_s = ctx;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -2297,6 +2299,12 @@
 #ifdef CONFIG_WIFI_DISPLAY
 	wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
 						    WFD_SUBELEM_DEVICE_INFO);
+	if (wfd_dev_info_hex) {
+		wfd_dev_info_len = strlen(wfd_dev_info_hex) / 2;
+		wfd_dev_info = os_zalloc(wfd_dev_info_len);
+		// Only used for notification, so not handling error.
+		hexstr2bin(wfd_dev_info_hex, wfd_dev_info, wfd_dev_info_len);
+	}
 #endif /* CONFIG_WIFI_DISPLAY */
 
 	if (info->p2ps_instance) {
@@ -2363,7 +2371,9 @@
 	os_free(wfd_dev_info_hex);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-	wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
+	wpas_notify_p2p_device_found(ctx, addr, info, wfd_dev_info,
+				     wfd_dev_info_len, new_device);
+	os_free(wfd_dev_info);
 }
 
 
@@ -3334,10 +3344,6 @@
 }
 
 
-enum chan_allowed {
-	NOT_ALLOWED, NO_IR, ALLOWED
-};
-
 static int has_channel(struct wpa_global *global,
 		       struct hostapd_hw_modes *mode, u8 chan, int *flags)
 {
@@ -5239,11 +5245,11 @@
 		if (!res && max_pref_freq > 0) {
 			*num_pref_freq = max_pref_freq;
 			i = 0;
-			while ((!p2p_supported_freq(wpa_s->global->p2p,
+			while (i < *num_pref_freq &&
+			       (!p2p_supported_freq(wpa_s->global->p2p,
 						    pref_freq_list[i]) ||
 				wpas_p2p_disallowed_freq(wpa_s->global,
-							pref_freq_list[i])) &&
-			       i < *num_pref_freq) {
+							 pref_freq_list[i]))) {
 				wpa_printf(MSG_DEBUG,
 					   "P2P: preferred_freq_list[%d]=%d is disallowed",
 					   i, pref_freq_list[i]);
@@ -5606,9 +5612,9 @@
 						 &size, pref_freq_list);
 		if (!res && size > 0) {
 			i = 0;
-			while (wpas_p2p_disallowed_freq(wpa_s->global,
-							pref_freq_list[i]) &&
-			       i < size) {
+			while (i < size &&
+			       wpas_p2p_disallowed_freq(wpa_s->global,
+							pref_freq_list[i])) {
 				wpa_printf(MSG_DEBUG,
 					   "P2P: preferred_freq_list[%d]=%d is disallowed",
 					   i, pref_freq_list[i]);
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index f4bba98..6ae239f 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -143,7 +143,7 @@
 }
 
 
-static int wpa_supplicant_add_pmkid(void *wpa_s,
+static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
 				    const u8 *bssid, const u8 *pmkid)
 {
 	printf("%s - not implemented\n", __func__);
@@ -151,7 +151,7 @@
 }
 
 
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
+static int wpa_supplicant_remove_pmkid(void *wpa_s, void *network_ctx,
 				       const u8 *bssid, const u8 *pmkid)
 {
 	printf("%s - not implemented\n", __func__);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
new file mode 100644
index 0000000..942eea7
--- /dev/null
+++ b/wpa_supplicant/rrm.c
@@ -0,0 +1,1453 @@
+/*
+ * wpa_supplicant - Radio Measurements
+ * Copyright (c) 2003-2016, 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 "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+
+
+static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
+{
+	struct rrm_data *rrm = data;
+
+	if (!rrm->notify_neighbor_rep) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Unexpected neighbor report timeout");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
+	rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
+
+	rrm->notify_neighbor_rep = NULL;
+	rrm->neighbor_rep_cb_ctx = NULL;
+}
+
+
+/*
+ * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
+ * @wpa_s: Pointer to wpa_supplicant
+ */
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->rrm.rrm_used = 0;
+
+	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+			     NULL);
+	if (wpa_s->rrm.notify_neighbor_rep)
+		wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+	wpa_s->rrm.next_neighbor_rep_token = 1;
+	wpas_clear_beacon_rep_data(wpa_s);
+}
+
+
+/*
+ * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
+ * @wpa_s: Pointer to wpa_supplicant
+ * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
+ * @report_len: Length of neighbor report buffer
+ */
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+				   const u8 *report, size_t report_len)
+{
+	struct wpabuf *neighbor_rep;
+
+	wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
+	if (report_len < 1)
+		return;
+
+	if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Discarding neighbor report with token %d (expected %d)",
+			   report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
+		return;
+	}
+
+	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+			     NULL);
+
+	if (!wpa_s->rrm.notify_neighbor_rep) {
+		wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+		return;
+	}
+
+	/* skipping the first byte, which is only an id (dialog token) */
+	neighbor_rep = wpabuf_alloc(report_len - 1);
+	if (!neighbor_rep) {
+		wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+		return;
+	}
+	wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
+	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+		   report[0]);
+	wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
+				       neighbor_rep);
+	wpa_s->rrm.notify_neighbor_rep = NULL;
+	wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+}
+
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+/* Workaround different, undefined for Windows, error codes used here */
+#define ENOTCONN -1
+#define EOPNOTSUPP -1
+#define ECANCELED -1
+#endif
+
+/* Measurement Request element + Location Subject + Maximum Age subelement */
+#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
+/* Measurement Request element + Location Civic Request */
+#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
+
+
+/**
+ * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
+ *	  is sent in the request.
+ * @lci: if set, neighbor request will include LCI request
+ * @civic: if set, neighbor request will include civic location request
+ * @cb: Callback function to be called once the requested report arrives, or
+ *	timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
+ *	In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
+ *	the requester's responsibility to free it.
+ *	In the latter case NULL will be sent in 'neighbor_rep'.
+ * @cb_ctx: Context value to send the callback function
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ * In case there is a previous request which has not been answered yet, the
+ * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
+ * Request must contain a callback function.
+ */
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+				       const struct wpa_ssid_value *ssid,
+				       int lci, int civic,
+				       void (*cb)(void *ctx,
+						  struct wpabuf *neighbor_rep),
+				       void *cb_ctx)
+{
+	struct wpabuf *buf;
+	const u8 *rrm_ie;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+		return -ENOTCONN;
+	}
+
+	if (!wpa_s->rrm.rrm_used) {
+		wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+		return -EOPNOTSUPP;
+	}
+
+	rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
+				WLAN_EID_RRM_ENABLED_CAPABILITIES);
+	if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
+	    !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: No network support for Neighbor Report.");
+		return -EOPNOTSUPP;
+	}
+
+	if (!cb) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Neighbor Report request must provide a callback.");
+		return -EINVAL;
+	}
+
+	/* Refuse if there's a live request */
+	if (wpa_s->rrm.notify_neighbor_rep) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Currently handling previous Neighbor Report.");
+		return -EBUSY;
+	}
+
+	/* 3 = action category + action code + dialog token */
+	buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
+			   (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
+			   (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
+	if (buf == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Failed to allocate Neighbor Report Request");
+		return -ENOMEM;
+	}
+
+	wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
+		   (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+		   wpa_s->rrm.next_neighbor_rep_token);
+
+	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
+	wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
+	if (ssid) {
+		wpabuf_put_u8(buf, WLAN_EID_SSID);
+		wpabuf_put_u8(buf, ssid->ssid_len);
+		wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
+	}
+
+	if (lci) {
+		/* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+		wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+		wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
+
+		/*
+		 * Measurement token; nonzero number that is unique among the
+		 * Measurement Request elements in a particular frame.
+		 */
+		wpabuf_put_u8(buf, 1); /* Measurement Token */
+
+		/*
+		 * Parallel, Enable, Request, and Report bits are 0, Duration is
+		 * reserved.
+		 */
+		wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+		wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
+
+		/* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
+		/* Location Subject */
+		wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+		/* Optional Subelements */
+		/*
+		 * IEEE P802.11-REVmc/D5.0 Figure 9-170
+		 * The Maximum Age subelement is required, otherwise the AP can
+		 * send only data that was determined after receiving the
+		 * request. Setting it here to unlimited age.
+		 */
+		wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+		wpabuf_put_u8(buf, 2);
+		wpabuf_put_le16(buf, 0xffff);
+	}
+
+	if (civic) {
+		/* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+		wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+		wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
+
+		/*
+		 * Measurement token; nonzero number that is unique among the
+		 * Measurement Request elements in a particular frame.
+		 */
+		wpabuf_put_u8(buf, 2); /* Measurement Token */
+
+		/*
+		 * Parallel, Enable, Request, and Report bits are 0, Duration is
+		 * reserved.
+		 */
+		wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+		/* Measurement Type */
+		wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
+
+		/* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
+		 * Location Civic request */
+		/* Location Subject */
+		wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+		wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
+		/* Location Service Interval Units: Seconds */
+		wpabuf_put_u8(buf, 0);
+		/* Location Service Interval: 0 - Only one report is requested
+		 */
+		wpabuf_put_le16(buf, 0);
+		/* No optional subelements */
+	}
+
+	wpa_s->rrm.next_neighbor_rep_token++;
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Failed to send Neighbor Report Request");
+		wpabuf_free(buf);
+		return -ECANCELED;
+	}
+
+	wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
+	wpa_s->rrm.notify_neighbor_rep = cb;
+	eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
+			       wpas_rrm_neighbor_rep_timeout_handler,
+			       &wpa_s->rrm, NULL);
+
+	wpabuf_free(buf);
+	return 0;
+}
+
+
+static int wpas_rrm_report_elem(struct wpabuf *buf, u8 token, u8 mode, u8 type,
+				const u8 *data, size_t data_len)
+{
+	if (wpabuf_tailroom(buf) < 5 + data_len)
+		return -1;
+
+	wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+	wpabuf_put_u8(buf, 3 + data_len);
+	wpabuf_put_u8(buf, token);
+	wpabuf_put_u8(buf, mode);
+	wpabuf_put_u8(buf, type);
+
+	if (data_len)
+		wpabuf_put_data(buf, data, data_len);
+
+	return 0;
+}
+
+
+static int
+wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
+			  const struct rrm_measurement_request_element *req,
+			  struct wpabuf **buf)
+{
+	u8 subject;
+	u16 max_age = 0;
+	struct os_reltime t, diff;
+	unsigned long diff_l;
+	const u8 *subelem;
+	const u8 *request = req->variable;
+	size_t len = req->len - 3;
+
+	if (len < 1)
+		return -1;
+
+	if (!wpa_s->lci)
+		goto reject;
+
+	subject = *request++;
+	len--;
+
+	wpa_printf(MSG_DEBUG, "Measurement request location subject=%u",
+		   subject);
+
+	if (subject != LOCATION_SUBJECT_REMOTE) {
+		wpa_printf(MSG_INFO,
+			   "Not building LCI report - bad location subject");
+		return 0;
+	}
+
+	/* Subelements are formatted exactly like elements */
+	wpa_hexdump(MSG_DEBUG, "LCI request subelements", request, len);
+	subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
+	if (subelem && subelem[1] == 2)
+		max_age = WPA_GET_LE16(subelem + 2);
+
+	if (os_get_reltime(&t))
+		goto reject;
+
+	os_reltime_sub(&t, &wpa_s->lci_time, &diff);
+	/* LCI age is calculated in 10th of a second units. */
+	diff_l = diff.sec * 10 + diff.usec / 100000;
+
+	if (max_age != 0xffff && max_age < diff_l)
+		goto reject;
+
+	if (wpabuf_resize(buf, 5 + wpabuf_len(wpa_s->lci)))
+		return -1;
+
+	if (wpas_rrm_report_elem(*buf, req->token,
+				 MEASUREMENT_REPORT_MODE_ACCEPT, req->type,
+				 wpabuf_head_u8(wpa_s->lci),
+				 wpabuf_len(wpa_s->lci)) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to add LCI report element");
+		return -1;
+	}
+
+	return 0;
+
+reject:
+	if (wpabuf_resize(buf, sizeof(struct rrm_measurement_report_element))) {
+		wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
+		return -1;
+	}
+
+	if (wpas_rrm_report_elem(*buf, req->token,
+				 MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+				 req->type, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s,
+					  const u8 *data, size_t len)
+{
+	struct wpabuf *report = wpabuf_alloc(len + 3);
+
+	if (!report)
+		return;
+
+	wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+	wpabuf_put_u8(report, wpa_s->rrm.token);
+
+	wpabuf_put_data(report, data, len);
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(report), wpabuf_len(report), 0)) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Radio measurement report failed: Sending Action frame failed");
+	}
+
+	wpabuf_free(report);
+}
+
+
+static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
+				     struct wpabuf *buf)
+{
+	int len = wpabuf_len(buf);
+	const u8 *pos = wpabuf_head_u8(buf), *next = pos;
+
+#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
+
+	while (len) {
+		int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
+
+		if (send_len == len ||
+		    (send_len + next[1] + 2) > MPDU_REPORT_LEN) {
+			wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
+			len -= send_len;
+			pos = next;
+		}
+
+		next += next[1] + 2;
+	}
+#undef MPDU_REPORT_LEN
+}
+
+
+static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels,
+			    int *freqs)
+{
+	size_t i;
+
+	for (i = 0; i < num_primary_channels; i++) {
+		u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4;
+
+		freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan);
+		if (freqs[i] < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon Report: Invalid channel %u",
+				   chan);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int * wpas_add_channels(const struct oper_class_map *op,
+			       struct hostapd_hw_modes *mode, int active,
+			       const u8 *channels, const u8 size)
+{
+	int *freqs, *next_freq;
+	u8 num_primary_channels, i;
+	u8 num_chans;
+
+	num_chans = channels ? size :
+		(op->max_chan - op->min_chan) / op->inc + 1;
+
+	if (op->bw == BW80 || op->bw == BW80P80)
+		num_primary_channels = 4;
+	else if (op->bw == BW160)
+		num_primary_channels = 8;
+	else
+		num_primary_channels = 1;
+
+	/* one extra place for the zero-terminator */
+	freqs = os_calloc(num_chans * num_primary_channels + 1, sizeof(*freqs));
+	if (!freqs) {
+		wpa_printf(MSG_ERROR,
+			   "Beacon Report: Failed to allocate freqs array");
+		return NULL;
+	}
+
+	next_freq = freqs;
+	for  (i = 0; i < num_chans; i++) {
+		u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
+		enum chan_allowed res = verify_channel(mode, chan, op->bw);
+
+		if (res == NOT_ALLOWED || (res == NO_IR && active))
+			continue;
+
+		if (wpas_add_channel(op->op_class, chan, num_primary_channels,
+				     next_freq) < 0) {
+			os_free(freqs);
+			return NULL;
+		}
+
+		next_freq += num_primary_channels;
+	}
+
+	if (!freqs[0]) {
+		os_free(freqs);
+		return NULL;
+	}
+
+	return freqs;
+}
+
+
+static int * wpas_op_class_freqs(const struct oper_class_map *op,
+				 struct hostapd_hw_modes *mode, int active)
+{
+	u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 };
+	u8 channels_160mhz[] = { 50, 114 };
+
+	/*
+	 * When adding all channels in the operating class, 80 + 80 MHz
+	 * operating classes are like 80 MHz channels because we add all valid
+	 * channels anyway.
+	 */
+	if (op->bw == BW80 || op->bw == BW80P80)
+		return wpas_add_channels(op, mode, active, channels_80mhz,
+					 ARRAY_SIZE(channels_80mhz));
+
+	if (op->bw == BW160)
+		return wpas_add_channels(op, mode, active, channels_160mhz,
+					 ARRAY_SIZE(channels_160mhz));
+
+	return wpas_add_channels(op, mode, active, NULL, 0);
+}
+
+
+static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active,
+				       const char *country, const u8 *subelems,
+				       size_t len)
+{
+	int *freqs = NULL, *new_freqs;
+	const u8 *end = subelems + len;
+
+	while (end - subelems > 2) {
+		const struct oper_class_map *op;
+		const u8 *ap_chan_elem, *pos;
+		u8 left;
+		struct hostapd_hw_modes *mode;
+
+		ap_chan_elem = get_ie(subelems, end - subelems,
+				      WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL);
+		if (!ap_chan_elem)
+			break;
+		pos = ap_chan_elem + 2;
+		left = ap_chan_elem[1];
+		if (left < 1)
+			break;
+		subelems = ap_chan_elem + 2 + left;
+
+		op = get_oper_class(country, *pos);
+		if (!op) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon request: unknown operating class in AP Channel Report subelement %u",
+				   *pos);
+			goto out;
+		}
+		pos++;
+		left--;
+
+		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+		if (!mode)
+			continue;
+
+		/*
+		 * For 80 + 80 MHz operating classes, this AP Channel Report
+		 * element should be followed by another element specifying
+		 * the second 80 MHz channel. For now just add this 80 MHz
+		 * channel, the second 80 MHz channel will be added when the
+		 * next element is parsed.
+		 * TODO: Verify that this AP Channel Report element is followed
+		 * by a corresponding AP Channel Report element as specified in
+		 * IEEE Std 802.11-2016, 11.11.9.1.
+		 */
+		new_freqs = wpas_add_channels(op, mode, active, pos, left);
+		if (new_freqs)
+			int_array_concat(&freqs, new_freqs);
+
+		os_free(new_freqs);
+	}
+
+	return freqs;
+out:
+	os_free(freqs);
+	return NULL;
+}
+
+
+static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
+				       u8 op_class, u8 chan, int active,
+				       const u8 *subelems, size_t len)
+{
+	int *freqs = NULL, *ext_freqs = NULL;
+	struct hostapd_hw_modes *mode;
+	const char *country = NULL;
+	const struct oper_class_map *op;
+	const u8 *elem;
+
+	if (!wpa_s->current_bss)
+		return NULL;
+	elem = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+	if (elem && elem[1] >= 2)
+		country = (const char *) (elem + 2);
+
+	op = get_oper_class(country, op_class);
+	if (!op) {
+		wpa_printf(MSG_DEBUG,
+			   "Beacon request: invalid operating class %d",
+			   op_class);
+		return NULL;
+	}
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+	if (!mode)
+		return NULL;
+
+	switch (chan) {
+	case 0:
+		freqs = wpas_op_class_freqs(op, mode, active);
+		if (!freqs)
+			return NULL;
+		break;
+	case 255:
+		/* freqs will be added from AP channel subelements */
+		break;
+	default:
+		freqs = wpas_add_channels(op, mode, active, &chan, 1);
+		if (!freqs)
+			return NULL;
+		break;
+	}
+
+	ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems,
+					      len);
+	if (ext_freqs) {
+		int_array_concat(&freqs, ext_freqs);
+		os_free(ext_freqs);
+	}
+
+	return freqs;
+}
+
+
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+			 u8 *op_class, u8 *chan, u8 *phy_type)
+{
+	const u8 *ie;
+	int sec_chan = 0, vht = 0;
+	struct ieee80211_ht_operation *ht_oper = NULL;
+	struct ieee80211_vht_operation *vht_oper = NULL;
+	u8 seg0, seg1;
+
+	ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
+	if (ie && ie[1] >= sizeof(struct ieee80211_ht_operation)) {
+		u8 sec_chan_offset;
+
+		ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+		sec_chan_offset = ht_oper->ht_param &
+			HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+		if (sec_chan_offset == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+			sec_chan = 1;
+		else if (sec_chan_offset ==
+			 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+			sec_chan = -1;
+	}
+
+	ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
+	if (ie && ie[1] >= sizeof(struct ieee80211_vht_operation)) {
+		vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+		switch (vht_oper->vht_op_info_chwidth) {
+		case 1:
+			seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
+			seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
+			if (seg1 && abs(seg1 - seg0) == 8)
+				vht = VHT_CHANWIDTH_160MHZ;
+			else if (seg1)
+				vht = VHT_CHANWIDTH_80P80MHZ;
+			else
+				vht = VHT_CHANWIDTH_80MHZ;
+			break;
+		case 2:
+			vht = VHT_CHANWIDTH_160MHZ;
+			break;
+		case 3:
+			vht = VHT_CHANWIDTH_80P80MHZ;
+			break;
+		default:
+			vht = VHT_CHANWIDTH_USE_HT;
+			break;
+		}
+	}
+
+	if (ieee80211_freq_to_channel_ext(freq, sec_chan, vht, op_class,
+					  chan) == NUM_HOSTAPD_MODES) {
+		wpa_printf(MSG_DEBUG,
+			   "Cannot determine operating class and channel");
+		return -1;
+	}
+
+	*phy_type = ieee80211_get_phy_type(freq, ht_oper != NULL,
+					   vht_oper != NULL);
+	if (*phy_type == PHY_TYPE_UNSPECIFIED) {
+		wpa_printf(MSG_DEBUG, "Cannot determine phy type");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
+					  enum beacon_report_detail detail,
+					  struct wpa_bss *bss, u8 *buf,
+					  size_t buf_len)
+{
+	u8 *ies = (u8 *) (bss + 1);
+	size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+	u8 *pos = buf;
+	int rem_len;
+
+	rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
+		sizeof(struct rrm_measurement_report_element) - 2;
+
+	if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+		wpa_printf(MSG_DEBUG,
+			   "Beacon Request: Invalid reporting detail: %d",
+			   detail);
+		return -1;
+	}
+
+	if (detail == BEACON_REPORT_DETAIL_NONE)
+		return 0;
+
+	/*
+	 * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
+	 * beacon interval(2) + capabilities(2) = 14 bytes
+	 */
+	if (buf_len < 14)
+		return 0;
+
+	*pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
+	/* The length will be filled later */
+	pos++;
+	WPA_PUT_LE64(pos, bss->tsf);
+	pos += sizeof(bss->tsf);
+	WPA_PUT_LE16(pos, bss->beacon_int);
+	pos += 2;
+	WPA_PUT_LE16(pos, bss->caps);
+	pos += 2;
+
+	rem_len -= pos - buf;
+
+	/*
+	 * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame
+	 * body subelement causes the element to exceed the maximum element
+	 * size, the subelement is truncated so that the last IE is a complete
+	 * IE. So even when required to report all IEs, add elements one after
+	 * the other and stop once there is no more room in the measurement
+	 * element.
+	 */
+	while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
+		if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
+		    (eids && bitfield_is_set(eids, ies[0]))) {
+			u8 eid = ies[0], elen = ies[1];
+
+			if ((eid == WLAN_EID_TIM || eid == WLAN_EID_RSN) &&
+			    elen > 4)
+				elen = 4;
+			/*
+			 * TODO: Truncate IBSS DFS element as described in
+			 * IEEE Std 802.11-2016, 9.4.2.22.7.
+			 */
+
+			if (2 + elen > buf + buf_len - pos ||
+			    2 + elen > rem_len)
+				break;
+
+			*pos++ = ies[0];
+			*pos++ = elen;
+			os_memcpy(pos, ies + 2, elen);
+			pos += elen;
+			rem_len -= 2 + elen;
+		}
+
+		ies_len -= 2 + ies[1];
+		ies += 2 + ies[1];
+	}
+
+	/* Now the length is known */
+	buf[1] = pos - buf - 2;
+	return pos - buf;
+}
+
+
+static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
+			       struct wpabuf **wpa_buf, struct wpa_bss *bss,
+			       u64 start, u64 parent_tsf)
+{
+	struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+	u8 *ie = (u8 *) (bss + 1);
+	size_t ie_len = bss->ie_len + bss->beacon_ie_len;
+	int ret;
+	u8 buf[2000];
+	struct rrm_measurement_beacon_report *rep;
+
+	if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
+	    os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
+		return 0;
+
+	if (data->ssid_len &&
+	    (data->ssid_len != bss->ssid_len ||
+	     os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
+		return 0;
+
+	rep = (struct rrm_measurement_beacon_report *) buf;
+	if (wpas_get_op_chan_phy(bss->freq, ie, ie_len, &rep->op_class,
+				 &rep->channel, &rep->report_info) < 0)
+		return 0;
+
+	rep->start_time = host_to_le64(start);
+	rep->duration = host_to_le16(data->scan_params.duration);
+	rep->rcpi = rssi_to_rcpi(bss->level);
+	rep->rsni = 255; /* 255 indicates that RSNI is not available */
+	os_memcpy(rep->bssid, bss->bssid, ETH_ALEN);
+	rep->antenna_id = 0; /* unknown */
+	rep->parent_tsf = host_to_le32(parent_tsf);
+
+	ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+					     bss, rep->variable,
+					     sizeof(buf) - sizeof(*rep));
+	if (ret < 0)
+		return -1;
+
+	if (wpabuf_resize(wpa_buf,
+			  sizeof(struct rrm_measurement_report_element) +
+			  sizeof(*rep) + ret)) {
+		wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+		return -1;
+	}
+
+	return wpas_rrm_report_elem(*wpa_buf, wpa_s->beacon_rep_data.token,
+				    MEASUREMENT_REPORT_MODE_ACCEPT,
+				    MEASURE_TYPE_BEACON, buf,
+				    ret + sizeof(*rep));
+}
+
+
+static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
+				      struct wpabuf **buf)
+{
+	if (wpabuf_resize(buf, 5)) {
+		wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
+		return -1;
+	}
+
+	return wpas_rrm_report_elem(*buf, wpa_s->beacon_rep_data.token,
+				    MEASUREMENT_REPORT_MODE_ACCEPT,
+				    MEASURE_TYPE_BEACON, NULL, 0);
+}
+
+
+static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s,
+				  struct wpabuf **buf)
+{
+	size_t i;
+
+	for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+		if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i],
+					0, 0) < 0)
+			break;
+	}
+
+	if (!(*buf))
+		wpas_beacon_rep_no_results(wpa_s, buf);
+
+	wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf);
+}
+
+
+static void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(sizeof(struct rrm_measurement_beacon_report));
+	if (!buf ||
+	    wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
+				 MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
+				 MEASURE_TYPE_BEACON, NULL, 0)) {
+		wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+		wpabuf_free(buf);
+		return;
+	}
+
+	wpas_rrm_send_msr_report(wpa_s, buf);
+	wpas_clear_beacon_rep_data(wpa_s);
+	wpabuf_free(buf);
+}
+
+
+static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_driver_scan_params *params =
+		&wpa_s->beacon_rep_data.scan_params;
+	u16 prev_duration = params->duration;
+
+	if (!wpa_s->current_bss)
+		return;
+
+	if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) &&
+	    params->duration) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Cannot set scan duration due to missing driver support");
+		params->duration = 0;
+	}
+	os_get_reltime(&wpa_s->beacon_rep_scan);
+	if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) ||
+	    wpa_supplicant_trigger_scan(wpa_s, params))
+		wpas_rrm_refuse_request(wpa_s);
+	params->duration = prev_duration;
+}
+
+
+static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s,
+					     struct beacon_rep_data *data,
+					     u8 sid, u8 slen, const u8 *subelem)
+{
+	u8 report_info, i;
+
+	switch (sid) {
+	case WLAN_BEACON_REQUEST_SUBELEM_SSID:
+		if (!slen) {
+			wpa_printf(MSG_DEBUG,
+				   "SSID subelement with zero length - wildcard SSID");
+			break;
+		}
+
+		if (slen > SSID_MAX_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid SSID subelement length: %u", slen);
+			return -1;
+		}
+
+		data->ssid_len = slen;
+		os_memcpy(data->ssid, subelem, data->ssid_len);
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_INFO:
+		if (slen != 2) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid reporting information subelement length: %u",
+				   slen);
+			return -1;
+		}
+
+		report_info = subelem[0];
+		if (report_info != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "reporting information=%u is not supported",
+				   report_info);
+			return 0;
+		}
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_DETAIL:
+		if (slen != 1) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid reporting detail subelement length: %u",
+				   slen);
+			return -1;
+		}
+
+		data->report_detail = subelem[0];
+		if (data->report_detail >
+		    BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+			wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u",
+				   subelem[0]);
+			return 0;
+		}
+
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_REQUEST:
+		if (data->report_detail !=
+		    BEACON_REPORT_DETAIL_REQUESTED_ONLY) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon request: request subelement is present but report detail is %u",
+				   data->report_detail);
+			return -1;
+		}
+
+		if (!slen) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid request subelement length: %u",
+				   slen);
+			return -1;
+		}
+
+		if (data->eids) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon Request: Request subelement appears more than once");
+			return -1;
+		}
+
+		data->eids = bitfield_alloc(255);
+		if (!data->eids) {
+			wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap");
+			return -1;
+		}
+
+		for (i = 0; i < slen; i++)
+			bitfield_set(data->eids, subelem[i]);
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
+		/* Skip - it will be processed when freqs are added */
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "Beacon request: Unknown subelement id %u", sid);
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Returns 0 if the next element can be processed, 1 if some operation was
+ * triggered, and -1 if processing failed (i.e., the element is in invalid
+ * format or an internal error occurred).
+ */
+static int
+wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
+			  u8 elem_token, int duration_mandatory,
+			  const struct rrm_measurement_beacon_request *req,
+			  size_t len, struct wpabuf **buf)
+{
+	struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+	struct wpa_driver_scan_params *params = &data->scan_params;
+	const u8 *subelems;
+	size_t elems_len;
+	u16 rand_interval;
+	u32 interval_usec;
+	u32 _rand;
+	int ret = 0, res;
+
+	if (len < sizeof(*req))
+		return -1;
+
+	if (req->mode != BEACON_REPORT_MODE_PASSIVE &&
+	    req->mode != BEACON_REPORT_MODE_ACTIVE &&
+	    req->mode != BEACON_REPORT_MODE_TABLE)
+		return 0;
+
+	subelems = req->variable;
+	elems_len = len - sizeof(*req);
+	rand_interval = le_to_host16(req->rand_interval);
+
+	os_memset(params, 0, sizeof(*params));
+
+	data->token = elem_token;
+
+	/* default reporting detail is all fixed length fields and all
+	 * elements */
+	data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS;
+	os_memcpy(data->bssid, req->bssid, ETH_ALEN);
+
+	while (elems_len >= 2) {
+		if (subelems[1] > elems_len - 2) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon Request: Truncated subelement");
+			ret = -1;
+			goto out;
+		}
+
+		res = wpas_rm_handle_beacon_req_subelem(
+			wpa_s, data, subelems[0], subelems[1], &subelems[2]);
+		if (res != 1) {
+			ret = res;
+			goto out;
+		}
+
+		elems_len -= 2 + subelems[1];
+		subelems += 2 + subelems[1];
+	}
+
+	if (req->mode == BEACON_REPORT_MODE_TABLE) {
+		wpas_beacon_rep_table(wpa_s, buf);
+		goto out;
+	}
+
+	params->freqs = wpas_beacon_request_freqs(
+		wpa_s, req->oper_class, req->channel,
+		req->mode == BEACON_REPORT_MODE_ACTIVE,
+		req->variable, len - sizeof(*req));
+	if (!params->freqs) {
+		wpa_printf(MSG_DEBUG, "Beacon request: No valid channels");
+		goto out;
+	}
+
+	params->duration = le_to_host16(req->duration);
+	params->duration_mandatory = duration_mandatory;
+	if (!params->duration) {
+		wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
+		ret = -1;
+		goto out;
+	}
+
+	params->only_new_results = 1;
+
+	if (req->mode == BEACON_REPORT_MODE_ACTIVE) {
+		params->ssids[params->num_ssids].ssid = data->ssid;
+		params->ssids[params->num_ssids++].ssid_len = data->ssid_len;
+	}
+
+	if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+		_rand = os_random();
+	interval_usec = (_rand % (rand_interval + 1)) * 1024;
+	eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s,
+			       NULL);
+	return 1;
+out:
+	wpas_clear_beacon_rep_data(wpa_s);
+	return ret;
+}
+
+
+static int
+wpas_rrm_handle_msr_req_element(
+	struct wpa_supplicant *wpa_s,
+	const struct rrm_measurement_request_element *req,
+	struct wpabuf **buf)
+{
+	int duration_mandatory;
+
+	wpa_printf(MSG_DEBUG, "Measurement request type %d token %d",
+		   req->type, req->token);
+
+	if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) {
+		/* Enable bit is not supported for now */
+		wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore");
+		return 0;
+	}
+
+	if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) &&
+	    req->type > MEASURE_TYPE_RPI_HIST) {
+		/* Parallel measurements are not supported for now */
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Parallel measurements are not supported, reject");
+		goto reject;
+	}
+
+	duration_mandatory =
+		!!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY);
+
+	switch (req->type) {
+	case MEASURE_TYPE_LCI:
+		return wpas_rrm_build_lci_report(wpa_s, req, buf);
+	case MEASURE_TYPE_BEACON:
+		if (duration_mandatory &&
+		    !(wpa_s->drv_rrm_flags &
+		      WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL)) {
+			wpa_printf(MSG_DEBUG,
+				   "RRM: Driver does not support dwell time configuration - reject beacon report with mandatory duration");
+			goto reject;
+		}
+		return wpas_rm_handle_beacon_req(wpa_s, req->token,
+						 duration_mandatory,
+						 (const void *) req->variable,
+						 req->len - 3, buf);
+	default:
+		wpa_printf(MSG_INFO,
+			   "RRM: Unsupported radio measurement type %u",
+			   req->type);
+		break;
+	}
+
+reject:
+	if (wpabuf_resize(buf, sizeof(struct rrm_measurement_report_element))) {
+		wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
+		return -1;
+	}
+
+	if (wpas_rrm_report_elem(*buf, req->token,
+				 MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+				 req->type, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf *
+wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos,
+			       size_t len)
+{
+	struct wpabuf *buf = NULL;
+
+	while (len) {
+		const struct rrm_measurement_request_element *req;
+		int res;
+
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "RRM: Truncated element");
+			goto out;
+		}
+
+		req = (const struct rrm_measurement_request_element *) pos;
+		if (req->eid != WLAN_EID_MEASURE_REQUEST) {
+			wpa_printf(MSG_DEBUG,
+				   "RRM: Expected Measurement Request element, but EID is %u",
+				   req->eid);
+			goto out;
+		}
+
+		if (req->len < 3) {
+			wpa_printf(MSG_DEBUG, "RRM: Element length too short");
+			goto out;
+		}
+
+		if (req->len > len - 2) {
+			wpa_printf(MSG_DEBUG, "RRM: Element length too long");
+			goto out;
+		}
+
+		res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf);
+		if (res < 0)
+			goto out;
+
+		pos += req->len + 2;
+		len -= req->len + 2;
+	}
+
+	return buf;
+
+out:
+	wpabuf_free(buf);
+	return NULL;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+					       const u8 *src,
+					       const u8 *frame, size_t len)
+{
+	struct wpabuf *report;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring radio measurement request: Not associated");
+		return;
+	}
+
+	if (!wpa_s->rrm.rrm_used) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring radio measurement request: Not RRM network");
+		return;
+	}
+
+	if (len < 3) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring too short radio measurement request");
+		return;
+	}
+
+	wpa_s->rrm.token = *frame;
+
+	/* Number of repetitions is not supported */
+
+	report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3);
+	if (!report)
+		return;
+
+	wpas_rrm_send_msr_report(wpa_s, report);
+	wpabuf_free(report);
+}
+
+
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+					      const u8 *src,
+					      const u8 *frame, size_t len,
+					      int rssi)
+{
+	struct wpabuf *buf;
+	const struct rrm_link_measurement_request *req;
+	struct rrm_link_measurement_report report;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring link measurement request. Not associated");
+		return;
+	}
+
+	if (!wpa_s->rrm.rrm_used) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring link measurement request. Not RRM network");
+		return;
+	}
+
+	if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Measurement report failed. TX power insertion not supported");
+		return;
+	}
+
+	req = (const struct rrm_link_measurement_request *) frame;
+	if (len < sizeof(*req)) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Link measurement report failed. Request too short");
+		return;
+	}
+
+	os_memset(&report, 0, sizeof(report));
+	report.tpc.eid = WLAN_EID_TPC_REPORT;
+	report.tpc.len = 2;
+	report.rsni = 255; /* 255 indicates that RSNI is not available */
+	report.dialog_token = req->dialog_token;
+	report.rcpi = rssi_to_rcpi(rssi);
+
+	/* action_category + action_code */
+	buf = wpabuf_alloc(2 + sizeof(report));
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Link measurement report failed. Buffer allocation failed");
+		return;
+	}
+
+	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+	wpabuf_put_data(buf, &report, sizeof(report));
+	wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
+		    wpabuf_head(buf), wpabuf_len(buf));
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0)) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Link measurement report failed. Send action failed");
+	}
+	wpabuf_free(buf);
+}
+
+
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+				 struct wpa_scan_results *scan_res,
+				 struct scan_info *info)
+{
+	size_t i = 0;
+	struct wpabuf *buf = NULL;
+
+	if (!wpa_s->beacon_rep_data.token)
+		return 0;
+
+	if (!wpa_s->current_bss)
+		goto out;
+
+	/* If the measurement was aborted, don't report partial results */
+	if (info->aborted)
+		goto out;
+
+	wpa_printf(MSG_DEBUG, "RRM: TSF BSSID: " MACSTR " current BSS: " MACSTR,
+		   MAC2STR(info->scan_start_tsf_bssid),
+		   MAC2STR(wpa_s->current_bss->bssid));
+	if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) &&
+	    os_memcmp(info->scan_start_tsf_bssid, wpa_s->current_bss->bssid,
+		      ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Ignore scan results due to mismatching TSF BSSID");
+		goto out;
+	}
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_bss *bss =
+			wpa_bss_get_bssid(wpa_s, scan_res->res[i]->bssid);
+
+		if (!bss)
+			continue;
+
+		if ((wpa_s->drv_rrm_flags &
+		     WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) &&
+		    os_memcmp(scan_res->res[i]->tsf_bssid,
+			      wpa_s->current_bss->bssid, ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RRM: Ignore scan result for " MACSTR
+				   " due to mismatching TSF BSSID" MACSTR,
+				   MAC2STR(scan_res->res[i]->bssid),
+				   MAC2STR(scan_res->res[i]->tsf_bssid));
+			continue;
+		}
+
+		if (!(wpa_s->drv_rrm_flags &
+		      WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) {
+			struct os_reltime update_time, diff;
+
+			/* For now, allow 8 ms older results due to some
+			 * unknown issue with cfg80211 BSS table updates during
+			 * a scan with the current BSS.
+			 * TODO: Fix this more properly to avoid having to have
+			 * this type of hacks in place. */
+			calculate_update_time(&scan_res->fetch_time,
+					      scan_res->res[i]->age,
+					      &update_time);
+			os_reltime_sub(&wpa_s->beacon_rep_scan,
+				       &update_time, &diff);
+			if (os_reltime_before(&update_time,
+					      &wpa_s->beacon_rep_scan) &&
+			    (diff.sec || diff.usec >= 8000)) {
+				wpa_printf(MSG_DEBUG,
+					   "RRM: Ignore scan result for " MACSTR
+					   " due to old update (age(ms) %u, calculated age %u.%06u seconds)",
+					   MAC2STR(scan_res->res[i]->bssid),
+					   scan_res->res[i]->age,
+					   (unsigned int) diff.sec,
+					   (unsigned int) diff.usec);
+				continue;
+			}
+		}
+
+		/*
+		 * Don't report results that were not received during the
+		 * current measurement.
+		 */
+		if (info->scan_start_tsf > scan_res->res[i]->parent_tsf)
+			continue;
+
+		if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf,
+					scan_res->res[i]->parent_tsf) < 0)
+			break;
+	}
+
+	if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf))
+		goto out;
+
+	wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf);
+
+	wpas_rrm_send_msr_report(wpa_s, buf);
+	wpabuf_free(buf);
+
+out:
+	wpas_clear_beacon_rep_data(wpa_s);
+	return 1;
+}
+
+
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s)
+{
+	struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+
+	eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL);
+	bitfield_free(data->eids);
+	os_free(data->scan_params.freqs);
+	os_memset(data, 0, sizeof(*data));
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 272e633..16f9c5c 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -714,6 +714,8 @@
 	size_t max_ssids;
 	int connect_without_scan = 0;
 
+	wpa_s->ignore_post_flush_scan_res = 0;
+
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
 		return;
@@ -2212,6 +2214,16 @@
 	}
 	dump_scan_res(scan_res);
 
+	if (wpa_s->ignore_post_flush_scan_res) {
+		/* FLUSH command aborted an ongoing scan and these are the
+		 * results from the aborted scan. Do not process the results to
+		 * maintain flushed state. */
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Do not update BSS table based on pending post-FLUSH scan results");
+		wpa_s->ignore_post_flush_scan_res = 0;
+		return scan_res;
+	}
+
 	wpa_bss_update_start(wpa_s);
 	for (i = 0; i < scan_res->num; i++)
 		wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
@@ -2336,6 +2348,8 @@
 	params->p2p_probe = src->p2p_probe;
 	params->only_new_results = src->only_new_results;
 	params->low_priority = src->low_priority;
+	params->duration = src->duration;
+	params->duration_mandatory = src->duration_mandatory;
 
 	if (src->sched_scan_plans_num > 0) {
 		params->sched_scan_plans =
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index ab71f6d..f478836 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -187,6 +187,10 @@
 	if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
 		*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
 
+	*pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+		WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+		WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+
 	if (wpa_s->lci)
 		pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT;
 
@@ -212,9 +216,6 @@
 	u8 ext_capab[18];
 	int ext_capab_len;
 	int skip_auth;
-#ifdef CONFIG_MBO
-	const u8 *mbo;
-#endif /* CONFIG_MBO */
 
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -440,20 +441,10 @@
 
 	sme_auth_handle_rrm(wpa_s, bss);
 
-#ifdef CONFIG_MBO
-	mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
-	if (mbo) {
-		int len;
-
-		len = wpas_mbo_supp_op_class_ie(
-			wpa_s, bss->freq,
-			wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
-			sizeof(wpa_s->sme.assoc_req_ie) -
-			wpa_s->sme.assoc_req_ie_len);
-		if (len > 0)
-			wpa_s->sme.assoc_req_ie_len += len;
-	}
-#endif /* CONFIG_MBO */
+	wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
+		wpa_s, bss->freq,
+		wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+		sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
 
 	if (params.p2p)
 		wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
@@ -511,7 +502,7 @@
 	}
 
 #ifdef CONFIG_MBO
-	if (mbo) {
+	if (wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
 		int len;
 
 		len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index f11028a..77038ca 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,7 +29,7 @@
 
 static const char *const wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
 
 #define VENDOR_ELEM_FRAME_ID \
 	"  0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
@@ -335,6 +335,22 @@
 }
 
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+
+static int wpa_cli_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "PMKSA_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv);
+}
+
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	print_help(argc > 0 ? argv[0] : NULL);
@@ -1392,6 +1408,7 @@
 	"macsec_policy",
 	"macsec_integ_only",
 	"macsec_port",
+	"mka_priority",
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	"update_identifier",
@@ -2868,6 +2885,14 @@
 	{ "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL,
 	  cli_cmd_flag_none,
 	  "= flush PMKSA cache entries" },
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+	{ "pmksa_get", wpa_cli_cmd_pmksa_get, NULL,
+	  cli_cmd_flag_none,
+	  "<network_id> = fetch all stored PMKSA cache entries" },
+	{ "pmksa_add", wpa_cli_cmd_pmksa_add, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> <expiration in seconds> <akmp> <opportunistic> = store PMKSA cache entry from external storage" },
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 	{ "reassociate", wpa_cli_cmd_reassociate, NULL,
 	  cli_cmd_flag_none,
 	  "= force reassociation" },
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index 9b568f0..adca1cc 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -17,6 +17,7 @@
 	unsigned char psk[32];
 	int i;
 	char *ssid, *passphrase, buf[64], *pos;
+	size_t len;
 
 	if (argc < 2) {
 		printf("usage: wpa_passphrase <ssid> [passphrase]\n"
@@ -47,10 +48,15 @@
 		passphrase = buf;
 	}
 
-	if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) {
+	len = os_strlen(passphrase);
+	if (len < 8 || len > 63) {
 		printf("Passphrase must be 8..63 characters\n");
 		return 1;
 	}
+	if (has_ctrl_char((u8 *) passphrase, len)) {
+		printf("Invalid passphrase character\n");
+		return 1;
+	}
 
 	pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
 
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 9b81fc1..46cb95e 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -1190,7 +1190,7 @@
 static void usage(void)
 {
 	printf("wpa_priv v" VERSION_STR "\n"
-	       "Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> and "
+	       "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
 	       "contributors\n"
 	       "\n"
 	       "usage:\n"
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 531004f..fe14cc8 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -62,7 +62,7 @@
 
 const char *const wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *const wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -202,6 +202,7 @@
 	wpa_sm_notify_disassoc(wpa_s->wpa);
 	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 	wpa_s->reassociate = 1;
+	wpas_notify_auth_timeout(wpa_s);
 
 	/*
 	 * If we timed out, the AP or the local radio may be busy.
@@ -585,6 +586,7 @@
 
 	wpabuf_free(wpa_s->lci);
 	wpa_s->lci = NULL;
+	wpas_clear_beacon_rep_data(wpa_s);
 }
 
 
@@ -1798,6 +1800,13 @@
 		return;
 	}
 
+#ifdef CONFIG_SME
+	if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
+		/* Clear possibly set auth_alg, if any, from last attempt. */
+		wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
+	}
+#endif /* CONFIG_SME */
+
 	wpas_abort_ongoing_scan(wpa_s);
 
 	cwork = os_zalloc(sizeof(*cwork));
@@ -2140,9 +2149,6 @@
        struct ieee80211_vht_capabilities vhtcaps;
        struct ieee80211_vht_capabilities vhtcaps_mask;
 #endif /* CONFIG_VHT_OVERRIDES */
-#ifdef CONFIG_MBO
-	const u8 *mbo = NULL;
-#endif /* CONFIG_MBO */
 
 	if (deinit) {
 		if (work->started) {
@@ -2331,21 +2337,12 @@
 	os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_MBO
 	if (bss) {
-		mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
-		if (mbo) {
-			int len;
-
-			len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
-							wpa_ie + wpa_ie_len,
-							sizeof(wpa_ie) -
-							wpa_ie_len);
-			if (len > 0)
-				wpa_ie_len += len;
-		}
+		wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+						    wpa_ie + wpa_ie_len,
+						    sizeof(wpa_ie) -
+						    wpa_ie_len);
 	}
-#endif /* CONFIG_MBO */
 
 	/*
 	 * Workaround: Add Extended Capabilities element only if the AP
@@ -2424,7 +2421,7 @@
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_MBO
-	if (mbo) {
+	if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
 		int len;
 
 		len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -6305,489 +6302,6 @@
 }
 
 
-static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
-{
-	struct rrm_data *rrm = data;
-
-	if (!rrm->notify_neighbor_rep) {
-		wpa_printf(MSG_ERROR,
-			   "RRM: Unexpected neighbor report timeout");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
-	rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
-
-	rrm->notify_neighbor_rep = NULL;
-	rrm->neighbor_rep_cb_ctx = NULL;
-}
-
-
-/*
- * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
- * @wpa_s: Pointer to wpa_supplicant
- */
-void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->rrm.rrm_used = 0;
-
-	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-			     NULL);
-	if (wpa_s->rrm.notify_neighbor_rep)
-		wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
-	wpa_s->rrm.next_neighbor_rep_token = 1;
-}
-
-
-/*
- * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
- * @wpa_s: Pointer to wpa_supplicant
- * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
- * @report_len: Length of neighbor report buffer
- */
-void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
-				   const u8 *report, size_t report_len)
-{
-	struct wpabuf *neighbor_rep;
-
-	wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
-	if (report_len < 1)
-		return;
-
-	if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Discarding neighbor report with token %d (expected %d)",
-			   report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
-		return;
-	}
-
-	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-			     NULL);
-
-	if (!wpa_s->rrm.notify_neighbor_rep) {
-		wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
-		return;
-	}
-
-	/* skipping the first byte, which is only an id (dialog token) */
-	neighbor_rep = wpabuf_alloc(report_len - 1);
-	if (neighbor_rep == NULL)
-		return;
-	wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
-	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
-		   report[0]);
-	wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
-				       neighbor_rep);
-	wpa_s->rrm.notify_neighbor_rep = NULL;
-	wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
-}
-
-
-#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
-/* Workaround different, undefined for Windows, error codes used here */
-#define ENOTCONN -1
-#define EOPNOTSUPP -1
-#define ECANCELED -1
-#endif
-
-/* Measurement Request element + Location Subject + Maximum Age subelement */
-#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
-/* Measurement Request element + Location Civic Request */
-#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
-
-
-/**
- * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
- * @wpa_s: Pointer to wpa_supplicant
- * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
- *	  is sent in the request.
- * @lci: if set, neighbor request will include LCI request
- * @civic: if set, neighbor request will include civic location request
- * @cb: Callback function to be called once the requested report arrives, or
- *	timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
- *	In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
- *	the requester's responsibility to free it.
- *	In the latter case NULL will be sent in 'neighbor_rep'.
- * @cb_ctx: Context value to send the callback function
- * Returns: 0 in case of success, negative error code otherwise
- *
- * In case there is a previous request which has not been answered yet, the
- * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
- * Request must contain a callback function.
- */
-int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-				       const struct wpa_ssid_value *ssid,
-				       int lci, int civic,
-				       void (*cb)(void *ctx,
-						  struct wpabuf *neighbor_rep),
-				       void *cb_ctx)
-{
-	struct wpabuf *buf;
-	const u8 *rrm_ie;
-
-	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
-		return -ENOTCONN;
-	}
-
-	if (!wpa_s->rrm.rrm_used) {
-		wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
-		return -EOPNOTSUPP;
-	}
-
-	rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
-				WLAN_EID_RRM_ENABLED_CAPABILITIES);
-	if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
-	    !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: No network support for Neighbor Report.");
-		return -EOPNOTSUPP;
-	}
-
-	if (!cb) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Neighbor Report request must provide a callback.");
-		return -EINVAL;
-	}
-
-	/* Refuse if there's a live request */
-	if (wpa_s->rrm.notify_neighbor_rep) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Currently handling previous Neighbor Report.");
-		return -EBUSY;
-	}
-
-	/* 3 = action category + action code + dialog token */
-	buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
-			   (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
-			   (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Failed to allocate Neighbor Report Request");
-		return -ENOMEM;
-	}
-
-	wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
-		   (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
-		   wpa_s->rrm.next_neighbor_rep_token);
-
-	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-	wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
-	wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
-	if (ssid) {
-		wpabuf_put_u8(buf, WLAN_EID_SSID);
-		wpabuf_put_u8(buf, ssid->ssid_len);
-		wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
-	}
-
-	if (lci) {
-		/* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
-		wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
-		wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
-
-		/*
-		 * Measurement token; nonzero number that is unique among the
-		 * Measurement Request elements in a particular frame.
-		 */
-		wpabuf_put_u8(buf, 1); /* Measurement Token */
-
-		/*
-		 * Parallel, Enable, Request, and Report bits are 0, Duration is
-		 * reserved.
-		 */
-		wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
-		wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
-
-		/* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
-		/* Location Subject */
-		wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
-
-		/* Optional Subelements */
-		/*
-		 * IEEE P802.11-REVmc/D5.0 Figure 9-170
-		 * The Maximum Age subelement is required, otherwise the AP can
-		 * send only data that was determined after receiving the
-		 * request. Setting it here to unlimited age.
-		 */
-		wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
-		wpabuf_put_u8(buf, 2);
-		wpabuf_put_le16(buf, 0xffff);
-	}
-
-	if (civic) {
-		/* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
-		wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
-		wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
-
-		/*
-		 * Measurement token; nonzero number that is unique among the
-		 * Measurement Request elements in a particular frame.
-		 */
-		wpabuf_put_u8(buf, 2); /* Measurement Token */
-
-		/*
-		 * Parallel, Enable, Request, and Report bits are 0, Duration is
-		 * reserved.
-		 */
-		wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
-		/* Measurement Type */
-		wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
-
-		/* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
-		 * Location Civic request */
-		/* Location Subject */
-		wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
-		wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
-		/* Location Service Interval Units: Seconds */
-		wpabuf_put_u8(buf, 0);
-		/* Location Service Interval: 0 - Only one report is requested
-		 */
-		wpabuf_put_le16(buf, 0);
-		/* No optional subelements */
-	}
-
-	wpa_s->rrm.next_neighbor_rep_token++;
-
-	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-				wpa_s->own_addr, wpa_s->bssid,
-				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Failed to send Neighbor Report Request");
-		wpabuf_free(buf);
-		return -ECANCELED;
-	}
-
-	wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
-	wpa_s->rrm.notify_neighbor_rep = cb;
-	eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
-			       wpas_rrm_neighbor_rep_timeout_handler,
-			       &wpa_s->rrm, NULL);
-
-	wpabuf_free(buf);
-	return 0;
-}
-
-
-static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
-						 const u8 *request, size_t len,
-						 struct wpabuf *report)
-{
-	u8 token, type, subject;
-	u16 max_age = 0;
-	struct os_reltime t, diff;
-	unsigned long diff_l;
-	u8 *ptoken;
-	const u8 *subelem;
-
-	if (!wpa_s->lci || len < 3 + 4)
-		return report;
-
-	token = *request++;
-	/* Measurement request mode isn't used */
-	request++;
-	type = *request++;
-	subject = *request++;
-
-	wpa_printf(MSG_DEBUG,
-		   "Measurement request token %u type %u location subject %u",
-		   token, type, subject);
-
-	if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) {
-		wpa_printf(MSG_INFO,
-			   "Not building LCI report - bad type or location subject");
-		return report;
-	}
-
-	/* Subelements are formatted exactly like elements */
-	subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
-	if (subelem && subelem[1] == 2)
-		max_age = WPA_GET_LE16(subelem + 2);
-
-	if (os_get_reltime(&t))
-		return report;
-
-	os_reltime_sub(&t, &wpa_s->lci_time, &diff);
-	/* LCI age is calculated in 10th of a second units. */
-	diff_l = diff.sec * 10 + diff.usec / 100000;
-
-	if (max_age != 0xffff && max_age < diff_l)
-		return report;
-
-	if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci)))
-		return report;
-
-	wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT);
-	wpabuf_put_u8(report, wpabuf_len(wpa_s->lci));
-	/* We'll override user's measurement token */
-	ptoken = wpabuf_put(report, 0);
-	wpabuf_put_buf(report, wpa_s->lci);
-	*ptoken = token;
-
-	return report;
-}
-
-
-void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
-					       const u8 *src,
-					       const u8 *frame, size_t len)
-{
-	struct wpabuf *buf, *report;
-	u8 token;
-	const u8 *ie, *end;
-
-	if (wpa_s->wpa_state != WPA_COMPLETED) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Ignoring radio measurement request: Not associated");
-		return;
-	}
-
-	if (!wpa_s->rrm.rrm_used) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Ignoring radio measurement request: Not RRM network");
-		return;
-	}
-
-	if (len < 3) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Ignoring too short radio measurement request");
-		return;
-	}
-
-	end = frame + len;
-
-	token = *frame++;
-
-	/* Ignore number of repetitions because it's not used in LCI request */
-	frame += 2;
-
-	report = NULL;
-	while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) &&
-	       ie[1] >= 3) {
-		u8 msmt_type;
-
-		msmt_type = ie[4];
-		wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type);
-
-		switch (msmt_type) {
-		case MEASURE_TYPE_LCI:
-			report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1],
-							   report);
-			break;
-		default:
-			wpa_printf(MSG_INFO,
-				   "RRM: Unsupported radio measurement request %d",
-				   msmt_type);
-			break;
-		}
-
-		frame = ie + ie[1] + 2;
-	}
-
-	if (!report)
-		return;
-
-	buf = wpabuf_alloc(3 + wpabuf_len(report));
-	if (!buf) {
-		wpabuf_free(report);
-		return;
-	}
-
-	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-	wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
-	wpabuf_put_u8(buf, token);
-
-	wpabuf_put_buf(buf, report);
-	wpabuf_free(report);
-
-	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-				wpa_s->own_addr, wpa_s->bssid,
-				wpabuf_head(buf), wpabuf_len(buf), 0)) {
-		wpa_printf(MSG_ERROR,
-			   "RRM: Radio measurement report failed: Sending Action frame failed");
-	}
-	wpabuf_free(buf);
-}
-
-
-void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
-					      const u8 *src,
-					      const u8 *frame, size_t len,
-					      int rssi)
-{
-	struct wpabuf *buf;
-	const struct rrm_link_measurement_request *req;
-	struct rrm_link_measurement_report report;
-
-	if (wpa_s->wpa_state != WPA_COMPLETED) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Ignoring link measurement request. Not associated");
-		return;
-	}
-
-	if (!wpa_s->rrm.rrm_used) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Ignoring link measurement request. Not RRM network");
-		return;
-	}
-
-	if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Measurement report failed. TX power insertion not supported");
-		return;
-	}
-
-	req = (const struct rrm_link_measurement_request *) frame;
-	if (len < sizeof(*req)) {
-		wpa_printf(MSG_INFO,
-			   "RRM: Link measurement report failed. Request too short");
-		return;
-	}
-
-	os_memset(&report, 0, sizeof(report));
-	report.tpc.eid = WLAN_EID_TPC_REPORT;
-	report.tpc.len = 2;
-	report.rsni = 255; /* 255 indicates that RSNI is not available */
-	report.dialog_token = req->dialog_token;
-
-	/*
-	 * It's possible to estimate RCPI based on RSSI in dBm. This
-	 * calculation will not reflect the correct value for high rates,
-	 * but it's good enough for Action frames which are transmitted
-	 * with up to 24 Mbps rates.
-	 */
-	if (!rssi)
-		report.rcpi = 255; /* not available */
-	else if (rssi < -110)
-		report.rcpi = 0;
-	else if (rssi > 0)
-		report.rcpi = 220;
-	else
-		report.rcpi = (rssi + 110) * 2;
-
-	/* action_category + action_code */
-	buf = wpabuf_alloc(2 + sizeof(report));
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR,
-			   "RRM: Link measurement report failed. Buffer allocation failed");
-		return;
-	}
-
-	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-	wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
-	wpabuf_put_data(buf, &report, sizeof(report));
-	wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
-		    wpabuf_head(buf), wpabuf_len(buf));
-
-	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-				wpa_s->own_addr, wpa_s->bssid,
-				wpabuf_head(buf), wpabuf_len(buf), 0)) {
-		wpa_printf(MSG_ERROR,
-			   "RRM: Link measurement report failed. Send action failed");
-	}
-	wpabuf_free(buf);
-}
-
-
 struct wpa_supplicant *
 wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
 {
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index edb230d..94cef4a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -901,13 +901,15 @@
 # Port component of the SCI
 # Range: 1-65534 (default: 1)
 #
-# mka_cak and mka_ckn: IEEE 802.1X/MACsec pre-shared authentication mode
+# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
 # This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
-# In this mode, instances of wpa_supplicant can act as peers, one of
-# which will become the key server and start distributing SAKs.
+# In this mode, instances of wpa_supplicant can act as MACsec peers. The peer
+# with lower priority will become the key server and start distributing SAKs.
 # mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit)
 # hex-string (32 hex-digits)
 # mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits)
+# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
+# default priority
 #
 # mixed_cell: This option can be used to configure whether so called mixed
 # cells, i.e., networks that use both plaintext and encryption in the same
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index ff3a531..3c902fa 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -9,6 +9,7 @@
 #ifndef WPA_SUPPLICANT_I_H
 #define WPA_SUPPLICANT_I_H
 
+#include "utils/bitfield.h"
 #include "utils/list.h"
 #include "common/defs.h"
 #include "common/sae.h"
@@ -424,6 +425,9 @@
 
 	/* next_neighbor_rep_token - Next request's dialog token */
 	u8 next_neighbor_rep_token;
+
+	/* token - Dialog token of the current radio measurement */
+	u8 token;
 };
 
 enum wpa_supplicant_test_failure {
@@ -446,6 +450,17 @@
 	struct os_reltime disallowed_until;
 };
 
+struct beacon_rep_data {
+	u8 token;
+	struct wpa_driver_scan_params scan_params;
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len;
+	u8 bssid[ETH_ALEN];
+	enum beacon_report_detail report_detail;
+	struct bitfield *eids;
+};
+
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -987,6 +1002,7 @@
 	unsigned int wmm_ac_supported:1;
 	unsigned int ext_work_in_progress:1;
 	unsigned int own_disconnect_req:1;
+	unsigned int ignore_post_flush_scan_res:1;
 
 #define MAC_ADDR_RAND_SCAN       BIT(0)
 #define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
@@ -1044,6 +1060,7 @@
 	u8 last_tspecs_count;
 
 	struct rrm_data rrm;
+	struct beacon_rep_data beacon_rep_data;
 
 #ifdef CONFIG_FST
 	struct fst_iface *fst;
@@ -1075,6 +1092,8 @@
 	 */
 	struct wpabuf *lci;
 	struct os_reltime lci_time;
+
+	struct os_reltime beacon_rep_scan;
 };
 
 
@@ -1195,6 +1214,10 @@
 					      const u8 *src,
 					      const u8 *frame, size_t len,
 					      int rssi);
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+				 struct wpa_scan_results *scan_res,
+				 struct scan_info *info);
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
 
 
 /* MBO functions */
@@ -1203,8 +1226,6 @@
 int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
 				  const char *non_pref_chan);
 void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
-int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
-			      size_t len);
 void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
 			   size_t len);
 size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
@@ -1214,6 +1235,16 @@
 struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
 				   struct wpa_bss *bss);
 
+/* op_classes.c */
+enum chan_allowed {
+	NOT_ALLOWED, NO_IR, ALLOWED
+};
+
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
+				 u8 bw);
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+			      size_t len);
+
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
  * @wpa_s: Pointer to wpa_supplicant data
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index f3f2a64..f55227f 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -4,3 +4,4 @@
 ap_scan=1
 fast_reauth=1
 pmf=1
+p2p_add_cli_chan=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index f84c8b9..16ffc7f 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
 #include "rsn_supp/wpa.h"
 #include "eloop.h"
 #include "config.h"
@@ -513,16 +514,44 @@
 }
 
 
-static int wpa_supplicant_add_pmkid(void *wpa_s,
+static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s,
+					      void *network_ctx)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (network_ctx == ssid)
+			return ssid;
+	}
+
+	return NULL;
+}
+
+
+static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
 				    const u8 *bssid, const u8 *pmkid)
 {
+	struct wpa_supplicant *wpa_s = _wpa_s;
+	struct wpa_ssid *ssid;
+
+	ssid = wpas_get_network_ctx(wpa_s, network_ctx);
+	if (ssid)
+		wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
+			MAC2STR(bssid), ssid->id);
 	return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
 }
 
 
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
+static int wpa_supplicant_remove_pmkid(void *_wpa_s, void *network_ctx,
 				       const u8 *bssid, const u8 *pmkid)
 {
+	struct wpa_supplicant *wpa_s = _wpa_s;
+	struct wpa_ssid *ssid;
+
+	ssid = wpas_get_network_ctx(wpa_s, network_ctx);
+	if (ssid)
+		wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_REMOVED MACSTR " %d",
+			MAC2STR(bssid), ssid->id);
 	return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
 }
 
@@ -865,6 +894,7 @@
 
 
 #ifdef CONFIG_EAP_PROXY
+
 static void wpa_supplicant_eap_proxy_cb(void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -880,6 +910,52 @@
 		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
 	}
 }
+
+
+static void wpa_sm_sim_state_error_handler(struct wpa_supplicant *wpa_s)
+{
+	int i;
+	struct wpa_ssid *ssid;
+	const struct eap_method_type *eap_methods;
+
+	if (!wpa_s->conf)
+		return;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)	{
+		eap_methods = ssid->eap.eap_methods;
+		if (!eap_methods)
+			continue;
+
+		for (i = 0; eap_methods[i].method != EAP_TYPE_NONE; i++) {
+			if (eap_methods[i].vendor == EAP_VENDOR_IETF &&
+			    (eap_methods[i].method == EAP_TYPE_SIM ||
+			     eap_methods[i].method == EAP_TYPE_AKA ||
+			     eap_methods[i].method == EAP_TYPE_AKA_PRIME)) {
+				wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+				break;
+			}
+		}
+	}
+}
+
+
+static void
+wpa_supplicant_eap_proxy_notify_sim_status(void *ctx,
+					   enum eap_proxy_sim_state sim_state)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status %u", sim_state);
+	switch (sim_state) {
+	case SIM_STATE_ERROR:
+		wpa_sm_sim_state_error_handler(wpa_s);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status unknown");
+		break;
+	}
+}
+
 #endif /* CONFIG_EAP_PROXY */
 
 
@@ -990,6 +1066,8 @@
 	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
 #ifdef CONFIG_EAP_PROXY
 	ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
+	ctx->eap_proxy_notify_sim_status =
+		wpa_supplicant_eap_proxy_notify_sim_status;
 #endif /* CONFIG_EAP_PROXY */
 	ctx->port_cb = wpa_supplicant_port_cb;
 	ctx->cb = wpa_supplicant_eapol_cb;
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index d3fefda..d087e00 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -233,7 +233,8 @@
 	kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
 
 	res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_port,
-				  wpa_s->ifname, wpa_s->own_addr);
+				  ssid->mka_priority, wpa_s->ifname,
+				  wpa_s->own_addr);
 	if (res == NULL) {
 		os_free(kay_ctx);
 		return -1;