/* * 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 #include #include #include #include #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& 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& 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& 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