247 lines
10 KiB
C++
247 lines
10 KiB
C++
|
|
/*
|
||
|
|
* 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
|