KH Shi | d97a308 | 2022-12-06 19:46:31 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <numeric> |
| 18 | #include <string> |
| 19 | |
| 20 | #include <android-base/logging.h> |
| 21 | #include <android-base/strings.h> |
| 22 | #include <netdb.h> |
| 23 | |
| 24 | #include "Offload.h" |
| 25 | |
| 26 | namespace aidl::android::hardware::tetheroffload::impl::example { |
| 27 | |
| 28 | using ::android::base::Join; |
| 29 | |
| 30 | ndk::ScopedAStatus Offload::addDownstream(const std::string& in_iface, |
| 31 | const std::string& in_prefix) { |
| 32 | LOG(VERBOSE) << __func__ << " Interface: " << in_iface << ", Prefix: " << in_prefix; |
| 33 | if (!isInitialized()) { |
| 34 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 35 | EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized"); |
| 36 | } |
| 37 | if (!isValidInterface(in_iface)) { |
| 38 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 39 | "Invalid interface name"); |
| 40 | } |
| 41 | if (!isValidIpPrefix(in_prefix)) { |
| 42 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 43 | "Invalid IP prefix"); |
| 44 | } |
| 45 | return ndk::ScopedAStatus::ok(); |
| 46 | } |
| 47 | |
| 48 | ndk::ScopedAStatus Offload::getForwardedStats(const std::string& in_upstream, |
| 49 | ForwardedStats* _aidl_return) { |
| 50 | LOG(VERBOSE) << __func__ << " Upstream: " << in_upstream; |
| 51 | ForwardedStats stats; |
| 52 | stats.rxBytes = 0; |
| 53 | stats.txBytes = 0; |
| 54 | *_aidl_return = std::move(stats); |
| 55 | return ndk::ScopedAStatus::ok(); |
| 56 | } |
| 57 | |
| 58 | ndk::ScopedAStatus Offload::initOffload(const ndk::ScopedFileDescriptor& in_fd1, |
| 59 | const ndk::ScopedFileDescriptor& in_fd2, |
| 60 | const std::shared_ptr<ITetheringOffloadCallback>& in_cb) { |
| 61 | LOG(VERBOSE) << __func__ << " FileDescriptor1: " << std::to_string(in_fd1.get()) |
| 62 | << ", FileDescriptor2: " << std::to_string(in_fd2.get()) |
| 63 | << ", ITetheringOffloadCallback: " << in_cb; |
| 64 | if (isInitialized()) { |
| 65 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 66 | EX_ILLEGAL_STATE, "Tetheroffload HAL already initialized"); |
| 67 | } |
| 68 | int fd1 = in_fd1.get(); |
| 69 | int fd2 = in_fd2.get(); |
| 70 | if (fd1 < 0 || fd2 < 0) { |
| 71 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 72 | "Invalid file descriptors"); |
| 73 | } |
| 74 | mFd1 = ndk::ScopedFileDescriptor(dup(fd1)); |
| 75 | mFd2 = ndk::ScopedFileDescriptor(dup(fd2)); |
| 76 | mInitialized = true; |
| 77 | return ndk::ScopedAStatus::ok(); |
| 78 | } |
| 79 | |
| 80 | ndk::ScopedAStatus Offload::removeDownstream(const std::string& in_iface, |
| 81 | const std::string& in_prefix) { |
| 82 | LOG(VERBOSE) << __func__ << " Interface: " << in_iface << ", Prefix: " << in_prefix; |
| 83 | if (!isInitialized()) { |
| 84 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 85 | EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized"); |
| 86 | } |
| 87 | if (!isValidIpPrefix(in_prefix)) { |
| 88 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 89 | "Invalid IP prefix"); |
| 90 | } |
| 91 | if (!isValidInterface(in_iface)) { |
| 92 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 93 | "Invalid interface name"); |
| 94 | } |
| 95 | return ndk::ScopedAStatus::ok(); |
| 96 | } |
| 97 | |
| 98 | ndk::ScopedAStatus Offload::setDataWarningAndLimit(const std::string& in_upstream, |
| 99 | int64_t in_warningBytes, int64_t in_limitBytes) { |
| 100 | LOG(VERBOSE) << __func__ << " Upstream: " << in_upstream |
| 101 | << ", WarningBytes: " << in_warningBytes << ", LimitBytes: " << in_limitBytes; |
| 102 | if (!isInitialized()) { |
| 103 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 104 | EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized"); |
| 105 | } |
| 106 | if (!isValidInterface(in_upstream)) { |
| 107 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 108 | "Invalid interface name"); |
| 109 | } |
| 110 | if (in_warningBytes < 0 || in_limitBytes < 0) { |
| 111 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 112 | "Threshold must be non-negative"); |
| 113 | } |
| 114 | return ndk::ScopedAStatus::ok(); |
| 115 | } |
| 116 | |
| 117 | ndk::ScopedAStatus Offload::setLocalPrefixes(const std::vector<std::string>& in_prefixes) { |
| 118 | LOG(VERBOSE) << __func__ << " Prefixes: " << Join(in_prefixes, ','); |
| 119 | if (!isInitialized()) { |
| 120 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 121 | EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized"); |
| 122 | } |
| 123 | if (in_prefixes.empty()) { |
| 124 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 125 | "No IP prefix"); |
| 126 | } |
| 127 | for (std::string prefix : in_prefixes) { |
| 128 | if (!isValidIpPrefix(prefix)) { |
| 129 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 130 | "Invalid IP prefix"); |
| 131 | } |
| 132 | } |
| 133 | return ndk::ScopedAStatus::ok(); |
| 134 | } |
| 135 | |
| 136 | ndk::ScopedAStatus Offload::setUpstreamParameters(const std::string& in_iface, |
| 137 | const std::string& in_v4Addr, |
| 138 | const std::string& in_v4Gw, |
| 139 | const std::vector<std::string>& in_v6Gws) { |
| 140 | LOG(VERBOSE) << __func__ << " Interface: " << in_iface << ", IPv4Address: " << in_v4Addr |
| 141 | << ", IPv4Gateway: " << in_v4Gw << ", IPv6Gateways: " << Join(in_v6Gws, ','); |
| 142 | if (!isInitialized()) { |
| 143 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 144 | EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized"); |
| 145 | } |
| 146 | if (!isValidInterface(in_iface)) { |
| 147 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 148 | "Invalid interface name"); |
| 149 | } |
| 150 | if (in_v4Addr.empty() && in_v4Gw.empty() && in_v6Gws.empty()) { |
| 151 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 152 | "No upstream IP address"); |
| 153 | } |
| 154 | if (!in_v4Addr.empty() && !in_v4Gw.empty()) { |
| 155 | if (!isValidIpv4Address(in_v4Addr) || !isValidIpv4Address(in_v4Gw)) { |
| 156 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 157 | "Invalid IP address"); |
| 158 | } |
| 159 | } |
| 160 | for (std::string ip : in_v6Gws) { |
| 161 | if (!isValidIpv6Address(ip)) { |
| 162 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, |
| 163 | "Invalid IP address"); |
| 164 | } |
| 165 | } |
| 166 | return ndk::ScopedAStatus::ok(); |
| 167 | } |
| 168 | |
| 169 | ndk::ScopedAStatus Offload::stopOffload() { |
| 170 | LOG(VERBOSE) << __func__; |
| 171 | if (!isInitialized()) { |
| 172 | return ndk::ScopedAStatus::fromExceptionCodeWithMessage( |
| 173 | EX_ILLEGAL_STATE, "Tetheroffload HAL not initialized"); |
| 174 | } |
| 175 | mInitialized = false; |
| 176 | return ndk::ScopedAStatus::ok(); |
| 177 | }; |
| 178 | |
| 179 | bool Offload::isInitialized() { |
| 180 | return (mInitialized == true); |
| 181 | } |
| 182 | |
| 183 | bool Offload::isValidInterface(const std::string& iface) { |
| 184 | return !iface.empty() && iface != "invalid"; |
| 185 | } |
| 186 | |
| 187 | bool Offload::isValidIpv4Address(const std::string& repr) { |
| 188 | return validateIpAddressOrPrefix(repr, AF_INET, false); |
| 189 | } |
| 190 | |
| 191 | bool Offload::isValidIpv4Prefix(const std::string& repr) { |
| 192 | return validateIpAddressOrPrefix(repr, AF_INET, true); |
| 193 | } |
| 194 | |
| 195 | bool Offload::isValidIpv6Address(const std::string& repr) { |
| 196 | return validateIpAddressOrPrefix(repr, AF_INET6, false); |
| 197 | } |
| 198 | |
| 199 | bool Offload::isValidIpv6Prefix(const std::string& repr) { |
| 200 | return validateIpAddressOrPrefix(repr, AF_INET6, true); |
| 201 | } |
| 202 | |
| 203 | bool Offload::isValidIpAddress(const std::string& repr) { |
| 204 | return isValidIpv4Address(repr) || isValidIpv6Address(repr); |
| 205 | } |
| 206 | |
| 207 | bool Offload::isValidIpPrefix(const std::string& repr) { |
| 208 | return isValidIpv4Prefix(repr) || isValidIpv6Prefix(repr); |
| 209 | } |
| 210 | |
| 211 | // Refer to libnetdutils's IPAddress and IPPrefix classes. |
| 212 | // Can't use them directly because libnetdutils is not "vendor_available". |
| 213 | bool Offload::validateIpAddressOrPrefix(const std::string& repr, const int expectedFamily, |
| 214 | const bool isPrefix) { |
| 215 | const addrinfo hints = { |
| 216 | .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV, |
| 217 | }; |
| 218 | addrinfo* res; |
| 219 | size_t index = repr.find('/'); |
| 220 | if (isPrefix && index == std::string::npos) return false; |
| 221 | |
| 222 | // Parse the IP address. |
| 223 | const std::string ipAddress = isPrefix ? repr.substr(0, index) : repr; |
| 224 | const int ret = getaddrinfo(ipAddress.c_str(), nullptr, &hints, &res); |
| 225 | if (ret != 0) return false; |
| 226 | |
| 227 | // Check the address family. |
| 228 | int family = res[0].ai_family; |
| 229 | freeaddrinfo(res); |
| 230 | if (family != expectedFamily) return false; |
| 231 | if (!isPrefix) return true; |
| 232 | |
| 233 | // Parse the prefix length. |
| 234 | const char* prefixString = repr.c_str() + index + 1; |
| 235 | if (!isdigit(*prefixString)) return false; |
| 236 | char* endptr; |
| 237 | unsigned long prefixlen = strtoul(prefixString, &endptr, 10); |
| 238 | if (*endptr != '\0') return false; |
| 239 | |
| 240 | uint8_t maxlen = (family == AF_INET) ? 32 : 128; |
| 241 | if (prefixlen > maxlen) return false; |
| 242 | |
| 243 | return true; |
| 244 | } |
| 245 | |
| 246 | } // namespace aidl::android::hardware::tetheroffload::impl::example |