Convert Tetheroffload HIDL to AIDL.
This patch converts Tetheroffload HIDL to AIDL and adds an empty
example implementation.
There are some changes in AIDL HAL:
1. Combine IOffloadConfig and IOffloadControl into IOffload
2. Use AIDL builtin errors exception code with message as return
Bug: b/205762647
Test: m android.hardware.tetheroffload-update-api
m android.hardware.tetheroffload-V1-ndk
m android.hardware.tetheroffload-service.example
atest VtsHalTetheroffloadTargetTest
Change-Id: I9859ff3df608c058786b4e2b91cb6cd5f38e653a
diff --git a/tetheroffload/aidl/default/Offload.cpp b/tetheroffload/aidl/default/Offload.cpp
new file mode 100644
index 0000000..8aa6916
--- /dev/null
+++ b/tetheroffload/aidl/default/Offload.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <numeric>
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <netdb.h>
+
+#include "Offload.h"
+
+namespace aidl::android::hardware::tetheroffload::impl::example {
+
+using ::android::base::Join;
+
+ndk::ScopedAStatus Offload::addDownstream(const std::string& in_iface,
+ const std::string& in_prefix) {
+ LOG(VERBOSE) << __func__ << " Interface: " << in_iface << ", Prefix: " << in_prefix;
+ if (!isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized");
+ }
+ if (!isValidInterface(in_iface)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid interface name");
+ }
+ if (!isValidIpPrefix(in_prefix)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid IP prefix");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::getForwardedStats(const std::string& in_upstream,
+ ForwardedStats* _aidl_return) {
+ LOG(VERBOSE) << __func__ << " Upstream: " << in_upstream;
+ ForwardedStats stats;
+ stats.rxBytes = 0;
+ stats.txBytes = 0;
+ *_aidl_return = std::move(stats);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::initOffload(const ndk::ScopedFileDescriptor& in_fd1,
+ const ndk::ScopedFileDescriptor& in_fd2,
+ const std::shared_ptr<ITetheringOffloadCallback>& in_cb) {
+ LOG(VERBOSE) << __func__ << " FileDescriptor1: " << std::to_string(in_fd1.get())
+ << ", FileDescriptor2: " << std::to_string(in_fd2.get())
+ << ", ITetheringOffloadCallback: " << in_cb;
+ if (isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL already initialized");
+ }
+ int fd1 = in_fd1.get();
+ int fd2 = in_fd2.get();
+ if (fd1 < 0 || fd2 < 0) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid file descriptors");
+ }
+ mFd1 = ndk::ScopedFileDescriptor(dup(fd1));
+ mFd2 = ndk::ScopedFileDescriptor(dup(fd2));
+ mInitialized = true;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::removeDownstream(const std::string& in_iface,
+ const std::string& in_prefix) {
+ LOG(VERBOSE) << __func__ << " Interface: " << in_iface << ", Prefix: " << in_prefix;
+ if (!isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized");
+ }
+ if (!isValidIpPrefix(in_prefix)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid IP prefix");
+ }
+ if (!isValidInterface(in_iface)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid interface name");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::setDataWarningAndLimit(const std::string& in_upstream,
+ int64_t in_warningBytes, int64_t in_limitBytes) {
+ LOG(VERBOSE) << __func__ << " Upstream: " << in_upstream
+ << ", WarningBytes: " << in_warningBytes << ", LimitBytes: " << in_limitBytes;
+ if (!isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized");
+ }
+ if (!isValidInterface(in_upstream)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid interface name");
+ }
+ if (in_warningBytes < 0 || in_limitBytes < 0) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Threshold must be non-negative");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::setLocalPrefixes(const std::vector<std::string>& in_prefixes) {
+ LOG(VERBOSE) << __func__ << " Prefixes: " << Join(in_prefixes, ',');
+ if (!isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized");
+ }
+ if (in_prefixes.empty()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "No IP prefix");
+ }
+ for (std::string prefix : in_prefixes) {
+ if (!isValidIpPrefix(prefix)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid IP prefix");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::setUpstreamParameters(const std::string& in_iface,
+ const std::string& in_v4Addr,
+ const std::string& in_v4Gw,
+ const std::vector<std::string>& in_v6Gws) {
+ LOG(VERBOSE) << __func__ << " Interface: " << in_iface << ", IPv4Address: " << in_v4Addr
+ << ", IPv4Gateway: " << in_v4Gw << ", IPv6Gateways: " << Join(in_v6Gws, ',');
+ if (!isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized");
+ }
+ if (!isValidInterface(in_iface)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid interface name");
+ }
+ if (in_v4Addr.empty() && in_v4Gw.empty() && in_v6Gws.empty()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "No upstream IP address");
+ }
+ if (!in_v4Addr.empty() && !in_v4Gw.empty()) {
+ if (!isValidIpv4Address(in_v4Addr) || !isValidIpv4Address(in_v4Gw)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid IP address");
+ }
+ }
+ for (std::string ip : in_v6Gws) {
+ if (!isValidIpv6Address(ip)) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid IP address");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Offload::stopOffload() {
+ LOG(VERBOSE) << __func__;
+ if (!isInitialized()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized");
+ }
+ mInitialized = false;
+ return ndk::ScopedAStatus::ok();
+};
+
+bool Offload::isInitialized() {
+ return (mInitialized == true);
+}
+
+bool Offload::isValidInterface(const std::string& iface) {
+ return !iface.empty() && iface != "invalid";
+}
+
+bool Offload::isValidIpv4Address(const std::string& repr) {
+ return validateIpAddressOrPrefix(repr, AF_INET, false);
+}
+
+bool Offload::isValidIpv4Prefix(const std::string& repr) {
+ return validateIpAddressOrPrefix(repr, AF_INET, true);
+}
+
+bool Offload::isValidIpv6Address(const std::string& repr) {
+ return validateIpAddressOrPrefix(repr, AF_INET6, false);
+}
+
+bool Offload::isValidIpv6Prefix(const std::string& repr) {
+ return validateIpAddressOrPrefix(repr, AF_INET6, true);
+}
+
+bool Offload::isValidIpAddress(const std::string& repr) {
+ return isValidIpv4Address(repr) || isValidIpv6Address(repr);
+}
+
+bool Offload::isValidIpPrefix(const std::string& repr) {
+ return isValidIpv4Prefix(repr) || isValidIpv6Prefix(repr);
+}
+
+// Refer to libnetdutils's IPAddress and IPPrefix classes.
+// Can't use them directly because libnetdutils is not "vendor_available".
+bool Offload::validateIpAddressOrPrefix(const std::string& repr, const int expectedFamily,
+ const bool isPrefix) {
+ const addrinfo hints = {
+ .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
+ };
+ addrinfo* res;
+ size_t index = repr.find('/');
+ if (isPrefix && index == std::string::npos) return false;
+
+ // Parse the IP address.
+ const std::string ipAddress = isPrefix ? repr.substr(0, index) : repr;
+ const int ret = getaddrinfo(ipAddress.c_str(), nullptr, &hints, &res);
+ if (ret != 0) return false;
+
+ // Check the address family.
+ int family = res[0].ai_family;
+ freeaddrinfo(res);
+ if (family != expectedFamily) return false;
+ if (!isPrefix) return true;
+
+ // Parse the prefix length.
+ const char* prefixString = repr.c_str() + index + 1;
+ if (!isdigit(*prefixString)) return false;
+ char* endptr;
+ unsigned long prefixlen = strtoul(prefixString, &endptr, 10);
+ if (*endptr != '\0') return false;
+
+ uint8_t maxlen = (family == AF_INET) ? 32 : 128;
+ if (prefixlen > maxlen) return false;
+
+ return true;
+}
+
+} // namespace aidl::android::hardware::tetheroffload::impl::example