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 addDownstream(const std::string & in_iface,const std::string & in_prefix)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 getForwardedStats(const std::string & in_upstream,ForwardedStats * _aidl_return)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 initOffload(const ndk::ScopedFileDescriptor & in_fd1,const ndk::ScopedFileDescriptor & in_fd2,const std::shared_ptr<ITetheringOffloadCallback> & in_cb)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 removeDownstream(const std::string & in_iface,const std::string & in_prefix)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 setDataWarningAndLimit(const std::string & in_upstream,int64_t in_warningBytes,int64_t in_limitBytes)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 setLocalPrefixes(const std::vector<std::string> & in_prefixes)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 setUpstreamParameters(const std::string & in_iface,const std::string & in_v4Addr,const std::string & in_v4Gw,const std::vector<std::string> & in_v6Gws)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 stopOffload()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 isInitialized()179 bool Offload::isInitialized() { 180 return (mInitialized == true); 181 } 182 isValidInterface(const std::string & iface)183 bool Offload::isValidInterface(const std::string& iface) { 184 return !iface.empty() && iface != "invalid"; 185 } 186 isValidIpv4Address(const std::string & repr)187 bool Offload::isValidIpv4Address(const std::string& repr) { 188 return validateIpAddressOrPrefix(repr, AF_INET, false); 189 } 190 isValidIpv4Prefix(const std::string & repr)191 bool Offload::isValidIpv4Prefix(const std::string& repr) { 192 return validateIpAddressOrPrefix(repr, AF_INET, true); 193 } 194 isValidIpv6Address(const std::string & repr)195 bool Offload::isValidIpv6Address(const std::string& repr) { 196 return validateIpAddressOrPrefix(repr, AF_INET6, false); 197 } 198 isValidIpv6Prefix(const std::string & repr)199 bool Offload::isValidIpv6Prefix(const std::string& repr) { 200 return validateIpAddressOrPrefix(repr, AF_INET6, true); 201 } 202 isValidIpAddress(const std::string & repr)203 bool Offload::isValidIpAddress(const std::string& repr) { 204 return isValidIpv4Address(repr) || isValidIpv6Address(repr); 205 } 206 isValidIpPrefix(const std::string & repr)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". validateIpAddressOrPrefix(const std::string & repr,const int expectedFamily,const bool isPrefix)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 247