Merge "P2P: introduce force_go_bssid bool to avoid changing p2p join behavior"
diff --git a/OWNERS b/OWNERS
index cd9dfa9..351212a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,2 @@
 etancohen@google.com
-haishalom@google.com
 arabawy@google.com
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index 2a25208..0c5d96b 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -55,7 +55,6 @@
         "libcrypto",
         "libssl",
         "libnl",
-        "libkeystore-wifi-hidl",
     ],
     relative_install_path: "hw",
     soc_specific: true,
@@ -169,6 +168,35 @@
         "-Wno-unused-variable",
         "-Wno-macro-redefined",
     ],
+    // Similar to suppressing clang compiler warnings, here we
+    // suppress clang-tidy warnings to reduce noises in Android build.log.
+    tidy_checks: [
+        "-android-cloexec-*",
+        "-bugprone-branch-clone",
+        "-bugprone-macro-parentheses",
+        "-bugprone-misplaced-widening-cast",
+        "-bugprone-signal-handler",
+        "-bugprone-signed-char-misuse",
+        "-bugprone-sizeof-expression",
+        "-bugprone-suspicious-string-compare",
+        "-bugprone-too-small-loop-variable",
+        "-cert-err34-c",
+        "-cert-msc30-c",
+        "-cert-msc50-cpp",
+        "-cert-msc54-cpp",
+        "-cert-sig30-c",
+        "-cert-str34-c",
+        "-clang-analyzer-core.NullDereference",
+        "-clang-analyzer-core.UndefinedBinaryOperatorResult",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.performance.Padding",
+        "-clang-analyzer-optin.portability.UnixAPI",
+        "-clang-analyzer-security.insecureAPI.UncheckedReturn",
+        "-clang-analyzer-unix.cstring.NullArg",
+        "-clang-analyzer-unix.Malloc",
+        "-clang-diagnostic-unused-but-set-variable",
+        "-misc-redundant-expression",
+    ],
 }
 
 
@@ -318,3 +346,9 @@
     ],
 
 }
+
+// This manifest can used by a vendor apex module for hostapd as well.
+filegroup {
+    name: "android.hardware.wifi.hostapd.xml",
+    srcs: ["android.hardware.wifi.hostapd.xml"],
+}
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index f2200d6..35bfbe7 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -702,6 +702,9 @@
 			   const std::vector<uint8_t>& client_address,
 			   const uint16_t reason_code) {
 	struct sta_info *sta;
+	if (client_address.size() != ETH_ALEN) {
+		return false;
+	}
 	for (sta = hapd->sta_list; sta; sta = sta->next) {
 		int res;
 		res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
diff --git a/src/common/dpp.h b/src/common/dpp.h
index ee29a08..3094be8 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -296,6 +296,7 @@
 	enum dpp_status_error auth_resp_status;
 	enum dpp_status_error conf_resp_status;
 	enum dpp_status_error force_conf_resp_status;
+	enum dpp_status_error conn_result_status;
 	u8 peer_mac_addr[ETH_ALEN];
 	u8 i_nonce[DPP_MAX_NONCE_LEN];
 	u8 r_nonce[DPP_MAX_NONCE_LEN];
@@ -340,6 +341,7 @@
 	int connect_on_tx_status;
 	int waiting_conf_result;
 	int waiting_conn_status_result;
+	int tx_conn_status_result_started;
 	int auth_success;
 	bool reconfig_success;
 	struct wpabuf *conf_req;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 52dc8df..d6fd792 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -312,10 +312,14 @@
 		elems->pasn_params_len = elen;
 		break;
 	case WLAN_EID_EXT_EHT_CAPABILITIES:
+		if (elen < EHT_CAPABILITIES_IE_MIN_LEN)
+			break;
 		elems->eht_capabilities = pos;
 		elems->eht_capabilities_len = elen;
 		break;
 	case WLAN_EID_EXT_EHT_OPERATION:
+		if (elen < EHT_OPERATION_IE_MIN_LEN)
+			break;
 		elems->eht_operation = pos;
 		elems->eht_operation_len = elen;
 		break;
@@ -2851,6 +2855,7 @@
 	struct supported_chan_width supported_width;
 	supported_width.is_160_supported = 0;
 	supported_width.is_80p80_supported = 0;
+	supported_width.is_320_supported = 0;
 	if (elems == NULL)
 		return supported_width;
 
@@ -2858,6 +2863,8 @@
 		(struct ieee80211_vht_capabilities *) elems->vht_capabilities;
 	struct ieee80211_he_capabilities *hecaps =
 		(struct ieee80211_he_capabilities *) elems->he_capabilities;
+	struct ieee80211_eht_capabilities *ehtcaps =
+		(struct ieee80211_eht_capabilities *) elems->eht_capabilities;
 
 	if (vhtcaps) {
 		le32 vht_capabilities_info =
@@ -2875,8 +2882,16 @@
 		if (channel_width_set & HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
 			supported_width.is_80p80_supported = 1;
 	}
-	wpa_printf(MSG_DEBUG, " IE indicate 160 supported: %u, 80+80 supported: %u",
-        supported_width.is_160_supported, supported_width.is_80p80_supported);
+	if (ehtcaps) {
+		if (ehtcaps->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+		    EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+			supported_width.is_320_supported = 1;
+	}
+	wpa_printf(MSG_DEBUG,
+		   " IE indicates 320 supported: %u, 160 supported: %u, 80+80 supported: %u",
+		   supported_width.is_320_supported,
+		   supported_width.is_160_supported,
+		   supported_width.is_80p80_supported);
 	return supported_width;
 }
 
@@ -2986,6 +3001,39 @@
 	return channel_width;
 }
 
+/* Parse EHT operation IE to get EHT operation channel width */
+static enum chan_width get_eht_operation_channel_width(
+				struct ieee80211_eht_operation *eht_oper,
+				int eht_oper_len)
+{
+	enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+	if (!(eht_oper->oper_params & EHT_OPER_INFO_PRESENT) ||
+	    eht_oper_len < (EHT_OPERATION_IE_MIN_LEN + EHT_OPER_INFO_MIN_LEN))
+		return channel_width;
+
+	switch (eht_oper->oper_info.control & EHT_OPER_CHANNEL_WIDTH_MASK) {
+	case EHT_OPER_CHANNEL_WIDTH_20MHZ:
+		channel_width = CHAN_WIDTH_20;
+		break;
+	case EHT_OPER_CHANNEL_WIDTH_40MHZ:
+		channel_width = CHAN_WIDTH_40;
+		break;
+	case EHT_OPER_CHANNEL_WIDTH_80MHZ:
+		channel_width = CHAN_WIDTH_80;
+		break;
+	case EHT_OPER_CHANNEL_WIDTH_160MHZ:
+		channel_width = CHAN_WIDTH_160;
+		break;
+	case EHT_OPER_CHANNEL_WIDTH_320MHZ:
+		channel_width = CHAN_WIDTH_320;
+		break;
+	default:
+		break;
+	}
+	wpa_printf(MSG_DEBUG, " EHT operation CBW: %u", channel_width);
+	return channel_width;
+}
+
 /* Parse HT/VHT/HE operation IEs to get operation channel width */
 enum chan_width get_operation_channel_width(struct ieee802_11_elems *elems)
 {
@@ -2999,7 +3047,14 @@
 	    (struct ieee80211_vht_operation_info *) elems->vht_operation;
 	struct ieee80211_he_operation *he_oper =
 	    (struct ieee80211_he_operation *) elems->he_operation;
-	if (he_oper)
+	struct ieee80211_eht_operation *eht_oper =
+	    (struct ieee80211_eht_operation *) elems->eht_operation;
+
+	if (eht_oper)
+		channel_width = get_eht_operation_channel_width(
+			eht_oper, elems->eht_operation_len);
+
+	if (channel_width == CHAN_WIDTH_UNKNOWN && he_oper)
 		channel_width = get_he_operation_channel_width(
 			he_oper, elems->he_operation_len);
 
@@ -3023,7 +3078,11 @@
 				enum chan_width ap_operation_chan_width,
 				struct supported_chan_width sta_supported_chan_width)
 {
-	if (ap_operation_chan_width == CHAN_WIDTH_160)
+	if (ap_operation_chan_width == CHAN_WIDTH_320 &&
+	    sta_supported_chan_width.is_320_supported)
+		return CHAN_WIDTH_320;
+	if (ap_operation_chan_width == CHAN_WIDTH_160 ||
+	    ap_operation_chan_width == CHAN_WIDTH_320)
 		return (sta_supported_chan_width.is_160_supported)
 			? CHAN_WIDTH_160 : CHAN_WIDTH_80;
 	if (ap_operation_chan_width == CHAN_WIDTH_80P80)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2e81751..ff31e8d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -351,6 +351,7 @@
 struct supported_chan_width {
 	u8 is_160_supported;
 	u8 is_80p80_supported;
+	u8 is_320_supported;
 };
 
 struct supported_chan_width get_supported_channel_width(struct ieee802_11_elems *elems);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 4345488..5c423eb 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2446,11 +2446,14 @@
 
 /* IEEE P802.11be/D1.5, 9.4.2.311 - EHT Operation element */
 
+#define EHT_OPERATION_IE_MIN_LEN 1
+
 /* Figure 9-1002b: EHT Operation Parameters field subfields */
 #define EHT_OPER_INFO_PRESENT                          BIT(0)
 #define EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT       BIT(1)
 
 /* Control subfield: Channel Width subfield; see Table 9-401b */
+#define EHT_OPER_CHANNEL_WIDTH_MASK                    0x7
 #define EHT_OPER_CHANNEL_WIDTH_20MHZ                   0
 #define EHT_OPER_CHANNEL_WIDTH_40MHZ                   1
 #define EHT_OPER_CHANNEL_WIDTH_80MHZ                   2
@@ -2458,6 +2461,8 @@
 #define EHT_OPER_CHANNEL_WIDTH_320MHZ                  4
 
 /* Figure 9-1002c: EHT Operation Information field format */
+#define EHT_OPER_INFO_MIN_LEN 3
+
 struct ieee80211_eht_oper_info {
 	u8 control; /* B0..B2: Channel Width */
 	u8 ccfs0;
@@ -2473,6 +2478,8 @@
 
 /* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */
 
+#define  EHT_CAPABILITIES_IE_MIN_LEN 11
+
 /* Figure 9-1002af: EHT MAC Capabilities Information field */
 #define EHT_MACCAP_EPCS_PRIO			BIT(0)
 #define EHT_MACCAP_OM_CONTROL			BIT(1)
@@ -2705,9 +2712,9 @@
 #define WFA_CAPA_QM_DSCP_POLICY BIT(0)
 #define WFA_CAPA_QM_UNSOLIC_DSCP BIT(1)
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 #define WPA_KEY_MGMT_CROSS_AKM_ROAM (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PSK)
 #define IS_CROSS_AKM_ROAM_KEY_MGMT(key_mgmt) \
 	((key_mgmt & WPA_KEY_MGMT_CROSS_AKM_ROAM) == WPA_KEY_MGMT_CROSS_AKM_ROAM)
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 7a2ee32..e215762 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -682,4 +682,13 @@
  */
 bool tls_connection_get_own_cert_used(struct tls_connection *conn);
 
+/**
+ * tls_register_cert_callback - Register a callback to retrieve certificates
+ * @cb: Callback object to register
+ */
+typedef ssize_t (*tls_get_certificate_cb)
+(void* ctx, const char* alias, uint8_t** value);
+
+void tls_register_cert_callback(tls_get_certificate_cb cb);
+
 #endif /* TLS_H */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index dc8a1b4..ab82e3d 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -126,9 +126,28 @@
 }
 #endif
 
+static int tls_openssl_ref_count = 0;
+static int tls_ex_idx_session = -1;
+
+struct tls_session_data {
+	struct dl_list list;
+	struct wpabuf *buf;
+};
+
+struct tls_context {
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
+	char *ocsp_stapling_response;
+	struct dl_list sessions; /* struct tls_session_data */
+};
+
+static struct tls_context *tls_global = NULL;
+static tls_get_certificate_cb certificate_callback_global = NULL;
+
 #ifdef ANDROID
 #include <openssl/pem.h>
-#include <keystore/keystore_get.h>
 
 #include <log/log.h>
 #include <log/log_event_list.h>
@@ -152,9 +171,11 @@
 {
 	BIO *bio = NULL;
 	uint8_t *value = NULL;
-	int length = keystore_get(alias, strlen(alias), &value);
-	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
-		BIO_write(bio, value, length);
+	if (tls_global != NULL && certificate_callback_global != NULL) {
+		int length = (*certificate_callback_global)(tls_global->cb_ctx, alias, &value);
+		if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+			BIO_write(bio, value, length);
+	}
 	free(value);
 	return bio;
 }
@@ -229,26 +250,6 @@
 
 #endif /* ANDROID */
 
-static int tls_openssl_ref_count = 0;
-static int tls_ex_idx_session = -1;
-
-struct tls_session_data {
-	struct dl_list list;
-	struct wpabuf *buf;
-};
-
-struct tls_context {
-	void (*event_cb)(void *ctx, enum tls_event ev,
-			 union tls_event_data *data);
-	void *cb_ctx;
-	int cert_in_cb;
-	char *ocsp_stapling_response;
-	struct dl_list sessions; /* struct tls_session_data */
-};
-
-static struct tls_context *tls_global = NULL;
-
-
 struct tls_data {
 	SSL_CTX *ssl;
 	unsigned int tls_session_lifetime;
@@ -6025,3 +6026,8 @@
 		return SSL_get_certificate(conn->ssl) != NULL;
 	return false;
 }
+
+void tls_register_cert_callback(tls_get_certificate_cb cb)
+{
+	certificate_callback_global = cb;
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6bbf1ec..71d799d 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1251,12 +1251,12 @@
 	 * 2 = both hunting-and-pecking loop and hash-to-element enabled
 	 */
 	int sae_pwe;
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	/**
 	 * td_policy - Transition Disable Policy
 	 */
 	u32 td_policy;
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 };
 
 enum hide_ssid {
@@ -2393,6 +2393,7 @@
 	int avg_beacon_signal;
 	int current_noise;
 	int current_txrate;
+	int current_rxrate;
 	enum chan_width chanwidth;
 	int center_frq1;
 	int center_frq2;
@@ -2598,9 +2599,9 @@
 	WPA_DRV_UPDATE_ASSOC_IES	= BIT(0),
 	WPA_DRV_UPDATE_FILS_ERP_INFO	= BIT(1),
 	WPA_DRV_UPDATE_AUTH_TYPE	= BIT(2),
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	WPA_DRV_UPDATE_TD_POLICY	= BIT(3),
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 };
 
 /**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 1385edb..0568894 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -201,9 +201,9 @@
 #endif /* CONFIG_MESH */
 static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 			     u16 reason);
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 static int nl80211_set_td_policy(void *priv, u32 td_policy);
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 /* Converts nl80211_chan_width to a common format */
 enum chan_width convert2width(int width)
@@ -1701,6 +1701,20 @@
 		}
 	}
 
+        if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
+		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
+				     sinfo[NL80211_STA_INFO_RX_BITRATE],
+				     rate_policy)) {
+			sig_change->current_rxrate = 0;
+		} else {
+			if (rinfo[NL80211_RATE_INFO_BITRATE]) {
+				sig_change->current_rxrate =
+					nla_get_u16(rinfo[
+					     NL80211_RATE_INFO_BITRATE]) * 100;
+			}
+		}
+	}
+
 	return NL_SKIP;
 }
 
@@ -1712,6 +1726,7 @@
 
 	sig->current_signal = -WPA_INVALID_NOISE;
 	sig->current_txrate = 0;
+	sig->current_rxrate = 0;
 
 	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
 	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) {
@@ -3313,7 +3328,7 @@
 }
 #endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 static int wpa_cross_akm_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
                         int max_suites)
 {
@@ -3329,7 +3344,7 @@
 
     return num_suites;
 }
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
 static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
@@ -6560,7 +6575,7 @@
 		os_free(mgmt);
 	}
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	if (IS_CROSS_AKM_ROAM_KEY_MGMT(params->key_mgmt_suite)) {
 		int num_suites;
 		u32 suites[NL80211_MAX_NR_AKM_SUITES];
@@ -6575,7 +6590,7 @@
 			return -1;
 		}
 	}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 	if (params->req_handshake_offload &&
 	    (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
 		    wpa_printf(MSG_DEBUG, "  * WANT_1X_4WAY_HS");
@@ -6638,13 +6653,13 @@
 	    nl80211_put_fils_connect_params(drv, params, msg) != 0)
 		return -1;
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	if (((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
 	     (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)) &&
 #else
 	if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
 	     wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
 	    nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
 		return -1;
@@ -6693,13 +6708,13 @@
 		goto fail;
 
 #ifdef CONFIG_SAE
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	if (((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
 	     (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)) &&
 #else
 	if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
 	     wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 	    nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
 		goto fail;
 #endif /* CONFIG_SAE */
@@ -6807,13 +6822,13 @@
 
 		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 		if ((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
 		    (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE))
 #else
 		if (wpa_key_mgmt_sae(params->key_mgmt_suite) ||
 		    wpa_key_mgmt_sae(params->allowed_key_mgmts))
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 			bss->use_nl_connect = 1;
 		else
 			bss->use_nl_connect = 0;
@@ -12740,7 +12755,7 @@
 		return 0;
 
 	/* Handle any connection param update here which might receive kernel handling in future */
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	if (mask & WPA_DRV_UPDATE_TD_POLICY) {
 		ret = nl80211_set_td_policy(priv, params->td_policy);
 		if (ret) {
@@ -12750,7 +12765,7 @@
 		}
 		return ret;
 	}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
 	if (!msg)
@@ -12905,7 +12920,7 @@
 }
 #endif /* CONFIG_DPP */
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 static int nl80211_set_td_policy(void *priv, u32 td_policy)
 {
 	struct i802_bss *bss = priv;
@@ -12934,7 +12949,7 @@
 
 	return ret;
 }
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 #ifdef CONFIG_TESTING_OPTIONS
 
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 46592b3..a211d2a 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1197,7 +1197,11 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES;
 
 	if (!drv->capa.max_num_akms)
+#ifdef CONFIG_DRIVER_NL80211_BRCM
 		drv->capa.max_num_akms = 1;
+#else
+		drv->capa.max_num_akms = NL80211_MAX_NR_AKM_SUITES;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 
 	return 0;
 }
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index db46d95..15664df 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1731,6 +1731,9 @@
 		wpa_hexdump_ascii(MSG_DEBUG,
 				  "EAP: using IMSI privacy anonymous identity",
 				  identity, identity_len);
+	} else if (config->strict_conservative_peer_mode) {
+		wpa_printf(MSG_DEBUG, "EAP: never use real identity in conservative peer mode.");
+		return NULL;
 	} else {
 		identity = config->identity;
 		identity_len = config->identity_len;
@@ -2193,6 +2196,14 @@
 	os_free(hash_hex);
 }
 
+ssize_t tls_certificate_callback(void* ctx, const char* alias, uint8_t** value) {
+	if (alias == NULL || ctx == NULL || value == NULL) return -1;
+	struct eap_sm *sm = (struct eap_sm*) ctx;
+	if (sm->eapol_cb && sm->eapol_cb->get_certificate) {
+		return sm->eapol_cb->get_certificate(sm->eapol_ctx, alias, value);
+	}
+	return -1;
+}
 
 /**
  * eap_peer_sm_init - Allocate and initialize EAP peer state machine
@@ -2236,6 +2247,7 @@
 	tlsconf.event_cb = eap_peer_sm_tls_event;
 	tlsconf.cb_ctx = sm;
 	tlsconf.cert_in_cb = conf->cert_in_cb;
+	tls_register_cert_callback(&tls_certificate_callback);
 	sm->ssl_ctx = tls_init(&tlsconf);
 	if (sm->ssl_ctx == NULL) {
 		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
@@ -2816,6 +2828,24 @@
 	return config->identity;
 }
 
+
+/**
+ * eap_get_config_strict_conservative_peer_mode - get the value of
+ * strict conservative peer mode in eap_peer_config.
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+*/
+int eap_get_config_strict_conservative_peer_mode(struct eap_sm *sm)
+{
+	struct eap_peer_config *config;
+	config = eap_get_config(sm);
+	if (config) {
+		return config->strict_conservative_peer_mode;
+	}
+
+	return 0;
+}
+
+
 static const u8 * strnchr(const u8 *str, size_t len, u8 needle) {
 	const u8 *cur = str;
 
@@ -3080,6 +3110,19 @@
 	return sm ? sm->eapKeyAvailable : 0;
 }
 
+/**
+ * eap_notify_permanent_id_req_denied - Notify that the AT_PERMANENT_ID_REQ
+ * is denied from eap_peer when the strict conservative mode is enabled.
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+*/
+void eap_notify_permanent_id_req_denied(struct eap_sm *sm)
+{
+	if (!sm || !sm->eapol_cb->notify_permanent_id_req_denied)
+		return;
+
+	sm->eapol_cb->notify_permanent_id_req_denied(sm->eapol_ctx);
+}
+
 
 /**
  * eap_notify_success - Notify EAP state machine about external success trigger
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index aae1a41..b98e878 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -233,6 +233,15 @@
 			    const char *cert_hash);
 
 	/**
+	 * notify_permanent_id_req_denied - Notify that the
+	 * AT_PERMANENT_ID_REQ from the server was denied. This
+	 * notification happens when the peer is in strict
+	 * conservative mode.
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	*/
+	void (*notify_permanent_id_req_denied)(void* ctx);
+
+	/**
 	 * notify_status - Notification of the current EAP state
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
 	 * @status: Step in the process of EAP authentication
@@ -295,6 +304,16 @@
 	 * @reason_string: Information to log about the event
 	 */
 	void (*notify_open_ssl_failure)(void *ctx, const char* reason_string);
+
+	/**
+	 * get_certificate - Retrieve a certificate from the certificate store
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @alias: key into the certificate key-value store
+	 * @value: pointer reference - pointer to the retrieved certificate will
+	 *         be stored here on success
+	 * Returns: size of the retrieved certificate or -1 on error
+	 */
+	ssize_t (*get_certificate)(void* ctx, const char* alias, uint8_t** value);
 };
 
 /**
@@ -366,11 +385,13 @@
 void eap_set_force_disabled(struct eap_sm *sm, int disabled);
 void eap_set_external_sim(struct eap_sm *sm, int external_sim);
 int eap_key_available(struct eap_sm *sm);
+void eap_notify_permanent_id_req_denied(struct eap_sm *sm);
 void eap_notify_success(struct eap_sm *sm);
 void eap_notify_lower_layer_success(struct eap_sm *sm);
 const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
 struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
+int eap_get_config_strict_conservative_peer_mode(struct eap_sm *sm);
 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
 void eap_invalidate_cached_session(struct eap_sm *sm);
 
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 7f660e6..49338cf 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -708,6 +708,12 @@
 		identity_len = data->pseudonym_len;
 		eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
 	} else if (id_req != NO_ID_REQ) {
+		if (id_req == PERMANENT_ID && eap_get_config_strict_conservative_peer_mode(sm)) {
+			wpa_printf(MSG_INFO, "EAP-AKA: permanent_id_req is denied in "
+				   "the strict conservative peer mode");
+			eap_notify_permanent_id_req_denied(sm);
+			return eap_aka_client_error(data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+		}
 		identity = eap_get_config_identity(sm, &identity_len);
 		if (identity) {
 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 26744ab..59fac90 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -338,6 +338,18 @@
 	char *imsi_privacy_attr;
 
 	/**
+	 * strict_conservative_peer_mode - Whether the strict conservative peer
+	 * mode is enabled or not
+	 *
+	 * This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+	 * for EAP-SIM/AKA/AKA', in conservative peer mode, a client error would
+	 * be sent to the server, but it allows to send the permanent identity
+	 * in some special cases according to 4.6.2 of RFC 4187; With the strict
+	 * mode, it never sends the permanent identity to server for privacy concern.
+	 */
+	int strict_conservative_peer_mode;
+
+	/**
 	 * machine_identity - EAP Identity for machine credential
 	 *
 	 * This field is used to set the machine identity or NAI for cases where
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 71e9108..6f18ebf 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -576,6 +576,12 @@
 		identity_len = data->pseudonym_len;
 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
 	} else if (id_req != NO_ID_REQ) {
+		if (id_req == PERMANENT_ID && eap_get_config_strict_conservative_peer_mode(sm)) {
+			wpa_printf(MSG_INFO, "EAP-SIM: permanent_id_req is denied in "
+				   "the strict conservative peer mode");
+			eap_notify_permanent_id_req_denied(sm);
+			return  eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+		}
 		identity = eap_get_config_identity(sm, &identity_len);
 		if (identity) {
 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 6173960..a8ac6fd 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -2031,6 +2031,13 @@
 		sm->ctx->cert_cb(sm->ctx->ctx, cert, cert_hash);
 }
 
+static void eapol_sm_notify_permanent_id_req_denied(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm->ctx->permanent_id_req_denied_cb)
+		sm->ctx->permanent_id_req_denied_cb(sm->ctx->ctx);
+}
+
 
 static void eapol_sm_notify_status(void *ctx, const char *status,
 				   const char *parameter)
@@ -2105,6 +2112,17 @@
 		sm->ctx->open_ssl_failure_cb(sm->ctx->ctx, reason_string);
 }
 
+static ssize_t
+eapol_sm_get_certificate(void *ctx, const char* alias, uint8_t** value)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->get_certificate_cb) {
+		return sm->ctx->get_certificate_cb(alias, value);
+	}
+	return -1;
+}
+
 static const struct eapol_callbacks eapol_cb =
 {
 	eapol_sm_get_config,
@@ -2118,6 +2136,7 @@
 	eapol_sm_notify_pending,
 	eapol_sm_eap_param_needed,
 	eapol_sm_notify_cert,
+	eapol_sm_notify_permanent_id_req_denied,
 	eapol_sm_notify_status,
 	eapol_sm_notify_eap_error,
 #ifdef CONFIG_EAP_PROXY
@@ -2127,7 +2146,8 @@
 #endif /* CONFIG_EAP_PROXY */
 	eapol_sm_set_anon_id,
 	eapol_sm_notify_eap_method_selected,
-	eapol_sm_notify_open_ssl_failure
+	eapol_sm_notify_open_ssl_failure,
+	eapol_sm_get_certificate
 };
 
 
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index bbe2b6f..fe34ec9 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -255,6 +255,14 @@
 			const char *cert_hash);
 
 	/**
+	 * permanent_id_req_denied_cb - Notify that the AT_PERMANENT_ID_REQ
+	 * from the server was denied. This notification happens when the
+	 * peer is in the strict conservative mode.
+	 * @ctx: Callback context (ctx)
+	*/
+	void (*permanent_id_req_denied_cb)(void *ctx);
+
+	/**
 	 * cert_in_cb - Include server certificates in callback
 	 */
 	int cert_in_cb;
@@ -328,6 +336,15 @@
 	 * Returns: Whether the current session requires encryption
 	 */
 	bool (*encryption_required)(void *ctx);
+
+	/**
+	 * get_certificate_cb - Retrieve a certificate from the certificate store
+	 * @alias: key into the certificate key-value store
+	 * @value: pointer reference - pointer to the retrieved certificate will
+	 *         be stored here on success
+	 * Returns: size of the retrieved certificate or -1 on error
+	 */
+	ssize_t (*get_certificate_cb)(const char* alias, uint8_t** value);
 };
 
 
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index a1f8ae9..3c55c5a 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -592,6 +592,7 @@
 ieee802_1x_kay_create_peer(const u8 *mi, u32 mn)
 {
 	struct ieee802_1x_kay_peer *peer;
+	struct os_reltime now;
 
 	peer = os_zalloc(sizeof(*peer));
 	if (!peer) {
@@ -601,7 +602,8 @@
 
 	os_memcpy(peer->mi, mi, MI_LEN);
 	peer->mn = mn;
-	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+	os_get_reltime(&now);
+	peer->expire = now.sec + MKA_LIFE_TIME / 1000;
 	peer->sak_used = false;
 	peer->missing_sak_use_count = 0;
 
@@ -678,6 +680,7 @@
 {
 	struct ieee802_1x_kay_peer *peer;
 	struct receive_sc *rxsc;
+	struct os_reltime now;
 
 	peer = ieee802_1x_kay_get_potential_peer(participant, mi);
 	if (!peer)
@@ -690,7 +693,8 @@
 	os_memcpy(&peer->sci, &participant->current_peer_sci,
 		  sizeof(peer->sci));
 	peer->mn = mn;
-	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+	os_get_reltime(&now);
+	peer->expire = now.sec + MKA_LIFE_TIME / 1000;
 
 	wpa_printf(MSG_DEBUG, "KaY: Move potential peer to live peer");
 	ieee802_1x_kay_dump_peer(peer);
@@ -873,13 +877,15 @@
 		peer = ieee802_1x_kay_get_peer_sci(participant,
 						   &body->actor_sci);
 		if (peer) {
-			time_t new_expire;
+			os_time_t new_expire;
+			struct os_reltime now;
 
 			wpa_printf(MSG_WARNING,
 				   "KaY: duplicated SCI detected - maybe active attacker or peer selected new MI - ignore MKPDU");
 			/* Reduce timeout to speed up this process but left the
 			 * chance for old one to prove aliveness. */
-			new_expire = time(NULL) + MKA_HELLO_TIME * 1.5 / 1000;
+			os_get_reltime(&now);
+			new_expire = now.sec + MKA_HELLO_TIME * 1.5 / 1000;
 			if (peer->expire > new_expire)
 				peer->expire = new_expire;
 			return NULL;
@@ -2130,6 +2136,7 @@
 	unsigned int key_len;
 	u8 *key;
 	struct macsec_ciphersuite *cs;
+	struct os_reltime now;
 
 	/* check condition for generating a fresh SAK:
 	 * must have one live peer
@@ -2150,7 +2157,8 @@
 	 * here only check first item and ingore
 	 *   && (!dl_list_empty(&participant->potential_peers))) {
 	 */
-	if ((time(NULL) - kay->dist_time) < MKA_LIFE_TIME / 1000) {
+	os_get_reltime(&now);
+	if ((now.sec - kay->dist_time) < MKA_LIFE_TIME / 1000) {
 		wpa_printf(MSG_ERROR,
 			   "KaY: Life time has not elapsed since prior SAK distributed");
 		return -1;
@@ -2244,7 +2252,7 @@
 	if (kay->dist_an > 3)
 		kay->dist_an = 0;
 
-	kay->dist_time = time(NULL);
+	kay->dist_time = now.sec;
 
 	return 0;
 
@@ -2548,17 +2556,19 @@
 	struct ieee802_1x_mka_participant *participant;
 	struct ieee802_1x_kay *kay;
 	struct ieee802_1x_kay_peer *peer, *pre_peer;
-	time_t now = time(NULL);
+	struct os_reltime now;
 	bool lp_changed;
 	struct receive_sc *rxsc, *pre_rxsc;
 	struct transmit_sa *txsa, *pre_txsa;
 
+	os_get_reltime(&now);
+
 	participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
 	kay = participant->kay;
 	wpa_printf(MSG_DEBUG, "KaY: Participant timer (ifname=%s)",
 		   kay->if_name);
 	if (participant->cak_life) {
-		if (now > participant->cak_life)
+		if (now.sec > participant->cak_life)
 			goto delete_mka;
 	}
 
@@ -2566,7 +2576,7 @@
 	 * when the MKA life elapsed since its creating */
 	if (participant->mka_life) {
 		if (dl_list_empty(&participant->live_peers)) {
-			if (now > participant->mka_life)
+			if (now.sec > participant->mka_life)
 				goto delete_mka;
 		} else {
 			participant->mka_life = 0;
@@ -2576,7 +2586,7 @@
 	lp_changed = false;
 	dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
 			      struct ieee802_1x_kay_peer, list) {
-		if (now > peer->expire) {
+		if (now.sec > peer->expire) {
 			wpa_printf(MSG_DEBUG, "KaY: Live peer removed");
 			wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
 				    sizeof(peer->mi));
@@ -2634,7 +2644,7 @@
 
 	dl_list_for_each_safe(peer, pre_peer, &participant->potential_peers,
 			      struct ieee802_1x_kay_peer, list) {
-		if (now > peer->expire) {
+		if (now.sec > peer->expire) {
 			wpa_printf(MSG_DEBUG, "KaY: Potential peer removed");
 			wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
 				    sizeof(peer->mi));
@@ -3371,11 +3381,14 @@
 				return -1;
 			}
 		} else {
+			struct os_reltime now;
+
+			os_get_reltime(&now);
 			peer->missing_sak_use_count = 0;
 
 			/* Only update live peer watchdog after successful
 			 * decode of all parameter sets */
-			peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+			peer->expire = now.sec + MKA_LIFE_TIME / 1000;
 		}
 	} else {
 		/* MKPDU is from new or potential peer */
@@ -3674,8 +3687,12 @@
 	os_memcpy(participant->cak.key, cak->key, cak->len);
 	wpa_hexdump_key(MSG_DEBUG, "KaY: CAK", participant->cak.key,
 			participant->cak.len);
-	if (life)
-		participant->cak_life = life + time(NULL);
+	if (life) {
+		struct os_reltime now;
+		os_get_reltime(&now);
+
+		participant->cak_life = life + now.sec;
+	}
 
 	switch (mode) {
 	case EAP_EXCHANGE:
@@ -3783,7 +3800,10 @@
 	 * some peer appears.
 	 */
 	if (mode != PSK) {
-		participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
+		struct os_reltime now;
+		os_get_reltime(&now);
+
+		participant->mka_life = MKA_LIFE_TIME / 1000 + now.sec +
 			usecs / 1000000;
 	}
 	participant->mode = mode;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 11cf7b7..525679f 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -213,7 +213,7 @@
 	u32 dist_kn;
 	u32 rcvd_keys;
 	u8 dist_an;
-	time_t dist_time;
+	os_time_t dist_time;
 
 	u8 mka_version;
 	u8 algo_agility[4];
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index 7a04169..e4650b5 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -45,7 +45,7 @@
 	struct ieee802_1x_mka_sci sci;
 	u8 mi[MI_LEN];
 	u32 mn;
-	time_t expire;
+	os_time_t expire;
 	bool is_key_server;
 	u8 key_server_priority;
 	bool macsec_desired;
@@ -135,8 +135,8 @@
 	struct ieee802_1x_mka_peer_id current_peer_id;
 	struct ieee802_1x_mka_sci current_peer_sci;
 
-	time_t cak_life;
-	time_t mka_life;
+	os_time_t cak_life;
+	os_time_t mka_life;
 	bool to_dist_sak;
 	bool to_use_sak;
 	bool new_sak;
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index db11387..be79765 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -67,14 +67,14 @@
     defaults: ["wpa_supplicant_cflags_defaults"],
     srcs: [":wpa_supplicant_srcs"],
     shared_libs: [
-        "android.hardware.wifi.supplicant-V1-ndk",
+        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.system.keystore2-V1-ndk",
         "libbase",
         "libbinder_ndk",
         "libc",
         "libcrypto",
         "libcutils",
         "libkeystore-engine-wifi-hidl",
-        "libkeystore-wifi-hidl",
         "liblog",
         "libnl",
         "libssl",
@@ -216,6 +216,35 @@
         "-Wno-unused-parameter",
         "-Wno-unused-variable",
     ],
+    // Similar to suppressing clang compiler warnings, here we
+    // suppress clang-tidy warnings to reduce noises in Android build.log.
+    tidy_checks: [
+        "-android-cloexec-*",
+        "-bugprone-branch-clone",
+        "-bugprone-macro-parentheses",
+        "-bugprone-misplaced-widening-cast",
+        "-bugprone-signal-handler",
+        "-bugprone-signed-char-misuse",
+        "-bugprone-sizeof-expression",
+        "-bugprone-suspicious-string-compare",
+        "-bugprone-too-small-loop-variable",
+        "-cert-err34-c",
+        "-cert-msc30-c",
+        "-cert-msc50-cpp",
+        "-cert-msc54-cpp",
+        "-cert-sig30-c",
+        "-cert-str34-c",
+        "-clang-analyzer-core.NullDereference",
+        "-clang-analyzer-core.UndefinedBinaryOperatorResult",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.performance.Padding",
+        "-clang-analyzer-optin.portability.UnixAPI",
+        "-clang-analyzer-security.insecureAPI.UncheckedReturn",
+        "-clang-analyzer-unix.cstring.NullArg",
+        "-clang-analyzer-unix.Malloc",
+        "-clang-diagnostic-unused-but-set-variable",
+        "-misc-redundant-expression",
+    ],
 }
 
 // Generated by building wpa_supplicant and printing LOCAL_SRC_FILES.
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 1eaebde..33dabf3 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1791,7 +1791,7 @@
 LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
 endif
 ifeq ($(CONFIG_TLS), openssl)
-LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore-wifi-hidl
+LOCAL_SHARED_LIBRARIES += libcrypto libssl
 endif
 
 # With BoringSSL we need libkeystore-engine in order to provide access to
@@ -1812,7 +1812,8 @@
 LOCAL_SHARED_LIBRARIES += libdbus
 endif
 ifeq ($(WPA_SUPPLICANT_USE_AIDL), y)
-LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V1-ndk
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V2-ndk
+LOCAL_SHARED_LIBRARIES += android.system.keystore2-V1-ndk
 LOCAL_SHARED_LIBRARIES += libutils libbase
 LOCAL_SHARED_LIBRARIES += libbinder_ndk
 LOCAL_STATIC_LIBRARIES += libwpa_aidl
@@ -1877,6 +1878,7 @@
 LOCAL_SRC_FILES := \
     aidl/aidl.cpp \
     aidl/aidl_manager.cpp \
+    aidl/certificate_utils.cpp \
     aidl/iface_config_utils.cpp \
     aidl/p2p_iface.cpp \
     aidl/p2p_network.cpp \
@@ -1884,7 +1886,8 @@
     aidl/sta_network.cpp \
     aidl/supplicant.cpp
 LOCAL_SHARED_LIBRARIES := \
-    android.hardware.wifi.supplicant-V1-ndk \
+    android.hardware.wifi.supplicant-V2-ndk \
+    android.system.keystore2-V1-ndk \
     libbinder_ndk \
     libbase \
     libutils \
diff --git a/wpa_supplicant/aidl/Android.bp b/wpa_supplicant/aidl/Android.bp
index 0785fe1..d7dcf97 100644
--- a/wpa_supplicant/aidl/Android.bp
+++ b/wpa_supplicant/aidl/Android.bp
@@ -33,9 +33,11 @@
     defaults: ["wpa_supplicant_cflags_defaults"],
     soc_specific: true,
     shared_libs: [
-        "android.hardware.wifi.supplicant-V1-ndk",
+        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.system.keystore2-V1-ndk",
         "libbinder_ndk",
         "libbase",
+        "libcrypto",
         "libutils",
         "liblog",
         "libssl",
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp
index a7945cc..75050c1 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/aidl.cpp
@@ -186,6 +186,21 @@
 		wpa_s, ssid, rtype, default_txt);
 }
 
+void wpas_aidl_notify_permanent_id_req_denied(
+		struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s || !wpa_s->global->aidl)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying permanent_id_req denied to aidl control.");
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	return aidl_manager->notifyPermanentIdReqDenied(wpa_s);
+}
+
 void wpas_aidl_notify_anqp_query_done(
 	struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
 	const struct wpa_bss_anqp *anqp)
@@ -671,7 +686,7 @@
 }
 
 void wpas_aidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
-		struct wpa_ssid *ssid)
+		struct wpa_ssid *ssid, bool conn_status_requested)
 {
 	if (!wpa_s || !ssid)
 		return;
@@ -684,7 +699,7 @@
 	if (!aidl_manager)
 		return;
 
-	aidl_manager->notifyDppConfigReceived(wpa_s, ssid);
+	aidl_manager->notifyDppConfigReceived(wpa_s, ssid, conn_status_requested);
 }
 
 void wpas_aidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
@@ -692,6 +707,21 @@
 	wpas_aidl_notify_dpp_success(wpa_s, DppEventType::CONFIGURATION_SENT);
 }
 
+void wpas_aidl_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
+                                                 enum dpp_status_error result)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(MSG_DEBUG, "wpas_aidl_notify_dpp_connection_status_sent %d ", result);
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	aidl_manager->notifyDppConnectionStatusSent(wpa_s, result);
+}
+
 /* DPP Progress notifications */
 void wpas_aidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
 {
@@ -1033,3 +1063,11 @@
 	aidl_manager->notifyQosPolicyRequest(wpa_s, policies, num_policies);
 }
 
+ssize_t wpas_aidl_get_certificate(const char* alias, uint8_t** value)
+{
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return -1;
+
+	return aidl_manager->getCertificate(alias, value);
+}
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h
index 2f3c7a0..b0ad1f2 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/aidl.h
@@ -37,6 +37,7 @@
 	int wpas_aidl_notify_network_request(
 		struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
 		enum wpa_ctrl_req_type rtype, const char *default_txt);
+	void wpas_aidl_notify_permanent_id_req_denied(struct wpa_supplicant *wpa_s);
 	void wpas_aidl_notify_anqp_query_done(
 		struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
 		const struct wpa_bss_anqp *anqp);
@@ -103,8 +104,10 @@
 	void wpas_aidl_notify_eap_error(
 		struct wpa_supplicant *wpa_s, int error_code);
 	void wpas_aidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
-			struct wpa_ssid *ssid);
+		struct wpa_ssid *ssid, bool conn_status_requested);
 	void wpas_aidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+	void wpas_aidl_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
+		enum dpp_status_error result);
 	void wpas_aidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
 	void wpas_aidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
 	void wpas_aidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
@@ -142,6 +145,7 @@
 	void wpas_aidl_notify_qos_policy_reset(struct wpa_supplicant *wpa_s);
 	void wpas_aidl_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
 		struct dscp_policy_data *policies, int num_policies);
+	ssize_t wpas_aidl_get_certificate(const char* alias, uint8_t** value);
 #else   // CONFIG_CTRL_IFACE_AIDL
 static inline int wpas_aidl_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -171,6 +175,8 @@
 {
 	return 0;
 }
+static void wpas_aidl_notify_permanent_id_req_denied(struct wpa_supplicant *wpa_s)
+{}
 static void wpas_aidl_notify_anqp_query_done(
 	struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
 	const struct wpa_bss_anqp *anqp)
@@ -185,7 +191,7 @@
 static void wpas_aidl_notify_hs20_rx_deauth_imminent_notice(
 	struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
 {}
-void wpas_aidl_notify_hs20_rx_terms_and_conditions_acceptance(
+static void wpas_aidl_notify_hs20_rx_terms_and_conditions_acceptance(
 		struct wpa_supplicant *wpa_s, const char *url)
 {}
 static void wpas_aidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
@@ -203,7 +209,8 @@
 static void wpas_aidl_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)
+	u8 peer_wfd_device_info_lenconst, u8 *peer_wfd_r2_device_info,
+	u8 peer_wfd_r2_device_info_len)
 {}
 static void wpas_aidl_notify_p2p_device_lost(
 	struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
@@ -252,12 +259,13 @@
 	struct wpa_supplicant *wpa_s, int error_code)
 {}
 static void wpas_aidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
-		struct wpa_ssid *ssid)
+	struct wpa_ssid *ssid, bool conn_status_requested)
 {}
-static void wpas_aidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
-		struct wpa_ssid *ssid);
 static void wpas_aidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
 {}
+static void wpas_aidl_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
+	enum dpp_status_error result)
+{}
 static void wpas_aidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
 {}
 static void wpas_aidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
@@ -272,20 +280,24 @@
 {}
 static void wpas_aidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
 {}
-static void wpas_aidl_notify_dpp_failure(struct wpa_supplicant *wpa_s)
+static void wpas_aidl_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s)
 {}
-void wpas_aidl_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s)
+static void wpas_aidl_notify_dpp_fail(struct wpa_supplicant *wpa_s)
 {}
-void wpas_aidl_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s)
+static void wpas_aidl_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s)
 {}
-void wpas_aidl_notify_dpp_config_applied(struct wpa_supplicant *wpa_s)
+static void wpas_aidl_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s)
 {}
-void wpas_aidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
+static void wpas_aidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_aidl_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
+			enum dpp_status_error status, const char *ssid,
+			const char *channel_list, unsigned short band_list[], int size)
 {}
 static void wpas_aidl_notify_pmk_cache_added(struct wpa_supplicant *wpas,
 						 struct rsn_pmksa_cache_entry *pmksa_entry)
 {}
-void wpas_aidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+static void wpas_aidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
 {}
 static void wpas_aidl_notify_transition_disable(struct wpa_supplicant *wpa_s,
 						struct wpa_ssid *ssid,
@@ -293,22 +305,22 @@
 {}
 static void wpas_aidl_notify_network_not_found(struct wpa_supplicant *wpa_s)
 {}
-void wpas_aidl_notify_frequency_changed(struct wpa_supplicant *wpa_s, int frequency)
+static void wpas_aidl_notify_frequency_changed(struct wpa_supplicant *wpa_s, int frequency)
 {}
-void wpas_aidl_notify_ceritification(struct wpa_supplicant *wpa_s,
+static void wpas_aidl_notify_ceritification(struct wpa_supplicant *wpa_s,
 	int depth, const char *subject,
 	const char *altsubject[],
 	int num_altsubject,
 	const char *cert_hash,
 	const struct wpabuf *cert)
 {}
-void wpas_aidl_notify_eap_method_selected(struct wpa_supplicant *wpa_s,
+static void wpas_aidl_notify_eap_method_selected(struct wpa_supplicant *wpa_s,
 	const char *reason_string)
 {}
-void wpas_aidl_notify_ssid_temp_disabled(struct wpa_supplicant *wpa_s,
+static void wpas_aidl_notify_ssid_temp_disabled(struct wpa_supplicant *wpa_s,
 	const char *reason_string)
 {}
-void wpas_aidl_notify_open_ssl_failure(struct wpa_supplicant *wpa_s,
+static void wpas_aidl_notify_open_ssl_failure(struct wpa_supplicant *wpa_s,
 	const char *reason_string)
 {}
 static void wpas_aidl_notify_qos_policy_reset(struct wpa_supplicant *wpa_s) {}
@@ -316,6 +328,10 @@
 						struct dscp_policy_data *policies,
 						int num_policies)
 {}
+static ssize_t wpas_aidl_get_certificate(const char* alias, uint8_t** value)
+{
+	return -1;
+}
 #endif  // CONFIG_CTRL_IFACE_AIDL
 
 #ifdef _cplusplus
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index 1791b2b..4833938 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -39,6 +39,7 @@
 const std::vector<uint8_t> kZeroBssid = {0, 0, 0, 0, 0, 0};
 
 using aidl::android::hardware::wifi::supplicant::GsmRand;
+using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
 
 /**
  * Check if the provided |wpa_supplicant| structure represents a P2P iface or
@@ -655,38 +656,46 @@
 		return 1;
 
 	// Invoke the |onStateChanged| method on all registered callbacks.
-	uint32_t aidl_network_id = UINT32_MAX;
-	std::vector<uint8_t> aidl_ssid;
+	SupplicantStateChangeData aidl_state_change_data = {};
+	aidl_state_change_data.id = UINT32_MAX;
+	aidl_state_change_data.newState = static_cast<StaIfaceCallbackState>(wpa_s->wpa_state);
+
 	if (wpa_s->current_ssid) {
-		aidl_network_id = wpa_s->current_ssid->id;
-		aidl_ssid.assign(
+		aidl_state_change_data.id = wpa_s->current_ssid->id;
+		std::vector<uint8_t> aidl_ssid(
 			wpa_s->current_ssid->ssid,
 			wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+		aidl_state_change_data.ssid = aidl_ssid;
+		wpa_printf(MSG_INFO, "assoc key_mgmt 0x%x network key_mgmt 0x%x",
+			wpa_s->key_mgmt, wpa_s->current_ssid->key_mgmt);
 	}
-	std::vector<uint8_t> bssid;
+	std::vector<uint8_t> aidl_bssid;
 	// wpa_supplicant sets the |pending_bssid| field when it starts a
 	// connection. Only after association state does it update the |bssid|
 	// field. So, in the AIDL callback send the appropriate bssid.
 	if (wpa_s->wpa_state <= WPA_ASSOCIATED) {
-		bssid = macAddrToVec(wpa_s->pending_bssid);
+		aidl_bssid = macAddrToVec(wpa_s->pending_bssid);
 	} else {
-		bssid = macAddrToVec(wpa_s->bssid);
+		aidl_bssid = macAddrToVec(wpa_s->bssid);
 	}
-	bool fils_hlp_sent =
+	aidl_state_change_data.bssid = aidl_bssid;
+
+	aidl_state_change_data.filsHlpSent =
 		(wpa_auth_alg_fils(wpa_s->auth_alg) &&
 		 !dl_list_empty(&wpa_s->fils_hlp_req) &&
 		 (wpa_s->wpa_state == WPA_COMPLETED)) ? true : false;
+	aidl_state_change_data.keyMgmtMask = (KeyMgmtMask) wpa_s->key_mgmt;
+	// wpa_supplicant sets the frequency on receiving the EVENT_ASSOC.
+	aidl_state_change_data.frequencyMhz =
+		wpa_s->wpa_state >= WPA_ASSOCIATED ? wpa_s->assoc_freq : 0;
 
 	// Invoke the |onStateChanged| method on all registered callbacks.
 	std::function<
 		ndk::ScopedAStatus(std::shared_ptr<ISupplicantStaIfaceCallback>)>
 		func = std::bind(
-			&ISupplicantStaIfaceCallback::onStateChanged,
+			&ISupplicantStaIfaceCallback::onSupplicantStateChanged,
 			std::placeholders::_1,
-			static_cast<StaIfaceCallbackState>(
-				wpa_s->wpa_state),
-				bssid, aidl_network_id, aidl_ssid,
-				fils_hlp_sent);
+			aidl_state_change_data);
 	callWithEachStaIfaceCallback(
 		misc_utils::charBufToString(wpa_s->ifname), func);
 	return 0;
@@ -759,6 +768,30 @@
 }
 
 /**
+ * Notify that the AT_PERMANENT_ID_REQ is denied from eap_peer when the strict
+ * conservative peer mode is enabled.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+*/
+void AidlManager::notifyPermanentIdReqDenied(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->current_ssid) {
+		wpa_printf(MSG_ERROR, "Current network NULL. Drop permanent_id_req_denied event!");
+		return;
+	}
+	struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+
+	callWithEachStaNetworkCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			current_ssid->id,
+			std::bind(
+			&ISupplicantStaNetworkCallback::
+				onPermanentIdReqDenied,
+			std::placeholders::_1));
+}
+
+/**
  * Notify all listeners about the end of an ANQP query.
  *
  * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
@@ -1350,14 +1383,22 @@
 		dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
 	}
 
+	P2pGroupStartedEventParams params;
+	params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname);
+	params.isGroupOwner = aidl_is_go;
+	params.ssid = byteArrToVec(ssid->ssid, ssid->ssid_len);
+	params.frequencyMHz = aidl_freq;
+	params.psk = aidl_psk;
+	params.passphrase = misc_utils::charBufToString(ssid->passphrase);
+	params.isPersistent = aidl_is_persistent;
+	params.goDeviceAddress = macAddrToVec(wpa_group_s->go_dev_addr);
+	params.goInterfaceAddress = aidl_is_go ? macAddrToVec(wpa_group_s->own_addr) :
+			macAddrToVec(wpa_group_s->current_bss->bssid);
+
 	callWithEachP2pIfaceCallback(
 		misc_utils::charBufToString(wpa_s->ifname),
-		std::bind(
-		&ISupplicantP2pIfaceCallback::onGroupStarted,
-		std::placeholders::_1, misc_utils::charBufToString(wpa_group_s->ifname),
-		aidl_is_go, byteArrToVec(ssid->ssid, ssid->ssid_len),
-		aidl_freq, aidl_psk, misc_utils::charBufToString(ssid->passphrase),
-		macAddrToVec(wpa_group_s->go_dev_addr), aidl_is_persistent));
+		std::bind(&ISupplicantP2pIfaceCallback::onGroupStartedWithParams,
+		std::placeholders::_1, params));
 }
 
 void AidlManager::notifyP2pGroupRemoved(
@@ -1559,19 +1600,18 @@
  * @param config Configuration object
  */
 void AidlManager::notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
-		struct wpa_ssid *config)
+		struct wpa_ssid *config, bool conn_status_requested)
 {
-	DppAkm securityAkm;
-	DppConnectionKeys aidl_keys{};
 	std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname);
+	DppConfigurationData aidl_dpp_config_data = {};
 
 	if ((config->key_mgmt & WPA_KEY_MGMT_SAE) &&
 			(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
-		securityAkm = DppAkm::SAE;
+		aidl_dpp_config_data.securityAkm = DppAkm::SAE;
 	} else if (config->key_mgmt & WPA_KEY_MGMT_PSK) {
-			securityAkm = DppAkm::PSK;
+		aidl_dpp_config_data.securityAkm = DppAkm::PSK;
 	} else if (config->key_mgmt & WPA_KEY_MGMT_DPP) {
-			securityAkm = DppAkm::DPP;
+		aidl_dpp_config_data.securityAkm = DppAkm::DPP;
 	} else {
 		/* Unsupported AKM */
 		wpa_printf(MSG_ERROR, "DPP: Error: Unsupported AKM 0x%X",
@@ -1580,29 +1620,31 @@
 		return;
 	}
 
-	std::string passphrase = misc_utils::charBufToString(config->passphrase);
+	aidl_dpp_config_data.password = misc_utils::charBufToString(config->passphrase);
+	aidl_dpp_config_data.psk = byteArrToVec(config->psk, 32);
 	std::vector<uint8_t> aidl_ssid(
 		config->ssid,
 		config->ssid + config->ssid_len);
+	aidl_dpp_config_data.ssid = aidl_ssid;
 
-	if (securityAkm == DppAkm::DPP) {
+	if (aidl_dpp_config_data.securityAkm == DppAkm::DPP) {
 		std::string connector_str = misc_utils::charBufToString(config->dpp_connector);
-		aidl_keys.connector = std::vector<uint8_t>(connector_str.begin(),
-			connector_str.end());
-		aidl_keys.cSign = byteArrToVec(config->dpp_csign, config->dpp_csign_len);
-		aidl_keys.netAccessKey = byteArrToVec(config->dpp_netaccesskey,
-			config->dpp_netaccesskey_len);
+		aidl_dpp_config_data.dppConnectionKeys.connector
+			= std::vector<uint8_t>(connector_str.begin(), connector_str.end());
+		aidl_dpp_config_data.dppConnectionKeys.cSign
+			= byteArrToVec(config->dpp_csign, config->dpp_csign_len);
+		aidl_dpp_config_data.dppConnectionKeys.netAccessKey
+			= byteArrToVec(config->dpp_netaccesskey, config->dpp_netaccesskey_len);
 	}
+	aidl_dpp_config_data.connStatusRequested = conn_status_requested;
 
 	/* At this point, the network is already registered, notify about new
 	 * received configuration
 	 */
 	callWithEachStaIfaceCallback(aidl_ifname,
 			std::bind(
-					&ISupplicantStaIfaceCallback::onDppSuccessConfigReceived,
-					std::placeholders::_1, aidl_ssid, passphrase,
-					byteArrToVec(config->psk, 32), securityAkm,
-					aidl_keys));
+					&ISupplicantStaIfaceCallback::onDppConfigReceived,
+					std::placeholders::_1, aidl_dpp_config_data));
 }
 
 /**
@@ -1619,6 +1661,55 @@
 					std::placeholders::_1));
 }
 
+DppStatusErrorCode convertSupplicantDppStatusErrorCodeToAidl(
+	enum dpp_status_error code)
+{
+	switch (code) {
+		case DPP_STATUS_OK:
+			return DppStatusErrorCode::SUCCESS;
+		case DPP_STATUS_NOT_COMPATIBLE:
+			return DppStatusErrorCode::NOT_COMPATIBLE;
+		case DPP_STATUS_AUTH_FAILURE:
+			return DppStatusErrorCode::AUTH_FAILURE;
+		case DPP_STATUS_UNWRAP_FAILURE:
+			return DppStatusErrorCode::UNWRAP_FAILURE;
+		case DPP_STATUS_BAD_GROUP:
+			return DppStatusErrorCode::BAD_GROUP;
+		case DPP_STATUS_CONFIGURE_FAILURE:
+			return DppStatusErrorCode::CONFIGURE_FAILURE;
+		case DPP_STATUS_RESPONSE_PENDING:
+			return DppStatusErrorCode::RESPONSE_PENDING;
+		case DPP_STATUS_INVALID_CONNECTOR:
+			return DppStatusErrorCode::INVALID_CONNECTOR;
+		case DPP_STATUS_CONFIG_REJECTED:
+			return DppStatusErrorCode::CONFIG_REJECTED;
+		case DPP_STATUS_NO_MATCH:
+			return DppStatusErrorCode::NO_MATCH;
+		case DPP_STATUS_NO_AP:
+			return DppStatusErrorCode::NO_AP;
+		case DPP_STATUS_CONFIGURE_PENDING:
+			return DppStatusErrorCode::CONFIGURE_PENDING;
+		case DPP_STATUS_CSR_NEEDED:
+			return DppStatusErrorCode::CSR_NEEDED;
+		case DPP_STATUS_CSR_BAD:
+			return DppStatusErrorCode::CSR_BAD;
+		case DPP_STATUS_NEW_KEY_NEEDED:
+			return DppStatusErrorCode::NEW_KEY_NEEDED;
+		default:
+			return DppStatusErrorCode::UNKNOWN;
+	}
+}
+
+void AidlManager::notifyDppConnectionStatusSent(struct wpa_supplicant *wpa_s,
+		enum dpp_status_error result)
+{
+	std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname);
+	callWithEachStaIfaceCallback(aidl_ifname,
+			std::bind(&ISupplicantStaIfaceCallback::onDppConnectionStatusResultSent,
+					std::placeholders::_1,
+					convertSupplicantDppStatusErrorCodeToAidl(result)));
+}
+
 /**
  * Notify listener about a DPP failure event
  *
@@ -1906,24 +1997,33 @@
 	callWithEachStaIfaceCallback(misc_utils::charBufToString(wpa_s->ifname), func);
 }
 
-void AidlManager::notifyFrequencyChanged(struct wpa_supplicant *wpa_group_s, int frequency)
+void AidlManager::notifyFrequencyChanged(struct wpa_supplicant *wpa_s, int frequency)
 {
-	if (!wpa_group_s || !wpa_group_s->parent)
+	if (!wpa_s)
 		return;
 
-	// For group notifications, need to use the parent iface for callbacks.
-	struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
-	if (!wpa_s) {
+	std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname);
+	struct wpa_supplicant *wpa_p2pdev_s = getTargetP2pIfaceForGroup(wpa_s);
+	if (wpa_p2pdev_s) {
+		// Notify frequency changed event on P2P interface
+		const std::function<
+			ndk::ScopedAStatus(std::shared_ptr<ISupplicantP2pIfaceCallback>)>
+			func = std::bind(&ISupplicantP2pIfaceCallback::onGroupFrequencyChanged,
+			std::placeholders::_1, aidl_ifname, frequency);
+		// For group notifications, need to use the parent iface for callbacks.
+		callWithEachP2pIfaceCallback(misc_utils::charBufToString(wpa_p2pdev_s->ifname), func);
+	} else if (wpa_s->current_ssid) {
+		// Notify frequency changed event on STA interface
+		const std::function<
+			ndk::ScopedAStatus(std::shared_ptr<ISupplicantStaIfaceCallback>)>
+			func = std::bind(
+			&ISupplicantStaIfaceCallback::onBssFrequencyChanged,
+			std::placeholders::_1, frequency);
+		callWithEachStaIfaceCallback(aidl_ifname, func);
+	} else {
 		wpa_printf(MSG_INFO, "Drop frequency changed event");
 		return;
-	}
-
-	const std::function<
-		ndk::ScopedAStatus(std::shared_ptr<ISupplicantP2pIfaceCallback>)>
-		func = std::bind(&ISupplicantP2pIfaceCallback::onGroupFrequencyChanged,
-		std::placeholders::_1, misc_utils::charBufToString(wpa_group_s->ifname),
-		frequency);
-	callWithEachP2pIfaceCallback(misc_utils::charBufToString(wpa_s->ifname), func);
+        }
 }
 
 void AidlManager::notifyCertification(struct wpa_supplicant *wpa_s,
@@ -2109,6 +2209,21 @@
 }
 
 /**
+ * Store the |INonStandardCertCallback| aidl object reference.
+ *
+ * @param callback Aidl reference of the |INonStandardCertCallback| object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int AidlManager::registerNonStandardCertCallbackAidlObject(
+	const std::shared_ptr<INonStandardCertCallback> &callback)
+{
+	if (callback == nullptr) return 1;
+	non_standard_cert_callback_ = callback;
+	return 0;
+}
+
+/**
  * Add a new iface callback aidl object reference to our
  * interface callback list.
  *
@@ -2460,6 +2575,20 @@
 			std::placeholders::_1, wpa_s->dscp_req_dialog_token, qosPolicyData));
 }
 
+ssize_t AidlManager::getCertificate(const char* alias, uint8_t** value) {
+	if (alias == nullptr || value == nullptr) {
+		wpa_printf(MSG_ERROR, "Null pointer argument was passed to getCertificate");
+		return -1;
+	}
+	if (auto cert = certificate_utils::getCertificate(alias, non_standard_cert_callback_)) {
+		*value = (uint8_t *) os_malloc(cert->size());
+		if (*value == nullptr) return -1;
+		os_memcpy(*value, cert->data(), cert->size());
+		return cert->size();
+	}
+	return -1;
+}
+
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h
index 1ed6899..e4af31a 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/aidl_manager.h
@@ -16,6 +16,7 @@
 #include <aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.h>
 #include <aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.h>
 
+#include "certificate_utils.h"
 #include "p2p_iface.h"
 #include "p2p_network.h"
 #include "rsn_supp/pmksa_cache.h"
@@ -61,6 +62,8 @@
 	int notifyNetworkRequest(
 		struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
 		const char *param);
+	void notifyPermanentIdReqDenied(
+		struct wpa_supplicant *wpa_s);
 	void notifyAnqpQueryDone(
 		struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
 		const struct wpa_bss_anqp *anqp);
@@ -125,8 +128,11 @@
 		const u8 *p2p_dev_addr);
 	void notifyEapError(struct wpa_supplicant *wpa_s, int error_code);
 	void notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
-			struct wpa_ssid *config);
+		struct wpa_ssid *config,
+		bool conn_status_requested);
 	void notifyDppConfigSent(struct wpa_supplicant *wpa_s);
+	void notifyDppConnectionStatusSent(struct wpa_supplicant *wpa_s,
+		enum dpp_status_error result);
 	void notifyDppSuccess(struct wpa_supplicant *wpa_s, DppEventType code);
 	void notifyDppFailure(struct wpa_supplicant *wpa_s,
 			DppFailureCode code);
@@ -157,6 +163,7 @@
 	void notifyQosPolicyRequest(struct wpa_supplicant *wpa_s,
 			struct dscp_policy_data *policies,
 			int num_policies);
+	ssize_t getCertificate(const char* alias, uint8_t** value);
 
 	// Methods called from aidl objects.
 	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -186,6 +193,8 @@
 	int addStaNetworkCallbackAidlObject(
 		const std::string &ifname, int network_id,
 		const std::shared_ptr<ISupplicantStaNetworkCallback> &callback);
+	int registerNonStandardCertCallbackAidlObject(
+		const std::shared_ptr<INonStandardCertCallback> &callback);
 
 private:
 	AidlManager() = default;
@@ -273,6 +282,8 @@
 		const std::string,
 		std::vector<std::shared_ptr<ISupplicantStaNetworkCallback>>>
 		sta_network_callbacks_map_;
+	// NonStandardCertCallback registered by the client.
+	std::shared_ptr<INonStandardCertCallback> non_standard_cert_callback_;
 };
 
 // The aidl interface uses some values which are the same as internal ones to
diff --git a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml b/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
index 3dc9b02..b80dadd 100644
--- a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
+++ b/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
 	<hal format="aidl">
 		<name>android.hardware.wifi.supplicant</name>
+		<version>2</version>
 		<fqname>ISupplicant/default</fqname>
 	</hal>
 </manifest>
diff --git a/wpa_supplicant/aidl/certificate_utils.cpp b/wpa_supplicant/aidl/certificate_utils.cpp
new file mode 100644
index 0000000..79fe38b
--- /dev/null
+++ b/wpa_supplicant/aidl/certificate_utils.cpp
@@ -0,0 +1,196 @@
+/*
+ * WPA Supplicant - Certificate utils
+ * Copyright (c) 2022, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "certificate_utils.h"
+
+#define AT __func__ << ":" << __LINE__ << " "
+
+namespace ks2 = aidl::android::system::keystore2;
+namespace KMV1 = aidl::android::hardware::security::keymint;
+
+using aidl::android::hardware::wifi::supplicant::INonStandardCertCallback;
+
+namespace {
+
+constexpr const int64_t KS2_NAMESPACE_WIFI = 102;
+
+constexpr const char kKeystore2ServiceName[] = "android.system.keystore2.IKeystoreService/default";
+
+const std::string keystore2_grant_id_prefix("ks2_keystore-engine_grant_id:");
+
+ks2::KeyDescriptor mkKeyDescriptor(const std::string& alias) {
+	// If the key_id starts with the grant id prefix, we parse the following string as numeric
+	// grant id. We can then use the grant domain without alias to load the designated key.
+	if (::android::base::StartsWith(alias, keystore2_grant_id_prefix)) {
+		std::stringstream s(alias.substr(keystore2_grant_id_prefix.size()));
+		uint64_t tmp;
+		s >> std::hex >> tmp;
+		if (s.fail() || !s.eof()) {
+			wpa_printf(MSG_ERROR, "Couldn't parse grant name: %s", alias.c_str());
+		}
+		return {
+			.domain = ks2::Domain::GRANT,
+			.nspace = static_cast<int64_t>(tmp),
+			.alias = std::nullopt,
+			.blob = std::nullopt,
+		};
+	} else {
+		return {
+			.domain = ks2::Domain::SELINUX,
+			.nspace = KS2_NAMESPACE_WIFI,
+			.alias = alias,
+			.blob = std::nullopt,
+		};
+	}
+}
+
+// Helper method to convert certs in DER format to PEM format required by
+// openssl library used by supplicant. If boringssl cannot parse the input as one or more
+// X509 certificates in DER encoding, this function returns the input as-is. The assumption in
+// that case is that either the `cert_bytes` is already PEM encoded, or `cert_bytes` is something
+// completely different that was intentionally installed by the Wi-Fi subsystem and it must not
+// be changed here.
+// If any error occurs during PEM encoding, this function returns std::nullopt and logs an error.
+std::optional<std::vector<uint8_t>> convertDerCertToPemOrPassthrough(
+	const std::vector<uint8_t>& cert_bytes) {
+	// If cert_bytes is a DER encoded X509 certificate, it must be reencoded as PEM, because
+	// wpa_supplicant only understand PEM. Otherwise the cert_bytes are returned as is.
+	const uint8_t* cert_current = cert_bytes.data();
+	const uint8_t* cert_end = cert_current + cert_bytes.size();
+	bssl::UniquePtr<BIO> pem_bio(BIO_new(BIO_s_mem()));
+	while (cert_current < cert_end) {
+		auto cert =
+			bssl::UniquePtr<X509>(d2i_X509(nullptr, &cert_current, cert_end - cert_current));
+		// If part of the bytes cannot be parsed as X509 DER certificate, the original blob
+		// shall be returned as-is.
+		if (!cert) {
+			wpa_printf(MSG_WARNING, "Could not parse DER X509 cert from buffer. Returning blob as is.");
+			return cert_bytes;
+		}
+
+		if (!PEM_write_bio_X509(pem_bio.get(), cert.get())) {
+			wpa_printf(MSG_ERROR, "Could not convert cert to PEM format.");
+			return std::nullopt;
+		}
+	}
+
+	const uint8_t* pem_bytes;
+	size_t pem_len;
+	if (!BIO_mem_contents(pem_bio.get(), &pem_bytes, &pem_len)) {
+		wpa_printf(MSG_ERROR, "Could not extract pem_bytes from BIO.");
+		return std::nullopt;
+	}
+	return {{pem_bytes, pem_bytes + pem_len}};
+}
+
+std::optional<std::vector<uint8_t>> getKeystore2Cert(const std::string& key) {
+	::ndk::SpAIBinder keystoreBinder(AServiceManager_checkService(kKeystore2ServiceName));
+	auto keystore2 = ks2::IKeystoreService::fromBinder(keystoreBinder);
+
+	if (!keystore2) {
+		wpa_printf(MSG_WARNING, "Unable to connect to Keystore 2.");
+		return {};
+	}
+
+	bool ca_cert = false;
+	std::string alias = key.c_str();
+	if (::android::base::StartsWith(alias, "CACERT_")) {
+		alias = alias.substr(7);
+		ca_cert = true;
+	} else if (::android::base::StartsWith(alias, "USRCERT_")) {
+		alias = alias.substr(8);
+	}
+
+	ks2::KeyDescriptor descriptor = mkKeyDescriptor(alias);
+
+	// If the key_id starts with the grant id prefix, we parse the following string as numeric
+	// grant id. We can then use the grant domain without alias to load the designated key.
+	if (::android::base::StartsWith(alias, keystore2_grant_id_prefix)) {
+		std::stringstream s(alias.substr(keystore2_grant_id_prefix.size()));
+		uint64_t tmp;
+		s >> std::hex >> tmp;
+		if (s.fail() || !s.eof()) {
+			wpa_printf(MSG_ERROR, "Couldn't parse grant name: %s", alias.c_str());
+		}
+		descriptor.nspace = static_cast<int64_t>(tmp);
+		descriptor.domain = ks2::Domain::GRANT;
+		descriptor.alias = std::nullopt;
+	}
+
+	ks2::KeyEntryResponse response;
+	auto rc = keystore2->getKeyEntry(descriptor, &response);
+	if (!rc.isOk()) {
+		if (rc.getServiceSpecificError() != int32_t(ks2::ResponseCode::KEY_NOT_FOUND)) {
+			wpa_printf(MSG_WARNING, "Entry not found in Keystore 2.");
+		} else {
+			wpa_printf(MSG_WARNING, "Keystore 2 getKeyEntry failed error: %s", rc.getDescription().c_str());
+		}
+		return {};
+	}
+
+	if (ca_cert && response.metadata.certificateChain) {
+		return std::move(*response.metadata.certificateChain);
+	} else if (!ca_cert && response.metadata.certificate) {
+		return std::move(*response.metadata.certificate);
+	} else {
+		wpa_printf(MSG_WARNING, "No %s certificate found.", (ca_cert ? "CA" : "client"));
+		return {};
+	}
+}
+
+std::optional<std::vector<uint8_t>> getNonStandardCert(const std::string& alias,
+		const std::shared_ptr<INonStandardCertCallback> &non_standard_callback) {
+	if (non_standard_callback == nullptr) {
+		wpa_printf(MSG_ERROR, "Non-standard cert callback is not available");
+		return std::nullopt;
+	}
+	std::vector<uint8_t> blob;
+	const auto& status = non_standard_callback->getBlob(alias, &blob);
+	if (!status.isOk()) {
+		wpa_printf(MSG_ERROR, "Cert callback error, code=%d",
+			status.getServiceSpecificError());
+		return std::nullopt;
+	}
+	return blob;
+}
+
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace certificate_utils {
+
+std::optional<std::vector<uint8_t>> getCertificate(const std::string& alias,
+		const std::shared_ptr<INonStandardCertCallback> &non_standard_callback) {
+	std::vector<uint8_t> cert;
+	if (auto ks2_cert = getKeystore2Cert(alias)) {
+		cert = std::move(*ks2_cert);
+	} else if (auto blob = getNonStandardCert(alias, non_standard_callback)) {
+		cert = std::move(*blob);
+	} else {
+		wpa_printf(MSG_ERROR, "Failed to get certificate.");
+		return std::nullopt;
+	}
+
+	if (auto result_cert = convertDerCertToPemOrPassthrough(cert)) {
+		return result_cert;
+	} else {
+		wpa_printf(MSG_ERROR, "Conversion to PEM failed.");
+		return std::nullopt;
+	}
+}
+
+}  // namespace certificate_utils
+}  // namespace supplicant
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wpa_supplicant/aidl/certificate_utils.h b/wpa_supplicant/aidl/certificate_utils.h
new file mode 100644
index 0000000..09da74b
--- /dev/null
+++ b/wpa_supplicant/aidl/certificate_utils.h
@@ -0,0 +1,40 @@
+/*
+ * WPA Supplicant - Certificate utils
+ * Copyright (c) 2022, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.h>
+#include <aidl/android/system/keystore2/IKeystoreService.h>
+#include <aidl/android/system/keystore2/ResponseCode.h>
+#include <android-base/strings.h>
+#include <android/binder_manager.h>
+#include <openssl/base.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <vector>
+
+extern "C"
+{
+#include "utils/common.h"
+}
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace certificate_utils {
+	std::optional<std::vector<uint8_t>> getCertificate(const std::string& alias,
+		const std::shared_ptr<INonStandardCertCallback> &non_standard_callback);
+}  // namespace certificate_utils
+}  // namespace supplicant
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/p2p_iface.cpp
index ce945a4..c8056f0 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/p2p_iface.cpp
@@ -992,6 +992,9 @@
 	if (go_intent > 15) {
 		return {"", createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return {"", createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
+	}
 	int go_intent_signed = join_existing_group ? -1 : go_intent;
 	p2p_wps_method wps_method = {};
 	switch (provision_method) {
@@ -1048,6 +1051,9 @@
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
 	p2ps_provision* prov_param;
 	const char* config_method_str = nullptr;
+	if (peer_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	switch (provision_method) {
 	case WpsProvisionMethod::PBC:
 		config_method_str = kConfigMethodStrPbc;
@@ -1087,6 +1093,9 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
 		return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	if (wpas_p2p_reject(wpa_s, peer_address.data())) {
 		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
 	}
@@ -1099,6 +1108,9 @@
 	const std::vector<uint8_t>& peer_address)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (peer_address.size() != ETH_ALEN) {
+		return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	if (wpas_p2p_invite_group(
 		wpa_s, group_ifname.c_str(), peer_address.data(),
 		go_device_address.data(), is6GhzAllowed(wpa_s))) {
@@ -1121,6 +1133,9 @@
 	if (ssid == NULL || ssid->disabled != 2) {
 		return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	if (wpas_p2p_invite(
 		wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
 		CONF_OPER_CHWIDTH_USE_HT, 0, he, edmg, is6GhzAllowed(wpa_s))) {
@@ -1182,6 +1197,10 @@
 	const std::vector<uint8_t>& peer_address)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (peer_address.size() != ETH_ALEN) {
+		return {std::vector<uint8_t>(),
+			createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const struct p2p_peer_info* info =
 		p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
 	if (!info) {
@@ -1204,6 +1223,10 @@
 	const std::vector<uint8_t>& peer_address)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (peer_address.size() != ETH_ALEN) {
+		return {static_cast<P2pGroupCapabilityMask>(0),
+			createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const struct p2p_peer_info* info =
 		p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
 	if (!info) {
@@ -1284,6 +1307,9 @@
 	if (!query_buf) {
 		return {0, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return {0, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const uint8_t* dst_addr = is_zero_ether_addr(peer_address.data())
 					  ? nullptr
 					  : peer_address.data();
@@ -1330,6 +1356,9 @@
 	if (!wpa_group_s) {
 		return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
 	}
+	if (bssid.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	const uint8_t* bssid_addr =
 		is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
 #ifdef CONFIG_AP
@@ -1378,6 +1407,9 @@
 	if (!wpa_group_s) {
 		return {"", createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN)};
 	}
+	if (bssid.size() != ETH_ALEN) {
+		return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const uint8_t* bssid_addr =
 		is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
 	int pin = wpas_wps_start_pin(
@@ -1410,6 +1442,9 @@
 	const std::vector<uint8_t>& type)
 {
 	std::array<uint8_t, 8> type_arr;
+	if (type.size() != 8) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	std::copy_n(type.begin(), 8, type_arr.begin());
 	return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type_arr);
 }
@@ -1629,6 +1664,10 @@
 	// The rest is for group join.
 	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND before group join.");
 	wpas_p2p_stop_find(wpa_s);
+	if (peer_address.size() != ETH_ALEN) {
+		return createStatusWithMsg(SupplicantStatusCode::FAILURE_ARGS_INVALID,
+			"Peer address is invalid.");
+	}
 	if (joinGroup(wpa_s, peer_address.data(), ssid, passphrase, freq)) {
 		return createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
 			"Failed to start scan.");
@@ -1732,6 +1771,9 @@
     const std::vector<uint8_t>& peer_address, bool isLegacyClient)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (peer_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	wpas_p2p_remove_client(wpa_s, peer_address.data(), isLegacyClient? 1 : 0);
 	return ndk::ScopedAStatus::ok();
 }
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index 7a07cc1..086c0a6 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -50,6 +50,7 @@
   WIDTH_80P80 = 4,
   WIDTH_5	 = 5,
   WIDTH_10	= 6,
+  WIDTH_320	= 7,
   WIDTH_INVALID = -1
 };
 
@@ -810,6 +811,40 @@
 		&StaIface::getConnectionMloLinksInfoInternal, _aidl_return);
 }
 
+::ndk::ScopedAStatus StaIface::getSignalPollResults(
+    std::vector<SignalPollResult> *results)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_UNKNOWN,
+	    &StaIface::getSignalPollResultsInternal, results);
+}
+
+::ndk::ScopedAStatus StaIface::addQosPolicyRequestForScs(
+		const std::vector<QosPolicyScsData>& in_qosPolicyData,
+		std::vector<QosPolicyScsRequestStatus>* _aidl_return)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_UNKNOWN,
+	    &StaIface::addQosPolicyRequestForScsInternal, _aidl_return, in_qosPolicyData);
+}
+
+::ndk::ScopedAStatus StaIface::removeQosPolicyForScs(
+		const std::vector<uint8_t>& in_scsPolicyIds,
+		std::vector<QosPolicyScsRequestStatus>* _aidl_return)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_UNKNOWN,
+	    &StaIface::removeQosPolicyForScsInternal, _aidl_return, in_scsPolicyIds);
+}
+
+::ndk::ScopedAStatus StaIface::removeAllQosPoliciesForScs(
+		std::vector<QosPolicyScsRequestStatus>* _aidl_return)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_UNKNOWN,
+	    &StaIface::removeAllQosPoliciesForScsInternal, _aidl_return);
+}
+
 std::pair<std::string, ndk::ScopedAStatus> StaIface::getNameInternal()
 {
 	return {ifname_, ndk::ScopedAStatus::ok()};
@@ -986,6 +1021,9 @@
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	int ret;
+	if (mac_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	const u8 *peer = mac_address.data();
 	if (wpa_tdls_is_external_setup(wpa_s->wpa)) {
 		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
@@ -1003,6 +1041,9 @@
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	int ret;
+	if (mac_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	const u8 *peer = mac_address.data();
 	if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
 		!(wpa_s->conf->tdls_external_control)) {
@@ -1022,6 +1063,9 @@
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	int ret;
+	if (mac_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	const u8 *peer = mac_address.data();
 	if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
 		!(wpa_s->conf->tdls_external_control)) {
@@ -1058,6 +1102,9 @@
 			static_cast<std::underlying_type<
 			Hs20AnqpSubtypes>::type>(type));
 	}
+	if (mac_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 
 	if (anqp_send_req(
 		wpa_s, mac_address.data(), 0, info_elems_buf, num_info_elems,
@@ -1072,6 +1119,9 @@
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	uint16_t info_elems_buf[1] = {ANQP_VENUE_URL};
+	if (mac_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 
 	if (anqp_send_req(
 		wpa_s, mac_address.data(), 0, info_elems_buf, 1, 0, 0)) {
@@ -1084,6 +1134,9 @@
 	const std::vector<uint8_t> &mac_address, const std::string &file_name)
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	if (mac_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	wpa_s->fetch_osu_icon_in_progress = 0;
 	if (hs20_anqp_send_req(
 		wpa_s, mac_address.data(), BIT(HS20_STYPE_ICON_REQUEST),
@@ -1185,6 +1238,10 @@
 	const std::vector<uint8_t> &code)
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	//2-Character alphanumeric country code
+	if (code.size() != 2) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	ndk::ScopedAStatus status = doOneArgDriverCommand(
 		wpa_s, kSetCountryCode,
 		std::string(std::begin(code), std::end(code)));
@@ -1206,6 +1263,9 @@
 	const std::vector<uint8_t> &bssid, const std::string &pin)
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	if (bssid.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	if (wpas_wps_start_reg(wpa_s, bssid.data(), pin.c_str(), nullptr)) {
 		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
 	}
@@ -1216,6 +1276,9 @@
 	const std::vector<uint8_t> &bssid)
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	if (bssid.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	const uint8_t *bssid_addr =
 		is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
 	if (wpas_wps_start_pbc(wpa_s, bssid_addr, 0, 0)) {
@@ -1238,6 +1301,9 @@
 	const std::vector<uint8_t> &bssid)
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	if (bssid.size() != ETH_ALEN) {
+		return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const uint8_t *bssid_addr =
 		is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
 	int pin =
@@ -1609,6 +1675,9 @@
 	}
 	cmd += " chan=" + listen_channel_str;
 
+	if (mac_address.size() != ETH_ALEN) {
+		return {bootstrap_info, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	cmd += " mac=";
 	for (int i = 0;i < 6;i++) {
 		snprintf(buf, sizeof(buf), "%02x", mac_address[i]);
@@ -1747,7 +1816,9 @@
 
 	if (wpa_s->connection_set) {
 		capa.legacyMode = LegacyMode::UNKNOWN;
-		if (wpa_s->connection_he) {
+		if (wpa_s->connection_eht) {
+			capa.technology = WifiTechnology::EHT;
+		} else if (wpa_s->connection_he) {
 			capa.technology = WifiTechnology::HE;
 		} else if (wpa_s->connection_vht) {
 			capa.technology = WifiTechnology::VHT;
@@ -1778,6 +1849,9 @@
 		case CHAN_WIDTH_80P80:
 			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
 			break;
+		case CHAN_WIDTH_320:
+			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_320;
+			break;
 		default:
 			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
 			break;
@@ -1817,6 +1891,12 @@
 
 	mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TRUST_ON_FIRST_USE);
 
+	mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::SET_TLS_MINIMUM_VERSION);
+
+#ifdef EAP_TLSV1_3
+	mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TLS_V1_3);
+#endif
+
 	wpa_printf(MSG_DEBUG, "Driver capability mask: 0x%x", mask);
 
 	return {static_cast<WpaDriverCapabilitiesMask>(mask),
@@ -1930,10 +2010,97 @@
 
 std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoInternal()
 {
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	MloLinksInfo linksInfo;
+	MloLink link;
+
+	if (!wpa_s->valid_links)
+		 return {linksInfo, ndk::ScopedAStatus::ok()};
+
+	for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+		if (!(wpa_s->valid_links & BIT(i)))
+			continue;
+
+		wpa_printf(MSG_DEBUG, "Add MLO Link ID %d info", i);
+		link.linkId = i;
+		link.staLinkMacAddress.assign(wpa_s->links[i].addr, wpa_s->links[i].addr + ETH_ALEN);
+		// TODO (b/259710591): Once suppllicant implements TID-to-link
+		// mapping, copy it here. Mapping can be changed in two
+		// scenarios
+		//    1. Mandatory mapping from AP
+		//    2. Negotiated mapping
+		// After association, framework call this API to get
+		// MloLinksInfo. If there is an update in mapping later, notify
+		// framework on the change using the callback,
+		// ISupplicantStaIfaceCallback.onMloLinksInfoChanged() with
+		// reason code as TID_TO_LINK_MAP. In absence of an advertised
+		// mapping by the AP, a default TID-to-link mapping is assumed
+		// unless an individual TID-to-link mapping is successfully
+		// negotiated.
+		link.tidsUplinkMap = 0xFF;
+		link.tidsDownlinkMap = 0xFF;
+		linksInfo.links.push_back(link);
+	}
+
 	return {linksInfo, ndk::ScopedAStatus::ok()};
 }
 
+std::pair<std::vector<SignalPollResult>, ndk::ScopedAStatus>
+StaIface::getSignalPollResultsInternal()
+{
+	std::vector<SignalPollResult> results;
+	struct wpa_signal_info si;
+	struct wpa_mlo_signal_info mlo_si;
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+
+	if (wpa_s->valid_links && wpa_drv_mlo_signal_poll(wpa_s, &mlo_si)) {
+		for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+			if (!(mlo_si.valid_links & BIT(i)))
+				continue;
+
+			SignalPollResult result;
+			result.linkId = 0;
+			result.currentRssiDbm = mlo_si.links[i].current_signal;
+			result.txBitrateMbps = mlo_si.links[i].current_txrate / 1000;
+			result.rxBitrateMbps = mlo_si.links[i].current_rxrate / 1000;
+			result.frequencyMhz = mlo_si.links[i].frequency;
+			results.push_back(result);
+		}
+	} else if (wpa_drv_signal_poll(wpa_s, &si) == 0) {
+		SignalPollResult result;
+		result.linkId = 0;
+		result.currentRssiDbm = si.current_signal;
+		result.txBitrateMbps = si.current_txrate / 1000;
+		result.rxBitrateMbps = si.current_rxrate / 1000;
+		result.frequencyMhz = si.frequency;
+		results.push_back(result);
+	}
+
+	return {results, ndk::ScopedAStatus::ok()};
+}
+
+
+std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
+StaIface::addQosPolicyRequestForScsInternal(const std::vector<QosPolicyScsData>& qosPolicyData)
+{
+	return {std::vector<QosPolicyScsRequestStatus>(),
+		createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+}
+
+std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
+StaIface::removeQosPolicyForScsInternal(const std::vector<uint8_t>& scsPolicyIds)
+{
+	return {std::vector<QosPolicyScsRequestStatus>(),
+		createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+}
+
+std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
+StaIface::removeAllQosPoliciesForScsInternal()
+{
+	return {std::vector<QosPolicyScsRequestStatus>(),
+		createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
diff --git a/wpa_supplicant/aidl/sta_iface.h b/wpa_supplicant/aidl/sta_iface.h
index 0ed29d8..88c6e45 100644
--- a/wpa_supplicant/aidl/sta_iface.h
+++ b/wpa_supplicant/aidl/sta_iface.h
@@ -157,6 +157,16 @@
 		const std::vector<QosPolicyStatus>& in_qosPolicyStatusList) override;
 	::ndk::ScopedAStatus removeAllQosPolicies() override;
 	::ndk::ScopedAStatus getConnectionMloLinksInfo(MloLinksInfo* _aidl_return) override;
+	::ndk::ScopedAStatus getSignalPollResults(
+		std::vector<SignalPollResult>* results) override;
+	::ndk::ScopedAStatus addQosPolicyRequestForScs(
+		const std::vector<QosPolicyScsData>& in_qosPolicyData,
+		std::vector<QosPolicyScsRequestStatus>* _aidl_return) override;
+	::ndk::ScopedAStatus removeQosPolicyForScs(
+		const std::vector<uint8_t>& in_scsPolicyIds,
+		std::vector<QosPolicyScsRequestStatus>* _aidl_return) override;
+	::ndk::ScopedAStatus removeAllQosPoliciesForScs(
+		std::vector<QosPolicyScsRequestStatus>* _aidl_return) override;
 
 private:
 	// Corresponding worker functions for the AIDL methods.
@@ -261,6 +271,17 @@
 		const std::vector<QosPolicyStatus>& qos_policy_status_list);
 	ndk::ScopedAStatus removeAllQosPoliciesInternal();
 	std::pair<MloLinksInfo, ndk::ScopedAStatus> getConnectionMloLinksInfoInternal();
+	std::pair<std::vector<SignalPollResult>, ndk::ScopedAStatus>
+		getSignalPollResultsInternal();
+	std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
+		addQosPolicyRequestForScsInternal(
+		const std::vector<QosPolicyScsData>& qosPolicyData);
+	std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
+		removeQosPolicyForScsInternal(
+		const std::vector<uint8_t>& scsPolicyIds);
+	std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
+		removeAllQosPoliciesForScsInternal();
+
 	struct wpa_supplicant* retrieveIfacePtr();
 
 	// Reference to the global wpa_struct. This is assumed to be valid for
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index 61c71a1..db13509 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -304,6 +304,15 @@
 		in_identity);
 }
 
+::ndk::ScopedAStatus StaNetwork::setStrictConservativePeerMode(
+	bool in_enable)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+		&StaNetwork::setStrictConservativePeerModeInternal,
+		in_enable);
+}
+
 ::ndk::ScopedAStatus StaNetwork::setEapAnonymousIdentity(
 	const std::vector<uint8_t>& in_identity)
 {
@@ -871,6 +880,14 @@
 		&StaNetwork::setRoamingConsortiumSelectionInternal, in_selectedRcoi);
 }
 
+::ndk::ScopedAStatus StaNetwork::setMinimumTlsVersionEapPhase1Param(
+	TlsVersion in_tlsVersion)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+		&StaNetwork::setMinimumTlsVersionEapPhase1ParamInternal, in_tlsVersion);
+}
+
 std::pair<uint32_t, ndk::ScopedAStatus> StaNetwork::getIdInternal()
 {
 	return {network_id_, ndk::ScopedAStatus::ok()};
@@ -1238,6 +1255,13 @@
 	return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StaNetwork::setStrictConservativePeerModeInternal(bool enable)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->eap.strict_conservative_peer_mode = enable ? 1 : 0;
+	return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus StaNetwork::setEapAnonymousIdentityInternal(
 	const std::vector<uint8_t> &identity)
 {
@@ -2005,10 +2029,13 @@
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	int val = enable == true ? 1 : 0;
-	std::string suiteb_phase1("tls_suiteb=" + std::to_string(val));
+	std::string phase1_params("tls_suiteb=" + std::to_string(val));
+	if (wpa_ssid->eap.phase1 != NULL) {
+		phase1_params.append(wpa_ssid->eap.phase1);
+	}
 
 	if (setStringKeyFieldAndResetState(
-		suiteb_phase1.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
+		phase1_params.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
 		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
 	}
 	return ndk::ScopedAStatus::ok();
@@ -2152,10 +2179,19 @@
 	KeyMgmtMask mask)
 {
 	uint32_t key_mgmt_mask = static_cast<uint32_t>(mask);
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	if (key_mgmt_mask & ~kAllowedKeyMgmtMask) {
 		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
 	}
+#ifdef CONFIG_SAE
+	struct wpa_driver_capa capa;
+	int res = wpa_drv_get_capa(wpa_s, &capa);
+	if ((res == 0) && (key_mgmt_mask & WPA_KEY_MGMT_SAE) &&
+		(capa.key_mgmt_iftype[WPA_IF_STATION] & WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY)) {
+		key_mgmt_mask |= WPA_KEY_MGMT_SAE_EXT_KEY;
+	}
+#endif
 	setFastTransitionKeyMgmt(key_mgmt_mask);
 
 	if (key_mgmt_mask & WPA_KEY_MGMT_OWE) {
@@ -2489,6 +2525,11 @@
 			(capa.key_mgmt_iftype[WPA_IF_STATION] & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE)) {
 			key_mgmt_mask |= WPA_KEY_MGMT_FT_SAE;
 		}
+		if ((key_mgmt_mask & WPA_KEY_MGMT_SAE_EXT_KEY) &&
+			(capa.key_mgmt_iftype[WPA_IF_STATION] &
+			    WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY)) {
+			key_mgmt_mask |= WPA_KEY_MGMT_FT_SAE_EXT_KEY;
+		}
 #endif
 #ifdef CONFIG_FILS
 		if ((key_mgmt_mask & WPA_KEY_MGMT_FILS_SHA256) &&
@@ -2597,6 +2638,41 @@
 #endif
 }
 
+ndk::ScopedAStatus StaNetwork::setMinimumTlsVersionEapPhase1ParamInternal(TlsVersion tlsVersion)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	std::string phase1_params;
+	if (wpa_ssid->eap.phase1 != NULL) {
+		phase1_params.append(wpa_ssid->eap.phase1);
+	}
+	if (tlsVersion < TlsVersion::TLS_V1_0) {
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+	// Fallback to disable lower version TLS cascadingly.
+	switch (tlsVersion) {
+		case TlsVersion::TLS_V1_3:
+			phase1_params.append("tls_disable_tlsv1_2=1");
+			FALLTHROUGH_INTENDED;
+		case TlsVersion::TLS_V1_2:
+			phase1_params.append("tls_disable_tlsv1_1=1");
+			FALLTHROUGH_INTENDED;
+		case TlsVersion::TLS_V1_1:
+			phase1_params.append("tls_disable_tlsv1_0=1");
+			FALLTHROUGH_INTENDED;
+		case TlsVersion::TLS_V1_0:
+			FALLTHROUGH_INTENDED;
+		default:
+			// no restriction
+			break;
+	}
+
+	if (setStringKeyFieldAndResetState(
+		phase1_params.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/aidl/sta_network.h b/wpa_supplicant/aidl/sta_network.h
index 524f44a..f794844 100644
--- a/wpa_supplicant/aidl/sta_network.h
+++ b/wpa_supplicant/aidl/sta_network.h
@@ -22,6 +22,7 @@
 #include <aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.h>
 #include <aidl/android/hardware/wifi/supplicant/SaeH2eMode.h>
 #include <aidl/android/hardware/wifi/supplicant/DppConnectionKeys.h>
+#include <aidl/android/hardware/wifi/supplicant/TlsVersion.h>
 
 extern "C"
 {
@@ -84,6 +85,8 @@
 		const std::vector<uint8_t>& in_identity) override;
 	::ndk::ScopedAStatus setEapEncryptedImsiIdentity(
 		const std::vector<uint8_t>& in_identity) override;
+	::ndk::ScopedAStatus setStrictConservativePeerMode(
+		bool in_enable) override;
 	::ndk::ScopedAStatus setEapAnonymousIdentity(
 		const std::vector<uint8_t>& in_identity) override;
 	::ndk::ScopedAStatus setEapPassword(
@@ -173,6 +176,8 @@
 	::ndk::ScopedAStatus enableSaePkOnlyMode(bool in_enable) override;
 	::ndk::ScopedAStatus setRoamingConsortiumSelection(
 		const std::vector<uint8_t>& in_selectedRcoi) override;
+	::ndk::ScopedAStatus setMinimumTlsVersionEapPhase1Param(
+		TlsVersion in_tlsVersion) override;
 
 private:
 	// Corresponding worker functions for the AIDL methods.
@@ -209,6 +214,8 @@
 		const std::vector<uint8_t>& identity);
 	ndk::ScopedAStatus setEapEncryptedImsiIdentityInternal(
 		const std::vector<uint8_t>& identity);
+	ndk::ScopedAStatus setStrictConservativePeerModeInternal(
+		bool enable);
 	ndk::ScopedAStatus setEapAnonymousIdentityInternal(
 		const std::vector<uint8_t>& identity);
 	ndk::ScopedAStatus setEapPasswordInternal(
@@ -302,6 +309,7 @@
 	ndk::ScopedAStatus enableSaePkOnlyModeInternal(bool enable);
 	ndk::ScopedAStatus setRoamingConsortiumSelectionInternal(
 		const std::vector<uint8_t>& selectedRcoi);
+	ndk::ScopedAStatus setMinimumTlsVersionEapPhase1ParamInternal(TlsVersion tlsVersion);
 
 	struct wpa_ssid* retrieveNetworkPtr();
 	struct wpa_supplicant* retrieveIfacePtr();
diff --git a/wpa_supplicant/aidl/supplicant.cpp b/wpa_supplicant/aidl/supplicant.cpp
index 799790b..74602e4 100644
--- a/wpa_supplicant/aidl/supplicant.cpp
+++ b/wpa_supplicant/aidl/supplicant.cpp
@@ -239,6 +239,14 @@
 		&Supplicant::registerCallbackInternal, in_callback);
 }
 
+::ndk::ScopedAStatus Supplicant::registerNonStandardCertCallback(
+	const std::shared_ptr<INonStandardCertCallback>& in_callback)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+		&Supplicant::registerNonStandardCertCallbackInternal, in_callback);
+}
+
 ::ndk::ScopedAStatus Supplicant::setDebugParams(
 	DebugLevel in_level, bool in_showTimestamp,
 	bool in_showKeys)
@@ -547,6 +555,17 @@
 	return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Supplicant::registerNonStandardCertCallbackInternal(
+	const std::shared_ptr<INonStandardCertCallback>& callback)
+{
+	AidlManager* aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager ||
+		aidl_manager->registerNonStandardCertCallbackAidlObject(callback)) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Supplicant::setDebugParamsInternal(
 	DebugLevel level, bool show_timestamp, bool show_keys)
 {
diff --git a/wpa_supplicant/aidl/supplicant.h b/wpa_supplicant/aidl/supplicant.h
index cbe9a67..12b9299 100644
--- a/wpa_supplicant/aidl/supplicant.h
+++ b/wpa_supplicant/aidl/supplicant.h
@@ -64,6 +64,8 @@
 		std::vector<IfaceInfo>* _aidl_return) override;
 	::ndk::ScopedAStatus registerCallback(
 		const std::shared_ptr<ISupplicantCallback>& in_callback) override;
+	::ndk::ScopedAStatus registerNonStandardCertCallback(
+		const std::shared_ptr<INonStandardCertCallback>& in_callback) override;
 	::ndk::ScopedAStatus setDebugParams(
 		DebugLevel in_level, bool in_showTimestamp, bool in_showKeys) override;
 	::ndk::ScopedAStatus getDebugLevel(DebugLevel* _aidl_return) override;
@@ -82,11 +84,13 @@
 		getP2pInterfaceInternal(const std::string& name);
 	std::pair<std::shared_ptr<ISupplicantStaIface>, ndk::ScopedAStatus>
 		getStaInterfaceInternal(const std::string& name);
-	
+
 	ndk::ScopedAStatus removeInterfaceInternal(const IfaceInfo& iface_info);
 	std::pair<std::vector<IfaceInfo>, ndk::ScopedAStatus> listInterfacesInternal();
 	ndk::ScopedAStatus registerCallbackInternal(
 		const std::shared_ptr<ISupplicantCallback>& callback);
+	ndk::ScopedAStatus registerNonStandardCertCallbackInternal(
+		const std::shared_ptr<INonStandardCertCallback>& callback);
 	ndk::ScopedAStatus setDebugParamsInternal(
 		DebugLevel level, bool show_timestamp, bool show_keys);
 	ndk::ScopedAStatus setConcurrencyPriorityInternal(IfaceType type);
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 52e4c04..bfdd53e 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -80,6 +80,7 @@
 
 # EAP-TLS
 CONFIG_EAP_TLS=y
+CONFIG_EAP_TLSV1_3=y
 
 # EAL-PEAP
 CONFIG_EAP_PEAP=y
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 065b6fb..2b1bdeb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2529,6 +2529,7 @@
 	{ INTe(sim_num, sim_num) },
 	{ STRe(imsi_privacy_cert, imsi_privacy_cert) },
 	{ STRe(imsi_privacy_attr, imsi_privacy_attr) },
+	{ INTe(strict_conservative_peer_mode, strict_conservative_peer_mode) },
 	{ STRe(openssl_ciphers, openssl_ciphers) },
 	{ INTe(erp, erp) },
 #endif /* IEEE8021X_EAPOL */
@@ -3953,6 +3954,11 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "strict_conservative_peer_mode") == 0) {
+		cred->strict_conservative_peer_mode = atoi(val);
+		return 0;
+	}
+
 	if (line) {
 		wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
 			   line, var);
@@ -4109,6 +4115,9 @@
 	if (os_strcmp(var, "imsi_privacy_attr") == 0)
 		return alloc_strdup(cred->imsi_privacy_attr);
 
+	if (os_strcmp(var, "strict_conservative_peer_mode") == 0)
+		return alloc_int_str(cred->strict_conservative_peer_mode);
+
 	if (os_strcmp(var, "milenage") == 0) {
 		if (!(cred->milenage))
 			return NULL;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index a81e9eb..0316e9b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -202,6 +202,18 @@
 	char *imsi_privacy_attr;
 
 	/**
+	 * strict_conservative_peer_mode - Whether the strict conservative peer
+	 * mode is enabled or not
+	 *
+	 * This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+	 * for EAP-SIM/AKA/AKA', in convervative peer mode, a client error would
+	 * be sent to the server, but it allows to send the permanent identity
+	 * in some special cases according to 4.6.2 of RFC 4187; With the strict
+	 * mode, it never send the permanent identity to server for privacy concern.
+	 */
+	int strict_conservative_peer_mode;
+
+	/**
 	 * engine - Use an engine for private key operations
 	 */
 	int engine;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 260df8f..372a57b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1044,6 +1044,9 @@
 	if (cred->imsi_privacy_attr)
 		fprintf(f, "\timsi_privacy_attr=\"%s\"\n",
 			cred->imsi_privacy_attr);
+	if (cred->strict_conservative_peer_mode)
+		fprintf(f,"\tstrict_conservative_peer_mode=\"%d\"\n",
+			cred->strict_conservative_peer_mode);
 }
 
 
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 55dcd70..d13a8d0 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -29,7 +29,7 @@
 #include "scan.h"
 #include "notify.h"
 #include "dpp_supplicant.h"
-#include "aidl.h"
+#include "aidl/aidl.h"
 
 
 static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
@@ -419,12 +419,21 @@
 		DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
 		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
 		DPP_PA_CONNECTION_STATUS_RESULT);
-	offchannel_send_action(wpa_s, auth->curr_freq,
-			       auth->peer_mac_addr, wpa_s->own_addr, broadcast,
-			       wpabuf_head(msg), wpabuf_len(msg),
-			       500, wpas_dpp_tx_status, 0);
+	if (offchannel_send_action(wpa_s, auth->curr_freq,
+				   auth->peer_mac_addr, wpa_s->own_addr, broadcast,
+				   wpabuf_head(msg), wpabuf_len(msg),
+				   500, wpas_dpp_tx_status, 0) < 0) {
+		wpas_notify_dpp_connection_status_sent(wpa_s, result);
+		wpabuf_free(msg);
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+		return;
+	}
+
 	wpabuf_free(msg);
 
+	auth->conn_result_status = result;
+	auth->tx_conn_status_result_started = 1;
 	/* This exchange will be terminated in the TX status handler */
 	auth->remove_on_tx_status = 1;
 
@@ -491,6 +500,9 @@
 #endif /* CONFIG_DPP2 */
 
 	if (wpa_s->dpp_auth->remove_on_tx_status) {
+		if (auth->tx_conn_status_result_started) {
+			wpas_notify_dpp_connection_status_sent(wpa_s, auth->conn_result_status);
+		}
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Terminate authentication exchange due to a request to do so on TX status");
 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
@@ -1476,7 +1488,7 @@
 
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
 
-	wpas_notify_dpp_config_received(wpa_s, ssid);
+	wpas_notify_dpp_config_received(wpa_s, ssid, auth->conn_status_requested ? 1 : 0);
 
 	if (wpa_s->conf->dpp_config_processing == 2)
 		ssid->disabled = 0;
@@ -1829,7 +1841,7 @@
 		wpabuf_free(msg);
 
 		/* This exchange will be terminated in the TX status handler */
-		if (wpa_s->conf->dpp_config_processing < 2 ||
+		if (wpa_s->conf->dpp_config_processing < 1 ||
 		    wpa_s->dpp_conf_backup_received)
 			auth->remove_on_tx_status = 1;
 		return;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 2d364bc..6c82b66 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1396,9 +1396,9 @@
 	if ((wpa_s->conf->sae_pwe == 1 || is_6ghz_freq(bss->freq) ||
 	     ssid->sae_password_id) &&
 	    wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	    !(wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) &&
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 	    !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
 		if (debug_print)
 			wpa_dbg(wpa_s, MSG_DEBUG,
@@ -2998,9 +2998,9 @@
 	const u8 *p;
 	u8 bssid[ETH_ALEN];
 	bool bssid_known;
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	struct wpa_ie_data ie;
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
 	bssid_known = wpa_drv_get_bssid(wpa_s, bssid) == 0;
@@ -3079,7 +3079,8 @@
 				get_supported_channel_width(&req_elems);
 			enum chan_width ap_operation_chan_width =
 				get_operation_channel_width(&resp_elems);
-			if (wpa_s->connection_vht || wpa_s->connection_he) {
+			if (wpa_s->connection_vht || wpa_s->connection_he ||
+			    wpa_s->connection_eht) {
 				wpa_s->connection_channel_bandwidth =
 					get_sta_operation_chan_width(ap_operation_chan_width,
 					sta_supported_chan_width);
@@ -3127,7 +3128,7 @@
 	if (!found_x && data->assoc_info.req_ies)
 		wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	/* The WPA/RSN IE has been updated at this point. Since the Firmware could have roamed
 	 * to a different security type, update the current supplicant configuration to use the AKM
 	 * and pairwise suites from the assoc IE passed by the driver.
@@ -3171,7 +3172,7 @@
 			// TODO: Notify the framework about security type change b/230766005
 		}
 	}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 #ifdef CONFIG_FILS
 #ifdef CONFIG_SME
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 6198bd7..acd9044 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1077,6 +1077,12 @@
 			goto fail;
 	}
 
+	if (cred->strict_conservative_peer_mode) {
+		if (wpa_config_set_quoted(ssid, "strict_conservative_peer_mode",
+					  "1") < 0)
+			goto fail;
+	}
+
 	wpa_s->next_ssid = ssid;
 	wpa_config_update_prio_list(wpa_s->conf);
 	if (!only_add)
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index a544c94..bb2c0b7 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -24,7 +24,7 @@
 #include "p2p_supplicant.h"
 #include "sme.h"
 #include "notify.h"
-#include "aidl.h"
+#include "aidl/aidl.h"
 
 int wpas_notify_supplicant_initialized(struct wpa_global *global)
 {
@@ -280,6 +280,12 @@
 }
 
 
+void wpas_notify_permanent_id_req_denied(struct wpa_supplicant *wpa_s)
+{
+	wpas_aidl_notify_permanent_id_req_denied(wpa_s);
+}
+
+
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->p2p_mgmt)
@@ -1103,13 +1109,13 @@
 /* DPP Success notifications */
 
 void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
-	    struct wpa_ssid *ssid)
+	    struct wpa_ssid *ssid, bool conn_status_requested)
 {
 #ifdef CONFIG_DPP
 	if (!wpa_s)
 		return;
 
-	wpas_aidl_notify_dpp_config_received(wpa_s, ssid);
+	wpas_aidl_notify_dpp_config_received(wpa_s, ssid, conn_status_requested);
 #endif /* CONFIG_DPP */
 }
 
@@ -1123,6 +1129,17 @@
 #endif /* CONFIG_DPP */
 }
 
+void wpas_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
+	    enum dpp_status_error result)
+{
+#ifdef CONFIG_DPP2
+	if (!wpa_s)
+		return;
+
+	wpas_aidl_notify_dpp_connection_status_sent(wpa_s, result);
+#endif /* CONFIG_DPP2 */
+}
+
 /* DPP Progress notifications */
 void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
 {
@@ -1335,3 +1352,8 @@
 
 	wpas_aidl_notify_frequency_changed(wpa_s, frequency);
 }
+
+ssize_t wpas_get_certificate(const char *alias, uint8_t** value)
+{
+	return wpas_aidl_get_certificate(alias, value);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 996be84..9a818ef 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -48,6 +48,7 @@
 				 struct wpa_ssid *ssid,
 				 enum wpa_ctrl_req_type rtype,
 				 const char *default_txt);
+void wpas_notify_permanent_id_req_denied(struct wpa_supplicant *wpa_s);
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s);
 void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success);
 void wpas_notify_scan_results(struct wpa_supplicant *wpa_s);
@@ -180,8 +181,10 @@
 void wpas_notify_hs20_rx_terms_and_conditions_acceptance(
 		struct wpa_supplicant *wpa_s, const char *url);
 void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
-	    struct wpa_ssid *ssid);
+		struct wpa_ssid *ssid, bool conn_status_requested);
 void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
+		enum dpp_status_error result);
 void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
 void wpas_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
 void wpas_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
@@ -218,5 +221,6 @@
 void wpas_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
 		struct dscp_policy_data *policies, int num_policies);
 void wpas_notify_frequency_changed(struct wpa_supplicant *wpa_s, int frequency);
+ssize_t wpas_get_certificate(const char *alias, uint8_t** value);
 
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 56dd5b9..7d896f4 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2031,11 +2031,12 @@
 		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
 	}
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	if ((wpa_s->key_mgmt & WPA_KEY_MGMT_CROSS_AKM_ROAM) &&
 		IS_CROSS_AKM_ROAM_KEY_MGMT(ssid->key_mgmt) &&
 		(wpa_s->group_cipher == WPA_CIPHER_CCMP) &&
-		(wpa_s->pairwise_cipher == WPA_CIPHER_CCMP)) {
+		(wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) &&
+		(wpa_s->wpa_proto == WPA_PROTO_RSN)) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PSK;
 		wpa_dbg(wpa_s, MSG_INFO,
 			"WPA: Updating to KEY_MGMT SAE+PSK for seamless roaming");
@@ -2044,7 +2045,7 @@
 	if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) &&
 	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
 		wpas_update_allowed_key_mgmt(wpa_s, ssid);
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 	return 0;
 }
@@ -4069,7 +4070,7 @@
 #endif /* CONFIG_WEP */
 
 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	     ((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
 	      (params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK))) {
 #else
@@ -4077,7 +4078,7 @@
 	     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
 	     (params.allowed_key_mgmts &
 	      (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 		params.passphrase = ssid->passphrase;
 		if (ssid->psk_set)
 			params.psk = ssid->psk;
@@ -4101,14 +4102,14 @@
 		else
 			params.req_key_mgmt_offload = 1;
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 		if (((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
 		     params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
 		     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
 #else
 		if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
 		     wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 		    ssid->psk_set)
 			params.psk = ssid->psk;
 	}
@@ -8366,6 +8367,8 @@
 		ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
 		ssid->auth_failures, dur, reason) + 1;
 	char *msg = os_malloc(msg_len);
+	if (!msg)
+		return;
 	snprintf(msg, msg_len, format_str,
 		ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
 		ssid->auth_failures, dur, reason);
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 8262eef..b6a1a74 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1175,6 +1175,14 @@
 #	unencrypted identity with EAP types that support different tunnelled
 #	identity, e.g., EAP-TTLS). This field can also be used with
 #	EAP-SIM/AKA/AKA' to store the pseudonym identity.
+# strict_conservative_peer_mode: Whether the strict conservative peer mode
+#	is enabled. This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+#	for EAP-SIM/AKA/AKA'. In non-strict convervative peer mode, a client
+#	error would be sent to the server, but the mode will send the permanent
+#	identity in some special cases according to 4.6.2 of RFC 4187; With the
+#	strict mode, the permanent identity is never sent to the server.
+#	0 = disabled (default)
+#	1 = enabled
 # password: Password string for EAP. This field can include either the
 #	plaintext password (using ASCII or hex string) or a NtPasswordHash
 #	(16-byte MD4 hash of password) in hash:<32 hex digits> format.
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index e13ea8f..556f9cf 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1093,6 +1093,12 @@
 	wpa_drv_set_supp_port(wpa_s, authorized);
 }
 
+static void wpa_supplicant_permanent_id_req_denied_cb(void *ctx)
+{
+	struct wpas_supplicant *wpa_s = ctx;
+
+	wpas_notify_permanent_id_req_denied(wpa_s);
+}
 
 static void wpa_supplicant_cert_cb(void *ctx, struct tls_cert_data *cert,
 				   const char *cert_hash)
@@ -1197,6 +1203,12 @@
 		wpa_sm_pmf_enabled(wpa_s->wpa);
 }
 
+static ssize_t wpa_supplicant_get_certificate_cb(
+						const char* alias, uint8_t** value)
+{
+	return wpas_get_certificate(alias, value);
+}
+
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -1238,6 +1250,7 @@
 	ctx->port_cb = wpa_supplicant_port_cb;
 	ctx->cb = wpa_supplicant_eapol_cb;
 	ctx->cert_cb = wpa_supplicant_cert_cb;
+	ctx->permanent_id_req_denied_cb = wpa_supplicant_permanent_id_req_denied_cb;
 	ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
 	ctx->status_cb = wpa_supplicant_status_cb;
 	ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
@@ -1245,6 +1258,7 @@
 	ctx->set_anon_id = wpa_supplicant_set_anon_id;
 	ctx->eap_method_selected_cb = wpa_supplicant_eap_method_selected_cb;
 	ctx->open_ssl_failure_cb = wpa_supplicant_open_ssl_failure_cb;
+	ctx->get_certificate_cb = wpa_supplicant_get_certificate_cb;
 	ctx->encryption_required = wpas_encryption_required;
 	ctx->cb_ctx = wpa_s;
 	wpa_s->eapol = eapol_sm_init(ctx);
@@ -1389,7 +1403,7 @@
 		changed = 1;
 	}
 
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 	/* driver call for transition disable */
 	{
 		struct wpa_driver_associate_params params;
@@ -1398,7 +1412,7 @@
 		params.td_policy = bitmap;
 		wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_TD_POLICY);
 	}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 	wpas_notify_transition_disable(wpa_s, ssid, bitmap);