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