Merge changes Iadfd290c,Ib9d5173a into main

* changes:
  Implement the remaining USD methods in the mainline supplicant.
  Implement getUsdCapabilities, cancelUsdPublish, and cancelUsdSubscribe in the mainline supplicant.
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 380fe47..a29093f 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -1427,6 +1427,7 @@
         "wpa_supplicant_mainline_srcs_default",
         "wpa_supplicant_includes_default",
         "wpa_supplicant_mainline_cflags_default",
+        "wpa_supplicant_usd_defaults",
     ],
     apex_available: [
         "//apex_available:platform",
@@ -1465,6 +1466,7 @@
         "wpa_supplicant_includes_default",
         "wpa_supplicant_mainline_cflags_default",
         "wpa_supplicant_mainline_srcs_default",
+        "wpa_supplicant_usd_defaults",
     ],
     shared_libs: [
         "android.system.wifi.mainline_supplicant-ndk",
diff --git a/wpa_supplicant/aidl/mainline/sta_iface.cpp b/wpa_supplicant/aidl/mainline/sta_iface.cpp
index 6104033..08d2b04 100644
--- a/wpa_supplicant/aidl/mainline/sta_iface.cpp
+++ b/wpa_supplicant/aidl/mainline/sta_iface.cpp
@@ -7,42 +7,153 @@
  */
 
 #include "sta_iface.h"
+#include "usd_utils.h"
+
+extern "C"
+{
+#include "utils/common.h"
+#include "nan_usd.h"
+#include "wpa_supplicant_i.h"
+}
 
 StaIface::StaIface(struct wpa_global* wpa_global, std::string iface_name)
     : wpa_global_(wpa_global), iface_name_(iface_name) {}
 
+struct wpa_supplicant* StaIface::retrieveIfacePtr() {
+    return wpa_supplicant_get_iface(wpa_global_, iface_name_.c_str());
+}
+
 ::ndk::ScopedAStatus StaIface::registerCallback(
         const std::shared_ptr<IStaInterfaceCallback>& in_callback) {
     return ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus StaIface::getUsdCapabilities(UsdCapabilities* _aidl_return) {
+    UsdCapabilities capabilities;
+    capabilities.isUsdPublisherSupported = kIsUsdPublisherSupported;
+    capabilities.isUsdSubscriberSupported = kIsUsdSubscriberSupported;
+    capabilities.maxLocalSsiLengthBytes = kMaxUsdLocalSsiLengthBytes;
+    capabilities.maxServiceNameLengthBytes = kMaxUsdServiceNameLengthBytes;
+    capabilities.maxMatchFilterLengthBytes = kMaxUsdMatchFilterLengthBytes;
+    capabilities.maxNumPublishSessions = kMaxNumUsdPublishSessions;
+    capabilities.maxNumSubscribeSessions = kMaxNumUsdSubscribeSessions;
+    *_aidl_return = capabilities;
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus StaIface::startUsdPublish(int32_t in_cmdId,
-        const UsdPublishConfig& in_publishConfig) {
+::ndk::ScopedAStatus StaIface::startUsdPublish(int32_t cmdId,
+        const UsdPublishConfig& publishConfig) {
+    if (!validateUsdPublishConfig(publishConfig)) {
+        wpa_printf(MSG_ERROR, "USD publish config is invalid");
+        return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+    }
+    wpabuf_unique_ptr ssiBuffer = {nullptr, nullptr};
+    if (!publishConfig.baseConfig.serviceSpecificInfo.empty()) {
+        ssiBuffer = convertVectorToWpaBuf(publishConfig.baseConfig.serviceSpecificInfo);
+        if (ssiBuffer.get() == nullptr) {
+            wpa_printf(MSG_ERROR, "Unable to convert USD publish SSI to buffer");
+            return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+        }
+    }
+
+    struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+    struct nan_publish_params nanPublishParams =
+        convertAidlUsdPublishConfigToInternal(publishConfig);
+    int publishId = wpas_nan_usd_publish(
+        wpa_s, publishConfig.baseConfig.serviceName.c_str(),
+        convertAidlServiceProtoTypeToInternal(
+            publishConfig.baseConfig.serviceProtoType),
+        ssiBuffer.get(), &nanPublishParams, false /* p2p */);
+    // TODO: Return status code in a callback
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus StaIface::startUsdSubscribe(int32_t in_cmdId,
-        const UsdSubscribeConfig& in_subscribeConfig) {
+::ndk::ScopedAStatus StaIface::startUsdSubscribe(int32_t cmdId,
+        const UsdSubscribeConfig& subscribeConfig) {
+    if (!validateUsdSubscribeConfig(subscribeConfig)) {
+        wpa_printf(MSG_ERROR, "USD subscribe config is invalid");
+        return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+    }
+    wpabuf_unique_ptr ssiBuffer = {nullptr, nullptr};
+    if (!subscribeConfig.baseConfig.serviceSpecificInfo.empty()) {
+        ssiBuffer = convertVectorToWpaBuf(subscribeConfig.baseConfig.serviceSpecificInfo);
+        if (ssiBuffer.get() == nullptr) {
+            wpa_printf(MSG_ERROR, "Unable to convert USD subscribe SSI to buffer");
+            return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+        }
+    }
+
+    struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+    struct nan_subscribe_params nanSubscribeParams =
+        convertAidlUsdSubscribeConfigToInternal(subscribeConfig);
+    int subscribeId = wpas_nan_usd_subscribe(
+        wpa_s, subscribeConfig.baseConfig.serviceName.c_str(),
+        convertAidlServiceProtoTypeToInternal(
+            subscribeConfig.baseConfig.serviceProtoType),
+        ssiBuffer.get(), &nanSubscribeParams, false /* p2p */);
+    // TODO: Return status code in a callback
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus StaIface::updateUsdPublish(int32_t in_publishId,
-        const std::vector<uint8_t>& in_serviceSpecificInfo) {
+::ndk::ScopedAStatus StaIface::updateUsdPublish(int32_t publishId,
+        const std::vector<uint8_t>& serviceSpecificInfo) {
+    if (!checkContainerSize(serviceSpecificInfo, kMaxUsdLocalSsiLengthBytes)) {
+        wpa_printf(MSG_ERROR, "Updated USD publish SSI of size %zu exceeds the"
+            " supported size of %d", serviceSpecificInfo.size(),
+            kMaxUsdLocalSsiLengthBytes);
+        return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+    }
+    wpabuf_unique_ptr ssiBuffer = {nullptr, nullptr};
+    if (!serviceSpecificInfo.empty()) {
+        ssiBuffer = convertVectorToWpaBuf(serviceSpecificInfo);
+        if (ssiBuffer.get() == nullptr) {
+            wpa_printf(MSG_ERROR, "Unable to convert updated USD publish 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_ERROR, "Failed to update USD publish");
+        return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+    }
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus StaIface::cancelUsdPublish(int32_t in_publishId) {
+::ndk::ScopedAStatus StaIface::cancelUsdPublish(int32_t publishId) {
+    // Status code is returned by the callback
+    wpas_nan_usd_cancel_publish(retrieveIfacePtr(), publishId);
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus StaIface::cancelUsdSubscribe(int32_t in_subscribeId) {
+::ndk::ScopedAStatus StaIface::cancelUsdSubscribe(int32_t subscribeId) {
+    // Status code is returned by the callback
+    wpas_nan_usd_cancel_subscribe(retrieveIfacePtr(), subscribeId);
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus StaIface::sendUsdMessage(const UsdMessageInfo& in_messageInfo) {
+::ndk::ScopedAStatus StaIface::sendUsdMessage(const UsdMessageInfo& messageInfo) {
+    if (!checkContainerSize(messageInfo.message, kMaxUsdLocalSsiLengthBytes)) {
+        wpa_printf(MSG_ERROR, "USD message of size %zu exceeds the supported size of %d",
+            messageInfo.message.size(), kMaxUsdLocalSsiLengthBytes);
+        return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+    }
+    wpabuf_unique_ptr msgBuffer = {nullptr, nullptr};
+    if (!messageInfo.message.empty()) {
+        msgBuffer = convertVectorToWpaBuf(messageInfo.message);
+        if (msgBuffer.get() == nullptr) {
+            wpa_printf(MSG_ERROR, "Unable to convert USD 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_ERROR, "Failed to send USD message");
+        return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+    }
     return ndk::ScopedAStatus::ok();
 }
diff --git a/wpa_supplicant/aidl/mainline/sta_iface.h b/wpa_supplicant/aidl/mainline/sta_iface.h
index 213eacf..8f9b665 100644
--- a/wpa_supplicant/aidl/mainline/sta_iface.h
+++ b/wpa_supplicant/aidl/mainline/sta_iface.h
@@ -35,6 +35,8 @@
     private:
         wpa_global* wpa_global_;
         std::string iface_name_;
+
+        struct wpa_supplicant* retrieveIfacePtr();
 };
 
 #endif // MAINLINE_SUPPLICANT_STA_IFACE_H
diff --git a/wpa_supplicant/aidl/mainline/usd_utils.h b/wpa_supplicant/aidl/mainline/usd_utils.h
new file mode 100644
index 0000000..428a599
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/usd_utils.h
@@ -0,0 +1,153 @@
+/*
+ * WPA Supplicant - Helper functions for USD
+ * Copyright (c) 2025, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_USD_UTILS_H
+#define MAINLINE_SUPPLICANT_USD_UTILS_H
+
+#include "utils.h"
+
+#include <aidl/android/system/wifi/mainline_supplicant/IStaInterface.h>
+#include <aidl/android/system/wifi/mainline_supplicant/UsdServiceProtoType.h>
+
+extern "C"
+{
+#include "utils/common.h"
+#include "src/common/nan_de.h"
+}
+
+using ::aidl::android::system::wifi::mainline_supplicant::IStaInterface;
+using ::aidl::android::system::wifi::mainline_supplicant::UsdServiceProtoType;
+
+constexpr bool kIsUsdPublisherSupported = true;
+constexpr bool kIsUsdSubscriberSupported = true;
+constexpr int32_t kMaxUsdLocalSsiLengthBytes = 1400;
+constexpr int32_t kMaxUsdServiceNameLengthBytes = 255;
+constexpr int32_t kMaxUsdMatchFilterLengthBytes = 0;
+constexpr int32_t kMaxNumUsdPublishSessions = NAN_DE_MAX_SERVICE;
+constexpr int32_t kMaxNumUsdSubscribeSessions = NAN_DE_MAX_SERVICE;
+
+static bool validateUsdBaseConfig(IStaInterface::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;
+}
+
+static bool validateUsdPublishConfig(IStaInterface::UsdPublishConfig publishConfig) {
+    if (!validateUsdBaseConfig(publishConfig.baseConfig)) {
+        return false;
+    }
+    if (!isValidEnumValue(publishConfig.publishType,
+            IStaInterface::UsdPublishType::SOLICITED_ONLY,
+            IStaInterface::UsdPublishType::SOLICITED_AND_UNSOLICITED)) {
+        wpa_printf(MSG_ERROR, "Unknown publish type received: %d",
+            static_cast<int>(publishConfig.publishType));
+        return false;
+    }
+    if (!isValidEnumValue(publishConfig.transmissionType,
+            IStaInterface::UsdPublishTransmissionType::UNICAST,
+            IStaInterface::UsdPublishTransmissionType::MULTICAST)) {
+        wpa_printf(MSG_ERROR, "Unknown transmission type received: %d",
+            static_cast<int>(publishConfig.transmissionType));
+        return false;
+    }
+    return true;
+}
+
+static bool validateUsdSubscribeConfig(IStaInterface::UsdSubscribeConfig subscribeConfig) {
+    if (!validateUsdBaseConfig(subscribeConfig.baseConfig)) {
+        return false;
+    }
+    if (!isValidEnumValue(subscribeConfig.subscribeType,
+            IStaInterface::UsdSubscribeType::PASSIVE_MODE,
+            IStaInterface::UsdSubscribeType::ACTIVE_MODE)) {
+        wpa_printf(MSG_ERROR, "Unknown subscribe type received: %d",
+            static_cast<int>(subscribeConfig.subscribeType));
+        return false;
+    }
+    return true;
+}
+
+static struct nan_publish_params convertAidlUsdPublishConfigToInternal(
+        IStaInterface::UsdPublishConfig publishConfig) {
+    struct nan_publish_params nanPublishParams;
+    nanPublishParams.unsolicited =
+        publishConfig.publishType == IStaInterface::UsdPublishType::SOLICITED_AND_UNSOLICITED
+            || publishConfig.publishType == IStaInterface::UsdPublishType::UNSOLICITED_ONLY;
+    nanPublishParams.solicited =
+        publishConfig.publishType == IStaInterface::UsdPublishType::SOLICITED_AND_UNSOLICITED
+            || publishConfig.publishType == IStaInterface::UsdPublishType::SOLICITED_ONLY;
+    nanPublishParams.solicited_multicast = nanPublishParams.solicited &&
+        publishConfig.transmissionType == IStaInterface::UsdPublishTransmissionType::MULTICAST;
+    nanPublishParams.ttl = publishConfig.baseConfig.ttlSec;
+    nanPublishParams.fsd = publishConfig.isFsd;
+    nanPublishParams.freq = publishConfig.baseConfig.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.baseConfig.freqsMhz.empty()
+        ? NULL : publishConfig.baseConfig.freqsMhz.data();
+    return nanPublishParams;
+}
+
+static struct nan_subscribe_params convertAidlUsdSubscribeConfigToInternal(
+        IStaInterface::UsdSubscribeConfig subscribeConfig) {
+    struct nan_subscribe_params nanSubscribeParams;
+    nanSubscribeParams.active =
+        subscribeConfig.subscribeType == IStaInterface::UsdSubscribeType::ACTIVE_MODE;
+    nanSubscribeParams.ttl = subscribeConfig.baseConfig.ttlSec;
+    nanSubscribeParams.freq = subscribeConfig.baseConfig.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.baseConfig.freqsMhz.empty()
+        ? NULL : subscribeConfig.baseConfig.freqsMhz.data();
+    return nanSubscribeParams;
+}
+
+static nan_service_protocol_type convertAidlServiceProtoTypeToInternal(
+        UsdServiceProtoType serviceProtoType) {
+    switch (serviceProtoType) {
+        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;
+    };
+}
+
+#endif // MAINLINE_SUPPLICANT_USD_UTILS_H
diff --git a/wpa_supplicant/aidl/mainline/utils.h b/wpa_supplicant/aidl/mainline/utils.h
index 703b9ee..8b1fd19 100644
--- a/wpa_supplicant/aidl/mainline/utils.h
+++ b/wpa_supplicant/aidl/mainline/utils.h
@@ -11,15 +11,53 @@
 
 #include <aidl/android/system/wifi/mainline_supplicant/SupplicantStatusCode.h>
 
+extern "C"
+{
+#include "utils/common.h"
+#include "wpabuf.h"
+}
+
+namespace {
+// Custom deleter for wpabuf
+void freeWpaBuf(wpabuf *ptr) { wpabuf_free(ptr); }
+}
+
+using ::aidl::android::system::wifi::mainline_supplicant::SupplicantStatusCode;
+
+using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
+
 inline ndk::ScopedAStatus createStatus(SupplicantStatusCode statusCode) {
-	return ndk::ScopedAStatus::fromServiceSpecificError(
-		static_cast<int32_t>(statusCode));
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(statusCode));
 }
 
 inline ndk::ScopedAStatus createStatusWithMsg(
-	    SupplicantStatusCode statusCode, std::string msg) {
-	return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-		static_cast<int32_t>(statusCode), msg.c_str());
+        SupplicantStatusCode statusCode, std::string msg) {
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+        static_cast<int32_t>(statusCode), msg.c_str());
+}
+
+// Check whether the container is within the maximum size
+template <typename T>
+inline bool checkContainerSize(const T& container, int maxSize) {
+    return container.size() <= maxSize;
+}
+
+// Check whether the enum value is within the specified range
+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);
+}
+
+// Create a unique_ptr for a wpabuf ptr with a custom deleter
+inline wpabuf_unique_ptr createWpaBufUniquePtr(struct wpabuf *raw_ptr) {
+    return {raw_ptr, freeWpaBuf};
+}
+
+// Create a wpabuf ptr with a custom deleter, copying the data from the provided vector
+inline wpabuf_unique_ptr convertVectorToWpaBuf(const std::vector<uint8_t> &data) {
+    return createWpaBufUniquePtr(wpabuf_alloc_copy(data.data(), data.size()));
 }
 
 #endif // MAINLINE_SUPPLICANT_UTILS_H