• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "jniClatCoordinator"
17 
18 #include <arpa/inet.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <linux/if_tun.h>
23 #include <linux/ioctl.h>
24 #include <log/log.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <net/if.h>
27 #include <spawn.h>
28 #include <sys/wait.h>
29 #include <string>
30 
31 #include <bpf/BpfMap.h>
32 #include <bpf/BpfUtils.h>
33 #include <bpf_shared.h>
34 #include <netjniutils/netjniutils.h>
35 #include <private/android_filesystem_config.h>
36 
37 #include "libclat/clatutils.h"
38 #include "nativehelper/scoped_utf_chars.h"
39 
40 // Sync from system/netd/include/netid_client.h
41 #define MARK_UNSET 0u
42 
43 // Sync from system/netd/server/NetdConstants.h
44 #define __INT_STRLEN(i) sizeof(#i)
45 #define _INT_STRLEN(i) __INT_STRLEN(i)
46 #define INT32_STRLEN _INT_STRLEN(INT32_MIN)
47 
48 #define DEVICEPREFIX "v4-"
49 
50 namespace android {
51 static const char* kClatdPath = "/apex/com.android.tethering/bin/for-system/clatd";
52 
throwIOException(JNIEnv * env,const char * msg,int error)53 static void throwIOException(JNIEnv* env, const char* msg, int error) {
54     jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, strerror(error));
55 }
56 
com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv * env,jobject clazz,jstring v4addr,jint prefixlen)57 jstring com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv* env,
58                                                                           jobject clazz,
59                                                                           jstring v4addr,
60                                                                           jint prefixlen) {
61     ScopedUtfChars address(env, v4addr);
62     in_addr ip;
63     if (inet_pton(AF_INET, address.c_str(), &ip) != 1) {
64         throwIOException(env, "invalid address", EINVAL);
65         return nullptr;
66     }
67 
68     // Pick an IPv4 address.
69     // TODO: this picks the address based on other addresses that are assigned to interfaces, but
70     // the address is only actually assigned to an interface once clatd starts up. So we could end
71     // up with two clatd instances with the same IPv4 address.
72     // Stop doing this and instead pick a free one from the kV4Addr pool.
73     in_addr v4 = {net::clat::selectIpv4Address(ip, prefixlen)};
74     if (v4.s_addr == INADDR_NONE) {
75         jniThrowExceptionFmt(env, "java/io/IOException", "No free IPv4 address in %s/%d",
76                              address.c_str(), prefixlen);
77         return nullptr;
78     }
79 
80     char addrstr[INET_ADDRSTRLEN];
81     if (!inet_ntop(AF_INET, (void*)&v4, addrstr, sizeof(addrstr))) {
82         throwIOException(env, "invalid address", EADDRNOTAVAIL);
83         return nullptr;
84     }
85     return env->NewStringUTF(addrstr);
86 }
87 
88 // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix.
com_android_server_connectivity_ClatCoordinator_generateIpv6Address(JNIEnv * env,jobject clazz,jstring ifaceStr,jstring v4Str,jstring prefix64Str)89 jstring com_android_server_connectivity_ClatCoordinator_generateIpv6Address(
90         JNIEnv* env, jobject clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str) {
91     ScopedUtfChars iface(env, ifaceStr);
92     ScopedUtfChars addr4(env, v4Str);
93     ScopedUtfChars prefix64(env, prefix64Str);
94 
95     if (iface.c_str() == nullptr) {
96         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid null interface name");
97         return nullptr;
98     }
99 
100     in_addr v4;
101     if (inet_pton(AF_INET, addr4.c_str(), &v4) != 1) {
102         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid clat v4 address %s",
103                              addr4.c_str());
104         return nullptr;
105     }
106 
107     in6_addr nat64Prefix;
108     if (inet_pton(AF_INET6, prefix64.c_str(), &nat64Prefix) != 1) {
109         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid prefix %s", prefix64.c_str());
110         return nullptr;
111     }
112 
113     in6_addr v6;
114     if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6)) {
115         jniThrowExceptionFmt(env, "java/io/IOException",
116                              "Unable to find global source address on %s for %s", iface.c_str(),
117                              prefix64.c_str());
118         return nullptr;
119     }
120 
121     char addrstr[INET6_ADDRSTRLEN];
122     if (!inet_ntop(AF_INET6, (void*)&v6, addrstr, sizeof(addrstr))) {
123         throwIOException(env, "invalid address", EADDRNOTAVAIL);
124         return nullptr;
125     }
126     return env->NewStringUTF(addrstr);
127 }
128 
com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv * env,jobject clazz,jstring tuniface)129 static jint com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv* env,
130                                                                                jobject clazz,
131                                                                                jstring tuniface) {
132     ScopedUtfChars v4interface(env, tuniface);
133 
134     // open the tun device in non blocking mode as required by clatd
135     jint fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
136     if (fd == -1) {
137         jniThrowExceptionFmt(env, "java/io/IOException", "open tun device failed (%s)",
138                              strerror(errno));
139         return -1;
140     }
141 
142     struct ifreq ifr = {
143             .ifr_flags = IFF_TUN,
144     };
145     strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name));
146 
147     if (ioctl(fd, TUNSETIFF, &ifr, sizeof(ifr))) {
148         close(fd);
149         jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(TUNSETIFF) failed (%s)",
150                              strerror(errno));
151         return -1;
152     }
153 
154     return fd;
155 }
156 
com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv * env,jobject clazz,jstring platSubnet,jint plat_suffix,jint mark)157 static jint com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv* env, jobject clazz,
158                                                                       jstring platSubnet,
159                                                                       jint plat_suffix, jint mark) {
160     ScopedUtfChars platSubnetStr(env, platSubnet);
161 
162     in6_addr plat_subnet;
163     if (inet_pton(AF_INET6, platSubnetStr.c_str(), &plat_subnet) != 1) {
164         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid plat prefix address %s",
165                              platSubnetStr.c_str());
166         return -1;
167     }
168 
169     int ret = net::clat::detect_mtu(&plat_subnet, plat_suffix, mark);
170     if (ret < 0) {
171         jniThrowExceptionFmt(env, "java/io/IOException", "detect mtu failed: %s", strerror(-ret));
172         return -1;
173     }
174 
175     return ret;
176 }
177 
com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv * env,jobject clazz)178 static jint com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv* env,
179                                                                               jobject clazz) {
180     // Will eventually be bound to htons(ETH_P_IPV6) protocol,
181     // but only after appropriate bpf filter is attached.
182     int sock = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
183     if (sock < 0) {
184         throwIOException(env, "packet socket failed", errno);
185         return -1;
186     }
187     return sock;
188 }
189 
com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv * env,jobject clazz,jint mark)190 static jint com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv* env,
191                                                                            jobject clazz,
192                                                                            jint mark) {
193     int sock = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_RAW);
194     if (sock < 0) {
195         throwIOException(env, "raw socket failed", errno);
196         return -1;
197     }
198 
199     // TODO: check the mark validation
200     if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
201         throwIOException(env, "could not set mark on raw socket", errno);
202         close(sock);
203         return -1;
204     }
205 
206     return sock;
207 }
208 
com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt(JNIEnv * env,jobject clazz,jobject javaFd,jstring addr6,jint ifindex)209 static void com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt(
210         JNIEnv* env, jobject clazz, jobject javaFd, jstring addr6, jint ifindex) {
211     int sock = netjniutils::GetNativeFileDescriptor(env, javaFd);
212     if (sock < 0) {
213         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
214         return;
215     }
216 
217     ScopedUtfChars addrStr(env, addr6);
218 
219     in6_addr addr;
220     if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) {
221         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s",
222                              addrStr.c_str());
223         return;
224     }
225 
226     struct ipv6_mreq mreq = {addr, ifindex};
227     int ret = setsockopt(sock, SOL_IPV6, IPV6_JOIN_ANYCAST, &mreq, sizeof(mreq));
228     if (ret) {
229         jniThrowExceptionFmt(env, "java/io/IOException", "setsockopt IPV6_JOIN_ANYCAST failed: %s",
230                              strerror(errno));
231         return;
232     }
233 }
234 
com_android_server_connectivity_ClatCoordinator_configurePacketSocket(JNIEnv * env,jobject clazz,jobject javaFd,jstring addr6,jint ifindex)235 static void com_android_server_connectivity_ClatCoordinator_configurePacketSocket(
236         JNIEnv* env, jobject clazz, jobject javaFd, jstring addr6, jint ifindex) {
237     ScopedUtfChars addrStr(env, addr6);
238 
239     int sock = netjniutils::GetNativeFileDescriptor(env, javaFd);
240     if (sock < 0) {
241         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
242         return;
243     }
244 
245     in6_addr addr;
246     if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) {
247         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s",
248                              addrStr.c_str());
249         return;
250     }
251 
252     int ret = net::clat::configure_packet_socket(sock, &addr, ifindex);
253     if (ret < 0) {
254         throwIOException(env, "configure packet socket failed", -ret);
255         return;
256     }
257 }
258 
com_android_server_connectivity_ClatCoordinator_startClatd(JNIEnv * env,jobject clazz,jobject tunJavaFd,jobject readSockJavaFd,jobject writeSockJavaFd,jstring iface,jstring pfx96,jstring v4,jstring v6)259 static jint com_android_server_connectivity_ClatCoordinator_startClatd(
260         JNIEnv* env, jobject clazz, jobject tunJavaFd, jobject readSockJavaFd,
261         jobject writeSockJavaFd, jstring iface, jstring pfx96, jstring v4, jstring v6) {
262     ScopedUtfChars ifaceStr(env, iface);
263     ScopedUtfChars pfx96Str(env, pfx96);
264     ScopedUtfChars v4Str(env, v4);
265     ScopedUtfChars v6Str(env, v6);
266 
267     int tunFd = netjniutils::GetNativeFileDescriptor(env, tunJavaFd);
268     if (tunFd < 0) {
269         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid tun file descriptor");
270         return -1;
271     }
272 
273     int readSock = netjniutils::GetNativeFileDescriptor(env, readSockJavaFd);
274     if (readSock < 0) {
275         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid read socket");
276         return -1;
277     }
278 
279     int writeSock = netjniutils::GetNativeFileDescriptor(env, writeSockJavaFd);
280     if (writeSock < 0) {
281         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid write socket");
282         return -1;
283     }
284 
285     // 1. these are the FD we'll pass to clatd on the cli, so need it as a string
286     char tunFdStr[INT32_STRLEN];
287     char sockReadStr[INT32_STRLEN];
288     char sockWriteStr[INT32_STRLEN];
289     snprintf(tunFdStr, sizeof(tunFdStr), "%d", tunFd);
290     snprintf(sockReadStr, sizeof(sockReadStr), "%d", readSock);
291     snprintf(sockWriteStr, sizeof(sockWriteStr), "%d", writeSock);
292 
293     // 2. we're going to use this as argv[0] to clatd to make ps output more useful
294     std::string progname("clatd-");
295     progname += ifaceStr.c_str();
296 
297     // clang-format off
298     const char* args[] = {progname.c_str(),
299                           "-i", ifaceStr.c_str(),
300                           "-p", pfx96Str.c_str(),
301                           "-4", v4Str.c_str(),
302                           "-6", v6Str.c_str(),
303                           "-t", tunFdStr,
304                           "-r", sockReadStr,
305                           "-w", sockWriteStr,
306                           nullptr};
307     // clang-format on
308 
309     // 3. register vfork requirement
310     posix_spawnattr_t attr;
311     if (int ret = posix_spawnattr_init(&attr)) {
312         throwIOException(env, "posix_spawnattr_init failed", ret);
313         return -1;
314     }
315 
316     // TODO: use android::base::ScopeGuard.
317     if (int ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK
318 #ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
319                                            | POSIX_SPAWN_CLOEXEC_DEFAULT
320 #endif
321                                            )) {
322         posix_spawnattr_destroy(&attr);
323         throwIOException(env, "posix_spawnattr_setflags failed", ret);
324         return -1;
325     }
326 
327     // 4. register dup2() action: this is what 'clears' the CLOEXEC flag
328     // on the tun fd that we want the child clatd process to inherit
329     // (this will happen after the vfork, and before the execve).
330     // Note that even though dup2(2) is a no-op if fd == new_fd but O_CLOEXEC flag will be removed.
331     // See implementation of bionic's posix_spawn_file_actions_adddup2().
332     posix_spawn_file_actions_t fa;
333     if (int ret = posix_spawn_file_actions_init(&fa)) {
334         posix_spawnattr_destroy(&attr);
335         throwIOException(env, "posix_spawn_file_actions_init failed", ret);
336         return -1;
337     }
338 
339     if (int ret = posix_spawn_file_actions_adddup2(&fa, tunFd, tunFd)) {
340         posix_spawnattr_destroy(&attr);
341         posix_spawn_file_actions_destroy(&fa);
342         throwIOException(env, "posix_spawn_file_actions_adddup2 for tun fd failed", ret);
343         return -1;
344     }
345     if (int ret = posix_spawn_file_actions_adddup2(&fa, readSock, readSock)) {
346         posix_spawnattr_destroy(&attr);
347         posix_spawn_file_actions_destroy(&fa);
348         throwIOException(env, "posix_spawn_file_actions_adddup2 for read socket failed", ret);
349         return -1;
350     }
351     if (int ret = posix_spawn_file_actions_adddup2(&fa, writeSock, writeSock)) {
352         posix_spawnattr_destroy(&attr);
353         posix_spawn_file_actions_destroy(&fa);
354         throwIOException(env, "posix_spawn_file_actions_adddup2 for write socket failed", ret);
355         return -1;
356     }
357 
358     // 5. actually perform vfork/dup2/execve
359     pid_t pid;
360     if (int ret = posix_spawn(&pid, kClatdPath, &fa, &attr, (char* const*)args, nullptr)) {
361         posix_spawnattr_destroy(&attr);
362         posix_spawn_file_actions_destroy(&fa);
363         throwIOException(env, "posix_spawn failed", ret);
364         return -1;
365     }
366 
367     posix_spawnattr_destroy(&attr);
368     posix_spawn_file_actions_destroy(&fa);
369 
370     return pid;
371 }
372 
373 // Stop clatd process. SIGTERM with timeout first, if fail, SIGKILL.
374 // See stopProcess() in system/netd/server/NetdConstants.cpp.
375 // TODO: have a function stopProcess(int pid, const char *name) in common location and call it.
376 static constexpr int WAITPID_ATTEMPTS = 50;
377 static constexpr int WAITPID_RETRY_INTERVAL_US = 100000;
378 
stopClatdProcess(int pid)379 static void stopClatdProcess(int pid) {
380     int err = kill(pid, SIGTERM);
381     if (err) {
382         err = errno;
383     }
384     if (err == ESRCH) {
385         ALOGE("clatd child process %d unexpectedly disappeared", pid);
386         return;
387     }
388     if (err) {
389         ALOGE("Error killing clatd child process %d: %s", pid, strerror(err));
390     }
391     int status = 0;
392     int ret = 0;
393     for (int count = 0; ret == 0 && count < WAITPID_ATTEMPTS; count++) {
394         usleep(WAITPID_RETRY_INTERVAL_US);
395         ret = waitpid(pid, &status, WNOHANG);
396     }
397     if (ret == 0) {
398         ALOGE("Failed to SIGTERM clatd pid=%d, try SIGKILL", pid);
399         // TODO: fix that kill failed or waitpid doesn't return.
400         kill(pid, SIGKILL);
401         ret = waitpid(pid, &status, 0);
402     }
403     if (ret == -1) {
404         ALOGE("Error waiting for clatd child process %d: %s", pid, strerror(errno));
405     } else {
406         ALOGD("clatd process %d terminated status=%d", pid, status);
407     }
408 }
409 
com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv * env,jobject clazz,jstring iface,jstring pfx96,jstring v4,jstring v6,jint pid)410 static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jobject clazz,
411                                                                       jstring iface, jstring pfx96,
412                                                                       jstring v4, jstring v6,
413                                                                       jint pid) {
414     ScopedUtfChars ifaceStr(env, iface);
415     ScopedUtfChars pfx96Str(env, pfx96);
416     ScopedUtfChars v4Str(env, v4);
417     ScopedUtfChars v6Str(env, v6);
418 
419     if (pid <= 0) {
420         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid pid");
421         return;
422     }
423 
424     stopClatdProcess(pid);
425 }
426 
com_android_server_connectivity_ClatCoordinator_tagSocketAsClat(JNIEnv * env,jobject clazz,jobject sockJavaFd)427 static jlong com_android_server_connectivity_ClatCoordinator_tagSocketAsClat(
428         JNIEnv* env, jobject clazz, jobject sockJavaFd) {
429     int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
430     if (sockFd < 0) {
431         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket file descriptor");
432         return -1;
433     }
434 
435     uint64_t sock_cookie = bpf::getSocketCookie(sockFd);
436     if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
437         throwIOException(env, "get socket cookie failed", errno);
438         return -1;
439     }
440 
441     bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
442     auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
443     if (!res.ok()) {
444         throwIOException(env, "failed to init the cookieTagMap", res.error().code());
445         return -1;
446     }
447 
448     // Tag raw socket with uid AID_CLAT and set tag as zero because tag is unused in bpf
449     // program for counting data usage in netd.c. Tagging socket is used to avoid counting
450     // duplicated clat traffic in bpf stat.
451     UidTagValue newKey = {.uid = (uint32_t)AID_CLAT, .tag = 0 /* unused */};
452     res = cookieTagMap.writeValue(sock_cookie, newKey, BPF_ANY);
453     if (!res.ok()) {
454         jniThrowExceptionFmt(env, "java/io/IOException", "Failed to tag the socket: %s, fd: %d",
455                              strerror(res.error().code()), cookieTagMap.getMap().get());
456         return -1;
457     }
458 
459     ALOGI("tag uid AID_CLAT to socket fd %d, cookie %" PRIu64 "", sockFd, sock_cookie);
460     return static_cast<jlong>(sock_cookie);
461 }
462 
com_android_server_connectivity_ClatCoordinator_untagSocket(JNIEnv * env,jobject clazz,jlong cookie)463 static void com_android_server_connectivity_ClatCoordinator_untagSocket(JNIEnv* env, jobject clazz,
464                                                                         jlong cookie) {
465     uint64_t sock_cookie = static_cast<uint64_t>(cookie);
466     if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
467         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket cookie");
468         return;
469     }
470 
471     // The reason that deleting entry from cookie tag map directly is that the tag socket destroy
472     // listener only monitors on group INET_TCP, INET_UDP, INET6_TCP, INET6_UDP. The other socket
473     // types, ex: raw, are not able to be removed automatically by the listener.
474     // See TrafficController::makeSkDestroyListener.
475     bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
476     auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
477     if (!res.ok()) {
478         throwIOException(env, "failed to init the cookieTagMap", res.error().code());
479         return;
480     }
481 
482     res = cookieTagMap.deleteValue(sock_cookie);
483     if (!res.ok()) {
484         jniThrowExceptionFmt(env, "java/io/IOException", "Failed to untag the socket: %s",
485                              strerror(res.error().code()));
486         return;
487     }
488 
489     ALOGI("untag socket cookie %" PRIu64 "", sock_cookie);
490     return;
491 }
492 
493 /*
494  * JNI registration.
495  */
496 static const JNINativeMethod gMethods[] = {
497         /* name, signature, funcPtr */
498         {"native_selectIpv4Address", "(Ljava/lang/String;I)Ljava/lang/String;",
499          (void*)com_android_server_connectivity_ClatCoordinator_selectIpv4Address},
500         {"native_generateIpv6Address",
501          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
502          (void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address},
503         {"native_createTunInterface", "(Ljava/lang/String;)I",
504          (void*)com_android_server_connectivity_ClatCoordinator_createTunInterface},
505         {"native_detectMtu", "(Ljava/lang/String;II)I",
506          (void*)com_android_server_connectivity_ClatCoordinator_detectMtu},
507         {"native_openPacketSocket", "()I",
508          (void*)com_android_server_connectivity_ClatCoordinator_openPacketSocket},
509         {"native_openRawSocket6", "(I)I",
510          (void*)com_android_server_connectivity_ClatCoordinator_openRawSocket6},
511         {"native_addAnycastSetsockopt", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
512          (void*)com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt},
513         {"native_configurePacketSocket", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
514          (void*)com_android_server_connectivity_ClatCoordinator_configurePacketSocket},
515         {"native_startClatd",
516          "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/lang/"
517          "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
518          (void*)com_android_server_connectivity_ClatCoordinator_startClatd},
519         {"native_stopClatd",
520          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
521          (void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
522         {"native_tagSocketAsClat", "(Ljava/io/FileDescriptor;)J",
523          (void*)com_android_server_connectivity_ClatCoordinator_tagSocketAsClat},
524         {"native_untagSocket", "(J)V",
525          (void*)com_android_server_connectivity_ClatCoordinator_untagSocket},
526 };
527 
register_com_android_server_connectivity_ClatCoordinator(JNIEnv * env)528 int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
529     return jniRegisterNativeMethods(env, "com/android/server/connectivity/ClatCoordinator",
530                                     gMethods, NELEM(gMethods));
531 }
532 
533 };  // namespace android
534