Merge "wifi: report generation is 11AX for 2.4G 11AX case" into main
diff --git a/OWNERS b/OWNERS
index bed29cb..5ddabe7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
 etancohen@google.com
 arabawy@google.com
 kumachang@google.com
+include platform/system/core:/janitors/OWNERS #{LAST_RESORT_SUGGESTION}
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 5361289..f2fb64f 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -1222,6 +1222,18 @@
     ],
 }
 
+cc_defaults {
+    name: "wpa_supplicant_usd_defaults",
+    cflags: [
+        "-DCONFIG_NAN_USD",
+    ],
+    srcs: [
+        "nan_usd.c",
+        "src/ap/nan_usd_ap.c",
+        "src/common/nan_de.c",
+    ],
+}
+
 cc_binary {
     name: "wpa_cli",
     proprietary: true,
@@ -1295,6 +1307,7 @@
         "wpa_supplicant_srcs_default",
         "wpa_supplicant_cflags_default",
         "wpa_supplicant_includes_default",
+        "wpa_supplicant_usd_defaults",
     ],
     soong_config_variables: {
         board_wpa_supplicant_private_lib: {
diff --git a/wpa_supplicant/aidl/vendor/aidl.cpp b/wpa_supplicant/aidl/vendor/aidl.cpp
index a0446fe..afda33f 100644
--- a/wpa_supplicant/aidl/vendor/aidl.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl.cpp
@@ -1116,3 +1116,81 @@
 	wpa_printf(MSG_DEBUG, "Notifying Qos Policy SCS Response");
 	aidl_manager->notifyQosPolicyScsResponse(wpa_s, count, scs_resp);
 }
+
+void wpas_aidl_notify_usd_service_discovered(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+		bool fsd, const u8 *ssi, size_t ssi_len)
+{
+	if (!wpa_s || !peer_addr || !ssi)
+		return;
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying USD service discovered");
+	aidl_manager->notifyUsdServiceDiscovered(wpa_s, srv_proto_type,
+		subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+}
+
+void wpas_aidl_notify_usd_publish_replied(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int publish_id, int peer_subscribe_id,
+		const u8 *peer_addr, const u8 *ssi, size_t ssi_len)
+{
+	if (!wpa_s || !peer_addr || !ssi)
+		return;
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying USD publish replied");
+	aidl_manager->notifyUsdPublishReplied(wpa_s, srv_proto_type,
+		publish_id, peer_subscribe_id, peer_addr, ssi, ssi_len);
+}
+
+void wpas_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s,
+		int id, int peer_instance_id, const u8 *peer_addr,
+		const u8 *message, size_t message_len)
+{
+	if (!wpa_s || !peer_addr || !message)
+		return;
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying USD message received");
+	aidl_manager->notifyUsdMessageReceived(wpa_s, id, peer_instance_id,
+		peer_addr, message, message_len);
+}
+
+void wpas_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+		int publish_id, enum nan_de_reason reason)
+{
+	if (!wpa_s)
+		return;
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying USD publish terminated");
+	aidl_manager->notifyUsdPublishTerminated(wpa_s, publish_id, reason);
+}
+
+void wpas_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+		int subscribe_id, enum nan_de_reason reason)
+{
+	if (!wpa_s)
+		return;
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying USD subscribe terminated");
+	aidl_manager->notifyUsdSubscribeTerminated(wpa_s, subscribe_id, reason);
+}
diff --git a/wpa_supplicant/aidl/vendor/aidl.h b/wpa_supplicant/aidl/vendor/aidl.h
index 71620f4..a8f38cb 100644
--- a/wpa_supplicant/aidl/vendor/aidl.h
+++ b/wpa_supplicant/aidl/vendor/aidl.h
@@ -157,6 +157,21 @@
 	ssize_t wpas_aidl_list_aliases(const char *prefix, char ***aliases);
 	void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
 		unsigned int count, int **scs_resp);
+	void wpas_aidl_notify_usd_service_discovered(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+		bool fsd, const u8 *ssi, size_t ssi_len);
+	void wpas_aidl_notify_usd_publish_replied(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int publish_id, int peer_subscribe_id,
+		const u8 *peer_addr, const u8 *ssi, size_t ssi_len);
+	void wpas_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+		int peer_instance_id, const u8 *peer_addr,
+		const u8 *message, size_t message_len);
+	void wpas_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+		int publish_id, enum nan_de_reason reason);
+	void wpas_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+		int subscribe_id, enum nan_de_reason reason);
 #else   // CONFIG_CTRL_IFACE_AIDL
 static inline int wpas_aidl_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -357,6 +372,21 @@
 }
 static void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
 	unsigned int count, int **scs_resp) {}
+static void wpas_aidl_notify_usd_service_discovered(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+		bool fsd, const u8 *ssi, size_t ssi_len) {}
+static void wpas_aidl_notify_usd_publish_replied(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int publish_id, int peer_subscribe_id,
+		const u8 *peer_addr, const u8 *ssi, size_t ssi_len) {}
+static void wpas_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+		int peer_instance_id, const u8 *peer_addr,
+		const u8 *message, size_t message_len) {}
+static void wpas_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+		int publish_id, enum nan_de_reason reason) {}
+static void wpas_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+		int subscribe_id, enum nan_de_reason reason) {}
 #endif  // CONFIG_CTRL_IFACE_AIDL
 
 #ifdef _cplusplus
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.cpp b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
index 177f478..89a4251 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
@@ -2976,6 +2976,162 @@
 			std::placeholders::_1, scsResponses));
 }
 
+void AidlManager::notifyUsdPublishStarted(struct wpa_supplicant *wpa_s,
+		int cmd_id, int publish_id)
+{
+	if (!wpa_s) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdPublishStarted,
+			std::placeholders::_1, cmd_id, publish_id));
+}
+void AidlManager::notifyUsdSubscribeStarted(struct wpa_supplicant *wpa_s,
+		int cmd_id, int subscribe_id)
+{
+	if (!wpa_s) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdSubscribeStarted,
+			std::placeholders::_1, cmd_id, subscribe_id));
+}
+void AidlManager::notifyUsdPublishConfigFailed(struct wpa_supplicant *wpa_s, int cmd_id)
+{
+	if (!wpa_s) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdPublishConfigFailed,
+			std::placeholders::_1, cmd_id));
+}
+
+void AidlManager::notifyUsdSubscribeConfigFailed(struct wpa_supplicant *wpa_s, int cmd_id)
+{
+	if (!wpa_s) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdSubscribeConfigFailed,
+			std::placeholders::_1, cmd_id));
+}
+
+UsdServiceProtoType convertUsdServiceProtoTypeToAidl(nan_service_protocol_type type) {
+	switch (type) {
+		case NAN_SRV_PROTO_GENERIC:
+			return UsdServiceProtoType::GENERIC;
+		case NAN_SRV_PROTO_CSA_MATTER:
+			return UsdServiceProtoType::CSA_MATTER;
+		default:
+			// Should not reach here
+			wpa_printf(MSG_ERROR, "Received invalid USD proto type %d from internal",
+				static_cast<int>(type));
+			return UsdServiceProtoType::GENERIC;
+	}
+}
+
+UsdServiceDiscoveryInfo createUsdServiceDiscoveryInfo(
+		enum nan_service_protocol_type srv_proto_type,
+		int own_id, int peer_id, const u8 *peer_addr,
+		bool fsd, const u8 *ssi, size_t ssi_len) {
+	// TODO: Fill the matchFilter field in the AIDL struct
+	UsdServiceDiscoveryInfo discoveryInfo;
+	discoveryInfo.ownId = own_id;
+	discoveryInfo.peerId = peer_id;
+	discoveryInfo.peerMacAddress = macAddrToArray(peer_addr);
+	discoveryInfo.protoType = convertUsdServiceProtoTypeToAidl(srv_proto_type);
+	discoveryInfo.serviceSpecificInfo = byteArrToVec(ssi, ssi_len);
+	discoveryInfo.isFsd = fsd;
+	return discoveryInfo;
+}
+
+void AidlManager::notifyUsdServiceDiscovered(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+		bool fsd, const u8 *ssi, size_t ssi_len)
+{
+	if (!wpa_s || !peer_addr || !ssi) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	UsdServiceDiscoveryInfo discoveryInfo = createUsdServiceDiscoveryInfo(
+		srv_proto_type, subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdServiceDiscovered,
+			std::placeholders::_1, discoveryInfo));
+}
+
+void AidlManager::notifyUsdPublishReplied(struct wpa_supplicant *wpa_s,
+		enum nan_service_protocol_type srv_proto_type,
+		int publish_id, int peer_subscribe_id,
+		const u8 *peer_addr, const u8 *ssi, size_t ssi_len)
+{
+	if (!wpa_s || !peer_addr || !ssi) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	UsdServiceDiscoveryInfo discoveryInfo = createUsdServiceDiscoveryInfo(
+		srv_proto_type, publish_id, peer_subscribe_id, peer_addr, false /* fsd */,
+		ssi, ssi_len);
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdPublishReplied,
+			std::placeholders::_1, discoveryInfo));
+}
+
+void AidlManager::notifyUsdMessageReceived(struct wpa_supplicant *wpa_s, int id,
+		int peer_instance_id, const u8 *peer_addr,
+		const u8 *message, size_t message_len)
+{
+	if (!wpa_s || !peer_addr || !message) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+
+	UsdMessageInfo messageInfo;
+	messageInfo.ownId = id;
+	messageInfo.peerId = peer_instance_id;
+	messageInfo.peerMacAddress = macAddrToArray(peer_addr);
+	messageInfo.message = byteArrToVec(message, message_len);
+
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdMessageReceived,
+			std::placeholders::_1, messageInfo));
+}
+
+UsdTerminateReasonCode convertUsdTerminateReasonCodeToAidl(nan_de_reason reason) {
+	switch (reason) {
+	case NAN_DE_REASON_TIMEOUT:
+		return UsdTerminateReasonCode::TIMEOUT;
+	case NAN_DE_REASON_USER_REQUEST:
+		return UsdTerminateReasonCode::USER_REQUEST;
+	case NAN_DE_REASON_FAILURE:
+		return UsdTerminateReasonCode::FAILURE;
+	default:
+		return UsdTerminateReasonCode::UNKNOWN;
+	}
+}
+
+void AidlManager::notifyUsdPublishTerminated(struct wpa_supplicant *wpa_s,
+		int publish_id, enum nan_de_reason reason)
+{
+	if (!wpa_s) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdPublishTerminated,
+			std::placeholders::_1, publish_id,
+			convertUsdTerminateReasonCodeToAidl(reason)));
+}
+
+void AidlManager::notifyUsdSubscribeTerminated(struct wpa_supplicant *wpa_s,
+		int subscribe_id, enum nan_de_reason reason)
+{
+	if (!wpa_s) return;
+	if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onUsdSubscribeTerminated,
+			std::placeholders::_1, subscribe_id,
+			convertUsdTerminateReasonCodeToAidl(reason)));
+}
+
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.h b/wpa_supplicant/aidl/vendor/aidl_manager.h
index 46a40aa..d40837c 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.h
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.h
@@ -178,6 +178,27 @@
 			unsigned int count, int **scs_resp);
 	void notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s,
 				       enum mlo_info_change_reason reason);
+	void notifyUsdPublishStarted(struct wpa_supplicant *wpa_s,
+			int cmd_id, int publish_id);
+	void notifyUsdSubscribeStarted(struct wpa_supplicant *wpa_s,
+			int cmd_id, int subscribe_id);
+	void notifyUsdPublishConfigFailed(struct wpa_supplicant *wpa_s, int cmd_id);
+	void notifyUsdSubscribeConfigFailed(struct wpa_supplicant *wpa_s, int cmd_id);
+	void notifyUsdServiceDiscovered(struct wpa_supplicant *wpa_s,
+			enum nan_service_protocol_type srv_proto_type,
+			int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+			bool fsd, const u8 *ssi, size_t ssi_len);
+	void notifyUsdPublishReplied(struct wpa_supplicant *wpa_s,
+			enum nan_service_protocol_type srv_proto_type,
+			int publish_id, int peer_subscribe_id,
+			const u8 *peer_addr, const u8 *ssi, size_t ssi_len);
+	void notifyUsdMessageReceived(struct wpa_supplicant *wpa_s, int id,
+			int peer_instance_id, const u8 *peer_addr,
+			const u8 *message, size_t message_len);
+	void notifyUsdPublishTerminated(struct wpa_supplicant *wpa_s,
+			int publish_id, enum nan_de_reason reason);
+	void notifyUsdSubscribeTerminated(struct wpa_supplicant *wpa_s,
+			int subscribe_id, enum nan_de_reason reason);
 
 	// Methods called from aidl objects.
 	int32_t isAidlServiceVersionAtLeast(int32_t expected_version);
diff --git a/wpa_supplicant/aidl/vendor/sta_iface.cpp b/wpa_supplicant/aidl/vendor/sta_iface.cpp
index 1a6ae08..aebd92a 100644
--- a/wpa_supplicant/aidl/vendor/sta_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/sta_iface.cpp
@@ -38,6 +38,12 @@
 using aidl::android::hardware::wifi::supplicant::LegacyMode;
 using aidl::android::hardware::wifi::supplicant::RxFilterType;
 using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
+using aidl::android::hardware::wifi::supplicant::UsdBaseConfig;
+using aidl::android::hardware::wifi::supplicant::UsdCapabilities;
+using aidl::android::hardware::wifi::supplicant::UsdPublishConfig;
+using aidl::android::hardware::wifi::supplicant::UsdPublishTransmissionType;
+using aidl::android::hardware::wifi::supplicant::UsdServiceProtoType;
+using aidl::android::hardware::wifi::supplicant::UsdSubscribeConfig;
 using aidl::android::hardware::wifi::supplicant::WifiChannelWidthInMhz;
 using aidl::android::hardware::wifi::supplicant::WifiTechnology;
 using aidl::android::hardware::wifi::supplicant::misc_utils::createStatus;
@@ -58,6 +64,14 @@
 	static_cast<uint32_t>(ISupplicant::EXT_RADIO_WORK_TIMEOUT_IN_SECS);
 constexpr char kExtRadioWorkNamePrefix[] = "ext:";
 
+constexpr bool kIsUsdPublisherSupported = false;
+constexpr bool kIsUsdSubscriberSupported = false;
+constexpr int32_t kMaxUsdLocalSsiLengthBytes = 1400;
+constexpr int32_t kMaxUsdServiceNameLengthBytes = 255;
+constexpr int32_t kMaxUsdMatchFilterLengthBytes = 255;
+constexpr int32_t kMaxNumUsdPublishSessions = 1;
+constexpr int32_t kMaxNumUsdSubscribeSessions = 1;
+
 uint8_t convertAidlRxFilterTypeToInternal(
 	RxFilterType type)
 {
@@ -84,6 +98,21 @@
 	WPA_ASSERT(false);
 }
 
+nan_service_protocol_type convertAidlServiceProtoTypeToInternal(
+	UsdServiceProtoType type)
+{
+	switch (type) {
+	case UsdServiceProtoType::GENERIC:
+		return NAN_SRV_PROTO_GENERIC;
+	case UsdServiceProtoType::CSA_MATTER:
+		return NAN_SRV_PROTO_CSA_MATTER;
+	default:
+		// Default case is not expected, due
+		// to the USD validation method
+		return NAN_SRV_PROTO_GENERIC;
+	};
+}
+
 ndk::ScopedAStatus doZeroArgDriverCommand(
 	struct wpa_supplicant *wpa_s, const char *cmd)
 {
@@ -284,6 +313,120 @@
 	return arr;
 }
 
+template <typename T>
+inline bool checkContainerSize(const T& container, int maxSize) {
+  return container.size() <= maxSize;
+}
+
+template <typename T>
+inline bool isValidEnumValue(T value, T enumRangeMin, T enumRangeMax) {
+	return static_cast<uint32_t>(value) >= static_cast<uint32_t>(enumRangeMin)
+		&& static_cast<uint32_t>(value) <= static_cast<uint32_t>(enumRangeMax);
+}
+
+bool validateUsdBaseConfig(UsdBaseConfig baseConfig) {
+	if (!isValidEnumValue(baseConfig.serviceProtoType,
+			UsdServiceProtoType::GENERIC, UsdServiceProtoType::CSA_MATTER)) {
+		wpa_printf(MSG_ERROR, "Unknown protocol type received: %d",
+			static_cast<int>(baseConfig.serviceProtoType));
+		return false;
+	}
+	if (!checkContainerSize(baseConfig.serviceName, kMaxUsdServiceNameLengthBytes)) {
+		wpa_printf(MSG_ERROR, "Service name of size %zu exceeds the supported size of %d",
+			baseConfig.serviceName.size(), kMaxUsdServiceNameLengthBytes);
+		return false;
+	}
+	if (!checkContainerSize(baseConfig.serviceSpecificInfo, kMaxUsdLocalSsiLengthBytes)) {
+		wpa_printf(MSG_ERROR, "Service specific info of size %zu exceeds"
+			" the supported size of %d", baseConfig.serviceSpecificInfo.size(),
+			kMaxUsdLocalSsiLengthBytes);
+		return false;
+	}
+	if (baseConfig.txMatchFilter.has_value() && !checkContainerSize(
+			baseConfig.txMatchFilter.value(), kMaxUsdMatchFilterLengthBytes)) {
+		wpa_printf(MSG_ERROR, "TX match filter of size %zu exceeds"
+			" the supported size of %d", baseConfig.txMatchFilter.value().size(),
+			kMaxUsdMatchFilterLengthBytes);
+		return false;
+	}
+	if (baseConfig.rxMatchFilter.has_value() && !checkContainerSize(
+			baseConfig.rxMatchFilter.value(), kMaxUsdMatchFilterLengthBytes)) {
+		wpa_printf(MSG_ERROR, "RX match filter of size %zu exceeds"
+			" the supported size of %d", baseConfig.rxMatchFilter.value().size(),
+			kMaxUsdMatchFilterLengthBytes);
+		return false;
+	}
+	return true;
+}
+
+bool validateUsdPublishConfig(UsdPublishConfig publishConfig) {
+	if (!validateUsdBaseConfig(publishConfig.usdBaseConfig)) {
+		return false;
+	}
+	if (!isValidEnumValue(publishConfig.publishType,
+			UsdPublishConfig::PublishType::SOLICITED_ONLY,
+			UsdPublishConfig::PublishType::SOLICITED_AND_UNSOLICITED)) {
+		wpa_printf(MSG_ERROR, "Unknown publish type received: %d",
+			static_cast<int>(publishConfig.publishType));
+		return false;
+	}
+	if (!isValidEnumValue(publishConfig.transmissionType,
+			UsdPublishTransmissionType::UNICAST,
+			UsdPublishTransmissionType::MULTICAST)) {
+		wpa_printf(MSG_ERROR, "Unknown transmission type received: %d",
+			static_cast<int>(publishConfig.transmissionType));
+		return false;
+	}
+	return true;
+}
+
+bool validateUsdSubscribeConfig(UsdSubscribeConfig subscribeConfig) {
+	if (!validateUsdBaseConfig(subscribeConfig.usdBaseConfig)) {
+		return false;
+	}
+	if (!isValidEnumValue(subscribeConfig.subscribeType,
+			UsdSubscribeConfig::SubscribeType::PASSIVE_MODE,
+			UsdSubscribeConfig::SubscribeType::ACTIVE_MODE)) {
+		wpa_printf(MSG_ERROR, "Unknown subscribe type received: %d",
+			static_cast<int>(subscribeConfig.subscribeType));
+		return false;
+	}
+	return true;
+}
+
+struct nan_publish_params convertAidlNanPublishParamsToInternal(UsdPublishConfig publishConfig) {
+	struct nan_publish_params nanPublishParams;
+	nanPublishParams.unsolicited =
+		publishConfig.publishType == UsdPublishConfig::PublishType::UNSOLICITED_ONLY
+			|| publishConfig.publishType == UsdPublishConfig::PublishType::SOLICITED_AND_UNSOLICITED;
+	nanPublishParams.solicited =
+		publishConfig.publishType == UsdPublishConfig::PublishType::SOLICITED_ONLY
+			|| publishConfig.publishType == UsdPublishConfig::PublishType::SOLICITED_AND_UNSOLICITED;
+	nanPublishParams.solicited_multicast = nanPublishParams.solicited &&
+		publishConfig.transmissionType == UsdPublishTransmissionType::MULTICAST;
+	nanPublishParams.ttl = publishConfig.usdBaseConfig.ttlSec;
+	nanPublishParams.fsd = publishConfig.isFsd;
+	nanPublishParams.freq = publishConfig.usdBaseConfig.defaultFreqMhz;
+	nanPublishParams.announcement_period = publishConfig.announcementPeriodMillis;
+	nanPublishParams.disable_events = !publishConfig.eventsEnabled;
+	// Pass the original pointer to the freq list, since the receiver will memcpy the data
+	nanPublishParams.freq_list = publishConfig.usdBaseConfig.freqsMhz.data();
+	return nanPublishParams;
+}
+
+struct nan_subscribe_params convertAidlNanSubscribeParamsToInternal(
+		UsdSubscribeConfig subscribeConfig) {
+	struct nan_subscribe_params nanSubscribeParams;
+	nanSubscribeParams.active =
+		subscribeConfig.subscribeType == UsdSubscribeConfig::SubscribeType::ACTIVE_MODE;
+	nanSubscribeParams.ttl = subscribeConfig.usdBaseConfig.ttlSec;
+	nanSubscribeParams.freq = subscribeConfig.usdBaseConfig.defaultFreqMhz;
+	nanSubscribeParams.query_period = subscribeConfig.queryPeriodMillis;
+	// Pass the original pointer to the freq list, since the receiver will memcpy the data
+	nanSubscribeParams.freq_list = subscribeConfig.usdBaseConfig.freqsMhz.data();
+	return nanSubscribeParams;
+}
+
 }  // namespace
 
 namespace aidl {
@@ -855,7 +998,7 @@
 {
 	return validateAndCall(
 		this, SupplicantStatusCode::FAILURE_UNKNOWN,
-		&StaIface::startUsdPublishInternal, in_usdPublishConfig);
+		&StaIface::startUsdPublishInternal, in_cmdId, in_usdPublishConfig);
 }
 
 ::ndk::ScopedAStatus StaIface::startUsdSubscribe(int32_t in_cmdId,
@@ -863,7 +1006,7 @@
 {
 	return validateAndCall(
 		this, SupplicantStatusCode::FAILURE_UNKNOWN,
-		&StaIface::startUsdSubscribeInternal, in_usdSubscribeConfig);
+		&StaIface::startUsdSubscribeInternal, in_cmdId, in_usdSubscribeConfig);
 }
 
 ::ndk::ScopedAStatus StaIface::updateUsdPublish(int32_t in_publishId,
@@ -2608,17 +2751,157 @@
 }
 
 std::pair<UsdCapabilities, ndk::ScopedAStatus> StaIface::getUsdCapabilitiesInternal() {
+	// TODO (b/382756996): Retrieve the capabilities dynamically
 	UsdCapabilities capabilities;
+	capabilities.isUsdPublisherSupported = kIsUsdPublisherSupported;
+	capabilities.isUsdSubscriberSupported = kIsUsdSubscriberSupported;
+	capabilities.maxLocalSsiLengthBytes = kMaxUsdLocalSsiLengthBytes;
+	capabilities.maxServiceNameLengthBytes = kMaxUsdServiceNameLengthBytes;
+	capabilities.maxMatchFilterLengthBytes = kMaxUsdMatchFilterLengthBytes;
+	capabilities.maxNumPublishSessions = kMaxNumUsdPublishSessions;
+	capabilities.maxNumSubscribeSessions = kMaxNumUsdSubscribeSessions;
 	return {capabilities, ndk::ScopedAStatus::ok()};
 }
 
+// TODO (b/384527237): Fix linker error to avoid having a separate default implementation
+#ifdef CONFIG_NAN_USD
+
 ndk::ScopedAStatus StaIface::startUsdPublishInternal(
-		const UsdPublishConfig& usdPublishConfig) {
+		int32_t cmdId, const UsdPublishConfig& usdPublishConfig) {
+	if (!validateUsdPublishConfig(usdPublishConfig)) {
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+	auto ssiBuffer = misc_utils::convertVectorToWpaBuf(
+		usdPublishConfig.usdBaseConfig.serviceSpecificInfo);
+	if (ssiBuffer.get() == nullptr) {
+		wpa_printf(MSG_INFO, "Unable to convert USD publish SSI to buffer");
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct nan_publish_params nanPublishParams =
+		convertAidlNanPublishParamsToInternal(usdPublishConfig);
+
+	int publishId = wpas_nan_usd_publish(
+		wpa_s, usdPublishConfig.usdBaseConfig.serviceName.c_str(),
+		convertAidlServiceProtoTypeToInternal(
+			usdPublishConfig.usdBaseConfig.serviceProtoType),
+		ssiBuffer.get(), &nanPublishParams, false /* p2p */);
+
+	// Core supplicant does not have an internal callback for USD publish, but some
+	// implementations may decide to offload and return the result in a callback.
+	// In our case (core supplicant), the AIDL callback will be invoked directly here.
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	WPA_ASSERT(aidl_manager);
+	if (publishId < 0) {
+		wpa_printf(MSG_INFO, "Failed to configure USD publish");
+		aidl_manager->notifyUsdPublishConfigFailed(wpa_s, cmdId);
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	aidl_manager->notifyUsdPublishStarted(wpa_s, cmdId, publishId);
+	return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StaIface::startUsdSubscribeInternal(
+		int32_t cmdId, const UsdSubscribeConfig& usdSubscribeConfig) {
+	if (!validateUsdSubscribeConfig(usdSubscribeConfig)) {
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+	auto ssiBuffer = misc_utils::convertVectorToWpaBuf(
+		usdSubscribeConfig.usdBaseConfig.serviceSpecificInfo);
+	if (ssiBuffer.get() == nullptr) {
+		wpa_printf(MSG_INFO, "Unable to convert USD subscribe SSI to buffer");
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct nan_subscribe_params nanSubscribeParams =
+		convertAidlNanSubscribeParamsToInternal(usdSubscribeConfig);
+
+	int subscribeId = wpas_nan_usd_subscribe(
+		wpa_s, usdSubscribeConfig.usdBaseConfig.serviceName.c_str(),
+		convertAidlServiceProtoTypeToInternal(
+			usdSubscribeConfig.usdBaseConfig.serviceProtoType),
+		ssiBuffer.get(), &nanSubscribeParams, false /* p2p */);
+
+	// See comment in startUsdPublishInternal regarding callbacks
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	WPA_ASSERT(aidl_manager);
+	if (subscribeId < 0) {
+		wpa_printf(MSG_INFO, "Failed to configure USD subscribe");
+		aidl_manager->notifyUsdSubscribeConfigFailed(wpa_s, cmdId);
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	aidl_manager->notifyUsdSubscribeStarted(wpa_s, cmdId, subscribeId);
+	return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus StaIface::updateUsdPublishInternal(int32_t publishId,
+		const std::vector<uint8_t>& serviceSpecificInfo) {
+	if (!checkContainerSize(serviceSpecificInfo, kMaxUsdLocalSsiLengthBytes)) {
+		wpa_printf(MSG_ERROR, "Service specific info of size %zu exceeds the"
+			" supported size of %d", serviceSpecificInfo.size(),
+			kMaxUsdLocalSsiLengthBytes);
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+	auto ssiBuffer = misc_utils::convertVectorToWpaBuf(serviceSpecificInfo);
+	if (ssiBuffer.get() == nullptr) {
+		wpa_printf(MSG_INFO, "Unable to convert USD update SSI to buffer");
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	int status = wpas_nan_usd_update_publish(
+		retrieveIfacePtr(), publishId, ssiBuffer.get());
+	if (status < 0) {
+		wpa_printf(MSG_INFO, "Failed to update USD publish");
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus StaIface::cancelUsdPublishInternal(int32_t publishId) {
+	// Status code is returned by the callback
+	wpas_nan_usd_cancel_publish(retrieveIfacePtr(), publishId);
+	return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus StaIface::cancelUsdSubscribeInternal(int32_t subscribeId) {
+	// Status code is returned by the callback
+	wpas_nan_usd_cancel_subscribe(retrieveIfacePtr(), subscribeId);
+	return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus StaIface::sendUsdMessageInternal(const UsdMessageInfo& messageInfo) {
+	if (!checkContainerSize(messageInfo.message, kMaxUsdLocalSsiLengthBytes)) {
+		wpa_printf(MSG_ERROR, "Message of size %zu exceeds the supported size of %d",
+			messageInfo.message.size(), kMaxUsdLocalSsiLengthBytes);
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+	auto msgBuffer = misc_utils::convertVectorToWpaBuf(messageInfo.message);
+	if (msgBuffer.get() == nullptr) {
+		wpa_printf(MSG_INFO, "Unable to convert message contents to buffer");
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	int handle = messageInfo.ownId;
+	int reqInstanceId = messageInfo.peerId;
+	int status = wpas_nan_usd_transmit(
+		retrieveIfacePtr(), handle, msgBuffer.get(), nullptr /* elems */,
+		messageInfo.peerMacAddress.data(), reqInstanceId);
+	if (status < 0) {
+		wpa_printf(MSG_INFO, "Failed to send USD message");
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+	return ndk::ScopedAStatus::ok();
+}
+
+#else /* CONFIG_NAN_USD */
+
+ndk::ScopedAStatus StaIface::startUsdPublishInternal(
+		int32_t cmdId, const UsdPublishConfig& usdPublishConfig) {
 	return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
 }
 
 ndk::ScopedAStatus StaIface::startUsdSubscribeInternal(
-		const UsdSubscribeConfig& usdSubscribeConfig) {
+		int32_t cmdId, const UsdSubscribeConfig& usdSubscribeConfig) {
 	return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
 }
 
@@ -2639,6 +2922,8 @@
 	return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
 }
 
+#endif /* CONFIG_NAN_USD */
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
diff --git a/wpa_supplicant/aidl/vendor/sta_iface.h b/wpa_supplicant/aidl/vendor/sta_iface.h
index 6c6cfb9..8703aaf 100644
--- a/wpa_supplicant/aidl/vendor/sta_iface.h
+++ b/wpa_supplicant/aidl/vendor/sta_iface.h
@@ -31,6 +31,7 @@
 #include "wpa_supplicant_i.h"
 #include "config.h"
 #include "driver_i.h"
+#include "nan_usd.h"
 #include "wpa.h"
 }
 
@@ -292,8 +293,10 @@
 	::ndk::ScopedAStatus configureMscsInternal(const MscsParams& params);
 	::ndk::ScopedAStatus disableMscsInternal();
 	std::pair<UsdCapabilities, ndk::ScopedAStatus> getUsdCapabilitiesInternal();
-	::ndk::ScopedAStatus startUsdPublishInternal(const UsdPublishConfig& usdPublishConfig);
-	::ndk::ScopedAStatus startUsdSubscribeInternal(const UsdSubscribeConfig& usdSubscribeConfig);
+	::ndk::ScopedAStatus startUsdPublishInternal(
+		int32_t cmdId, const UsdPublishConfig& usdPublishConfig);
+	::ndk::ScopedAStatus startUsdSubscribeInternal(
+		int32_t cmdId, const UsdSubscribeConfig& usdSubscribeConfig);
 	::ndk::ScopedAStatus updateUsdPublishInternal(int32_t publishId,
 		const std::vector<uint8_t>& serviceSpecificInfo);
 	::ndk::ScopedAStatus cancelUsdPublishInternal(int32_t publishId);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 2dc68b0..0cd7c63 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -1512,6 +1512,9 @@
 		subscribe_id, peer_publish_id, MAC2STR(peer_addr),
 		fsd, fsd_gas, srv_proto_type, ssi_hex);
 	os_free(ssi_hex);
+
+	wpas_aidl_notify_usd_service_discovered(wpa_s, srv_proto_type,
+		subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
 }
 
 
@@ -1534,6 +1537,9 @@
 		publish_id, MAC2STR(peer_addr), peer_subscribe_id,
 		srv_proto_type, ssi_hex);
 	os_free(ssi_hex);
+
+	wpas_aidl_notify_usd_publish_replied(wpa_s, srv_proto_type,
+		publish_id, peer_subscribe_id, peer_addr, ssi, ssi_len);
 }
 
 
@@ -1552,6 +1558,9 @@
 		"id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
 		id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
 	os_free(ssi_hex);
+
+	wpas_aidl_notify_usd_message_received(wpa_s, id, peer_instance_id,
+		peer_addr, ssi, ssi_len);
 }
 
 
@@ -1577,6 +1586,7 @@
 	wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED
 		"publish_id=%d reason=%s",
 		publish_id, nan_reason_txt(reason));
+	wpas_aidl_notify_usd_publish_terminated(wpa_s, publish_id, reason);
 }
 
 
@@ -1587,6 +1597,7 @@
 	wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
 		"subscribe_id=%d reason=%s",
 		subscribe_id, nan_reason_txt(reason));
+	wpas_aidl_notify_usd_subscribe_terminated(wpa_s, subscribe_id, reason);
 }
 
 #endif /* CONFIG_NAN_USD */