Merge Android 24Q1 Release (ab/11220357)

Bug: 319669529
Merged-In: Ia6c05d88e711f2a636e4365efcc246bac31b0401
Change-Id: Ibf8f5d7887561c8a8b669a14a68358dfbd9400ce
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index e4b3718..119f66e 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -45,7 +45,7 @@
     defaults: ["hostapd_cflags_defaults"],
     srcs: [":hostapd_srcs"],
     shared_libs: [
-        "android.hardware.wifi.hostapd-V1-ndk",
+        "android.hardware.wifi.hostapd-V2-ndk",
         "libbase",
         "libutils",
         "libbinder_ndk",
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 7a1b612..35ada83 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -1194,7 +1194,8 @@
 endif
 endif
 ifeq ($(HOSTAPD_USE_AIDL), y)
-LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd-V1-ndk
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd-V2-ndk
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.common-V1-ndk
 LOCAL_SHARED_LIBRARIES += libbase libutils
 LOCAL_SHARED_LIBRARIES += libbinder_ndk
 LOCAL_STATIC_LIBRARIES += libhostapd_aidl
@@ -1248,7 +1249,8 @@
     aidl/aidl.cpp \
     aidl/hostapd.cpp
 LOCAL_SHARED_LIBRARIES := \
-    android.hardware.wifi.hostapd-V1-ndk \
+    android.hardware.wifi.hostapd-V2-ndk \
+    android.hardware.wifi.common-V1-ndk \
     libbinder_ndk \
     libbase \
     libutils \
diff --git a/hostapd/aidl/Android.bp b/hostapd/aidl/Android.bp
index 3cbccee..410e701 100644
--- a/hostapd/aidl/Android.bp
+++ b/hostapd/aidl/Android.bp
@@ -31,7 +31,7 @@
     defaults: ["hostapd_cflags_defaults"],
     soc_specific: true,
     shared_libs: [
-        "android.hardware.wifi.hostapd-V1-ndk",
+        "android.hardware.wifi.hostapd-V2-ndk",
         "libbinder_ndk",
         "libbase",
         "libutils",
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index a036540..ed77a82 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -788,7 +788,7 @@
 std::function<void(struct hostapd_data*, const u8 *mac_addr, int authorized,
 		const u8 *p2p_dev_addr)> on_sta_authorized_internal_callback;
 void onAsyncStaAuthorizedCb(void* ctx, const u8 *mac_addr, int authorized,
-		const u8 *p2p_dev_addr)
+		const u8 *p2p_dev_addr, const u8 *ip)
 {
 	struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
 	if (on_sta_authorized_internal_callback) {
diff --git a/hostapd/android.hardware.wifi.hostapd.xml b/hostapd/android.hardware.wifi.hostapd.xml
index eb91ee2..c0fe942 100644
--- a/hostapd/android.hardware.wifi.hostapd.xml
+++ b/hostapd/android.hardware.wifi.hostapd.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.wifi.hostapd</name>
+        <version>2</version>
         <fqname>IHostapd/default</fqname>
     </hal>
 </manifest>
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index b81da30..b9a67b9 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -286,7 +286,8 @@
 	void *wps_event_cb_ctx;
 
 	void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
-				  int authorized, const u8 *p2p_dev_addr);
+				  int authorized, const u8 *p2p_dev_addr,
+				  const u8 *ip);
 	void *sta_authorized_cb_ctx;
 
 	void (*setup_complete_cb)(void *ctx);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 2fb6edf..07100f2 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1279,6 +1279,7 @@
 	u8 addr[ETH_ALEN];
 	u8 ip_addr_buf[4];
 #endif /* CONFIG_P2P */
+	u8 *ip_ptr = NULL;
 
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
 		return;
@@ -1305,10 +1306,6 @@
 #endif /* CONFIG_P2P */
 		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
 
-	if (hapd->sta_authorized_cb)
-		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
-					sta->addr, authorized, dev_addr);
-
 	if (authorized) {
 		const u8 *dpp_pkhash;
 		const char *keyid;
@@ -1325,6 +1322,7 @@
 				    " ip_addr=%u.%u.%u.%u",
 				    ip_addr_buf[0], ip_addr_buf[1],
 				    ip_addr_buf[2], ip_addr_buf[3]);
+			ip_ptr = ip_addr_buf;
 		}
 #endif /* CONFIG_P2P */
 
@@ -1364,6 +1362,11 @@
 					  AP_STA_DISCONNECTED "%s", buf);
 	}
 
+	if (hapd->sta_authorized_cb)
+		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+					sta->addr, authorized, dev_addr,
+					ip_ptr);
+
 #ifdef CONFIG_FST
 	if (hapd->iface->fst) {
 		if (authorized)
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index c201dcd..82276c5 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -693,4 +693,14 @@
 
 void tls_register_cert_callback(tls_get_certificate_cb cb);
 
+/**
+ * tls_register_openssl_failure_callback - Register a callback to indicate
+ * that an OpenSSL failure has occurred
+ * @cb: Callback object to register
+ */
+typedef void (*tls_openssl_failure_cb)
+(void* ctx, const char* msg);
+
+void tls_register_openssl_failure_callback(tls_openssl_failure_cb cb);
+
 #endif /* TLS_H */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 23bbe68..b378356 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -201,6 +201,7 @@
 
 static struct tls_context *tls_global = NULL;
 static tls_get_certificate_cb certificate_callback_global = NULL;
+static tls_openssl_failure_cb openssl_failure_callback_global = NULL;
 
 #ifdef ANDROID
 #include <openssl/pem.h>
@@ -2634,9 +2635,19 @@
 		if (chain)
 			sk_X509_pop_free(chain, X509_free);
 
-		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
-			   " error %d (%s) depth %d for '%s'", err, err_str,
-			   depth, buf);
+		char *format_str = "TLS: Certificate verification failed,"
+			   " error %d (%s) depth %d for '%s'";
+		int msg_len = snprintf(NULL, 0, format_str, err, err_str, depth, buf) + 1;
+		char *msg = os_malloc(msg_len);
+		snprintf(msg, msg_len, format_str, err, err_str, depth, buf);
+
+		wpa_printf(MSG_WARNING, "%s", msg);
+		if (conn != NULL && conn->context != NULL
+				&& openssl_failure_callback_global != NULL) {
+			(*openssl_failure_callback_global)(conn->context->cb_ctx, msg);
+		}
+		os_free(msg);
+
 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 				       err_str, TLS_FAIL_UNSPECIFIED);
 		return preverify_ok;
@@ -6048,3 +6059,8 @@
 {
 	certificate_callback_global = cb;
 }
+
+void tls_register_openssl_failure_callback(tls_openssl_failure_cb cb)
+{
+	openssl_failure_callback_global = cb;
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5f39e80..1acc43b 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6982,13 +6982,8 @@
 	    nl80211_put_fils_connect_params(drv, params, msg) != 0)
 		return -1;
 
-#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 || CONFIG_DRIVER_NL80211_SYNA */
 	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
 	    nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
 		return -1;
@@ -7041,13 +7036,8 @@
 		goto fail;
 
 #ifdef CONFIG_SAE
-#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 || CONFIG_DRIVER_NL80211_SYNA */
 	    nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
 		goto fail;
 #endif /* CONFIG_SAE */
@@ -7155,13 +7145,8 @@
 
 		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
-#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 || CONFIG_DRIVER_NL80211_SYNA */
 			bss->use_nl_connect = 1;
 		else
 			bss->use_nl_connect = 0;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index e99afdc..16d6f5b 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1104,6 +1104,7 @@
 	 * operation that happened in parallel with the disconnection request.
 	 */
 	drv->ignore_next_local_disconnect = 0;
+	drv->sta_mlo_info.default_map = true;
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
 	if (drv->pending_t2lm_data)
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 8338c47..ff7dc1e 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -2207,6 +2207,14 @@
 	return -1;
 }
 
+void tls_openssl_failure_callback(void* ctx, const char* msg) {
+	if (ctx == NULL || msg == NULL) return;
+	struct eap_sm *sm = (struct eap_sm*) ctx;
+	if (sm->eapol_cb && sm->eapol_cb->notify_open_ssl_failure) {
+		sm->eapol_cb->notify_open_ssl_failure(sm->eapol_ctx, msg);
+	}
+}
+
 /**
  * eap_peer_sm_init - Allocate and initialize EAP peer state machine
  * @eapol_ctx: Context data to be used with eapol_cb calls
@@ -2251,6 +2259,7 @@
 	tlsconf.cb_ctx = sm;
 	tlsconf.cert_in_cb = conf->cert_in_cb;
 	tls_register_cert_callback(&tls_certificate_callback);
+	tls_register_openssl_failure_callback(&tls_openssl_failure_callback);
 	sm->ssl_ctx = tls_init(&tlsconf);
 	if (sm->ssl_ctx == NULL) {
 		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
diff --git a/src/pae/aidl/aidl_psk.cpp b/src/pae/aidl/aidl_psk.cpp
new file mode 100644
index 0000000..67afef0
--- /dev/null
+++ b/src/pae/aidl/aidl_psk.cpp
@@ -0,0 +1,149 @@
+/*
+ * WPA Supplicant - Aidl interface to access macsec PSK
+ * Copyright (c) 2023, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <aidl/android/hardware/macsec/IMacsecPskPlugin.h>
+#include <android/binder_manager.h>
+
+extern "C"
+{
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+
+#include "aidl_psk.h"
+}
+
+using aidl::android::hardware::macsec::IMacsecPskPlugin;
+
+static std::shared_ptr<IMacsecPskPlugin> pskPlugin;
+
+int aidl_psk_init()
+{
+	if (pskPlugin != NULL) {
+		wpa_printf(MSG_ERROR, "Already connected to Macsec plugin");
+		return 0;
+	}
+	std::string instanceName = std::string(IMacsecPskPlugin::descriptor) + "/default";
+	pskPlugin = IMacsecPskPlugin::fromBinder(
+		ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
+
+	if (pskPlugin == NULL) {
+		wpa_printf(MSG_ERROR, "Cannot get Macsec PSK plugin service");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int aidl_psk_aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain,
+		u8 *cipher)
+{
+	if (pskPlugin == NULL)
+		return -ENODEV;
+
+	n = n * 8;
+
+	const std::vector<u8> key_id(kek, kek + kek_len);
+	const std::vector<u8> sak(plain, plain + n);
+	std::vector<u8> out(n + 8);
+
+	auto aidlStatus = pskPlugin->wrapSak(key_id, sak, &out);
+	if (!aidlStatus.isOk()) {
+		wpa_printf(MSG_ERROR, "wrapSak return error: %s", aidlStatus.getMessage());
+		return -ENODEV;
+	}
+
+	if (out.size() != (n + 8)) {
+		wpa_printf(MSG_ERROR, "wrapSak return size not n + 8");
+		return -ENODEV;
+	}
+
+	memcpy(cipher, out.data(), n + 8);
+
+	return 0;
+}
+
+int aidl_psk_aes_unwrap(const u8 *kek, size_t kek_len, int n,
+		const u8 *cipher, u8 *plain)
+{
+	if (pskPlugin == NULL)
+		return -ENODEV;
+
+	n = n * 8;
+	if (n < 8)
+		return -ENODEV;
+
+	const std::vector<u8> key_id(kek, kek + kek_len);
+	const std::vector<u8> sak(cipher, cipher + n);
+	std::vector<u8> out(n - 8);
+
+	auto aidlStatus = pskPlugin->unwrapSak(key_id, sak, &out);
+	if (!aidlStatus.isOk()) {
+		return -ENODEV;
+	}
+
+	if (out.size() != (n - 8)) {
+		return -ENODEV;
+	}
+
+	memcpy(plain, out.data(), n - 8);
+
+	return 0;
+}
+
+int aidl_psk_icv_hash(const u8 *ick, size_t ick_bytes, const u8 *msg,
+		size_t msg_bytes, u8 *icv)
+{
+	if (pskPlugin == NULL) {
+		wpa_printf(MSG_ERROR, "pskPlugin not init");
+		return -ENODEV;
+	}
+
+	const std::vector<u8> key_id(ick, ick + ick_bytes);
+	const std::vector<u8> data(msg, msg + msg_bytes);
+	std::vector<u8> out(16);
+
+	auto aidlStatus = pskPlugin->calcIcv(key_id, data, &out);
+	if (!aidlStatus.isOk()) {
+		wpa_printf(MSG_ERROR, "calcIcv return error: %s", aidlStatus.getMessage());
+		return -ENODEV;
+	}
+
+	if (out.size() != 16) {
+		wpa_printf(MSG_ERROR, "calcIcv out size not 16 bytes");
+		return -ENODEV;
+	}
+
+	memcpy(icv, out.data(), 16);
+
+	return 0;
+}
+
+int aidl_psk_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+		size_t ctx_bytes, u8 *sak, size_t sak_bytes)
+{
+	if (pskPlugin == NULL)
+		return -ENODEV;
+
+	const std::vector<u8> key_id(cak, cak + cak_bytes);
+	const std::vector<u8> data(ctx, ctx + ctx_bytes);
+	std::vector<u8> out(sak_bytes);
+
+	auto aidlStatus = pskPlugin->generateSak(key_id, data, sak_bytes, &out);
+	if (!aidlStatus.isOk()) {
+		return -ENODEV;
+	}
+
+	if (out.size() != sak_bytes) {
+		return -ENODEV;
+	}
+
+	memcpy(sak, out.data(), sak_bytes);
+
+	return 0;
+}
diff --git a/src/pae/aidl/aidl_psk.h b/src/pae/aidl/aidl_psk.h
new file mode 100644
index 0000000..ad131ba
--- /dev/null
+++ b/src/pae/aidl/aidl_psk.h
@@ -0,0 +1,33 @@
+/*
+ * WPA Supplicant - Aidl interface to access macsec PSK
+ * Copyright (c) 2023, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_PAE_AIDL_PSK_H
+#define WPA_SUPPLICANT_PAE_AIDL_PSK_H
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif  // _cplusplus
+
+	/* cak, kek, ick are all reference index only for HAL, not real key, the
+	 * HAL will use the actual key */
+	int aidl_psk_init();
+	int __must_check aidl_psk_aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain,
+			  u8 *cipher);
+	int __must_check aidl_psk_aes_unwrap(const u8 *kek, size_t kek_len, int n,
+			    const u8 *cipher, u8 *plain);
+	int aidl_psk_icv_hash(const u8 *ick, size_t ick_bytes, const u8 *msg,
+			    size_t msg_bytes, u8 *icv);
+	int aidl_psk_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+			    size_t ctx_bytes, u8 *sak, size_t sak_bytes);
+
+#ifdef _cplusplus
+}
+#endif  // _cplusplus
+
+#endif  // WPA_SUPPLICANT_PAE_AIDL_PSK_H
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 66c65aa..741b093 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -22,6 +22,10 @@
 #include "ieee802_1x_kay_i.h"
 #include "ieee802_1x_secy_ops.h"
 
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+#include "aidl/aidl_psk.h"
+#endif
+
 
 #define DEFAULT_SA_KEY_LEN	16
 #define DEFAULT_ICV_LEN		16
@@ -1659,9 +1663,15 @@
 		os_memcpy(body->sak, &cs, CS_ID_LEN);
 		sak_pos = CS_ID_LEN;
 	}
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+	if (aidl_psk_aes_wrap(participant->kek.key, participant->kek.len,
+		     cipher_suite_tbl[cs_index].sak_len / 8,
+		     sak->key, body->sak + sak_pos)) {
+#else
 	if (aes_wrap(participant->kek.key, participant->kek.len,
 		     cipher_suite_tbl[cs_index].sak_len / 8,
 		     sak->key, body->sak + sak_pos)) {
+#endif
 		wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
 		return -1;
 	}
@@ -1800,8 +1810,13 @@
 		wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
 		return -1;
 	}
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+	if (aidl_psk_aes_unwrap(participant->kek.key, participant->kek.len,
+		       sak_len >> 3, wrap_sak, unwrap_sak)) {
+#else
 	if (aes_unwrap(participant->kek.key, participant->kek.len,
 		       sak_len >> 3, wrap_sak, unwrap_sak)) {
+#endif
 		wpa_printf(MSG_ERROR, "KaY: AES unwrap failed");
 		os_free(unwrap_sak);
 		return -1;
@@ -1896,7 +1911,11 @@
 		set_mka_param_body_len(body, length);
 	}
 
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+	if (aidl_psk_icv_hash(
+#else
 	if (mka_alg_tbl[participant->kay->mka_algindex].icv_hash(
+#endif
 		    participant->ick.key, participant->ick.len,
 		    wpabuf_head(buf), wpabuf_len(buf), cmac)) {
 		wpa_printf(MSG_ERROR, "KaY: failed to calculate ICV");
@@ -2198,10 +2217,17 @@
 	os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
 
 	if (key_len == 16 || key_len == 32) {
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+		if (aidl_psk_sak_aes_cmac(participant->cak.key,
+					  participant->cak.len,
+					  context, ctx_len,
+					  key, key_len)) {
+#else
 		if (ieee802_1x_sak_aes_cmac(participant->cak.key,
 					    participant->cak.len,
 					    context, ctx_len,
 					    key, key_len)) {
+#endif
 			wpa_printf(MSG_ERROR, "KaY: Failed to generate SAK");
 			goto fail;
 		}
@@ -3183,7 +3209,11 @@
 	 * packet body length.
 	 */
 	if (len < mka_alg_tbl[kay->mka_algindex].icv_len ||
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+	    aidl_psk_icv_hash(
+#else
 	    mka_alg_tbl[kay->mka_algindex].icv_hash(
+#endif
 		    participant->ick.key, participant->ick.len,
 		    buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) {
 		wpa_printf(MSG_ERROR, "KaY: Failed to calculate ICV");
@@ -3745,6 +3775,18 @@
 	wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s",
 		   mi_txt(participant->mi));
 
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+	if (mode != PSK)  {
+		wpa_printf(MSG_ERROR, "CONFIG_AIDL_MACSEC_PSK_METHODS only support PSK");
+		goto fail;
+	}
+	wpa_printf(MSG_INFO, "Init macsec PSK HAL");
+        if (aidl_psk_init()) {
+		wpa_printf(MSG_ERROR, "Cannot init aidl macsec psk HAL");
+		goto fail;
+        }
+#endif
+
 	participant->lrx = false;
 	participant->ltx = false;
 	participant->orx = false;
@@ -3763,6 +3805,14 @@
 	if (secy_create_transmit_sc(kay, participant->txsc))
 		goto fail;
 
+#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS
+	/* If using external PSK methods, we don't need to generate kek and ick
+	 * key here and cak.key is actually a reference index */
+	participant->kek.len = participant->cak.len;
+	participant->ick.len = participant->cak.len;
+	memcpy(participant->kek.key, participant->cak.key, participant->cak.len);
+	memcpy(participant->ick.key, participant->cak.key, participant->cak.len);
+#else
 	/* to derive KEK from CAK and CKN */
 	participant->kek.len = participant->cak.len;
 	if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key,
@@ -3790,6 +3840,7 @@
 	}
 	wpa_hexdump_key(MSG_DEBUG, "KaY: Derived ICK",
 			participant->ick.key, participant->ick.len);
+#endif
 
 	dl_list_add(&kay->participant_list, &participant->list);
 
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index e7b4d54..eb434fa 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -224,22 +224,22 @@
 	if (pmk_len > PMK_LEN_MAX)
 		return NULL;
 
-	if (wpa_key_mgmt_suite_b(akmp) && !kck)
-		return NULL;
-
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL)
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
-	if (pmkid)
-		os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
-	else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
-		rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
-	else if (wpa_key_mgmt_suite_b(akmp))
-		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
-	else
-		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
+	if (pmkid) {
+ 		os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+	} else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+		if (kck)
+			rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+	} else if (wpa_key_mgmt_suite_b(akmp)) {
+		if (kck)
+			rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
+	} else {
+ 		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
+	}
 	os_get_reltime(&now);
 	if (pmksa->sm) {
 		pmk_lifetime = pmksa->sm->dot11RSNAConfigPMKLifetime;
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index dd4423a..ca56d14 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -67,7 +67,7 @@
     defaults: ["wpa_supplicant_cflags_defaults"],
     srcs: [":wpa_supplicant_srcs"],
     shared_libs: [
-        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.hardware.wifi.supplicant-V3-ndk",
         "android.system.keystore2-V1-ndk",
         "libbase",
         "libbinder_ndk",
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 03dc209..509dbbc 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1835,7 +1835,7 @@
 PASNOBJS += src/crypto/crypto_openssl.c
 ifdef TLS_FUNCS
 PASNOBJS += src/crypto/tls_openssl.c
-#PASNOBJS += -lssl -lcrypto
+PASNOBJS += src/crypto/tls_openssl_ocsp.c
 NEED_TLS_PRF_SHA256=y
 endif
 endif
@@ -1912,8 +1912,13 @@
 include $(BUILD_EXECUTABLE)
 
 ########################
+# Build wpa_supplicant
+#
+# $(1): if defined build wpa_supplicant with macsec support (with different executable name wpa_supplicant_macsec
+#
+define wpa_supplicant_gen
+
 include $(CLEAR_VARS)
-LOCAL_MODULE := wpa_supplicant
 LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD SPDX-license-identifier-BSD-3-Clause SPDX-license-identifier-ISC legacy_unencumbered
 LOCAL_LICENSE_CONDITIONS := notice unencumbered
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../LICENSE
@@ -1945,14 +1950,19 @@
 LOCAL_STATIC_LIBRARIES += libnl_2
 endif
 endif
-LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_SRC_FILES := $(OBJS)
 LOCAL_C_INCLUDES := $(INCLUDES)
 ifeq ($(DBUS), y)
 LOCAL_SHARED_LIBRARIES += libdbus
 endif
+
+ifneq ($(1),)
+# wpa_supplicant for wifi
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_MODULE := wpa_supplicant
+
 ifeq ($(WPA_SUPPLICANT_USE_AIDL), y)
-LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V2-ndk
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V3-ndk
 LOCAL_SHARED_LIBRARIES += android.system.keystore2-V1-ndk
 LOCAL_SHARED_LIBRARIES += libutils libbase
 LOCAL_SHARED_LIBRARIES += libbinder_ndk
@@ -1962,7 +1972,37 @@
 LOCAL_INIT_RC=aidl/android.hardware.wifi.supplicant-service.rc
 endif
 endif
+
+else
+# wpa_supplicant for macsec
+# remove aidl control interface, standalone
+LOCAL_CFLAGS := $(patsubst -DCONFIG_CTRL_IFACE_AIDL,,$(patsubst -DCONFIG_AIDL,,$(L_CFLAGS)))
+LOCAL_CFLAGS += -DCONFIG_MACSEC -DCONFIG_DRIVER_MACSEC_LINUX
+# config macsec to use AIDL interface for CAK key.
+LOCAL_CFLAGS += -DCONFIG_AIDL_MACSEC_PSK_METHODS
+LOCAL_SRC_FILES += ../src/drivers/driver_macsec_linux.c \
+                  ../src/drivers/driver_wired_common.c
+LOCAL_SRC_FILES += wpas_kay.c \
+                   src/pae/ieee802_1x_cp.c \
+                   src/pae/ieee802_1x_kay.c \
+                   src/pae/ieee802_1x_key.c \
+                   src/pae/ieee802_1x_secy_ops.c
+LOCAL_SRC_FILES += src/pae/aidl/aidl_psk.cpp
+LOCAL_SHARED_LIBRARIES += android.hardware.macsec-V1-ndk \
+			  libbinder_ndk
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/aidl
+
+ifdef CONFIG_AP
+LOCAL_SRC_FILES += src/ap/wpa_auth_kay.c
+endif
+LOCAL_MODULE := wpa_supplicant_macsec
+endif
+
 include $(BUILD_EXECUTABLE)
+endef
+
+$(eval $(call wpa_supplicant_gen,))
+$(eval $(call wpa_supplicant_gen, macsec))
 
 ########################
 #
@@ -2026,7 +2066,7 @@
     aidl/sta_network.cpp \
     aidl/supplicant.cpp
 LOCAL_SHARED_LIBRARIES := \
-    android.hardware.wifi.supplicant-V2-ndk \
+    android.hardware.wifi.supplicant-V3-ndk \
     android.system.keystore2-V1-ndk \
     libbinder_ndk \
     libbase \
@@ -2038,13 +2078,20 @@
 include $(BUILD_STATIC_LIBRARY)
 endif # WPA_SUPPLICANT_USE_AIDL == y
 
-#include $(CLEAR_VARS)
-#LOCAL_MODULE = libpasn
-#LOCAL_CFLAGS = $(L_CFLAGS)
-#LOCAL_SRC_FILES = $(PASNOBJS)
-#LOCAL_C_INCLUDES = $(INCLUDES)
-#LOCAL_SHARED_LIBRARIES := libc libcutils liblog
-#ifeq ($(CONFIG_TLS), openssl)
-#LOCAL_SHARED_LIBRARIES := libcrypto libssl
-#endif
-#include $(BUILD_SHARED_LIBRARY)
+ifeq ($(CONFIG_PASN), y)
+include $(CLEAR_VARS)
+LOCAL_MODULE = libpasn
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD SPDX-license-identifier-BSD-3-Clause SPDX-license-identifier-ISC legacy_unencumbered
+LOCAL_LICENSE_CONDITIONS := notice unencumbered
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../LICENSE
+LOCAL_VENDOR_MODULE := true
+LOCAL_CFLAGS = $(L_CFLAGS)
+LOCAL_SRC_FILES = $(PASNOBJS)
+LOCAL_C_INCLUDES = $(INCLUDES)
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+ifeq ($(CONFIG_TLS), openssl)
+LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore-wifi-hidl
+LOCAL_SHARED_LIBRARIES += libkeystore-engine-wifi-hidl
+endif
+include $(BUILD_SHARED_LIBRARY)
+endif # CONFIG_PASN == y
diff --git a/wpa_supplicant/aidl/Android.bp b/wpa_supplicant/aidl/Android.bp
index d7dcf97..481ad0b 100644
--- a/wpa_supplicant/aidl/Android.bp
+++ b/wpa_supplicant/aidl/Android.bp
@@ -33,7 +33,7 @@
     defaults: ["wpa_supplicant_cflags_defaults"],
     soc_specific: true,
     shared_libs: [
-        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.hardware.wifi.supplicant-V3-ndk",
         "android.system.keystore2-V1-ndk",
         "libbinder_ndk",
         "libbase",
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp
index f221862..d1cf891 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/aidl.cpp
@@ -613,7 +613,7 @@
 void wpas_aidl_notify_p2p_provision_discovery(
 	struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
 	enum p2p_prov_disc_status status, u16 config_methods,
-	unsigned int generated_pin)
+	unsigned int generated_pin, const char *group_ifname)
 {
 	if (!wpa_s || !dev_addr)
 		return;
@@ -628,7 +628,8 @@
 		return;
 
 	aidl_manager->notifyP2pProvisionDiscovery(
-		wpa_s, dev_addr, request, status, config_methods, generated_pin);
+		wpa_s, dev_addr, request, status, config_methods,
+		generated_pin, group_ifname);
 }
 
 void wpas_aidl_notify_p2p_sd_response(
@@ -652,7 +653,8 @@
 }
 
 void wpas_aidl_notify_ap_sta_authorized(
-	struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+	struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr,
+	const u8 *ip)
 {
 	if (!wpa_s || !sta)
 		return;
@@ -666,7 +668,7 @@
 	if (!aidl_manager)
 		return;
 
-	aidl_manager->notifyApStaAuthorized(wpa_s, sta, p2p_dev_addr);
+	aidl_manager->notifyApStaAuthorized(wpa_s, sta, p2p_dev_addr, ip);
 }
 
 void wpas_aidl_notify_ap_sta_deauthorized(
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h
index dfe5c74..eb1426a 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/aidl.h
@@ -95,13 +95,13 @@
 	void wpas_aidl_notify_p2p_provision_discovery(
 		struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
 		enum p2p_prov_disc_status status, u16 config_methods,
-		unsigned int generated_pin);
+		unsigned int generated_pin, const char *group_ifname);
 	void wpas_aidl_notify_p2p_sd_response(
 		struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
 		const u8 *tlvs, size_t tlvs_len);
 	void wpas_aidl_notify_ap_sta_authorized(
 		struct wpa_supplicant *wpa_s, const u8 *sta,
-		const u8 *p2p_dev_addr);
+		const u8 *p2p_dev_addr, const u8 *ip);
 	void wpas_aidl_notify_ap_sta_deauthorized(
 		struct wpa_supplicant *wpa_s, const u8 *sta,
 		const u8 *p2p_dev_addr);
@@ -253,14 +253,15 @@
 static void wpas_aidl_notify_p2p_provision_discovery(
 	struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
 	enum p2p_prov_disc_status status, u16 config_methods,
-	unsigned int generated_pin)
+	unsigned int generated_pin, const char *group_ifname)
 {}
 static void wpas_aidl_notify_p2p_sd_response(
 	struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
 	const u8 *tlvs, size_t tlvs_len)
 {}
 static void wpas_aidl_notify_ap_sta_authorized(
-	struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+	struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr,
+	const u8 *ip)
 {}
 static void wpas_aidl_notify_ap_sta_deauthorized(
 	struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index b3baf5b..cac9ddb 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -37,11 +37,21 @@
 constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN;
 constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN;
 const std::vector<uint8_t> kZeroBssid = {0, 0, 0, 0, 0, 0};
+int32_t aidl_service_version = 0;
 
 using aidl::android::hardware::wifi::supplicant::GsmRand;
 using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
 
 /**
+  * Check that the AIDL service is running at least the expected version.
+  * Use to avoid the case where the AIDL interface version
+  * is greater than the version implemented by the service.
+  */
+inline int32_t isAidlServiceVersionAtLeast(int32_t expected_version)
+{
+	return expected_version <= aidl_service_version;
+}
+/**
  * Check if the provided |wpa_supplicant| structure represents a P2P iface or
  * not.
  */
@@ -407,8 +417,11 @@
 {
 	// Create the main aidl service object and register it.
 	wpa_printf(MSG_INFO, "Starting AIDL supplicant");
-	wpa_printf(MSG_INFO, "Interface version: %d", Supplicant::version);
 	supplicant_object_ = ndk::SharedRefBase::make<Supplicant>(global);
+	if (!supplicant_object_->getInterfaceVersion(&aidl_service_version).isOk()) {
+		aidl_service_version = Supplicant::version;
+	}
+	wpa_printf(MSG_INFO, "AIDL Interface version: %d", aidl_service_version);
 	wpa_global_ = global;
 	std::string instance = std::string() + Supplicant::descriptor + "/default";
 	if (AServiceManager_addService(supplicant_object_->asBinder().get(),
@@ -1331,16 +1344,35 @@
 			std::back_inserter(aidl_vendor_elems));
 	}
 
-	const std::function<
-		ndk::ScopedAStatus(std::shared_ptr<ISupplicantP2pIfaceCallback>)>
-		func = std::bind(
-		&ISupplicantP2pIfaceCallback::onDeviceFoundWithVendorElements,
-		std::placeholders::_1, macAddrToVec(addr), macAddrToVec(info->p2p_device_addr),
-		byteArrToVec(info->pri_dev_type, 8), misc_utils::charBufToString(info->device_name),
-		static_cast<WpsConfigMethods>(info->config_methods),
-		info->dev_capab, static_cast<P2pGroupCapabilityMask>(info->group_capab), aidl_peer_wfd_device_info,
-		aidl_peer_wfd_r2_device_info, aidl_vendor_elems);
-	callWithEachP2pIfaceCallback(wpa_s->ifname, func);
+	if (isAidlServiceVersionAtLeast(3)) {
+		P2pDeviceFoundEventParams params;
+		params.srcAddress = macAddrToArray(addr);
+		params.p2pDeviceAddress = macAddrToArray(info->p2p_device_addr);
+		params.primaryDeviceType = byteArrToVec(info->pri_dev_type, 8);
+		params.deviceName = misc_utils::charBufToString(info->device_name);
+		params.configMethods = info->config_methods;
+		params.deviceCapabilities = info->dev_capab;
+		params.groupCapabilities = info->group_capab;
+		params.wfdDeviceInfo = aidl_peer_wfd_device_info;
+		params.wfdR2DeviceInfo = aidl_peer_wfd_r2_device_info;
+		params.vendorElemBytes = aidl_vendor_elems;
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onDeviceFoundWithParams,
+			std::placeholders::_1, params));
+	} else {
+		const std::function<
+			ndk::ScopedAStatus(std::shared_ptr<ISupplicantP2pIfaceCallback>)>
+			func = std::bind(
+			&ISupplicantP2pIfaceCallback::onDeviceFoundWithVendorElements,
+			std::placeholders::_1, macAddrToVec(addr), macAddrToVec(info->p2p_device_addr),
+			byteArrToVec(info->pri_dev_type, 8), misc_utils::charBufToString(info->device_name),
+			static_cast<WpsConfigMethods>(info->config_methods),
+			info->dev_capab, static_cast<P2pGroupCapabilityMask>(info->group_capab), aidl_peer_wfd_device_info,
+			aidl_peer_wfd_r2_device_info, aidl_vendor_elems);
+		callWithEachP2pIfaceCallback(wpa_s->ifname, func);
+	}
 }
 
 void AidlManager::notifyP2pDeviceLost(
@@ -1558,7 +1590,7 @@
 void AidlManager::notifyP2pProvisionDiscovery(
 	struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
 	enum p2p_prov_disc_status status, u16 config_methods,
-	unsigned int generated_pin)
+	unsigned int generated_pin, const char *group_ifname)
 {
 	if (!wpa_s || !dev_addr)
 		return;
@@ -1572,15 +1604,33 @@
 		aidl_generated_pin =
 			misc_utils::convertWpsPinToString(generated_pin);
 	}
-	bool aidl_is_request = (request == 1 ? true : false);
+	bool aidl_is_request = (request == 1);
 
-	callWithEachP2pIfaceCallback(
-		misc_utils::charBufToString(wpa_s->ifname),
-		std::bind(
-		&ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompleted,
-		std::placeholders::_1, macAddrToVec(dev_addr), aidl_is_request,
-		static_cast<P2pProvDiscStatusCode>(status),
-		static_cast<WpsConfigMethods>(config_methods), aidl_generated_pin));
+	if (isAidlServiceVersionAtLeast(3)) {
+		P2pProvisionDiscoveryCompletedEventParams params;
+		params.p2pDeviceAddress =  macAddrToArray(dev_addr);
+		params.isRequest = aidl_is_request;
+		params.status = static_cast<P2pProvDiscStatusCode>(status);
+		params.configMethods = static_cast<WpsConfigMethods>(config_methods);
+		params.generatedPin = aidl_generated_pin;
+		if (group_ifname != NULL) {
+			params.groupInterfaceName = misc_utils::charBufToString(group_ifname);
+		}
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompletedEvent,
+			std::placeholders::_1, params));
+	} else {
+		// Use legacy callback if interface version < 3
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompleted,
+			std::placeholders::_1, macAddrToVec(dev_addr), aidl_is_request,
+			static_cast<P2pProvDiscStatusCode>(status),
+			static_cast<WpsConfigMethods>(config_methods), aidl_generated_pin));
+	}
 }
 
 void AidlManager::notifyP2pSdResponse(
@@ -1603,19 +1653,40 @@
 }
 
 void AidlManager::notifyApStaAuthorized(
-	struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr)
+	struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr,
+	const u8 *ip)
 {
 	if (!wpa_group_s || !wpa_group_s->parent || !sta)
 		return;
 	wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
 	if (!wpa_s)
 		return;
-	callWithEachP2pIfaceCallback(
-		misc_utils::charBufToString(wpa_s->ifname),
-		std::bind(
-		&ISupplicantP2pIfaceCallback::onStaAuthorized,
-		std::placeholders::_1, macAddrToVec(sta),
-		p2p_dev_addr ? macAddrToVec(p2p_dev_addr) : kZeroBssid));
+
+	if (isAidlServiceVersionAtLeast(3)) {
+		P2pPeerClientJoinedEventParams params;
+		params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname);
+		params.clientInterfaceAddress = macAddrToArray(sta);
+		params.clientDeviceAddress = p2p_dev_addr ?
+				macAddrToArray(p2p_dev_addr) : macAddrToArray(kZeroBssid.data());
+		int aidl_ip = 0;
+		if (NULL != ip) {
+			os_memcpy(&aidl_ip, &ip[0], 4);
+		}
+		params.clientIpAddress = aidl_ip;
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onPeerClientJoined,
+			std::placeholders::_1, params));
+	} else {
+		// Use legacy callback if interface version < 3
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onStaAuthorized,
+			std::placeholders::_1, macAddrToVec(sta),
+			p2p_dev_addr ? macAddrToVec(p2p_dev_addr) : kZeroBssid));
+	}
 }
 
 void AidlManager::notifyApStaDeauthorized(
@@ -1627,12 +1698,27 @@
 	if (!wpa_s)
 		return;
 
-	callWithEachP2pIfaceCallback(
-		misc_utils::charBufToString(wpa_s->ifname),
-		std::bind(
-		&ISupplicantP2pIfaceCallback::onStaDeauthorized,
-		std::placeholders::_1, macAddrToVec(sta),
-		p2p_dev_addr ? macAddrToVec(p2p_dev_addr) : kZeroBssid));
+	if (isAidlServiceVersionAtLeast(3)) {
+		P2pPeerClientDisconnectedEventParams params;
+		params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname);
+		params.clientInterfaceAddress = macAddrToArray(sta);
+		params.clientDeviceAddress = p2p_dev_addr ?
+				macAddrToArray(p2p_dev_addr) : macAddrToArray(kZeroBssid.data());
+
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onPeerClientDisconnected,
+			std::placeholders::_1, params));
+	} else {
+		// Use legacy callback if interface version < 3
+		callWithEachP2pIfaceCallback(
+			misc_utils::charBufToString(wpa_s->ifname),
+			std::bind(
+			&ISupplicantP2pIfaceCallback::onStaDeauthorized,
+			std::placeholders::_1, macAddrToVec(sta),
+			p2p_dev_addr ? macAddrToVec(p2p_dev_addr) : kZeroBssid));
+	}
 }
 
 void AidlManager::notifyExtRadioWorkStart(
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h
index 8f1f177..cd9d5f6 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/aidl_manager.h
@@ -116,13 +116,13 @@
 	void notifyP2pProvisionDiscovery(
 		struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
 		enum p2p_prov_disc_status status, u16 config_methods,
-		unsigned int generated_pin);
+		unsigned int generated_pin, const char *group_ifname);
 	void notifyP2pSdResponse(
 		struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
 		const u8 *tlvs, size_t tlvs_len);
 	void notifyApStaAuthorized(
 		struct wpa_supplicant *wpa_s, const u8 *sta,
-		const u8 *p2p_dev_addr);
+		const u8 *p2p_dev_addr, const u8 *ip);
 	void notifyApStaDeauthorized(
 		struct wpa_supplicant *wpa_s, const u8 *sta,
 		const u8 *p2p_dev_addr);
diff --git a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml b/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
index b80dadd..37cc3af 100644
--- a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
+++ b/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
 	<hal format="aidl">
 		<name>android.hardware.wifi.supplicant</name>
-		<version>2</version>
+		<version>3</version>
 		<fqname>ISupplicant/default</fqname>
 	</hal>
 </manifest>
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/p2p_iface.cpp
index 33db802..ec52b44 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/p2p_iface.cpp
@@ -815,6 +815,21 @@
 		in_ipAddressGo, in_ipAddressMask, in_ipAddressStart, in_ipAddressEnd);
 }
 
+::ndk::ScopedAStatus P2pIface::connectWithParams(
+		const P2pConnectInfo& in_connectInfo, std::string* _aidl_return)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+		&P2pIface::connectWithParamsInternal, _aidl_return, in_connectInfo);
+}
+
+::ndk::ScopedAStatus P2pIface::findWithParams(const P2pDiscoveryInfo& in_discoveryInfo)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+		&P2pIface::findWithParamsInternal, in_discoveryInfo);
+}
+
 std::pair<std::string, ndk::ScopedAStatus> P2pIface::getNameInternal()
 {
 	return {ifname_, ndk::ScopedAStatus::ok()};
@@ -1852,6 +1867,33 @@
 	return ndk::ScopedAStatus::ok();
 }
 
+std::pair<std::string, ndk::ScopedAStatus> P2pIface::connectWithParamsInternal(
+		const P2pConnectInfo& connectInfo)
+{
+	std::vector<uint8_t> peerAddressVec {
+		connectInfo.peerAddress.begin(), connectInfo.peerAddress.end()};
+	return connectInternal(peerAddressVec, connectInfo.provisionMethod,
+		connectInfo.preSelectedPin, connectInfo.joinExistingGroup,
+		connectInfo.persistent, connectInfo.goIntent);
+}
+
+ndk::ScopedAStatus P2pIface::findWithParamsInternal(const P2pDiscoveryInfo& discoveryInfo)
+{
+	switch (discoveryInfo.scanType) {
+		case P2pScanType::FULL:
+			return findInternal(discoveryInfo.timeoutInSec);
+		case P2pScanType::SOCIAL:
+			return findOnSocialChannelsInternal(discoveryInfo.timeoutInSec);
+		case P2pScanType::SPECIFIC_FREQ:
+			return findOnSpecificFrequencyInternal(
+				discoveryInfo.frequencyMhz, discoveryInfo.timeoutInSec);
+		default:
+			wpa_printf(MSG_DEBUG,
+				"findWithParams received invalid scan type %d", discoveryInfo.scanType);
+			return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
diff --git a/wpa_supplicant/aidl/p2p_iface.h b/wpa_supplicant/aidl/p2p_iface.h
index 61972f2..c4f036c 100644
--- a/wpa_supplicant/aidl/p2p_iface.h
+++ b/wpa_supplicant/aidl/p2p_iface.h
@@ -175,6 +175,9 @@
 	::ndk::ScopedAStatus configureEapolIpAddressAllocationParams(
 		int32_t in_ipAddressGo, int32_t in_ipAddressMask,
 		int32_t in_ipAddressStart, int32_t in_ipAddressEnd) override;
+	::ndk::ScopedAStatus connectWithParams(
+		const P2pConnectInfo& in_connectInfo, std::string* _aidl_return) override;
+	::ndk::ScopedAStatus findWithParams(const P2pDiscoveryInfo& in_discoveryInfo) override;
 
 private:
 	// Corresponding worker functions for the AIDL methods.
@@ -298,6 +301,9 @@
 	::ndk::ScopedAStatus configureEapolIpAddressAllocationParamsInternal(
 		uint32_t ipAddressGo, uint32_t ipAddressMask,
 		uint32_t ipAddressStart, uint32_t ipAddressEnd);
+	std::pair<std::string, ndk::ScopedAStatus> connectWithParamsInternal(
+		const P2pConnectInfo& connectInfo);
+	ndk::ScopedAStatus findWithParamsInternal(const P2pDiscoveryInfo& discoveryInfo);
 
 	struct wpa_supplicant* retrieveIfacePtr();
 	struct wpa_supplicant* retrieveGroupIfacePtr(
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index fb3ebcd..78e6cd3 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -843,6 +843,18 @@
 	    &StaIface::removeQosPolicyForScsInternal, _aidl_return, in_scsPolicyIds);
 }
 
+::ndk::ScopedAStatus StaIface::configureMscs(const MscsParams& in_params) {
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_UNKNOWN,
+	    &StaIface::configureMscsInternal, in_params);
+}
+
+::ndk::ScopedAStatus StaIface::disableMscs() {
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_UNKNOWN,
+		&StaIface::disableMscsInternal);
+}
+
 std::pair<std::string, ndk::ScopedAStatus> StaIface::getNameInternal()
 {
 	return {ifname_, ndk::ScopedAStatus::ok()};
@@ -2427,6 +2439,14 @@
 		ndk::ScopedAStatus::ok()};
 }
 
+::ndk::ScopedAStatus StaIface::configureMscsInternal(const MscsParams& params) {
+	return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
+::ndk::ScopedAStatus StaIface::disableMscsInternal() {
+	return 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 db91445..b52c6b0 100644
--- a/wpa_supplicant/aidl/sta_iface.h
+++ b/wpa_supplicant/aidl/sta_iface.h
@@ -165,6 +165,8 @@
 	::ndk::ScopedAStatus removeQosPolicyForScs(
 		const std::vector<uint8_t>& in_scsPolicyIds,
 		std::vector<QosPolicyScsRequestStatus>* _aidl_return) override;
+	::ndk::ScopedAStatus configureMscs(const MscsParams& in_params) override;
+	::ndk::ScopedAStatus disableMscs() override;
 
 private:
 	// Corresponding worker functions for the AIDL methods.
@@ -277,6 +279,8 @@
 	std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
 		removeQosPolicyForScsInternal(
 		const std::vector<uint8_t>& scsPolicyIds);
+	::ndk::ScopedAStatus configureMscsInternal(const MscsParams& params);
+	::ndk::ScopedAStatus disableMscsInternal();
 
 	struct wpa_supplicant* retrieveIfacePtr();
 
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index bb3045c..f373e71 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -891,6 +891,21 @@
 		&StaNetwork::setMinimumTlsVersionEapPhase1ParamInternal, in_tlsVersion);
 }
 
+::ndk::ScopedAStatus StaNetwork::disableEht()
+{
+    return validateAndCall(
+            this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+                &StaNetwork::disableEhtInternal);
+}
+
+::ndk::ScopedAStatus StaNetwork::setVendorData(
+	const std::vector<common::OuiKeyedData>& in_vendorData)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+		&StaNetwork::setVendorDataInternal, in_vendorData);
+}
+
 std::pair<uint32_t, ndk::ScopedAStatus> StaNetwork::getIdInternal()
 {
 	return {network_id_, ndk::ScopedAStatus::ok()};
@@ -2689,15 +2704,32 @@
 			FALLTHROUGH_INTENDED;
 		case TlsVersion::TLS_V1_1:
 			tlsFlags |= TLS_CONN_DISABLE_TLSv1_0;
-			FALLTHROUGH_INTENDED;
-		default:
 			break;
+		default:
+			return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
 	}
 
 	generateTlsParams();
 	return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StaNetwork::disableEhtInternal()
+{
+  struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+  if (wpa_ssid == nullptr ) {
+    return createStatus(SupplicantStatusCode::FAILURE_NETWORK_INVALID);
+  }
+  wpa_ssid->disable_eht = 1;
+  resetInternalStateAfterParamsUpdate();
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StaNetwork::setVendorDataInternal(
+		const std::vector<common::OuiKeyedData>& /* vendorData */) {
+	// Not implemented in the default implementation.
+	return ndk::ScopedAStatus::ok();
+}
+
 /**
  * WPA3-Enterprise 192-bit mode workaround to force the connection to EAP-TLSv1.2 due to
  * interoperability issues in TLSv1.3 which disables the SSL_SIGN_RSA_PKCS1_SHA384
diff --git a/wpa_supplicant/aidl/sta_network.h b/wpa_supplicant/aidl/sta_network.h
index 1c24702..b0cb3de 100644
--- a/wpa_supplicant/aidl/sta_network.h
+++ b/wpa_supplicant/aidl/sta_network.h
@@ -178,6 +178,9 @@
 		const std::vector<uint8_t>& in_selectedRcoi) override;
 	::ndk::ScopedAStatus setMinimumTlsVersionEapPhase1Param(
 		TlsVersion in_tlsVersion) override;
+	::ndk::ScopedAStatus disableEht() override;
+	::ndk::ScopedAStatus setVendorData(
+		const std::vector<common::OuiKeyedData>& in_vendorData) override;
 
 private:
 	// Corresponding worker functions for the AIDL methods.
@@ -310,6 +313,9 @@
 	ndk::ScopedAStatus setRoamingConsortiumSelectionInternal(
 		const std::vector<uint8_t>& selectedRcoi);
 	ndk::ScopedAStatus setMinimumTlsVersionEapPhase1ParamInternal(TlsVersion tlsVersion);
+	ndk::ScopedAStatus disableEhtInternal();
+	ndk::ScopedAStatus setVendorDataInternal(
+		const std::vector<common::OuiKeyedData>& vendorData);
 
 	struct wpa_ssid* retrieveNetworkPtr();
 	struct wpa_supplicant* retrieveIfacePtr();
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index bfdd53e..4cc3808 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -541,6 +541,9 @@
 # WPA3-Personal (SAE)
 CONFIG_SAE=y
 
+# PASN
+CONFIG_PASN=y
+
 # WPA3-Enterprise (SuiteB-192)
 CONFIG_SUITEB=y
 CONFIG_SUITEB192=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 9a2598b..62d2e90 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -856,9 +856,9 @@
 
 
 static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
-				 int authorized, const u8 *p2p_dev_addr)
+				 int authorized, const u8 *p2p_dev_addr, const u8 *ip)
 {
-	wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr);
+	wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr, ip);
 }
 
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index b09d51d..eefae53 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -5830,6 +5830,8 @@
 			notify_bss_changes(
 				wpa_s, WPA_BSS_FREQ_CHANGED_FLAG,
 				wpa_s->links[data->ch_switch.link_id].bss);
+			if (data->ch_switch.freq)
+				wpas_notify_frequency_changed(wpa_s, data->ch_switch.freq);
 		}
 		break;
 	case EVENT_CH_SWITCH_STARTED:
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index c6e2dbe..a20f1c0 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -793,6 +793,10 @@
  * @status: Valid only in case of response (0 in case of success)
  * @config_methods: WPS config methods
  * @generated_pin: PIN to be displayed in case of WPS_CONFIG_DISPLAY method
+ * @group_ifname: Group interface name of the group owner in case the provision
+ *                discovery request is received with P2P Group ID attribute.
+ *                i.e., valid only when the peer device is joining an
+ *                operating P2P group.
  *
  * This can be used to notify:
  * - Requests or responses
@@ -803,7 +807,8 @@
 					 const u8 *dev_addr, int request,
 					 enum p2p_prov_disc_status status,
 					 u16 config_methods,
-					 unsigned int generated_pin)
+					 unsigned int generated_pin,
+					 const char *group_ifname)
 {
 	wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
 						 status, config_methods,
@@ -811,7 +816,7 @@
 
 	wpas_aidl_notify_p2p_provision_discovery(wpa_s, dev_addr, request,
 						 status, config_methods,
-						 generated_pin);
+						 generated_pin, group_ifname);
 
 }
 
@@ -863,7 +868,7 @@
 
 static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 					  const u8 *sta,
-					  const u8 *p2p_dev_addr)
+					  const u8 *p2p_dev_addr, const u8 *ip)
 {
 #ifdef CONFIG_P2P
 	wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr);
@@ -882,7 +887,7 @@
 	/* Notify listeners a new station has been authorized */
 	wpas_dbus_signal_sta_authorized(wpa_s, sta);
 
-	wpas_aidl_notify_ap_sta_authorized(wpa_s, sta, p2p_dev_addr);
+	wpas_aidl_notify_ap_sta_authorized(wpa_s, sta, p2p_dev_addr, ip);
 }
 
 
@@ -902,7 +907,7 @@
 	/* Notify listeners a station has been deauthorized */
 	wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
 
-        wpas_aidl_notify_ap_sta_deauthorized(wpa_s, sta, p2p_dev_addr);
+	wpas_aidl_notify_ap_sta_deauthorized(wpa_s, sta, p2p_dev_addr);
 	/* Unregister the station */
 	wpas_dbus_unregister_sta(wpa_s, sta);
 }
@@ -910,10 +915,10 @@
 
 void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
 				const u8 *mac_addr, int authorized,
-				const u8 *p2p_dev_addr)
+				const u8 *p2p_dev_addr, const u8 *ip)
 {
 	if (authorized)
-		wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr);
+		wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr, ip);
 	else
 		wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr, p2p_dev_addr);
 }
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index c41aa6e..260f439 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -100,7 +100,7 @@
 
 void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
 				const u8 *mac_addr, int authorized,
-				const u8 *p2p_dev_addr);
+				const u8 *p2p_dev_addr, const u8 *ip);
 void wpas_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
 void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
 				 const u8 *addr, const struct p2p_peer_info *info,
@@ -129,7 +129,8 @@
 					 const u8 *dev_addr, int request,
 					 enum p2p_prov_disc_status status,
 					 u16 config_methods,
-					 unsigned int generated_pin);
+					 unsigned int generated_pin,
+					 const char *group_ifname);
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid, int persistent,
 				   int client, const u8 *ip);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 09c11e0..db99177 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2666,6 +2666,7 @@
 				     wfd_dev_info_len, wfd_r2_dev_info,
 				     wfd_r2_dev_info_len, new_device);
 	os_free(wfd_dev_info);
+	os_free(wfd_r2_dev_info);
 }
 
 
@@ -2904,7 +2905,7 @@
 			wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
 			wpas_notify_p2p_provision_discovery(
 				wpa_s, peer, 0 /* response */,
-				P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+				P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0, NULL);
 			return;
 		}
 		wpas_prov_disc_local_display(wpa_s, peer, params,
@@ -2917,7 +2918,8 @@
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
 					    P2P_PROV_DISC_SUCCESS,
-					    config_methods, generated_pin);
+					    config_methods, generated_pin,
+					    group ? group->ifname : NULL);
 }
 
 
@@ -2955,7 +2957,7 @@
 			wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
 			wpas_notify_p2p_provision_discovery(
 				wpa_s, peer, 0 /* response */,
-				P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+				P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0, NULL);
 			return;
 		}
 		wpas_prov_disc_local_display(wpa_s, peer, params,
@@ -2966,7 +2968,8 @@
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
 					    P2P_PROV_DISC_SUCCESS,
-					    config_methods, generated_pin);
+					    config_methods, generated_pin,
+					    NULL);
 }
 
 
@@ -3013,7 +3016,7 @@
 	}
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
-					    status, 0, 0);
+					    status, 0, 0, NULL);
 }
 
 
diff --git a/wpa_supplicant/wpa_supplicant/Android.bp b/wpa_supplicant/wpa_supplicant/Android.bp
new file mode 100644
index 0000000..b70e5b9
--- /dev/null
+++ b/wpa_supplicant/wpa_supplicant/Android.bp
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+soong_namespace {
+
+}
+
+package {
+    default_applicable_licenses: [
+        // Inherits SPDX-license-identifier-BSD-3-Clause
+        "external_wpa_supplicant_8_license",
+    ],
+}
+
+soong_config_module_type_import {
+    from: "frameworks/opt/net/wifi/libwifi_hal/Android.bp",
+    module_types: ["wifi_cc_defaults"],
+}
+
+wifi_cc_defaults {
+    name: "lib_vendor_wpa_supplicant",
+    soong_config_variables: {
+        board_wlan_device: {
+            emulator: {
+                static_libs: ["lib_driver_cmd_simulated_cf_bp"],
+            },
+            // TODO(b/295186835): Convert lib_driver_cmd_* to soong
+            conditions_default: {
+                static_libs: ["lib_driver_cmd_fallback"],
+            },
+        }
+    }
+}
+
+cc_binary {
+    name: "wpa_supplicant",
+    defaults: [
+        "wpa_supplicant_defaults",
+        "lib_vendor_wpa_supplicant",
+    ],
+}
diff --git a/wpa_supplicant/wpa_supplicant/libdrivercmdfallback/Android.bp b/wpa_supplicant/wpa_supplicant/libdrivercmdfallback/Android.bp
new file mode 100644
index 0000000..3fe900b
--- /dev/null
+++ b/wpa_supplicant/wpa_supplicant/libdrivercmdfallback/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "lib_driver_cmd_fallback",
+    srcs: ["driver_cmd_nl80211.c"],
+    header_libs: [
+        "wpa_supplicant_headers",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-macro-redefined",
+    ],
+    soc_specific: true,
+}
\ No newline at end of file
diff --git a/wpa_supplicant/wpa_supplicant/libdrivercmdfallback/driver_cmd_nl80211.c b/wpa_supplicant/wpa_supplicant/libdrivercmdfallback/driver_cmd_nl80211.c
new file mode 100644
index 0000000..6cdc57a
--- /dev/null
+++ b/wpa_supplicant/wpa_supplicant/libdrivercmdfallback/driver_cmd_nl80211.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Driver interaction with extended Linux CFG8021
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+int wpa_driver_nl80211_driver_cmd(void* priv, char* cmd, char* buf,
+                                  size_t buf_len) {
+  return 0;
+}
+
+int wpa_driver_set_p2p_noa(void* priv, u8 count, int start, int duration) {
+  return 0;
+}
+
+int wpa_driver_get_p2p_noa(void* priv, u8* buf, size_t len) {
+  return 0;
+}
+
+int wpa_driver_set_p2p_ps(void* priv, int legacy_ps, int opp_ps, int ctwindow) {
+  return -1;
+}
+
+int wpa_driver_set_ap_wps_p2p_ie(void* priv, const struct wpabuf* beacon,
+                                 const struct wpabuf* proberesp,
+                                 const struct wpabuf* assocresp) {
+  return 0;
+}
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index bba7777..0047531 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -380,6 +380,12 @@
 		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
 	}
 
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) {
+		/* Add PMKSA cache entry */
+		wpa_printf(MSG_INFO, "add pmksa entry for the PMK");
+		wpa_sm_set_pmk(wpa_s->wpa, pmk, pmk_len, NULL, wpa_sm_get_auth_addr(wpa_s->wpa));
+	}
+
 	wpa_supplicant_cancel_scan(wpa_s);
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
 	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);