wifi: implement PMK cache interface and callback

Bug: 36505680
Test: atest VtsHalWifiSupplicantV1_3TargetTest
Test: connect EAP access point and verify PMK cache works correctly.
Change-Id: I11cf80615839277f2b57906085aac4378dd2d550
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index d720f7b..35120a1 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -14,6 +14,8 @@
 #include "wpa.h"
 #include "wpa_i.h"
 #include "pmksa_cache.h"
+#include "wpa_supplicant_i.h"
+#include "notify.h"
 
 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
@@ -265,6 +267,7 @@
 	wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
 		   " network_ctx=%p akmp=0x%x", MAC2STR(entry->aa),
 		   entry->network_ctx, entry->akmp);
+	wpas_notify_pmk_cache_added((struct wpa_supplicant *)pmksa->sm->ctx->ctx, entry);
 	wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
 			 entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
 			 entry->pmk, entry->pmk_len);
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 8b5c73d..6391fd5 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1758,6 +1758,7 @@
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.3
 LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils libbase
 LOCAL_STATIC_LIBRARIES += libwpa_hidl
+LOCAL_VINTF_FRAGMENTS := hidl/1.3/manifest.xml
 endif
 include $(BUILD_EXECUTABLE)
 
diff --git a/wpa_supplicant/hidl/1.3/hidl.cpp b/wpa_supplicant/hidl/1.3/hidl.cpp
index 748bd61..986fc10 100644
--- a/wpa_supplicant/hidl/1.3/hidl.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl.cpp
@@ -776,3 +776,21 @@
 
 	hidl_manager->notifyDppProgress(wpa_s, code);
 }
+
+void wpas_hidl_notify_pmk_cache_added(
+    struct wpa_supplicant *wpa_s,
+    struct rsn_pmksa_cache_entry *pmksa_entry)
+{
+	if (!wpa_s || !pmksa_entry)
+		return;
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying PMK cache added event");
+
+	hidl_manager->notifyPmkCacheAdded(wpa_s, pmksa_entry);
+}
diff --git a/wpa_supplicant/hidl/1.3/hidl.h b/wpa_supplicant/hidl/1.3/hidl.h
index a177f6e..ca9980b 100644
--- a/wpa_supplicant/hidl/1.3/hidl.h
+++ b/wpa_supplicant/hidl/1.3/hidl.h
@@ -111,6 +111,8 @@
 	void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s);
 	void wpas_hidl_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
 	void wpas_hidl_notify_dpp_fail(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_pmk_cache_added(
+	    struct wpa_supplicant *wpas, struct rsn_pmksa_cache_entry *pmksa_entry);
 #else   // CONFIG_CTRL_IFACE_HIDL
 static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -239,6 +241,9 @@
 {}
 static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s)
 {}
+static void wpas_hidl_notify_pmk_cache_added(struct wpa_supplicant *wpas,
+					     struct rsn_pmksa_cache_entry *pmksa_entry)
+{}
 #endif  // CONFIG_CTRL_IFACE_HIDL
 
 #ifdef _cplusplus
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.cpp b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
index c1c1963..559d13d 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
@@ -8,6 +8,7 @@
  */
 
 #include <algorithm>
+#include <iostream>
 #include <regex>
 
 #include "hidl_manager.h"
@@ -289,13 +290,13 @@
 	}
 }
 
-template <class CallbackTypeV1_0, class CallbackTypeV1_1>
-void callWithEachIfaceCallback_1_1(
+template <class CallbackTypeBase, class CallbackTypeDerived>
+void callWithEachIfaceCallbackDerived(
     const std::string &ifname,
     const std::function<
-	android::hardware::Return<void>(android::sp<CallbackTypeV1_1>)> &method,
+	android::hardware::Return<void>(android::sp<CallbackTypeDerived>)> &method,
     const std::map<
-	const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
+	const std::string, std::vector<android::sp<CallbackTypeBase>>>
 	&callbacks_map)
 {
 	if (ifname.empty())
@@ -306,41 +307,12 @@
 		return;
 	const auto &iface_callback_list = iface_callback_map_iter->second;
 	for (const auto &callback : iface_callback_list) {
-		android::sp<CallbackTypeV1_1> callback_1_1 =
-		    CallbackTypeV1_1::castFrom(callback);
-		if (callback_1_1 == nullptr)
+		android::sp<CallbackTypeDerived> callback_derived =
+		    CallbackTypeDerived::castFrom(callback);
+		if (callback_derived == nullptr)
 			continue;
 
-		if (!method(callback_1_1).isOk()) {
-			wpa_printf(
-			    MSG_ERROR, "Failed to invoke HIDL iface callback");
-		}
-	}
-}
-
-template <class CallbackTypeV1_0, class CallbackTypeV1_2>
-void callWithEachIfaceCallback_1_2(
-    const std::string &ifname,
-    const std::function<
-	android::hardware::Return<void>(android::sp<CallbackTypeV1_2>)> &method,
-    const std::map<
-	const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
-	&callbacks_map)
-{
-	if (ifname.empty())
-		return;
-
-	auto iface_callback_map_iter = callbacks_map.find(ifname);
-	if (iface_callback_map_iter == callbacks_map.end())
-		return;
-	const auto &iface_callback_list = iface_callback_map_iter->second;
-	for (const auto &callback : iface_callback_list) {
-		android::sp<CallbackTypeV1_2> callback_1_2 =
-		    CallbackTypeV1_2::castFrom(callback);
-		if (callback_1_2 == nullptr)
-			continue;
-
-		if (!method(callback_1_2).isOk()) {
+		if (!method(callback_derived).isOk()) {
 			wpa_printf(
 			    MSG_ERROR, "Failed to invoke HIDL iface callback");
 		}
@@ -1570,6 +1542,32 @@
 }
 
 /**
+ * Notify listener about a PMK cache added event
+ *
+ * @param ifname Interface name
+ * @param entry PMK cache entry
+ */
+void HidlManager::notifyPmkCacheAdded(
+    struct wpa_supplicant *wpa_s, struct rsn_pmksa_cache_entry *pmksa_entry)
+{
+	std::string hidl_ifname = wpa_s->ifname;
+
+	// Serialize PmkCacheEntry into blob.
+	std::stringstream ss(
+	    std::stringstream::in | std::stringstream::out | std::stringstream::binary);
+	misc_utils::serializePmkCacheEntry(ss, pmksa_entry);
+	std::vector<uint8_t> serializedEntry(
+		std::istreambuf_iterator<char>(ss), {});
+
+	const std::function<
+	    Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)>
+	    func = std::bind(
+		&V1_3::ISupplicantStaIfaceCallback::onPmkCacheAdded,
+		std::placeholders::_1, pmksa_entry->expiration, serializedEntry);
+	callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
+}
+
+/**
  * Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
  * ifname.
  *
@@ -1911,7 +1909,7 @@
     const std::function<
 	Return<void>(android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method)
 {
-	callWithEachIfaceCallback_1_1(ifname, method, sta_iface_callbacks_map_);
+	callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
 }
 
 /**
@@ -1928,7 +1926,25 @@
     const std::function<
 	Return<void>(android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method)
 {
-	callWithEachIfaceCallback_1_2(ifname, method, sta_iface_callbacks_map_);
+	callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered derived interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * derived |V1_x::ISupplicantIfaceCallback|.
+ */
+template <class CallbackTypeDerived>
+void HidlManager::callWithEachStaIfaceCallbackDerived(
+    const std::string &ifname,
+    const std::function<
+	Return<void>(android::sp<CallbackTypeDerived>)> &method)
+{
+	callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
 }
 
 /**
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.h b/wpa_supplicant/hidl/1.3/hidl_manager.h
index 5e44462..07e3066 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.h
@@ -16,11 +16,12 @@
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
 
 #include "p2p_iface.h"
 #include "p2p_network.h"
+#include "rsn_supp/pmksa_cache.h"
 #include "sta_iface.h"
 #include "sta_network.h"
 #include "supplicant.h"
@@ -134,6 +135,8 @@
 	void notifyDppConfigSent(struct wpa_supplicant *wpa_s);
 	void notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code);
 	void notifyDppProgress(struct wpa_supplicant *wpa_s, DppProgressCode code);
+	void notifyPmkCacheAdded(struct wpa_supplicant *wpa_s,
+			struct rsn_pmksa_cache_entry *pmksa_entry);
 
 	// Methods called from hidl objects.
 	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -207,6 +210,11 @@
 	    const std::string &ifname,
 	    const std::function<android::hardware::Return<void>(
 	    android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method);
+	template <class CallbackTypeDerived>
+	void callWithEachStaIfaceCallbackDerived(
+	    const std::string &ifname,
+	    const std::function<
+		Return<void>(android::sp<CallbackTypeDerived>)> &method);
 	void callWithEachP2pNetworkCallback(
 	    const std::string &ifname, int network_id,
 	    const std::function<android::hardware::Return<void>(
diff --git a/wpa_supplicant/hidl/1.3/manifest.xml b/wpa_supplicant/hidl/1.3/manifest.xml
new file mode 100644
index 0000000..33e4fd4
--- /dev/null
+++ b/wpa_supplicant/hidl/1.3/manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.wifi.supplicant</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/wpa_supplicant/hidl/1.3/misc_utils.h b/wpa_supplicant/hidl/1.3/misc_utils.h
index 5f1c060..b95b1ee 100644
--- a/wpa_supplicant/hidl/1.3/misc_utils.h
+++ b/wpa_supplicant/hidl/1.3/misc_utils.h
@@ -10,6 +10,8 @@
 #ifndef MISC_UTILS_H_
 #define MISC_UTILS_H_
 
+#include <iostream>
+
 extern "C"
 {
 #include "wpabuf.h"
@@ -63,6 +65,42 @@
 	return pin_str;
 }
 
+inline std::stringstream& serializePmkCacheEntry(
+    std::stringstream &ss, struct rsn_pmksa_cache_entry *pmksa_entry) {
+	ss.write((char *) &pmksa_entry->pmk_len, sizeof(pmksa_entry->pmk_len));
+	ss.write((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
+	ss.write((char *) pmksa_entry->pmkid, PMKID_LEN);
+	ss.write((char *) pmksa_entry->aa, ETH_ALEN);
+	// Omit wpa_ssid field because the network is created on connecting to a access point.
+	ss.write((char *) &pmksa_entry->akmp, sizeof(pmksa_entry->akmp));
+	ss.write((char *) &pmksa_entry->reauth_time, sizeof(pmksa_entry->reauth_time));
+	ss.write((char *) &pmksa_entry->expiration, sizeof(pmksa_entry->expiration));
+	ss.write((char *) &pmksa_entry->opportunistic, sizeof(pmksa_entry->opportunistic));
+	char byte = (pmksa_entry->fils_cache_id_set) ? 1 : 0;
+	ss.write((char *) &byte, sizeof(byte));
+	ss.write((char *) pmksa_entry->fils_cache_id, FILS_CACHE_ID_LEN);
+	ss << std::flush;
+	return ss;
+}
+
+inline std::stringstream& deserializePmkCacheEntry(
+    std::stringstream &ss, struct rsn_pmksa_cache_entry *pmksa_entry) {
+	ss.seekg(0);
+	ss.read((char *) &pmksa_entry->pmk_len, sizeof(pmksa_entry->pmk_len));
+	ss.read((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
+	ss.read((char *) pmksa_entry->pmkid, PMKID_LEN);
+	ss.read((char *) pmksa_entry->aa, ETH_ALEN);
+	// Omit wpa_ssid field because the network is created on connecting to a access point.
+	ss.read((char *) &pmksa_entry->akmp, sizeof(pmksa_entry->akmp));
+	ss.read((char *) &pmksa_entry->reauth_time, sizeof(pmksa_entry->reauth_time));
+	ss.read((char *) &pmksa_entry->expiration, sizeof(pmksa_entry->expiration));
+	ss.read((char *) &pmksa_entry->opportunistic, sizeof(pmksa_entry->opportunistic));
+	char byte = 0;
+	ss.read((char *) &byte, sizeof(byte));
+	pmksa_entry->fils_cache_id_set = (byte) ? 1 : 0;
+	ss.read((char *) pmksa_entry->fils_cache_id, FILS_CACHE_ID_LEN);
+	return ss;
+}
 }  // namespace misc_utils
 }  // namespace implementation
 }  // namespace V1_3
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.cpp b/wpa_supplicant/hidl/1.3/sta_iface.cpp
index 80e31c8..03e32a2 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_iface.cpp
@@ -22,12 +22,14 @@
 #include "wps_supplicant.h"
 #include "dpp_supplicant.h"
 #include "dpp.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
 }
 
 namespace {
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
 using android::hardware::wifi::supplicant::V1_3::implementation::HidlManager;
 
 constexpr uint32_t kMaxAnqpElems = 100;
@@ -249,6 +251,16 @@
 	    &StaIface::registerCallbackInternal, _hidl_cb, callback_1_1);
 }
 
+Return<void> StaIface::registerCallback_1_3(
+    const sp<V1_3::ISupplicantStaIfaceCallback> &callback,
+    registerCallback_cb _hidl_cb)
+{
+	sp<V1_3::ISupplicantStaIfaceCallback> callback_1_3 = callback;
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::registerCallbackInternal, _hidl_cb, callback_1_3);
+}
+
 Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
 {
 	return validateAndCall(
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.h b/wpa_supplicant/hidl/1.3/sta_iface.h
index a179956..fbd91e6 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.h
+++ b/wpa_supplicant/hidl/1.3/sta_iface.h
@@ -15,7 +15,7 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
 
@@ -35,14 +35,16 @@
 namespace supplicant {
 namespace V1_3 {
 namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_2;
+using namespace android::hardware::wifi::supplicant::V1_3;
+using android::hardware::wifi::supplicant::V1_2::DppAkm;
+using android::hardware::wifi::supplicant::V1_2::DppNetRole;
 
 /**
  * Implementation of StaIface hidl object. Each unique hidl
  * object is used for control operations on a specific interface
  * controlled by wpa_supplicant.
  */
-class StaIface : public V1_2::ISupplicantStaIface
+class StaIface : public V1_3::ISupplicantStaIface
 {
 public:
 	StaIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -80,6 +82,9 @@
 	Return<void> registerCallback_1_2(
 	    const sp<V1_2::ISupplicantStaIfaceCallback>& callback,
 	    registerCallback_cb _hidl_cb) override;
+	Return<void> registerCallback_1_3(
+	    const sp<V1_3::ISupplicantStaIfaceCallback>& callback,
+	    registerCallback_cb _hidl_cb) override;
 	Return<void> reassociate(reassociate_cb _hidl_cb) override;
 	Return<void> reconnect(reconnect_cb _hidl_cb) override;
 	Return<void> disconnect(disconnect_cb _hidl_cb) override;
diff --git a/wpa_supplicant/hidl/1.3/sta_network.cpp b/wpa_supplicant/hidl/1.3/sta_network.cpp
index 799981b..4209a97 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_network.cpp
@@ -805,6 +805,15 @@
 	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
 	    &StaNetwork::getOcspInternal, _hidl_cb);
 }
+
+Return<void> StaNetwork::setPmkCache(const hidl_vec<uint8_t> &serializedEntry,
+    setPmkCache_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setPmkCacheInternal, _hidl_cb, serializedEntry);
+}
+
 std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -1978,6 +1987,26 @@
 	return {{SupplicantStatusCode::SUCCESS, ""},
 		(OcspType) wpa_ssid->eap.ocsp};
 }
+
+SupplicantStatus StaNetwork::setPmkCacheInternal(const std::vector<uint8_t>& serializedEntry) {
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	struct rsn_pmksa_cache_entry *new_entry = NULL;
+
+	new_entry = (struct rsn_pmksa_cache_entry *) os_zalloc(sizeof(*new_entry));
+	if (!new_entry) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, "Allocating memory failed"};
+	}
+
+	std::stringstream ss(
+	    std::stringstream::in | std::stringstream::out | std::stringstream::binary);
+	ss.write((char *) serializedEntry.data(), std::streamsize(serializedEntry.size()));
+	misc_utils::deserializePmkCacheEntry(ss, new_entry);
+	new_entry->network_ctx = wpa_ssid;
+	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, new_entry);
+
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
 /**
  * Retrieve the underlying |wpa_ssid| struct pointer for
  * this network.
diff --git a/wpa_supplicant/hidl/1.3/sta_network.h b/wpa_supplicant/hidl/1.3/sta_network.h
index f018a10..2db1b03 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.h
+++ b/wpa_supplicant/hidl/1.3/sta_network.h
@@ -230,6 +230,8 @@
 	    OcspType ocspType, setOcsp_cb _hidl_cb) override;
 	Return<void> getOcsp(
 	    getOcsp_cb _hidl_cb) override;
+	Return<void> setPmkCache(const hidl_vec<uint8_t>& serializedEntry,
+			setPmkCache_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -348,6 +350,7 @@
 	std::pair<SupplicantStatus, uint32_t> getGroupMgmtCipherInternal();
 	SupplicantStatus setOcspInternal(OcspType ocspType);
 	std::pair<SupplicantStatus, OcspType> getOcspInternal();
+	SupplicantStatus setPmkCacheInternal(const std::vector<uint8_t>& serialziedEntry);
 
 	struct wpa_ssid* retrieveNetworkPtr();
 	struct wpa_supplicant* retrieveIfacePtr();
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index bd16fed..ebefd48 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -1163,3 +1163,12 @@
 	wpas_hidl_notify_dpp_fail(wpa_s);
 #endif /* CONFIG_DPP */
 }
+
+void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
+				 struct rsn_pmksa_cache_entry *entry)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_pmk_cache_added(wpa_s, entry);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 8600ee9..c78ca68 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -11,6 +11,7 @@
 
 #include "p2p/p2p.h"
 #include "bss.h"
+#include "rsn_supp/pmksa_cache.h"
 
 struct wps_credential;
 struct wps_event_m2d;
@@ -183,5 +184,7 @@
 void wpas_notify_dpp_timeout(struct wpa_supplicant *wpa_s);
 void wpas_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
 void wpas_notify_dpp_failure(struct wpa_supplicant *wpa_s);
+void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
+				 struct rsn_pmksa_cache_entry *entry);
 
 #endif /* NOTIFY_H */