• 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_packet.h>
23 #include <linux/if_tun.h>
24 #include <linux/ioctl.h>
25 #include <log/log.h>
26 #include <nativehelper/JNIHelp.h>
27 #include <net/if.h>
28 #include <spawn.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/xattr.h>
33 #include <string>
34 #include <unistd.h>
35 
36 #include <android-modules-utils/sdk_level.h>
37 #include <bpf/BpfMap.h>
38 #include <bpf/BpfUtils.h>
39 #include <netjniutils/netjniutils.h>
40 #include <private/android_filesystem_config.h>
41 
42 #include "libclat/clatutils.h"
43 #include "nativehelper/scoped_utf_chars.h"
44 
45 // Sync from system/netd/server/NetdConstants.h
46 #define __INT_STRLEN(i) sizeof(#i)
47 #define _INT_STRLEN(i) __INT_STRLEN(i)
48 #define INT32_STRLEN _INT_STRLEN(INT32_MIN)
49 
50 #define DEVICEPREFIX "v4-"
51 
52 namespace android {
53 
54 static bool fatal = false;
55 
56 #define ALOGF(s ...) do { ALOGE(s); fatal = true; } while(0)
57 
58 enum verify { VERIFY_DIR, VERIFY_BIN, VERIFY_PROG, VERIFY_MAP_RO, VERIFY_MAP_RW };
59 
verifyPerms(const char * const path,const mode_t mode,const uid_t uid,const gid_t gid,const char * const ctxt,const verify vtype)60 static void verifyPerms(const char * const path,
61                         const mode_t mode, const uid_t uid, const gid_t gid,
62                         const char * const ctxt,
63                         const verify vtype) {
64     struct stat s = {};
65 
66     if (lstat(path, &s)) ALOGF("lstat '%s' errno=%d", path, errno);
67     if (s.st_mode != mode) ALOGF("'%s' mode is 0%o != 0%o", path, s.st_mode, mode);
68     if (s.st_uid != uid) ALOGF("'%s' uid is %d != %d", path, s.st_uid, uid);
69     if (s.st_gid != gid) ALOGF("'%s' gid is %d != %d", path, s.st_gid, gid);
70 
71     char b[255] = {};
72     int v = lgetxattr(path, "security.selinux", &b, sizeof(b));
73     if (v < 0) ALOGF("lgetxattr '%s' errno=%d", path, errno);
74     if (strncmp(ctxt, b, sizeof(b))) ALOGF("context of '%s' is '%s' != '%s'", path, b, ctxt);
75 
76     int fd = -1;
77 
78     switch (vtype) {
79       case VERIFY_DIR: return;
80       case VERIFY_BIN: return;
81       case VERIFY_PROG:   fd = bpf::retrieveProgram(path); break;
82       case VERIFY_MAP_RO: fd = bpf::mapRetrieveRO(path); break;
83       case VERIFY_MAP_RW: fd = bpf::mapRetrieveRW(path); break;
84     }
85 
86     if (fd < 0) ALOGF("bpf_obj_get '%s' failed, errno=%d", path, errno);
87 
88     if (fd >= 0) close(fd);
89 }
90 
91 #undef ALOGF
92 
isGsiImage()93 bool isGsiImage() {
94     // this implementation matches 2 other places in the codebase (same function name too)
95     return !access("/system/system_ext/etc/init/init.gsi.rc", F_OK);
96 }
97 
98 static const char* kClatdDir = "/apex/com.android.tethering/bin/for-system";
99 static const char* kClatdBin = "/apex/com.android.tethering/bin/for-system/clatd";
100 
101 #define V(path, md, uid, gid, ctx, vtype) \
102     verifyPerms((path), (md), AID_ ## uid, AID_ ## gid, "u:object_r:" ctx ":s0", VERIFY_ ## vtype)
103 
verifyClatPerms()104 static void verifyClatPerms() {
105     // We might run as part of tests instead of as part of system server
106     if (getuid() != AID_SYSTEM) return;
107 
108     // First verify the clatd directory and binary,
109     // since this is built into the apex file system image,
110     // failures here are 99% likely to be build problems.
111     V(kClatdDir, S_IFDIR|0750, ROOT, SYSTEM, "system_file", DIR);
112     V(kClatdBin, S_IFREG|S_ISUID|S_ISGID|0755, CLAT, CLAT, "clatd_exec", BIN);
113 
114     // Move on to verifying that the bpf programs and maps are as expected.
115     // This relies on the kernel and bpfloader.
116 
117     // Clat BPF was only mainlined during T.
118     if (!modules::sdklevel::IsAtLeastT()) return;
119 
120     V("/sys/fs/bpf", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf", DIR);
121     V("/sys/fs/bpf/net_shared", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf_net_shared", DIR);
122 
123     // pre-U we do not have selinux privs to getattr on bpf maps/progs
124     // so while the below *should* be as listed, we have no way to actually verify
125     if (!modules::sdklevel::IsAtLeastU()) return;
126 
127 #define V2(path, md, vtype) \
128     V("/sys/fs/bpf/net_shared/" path, (md), ROOT, SYSTEM, "fs_bpf_net_shared", vtype)
129 
130     V2("prog_clatd_schedcls_egress4_clat_rawip",  S_IFREG|0440, PROG);
131     V2("prog_clatd_schedcls_ingress6_clat_rawip", S_IFREG|0440, PROG);
132     V2("prog_clatd_schedcls_ingress6_clat_ether", S_IFREG|0440, PROG);
133     V2("map_clatd_clat_egress4_map",              S_IFREG|0660, MAP_RW);
134     V2("map_clatd_clat_ingress6_map",             S_IFREG|0660, MAP_RW);
135 
136 #undef V2
137 
138     // HACK: Some old vendor kernels lack ~5.10 backport of 'bpffs selinux genfscon' support.
139     // This is *NOT* supported, but let's allow, at least for now, U+ GSI to boot on them.
140     // (without this hack pixel5 R vendor + U gsi breaks)
141     if (isGsiImage() && !bpf::isAtLeastKernelVersion(5, 10, 0)) {
142         ALOGE("GSI with *BAD* pre-5.10 kernel lacking bpffs selinux genfscon support.");
143         return;
144     }
145 
146     if (fatal) abort();
147 }
148 
149 #undef V
150 
throwIOException(JNIEnv * env,const char * msg,int error)151 static void throwIOException(JNIEnv* env, const char* msg, int error) {
152     jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, strerror(error));
153 }
154 
com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv * env,jclass clazz,jstring v4addr,jint prefixlen)155 jstring com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv* env,
156                                                                           jclass clazz,
157                                                                           jstring v4addr,
158                                                                           jint prefixlen) {
159     ScopedUtfChars address(env, v4addr);
160     in_addr ip;
161     if (inet_pton(AF_INET, address.c_str(), &ip) != 1) {
162         throwIOException(env, "invalid address", EINVAL);
163         return nullptr;
164     }
165 
166     // Pick an IPv4 address.
167     // TODO: this picks the address based on other addresses that are assigned to interfaces, but
168     // the address is only actually assigned to an interface once clatd starts up. So we could end
169     // up with two clatd instances with the same IPv4 address.
170     // Stop doing this and instead pick a free one from the kV4Addr pool.
171     in_addr v4 = {net::clat::selectIpv4Address(ip, prefixlen)};
172     if (v4.s_addr == INADDR_NONE) {
173         jniThrowExceptionFmt(env, "java/io/IOException", "No free IPv4 address in %s/%d",
174                              address.c_str(), prefixlen);
175         return nullptr;
176     }
177 
178     char addrstr[INET_ADDRSTRLEN];
179     if (!inet_ntop(AF_INET, (void*)&v4, addrstr, sizeof(addrstr))) {
180         throwIOException(env, "invalid address", EADDRNOTAVAIL);
181         return nullptr;
182     }
183     return env->NewStringUTF(addrstr);
184 }
185 
186 // 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,jclass clazz,jstring ifaceStr,jstring v4Str,jstring prefix64Str,jint mark)187 jstring com_android_server_connectivity_ClatCoordinator_generateIpv6Address(
188         JNIEnv* env, jclass clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str,
189         jint mark) {
190     ScopedUtfChars iface(env, ifaceStr);
191     ScopedUtfChars addr4(env, v4Str);
192     ScopedUtfChars prefix64(env, prefix64Str);
193 
194     if (iface.c_str() == nullptr) {
195         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid null interface name");
196         return nullptr;
197     }
198 
199     in_addr v4;
200     if (inet_pton(AF_INET, addr4.c_str(), &v4) != 1) {
201         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid clat v4 address %s",
202                              addr4.c_str());
203         return nullptr;
204     }
205 
206     in6_addr nat64Prefix;
207     if (inet_pton(AF_INET6, prefix64.c_str(), &nat64Prefix) != 1) {
208         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid prefix %s", prefix64.c_str());
209         return nullptr;
210     }
211 
212     in6_addr v6;
213     if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6, mark)) {
214         jniThrowExceptionFmt(env, "java/io/IOException",
215                              "Unable to find global source address on %s for %s", iface.c_str(),
216                              prefix64.c_str());
217         return nullptr;
218     }
219 
220     char addrstr[INET6_ADDRSTRLEN];
221     if (!inet_ntop(AF_INET6, (void*)&v6, addrstr, sizeof(addrstr))) {
222         throwIOException(env, "invalid address", EADDRNOTAVAIL);
223         return nullptr;
224     }
225     return env->NewStringUTF(addrstr);
226 }
227 
com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv * env,jclass clazz,jstring tuniface)228 static jint com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv* env,
229                                                                                jclass clazz,
230                                                                                jstring tuniface) {
231     ScopedUtfChars v4interface(env, tuniface);
232 
233     // open the tun device in non blocking mode as required by clatd
234     jint fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
235     if (fd == -1) {
236         jniThrowExceptionFmt(env, "java/io/IOException", "open tun device failed (%s)",
237                              strerror(errno));
238         return -1;
239     }
240 
241     struct ifreq ifr = {
242             .ifr_flags = static_cast<short>(IFF_TUN | IFF_TUN_EXCL),
243     };
244     strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name));
245 
246     if (ioctl(fd, TUNSETIFF, &ifr, sizeof(ifr))) {
247         close(fd);
248         jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(TUNSETIFF) failed (%s)",
249                              strerror(errno));
250         return -1;
251     }
252 
253     return fd;
254 }
255 
com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv * env,jclass clazz,jstring platSubnet,jint plat_suffix,jint mark)256 static jint com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv* env, jclass clazz,
257                                                                       jstring platSubnet,
258                                                                       jint plat_suffix, jint mark) {
259     ScopedUtfChars platSubnetStr(env, platSubnet);
260 
261     in6_addr plat_subnet;
262     if (inet_pton(AF_INET6, platSubnetStr.c_str(), &plat_subnet) != 1) {
263         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid plat prefix address %s",
264                              platSubnetStr.c_str());
265         return -1;
266     }
267 
268     int ret = net::clat::detect_mtu(&plat_subnet, plat_suffix, mark);
269     if (ret < 0) {
270         jniThrowExceptionFmt(env, "java/io/IOException", "detect mtu failed: %s", strerror(-ret));
271         return -1;
272     }
273 
274     return ret;
275 }
276 
com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv * env,jclass clazz)277 static jint com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv* env,
278                                                                               jclass clazz) {
279     // Will eventually be bound to htons(ETH_P_IPV6) protocol,
280     // but only after appropriate bpf filter is attached.
281     const int sock = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0);
282     if (sock < 0) {
283         throwIOException(env, "packet socket failed", errno);
284         return -1;
285     }
286     const int on = 1;
287     // enable tpacket_auxdata cmsg delivery, which includes L2 header length
288     if (setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on))) {
289         throwIOException(env, "packet socket auxdata enablement failed", errno);
290         close(sock);
291         return -1;
292     }
293     // needed for virtio_net_hdr prepending, which includes checksum metadata
294     if (setsockopt(sock, SOL_PACKET, PACKET_VNET_HDR, &on, sizeof(on))) {
295         throwIOException(env, "packet socket vnet_hdr enablement failed", errno);
296         close(sock);
297         return -1;
298     }
299     return sock;
300 }
301 
com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv * env,jclass clazz,jint mark)302 static jint com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv* env,
303                                                                            jclass clazz,
304                                                                            jint mark) {
305     int sock = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_RAW);
306     if (sock < 0) {
307         throwIOException(env, "raw socket failed", errno);
308         return -1;
309     }
310 
311     // TODO: check the mark validation
312     if (setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
313         throwIOException(env, "could not set mark on raw socket", errno);
314         close(sock);
315         return -1;
316     }
317 
318     return sock;
319 }
320 
com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt(JNIEnv * env,jclass clazz,jobject javaFd,jstring addr6,jint ifindex)321 static void com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt(
322         JNIEnv* env, jclass clazz, jobject javaFd, jstring addr6, jint ifindex) {
323     int sock = netjniutils::GetNativeFileDescriptor(env, javaFd);
324     if (sock < 0) {
325         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
326         return;
327     }
328 
329     ScopedUtfChars addrStr(env, addr6);
330 
331     in6_addr addr;
332     if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) {
333         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s",
334                              addrStr.c_str());
335         return;
336     }
337 
338     struct ipv6_mreq mreq = {addr, ifindex};
339     int ret = setsockopt(sock, SOL_IPV6, IPV6_JOIN_ANYCAST, &mreq, sizeof(mreq));
340     if (ret) {
341         jniThrowExceptionFmt(env, "java/io/IOException", "setsockopt IPV6_JOIN_ANYCAST failed: %s",
342                              strerror(errno));
343         return;
344     }
345 }
346 
com_android_server_connectivity_ClatCoordinator_configurePacketSocket(JNIEnv * env,jclass clazz,jobject javaFd,jstring addr6,jint ifindex)347 static void com_android_server_connectivity_ClatCoordinator_configurePacketSocket(
348         JNIEnv* env, jclass clazz, jobject javaFd, jstring addr6, jint ifindex) {
349     ScopedUtfChars addrStr(env, addr6);
350 
351     int sock = netjniutils::GetNativeFileDescriptor(env, javaFd);
352     if (sock < 0) {
353         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
354         return;
355     }
356 
357     in6_addr addr;
358     if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) {
359         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s",
360                              addrStr.c_str());
361         return;
362     }
363 
364     int ret = net::clat::configure_packet_socket(sock, &addr, ifindex);
365     if (ret < 0) {
366         throwIOException(env, "configure packet socket failed", -ret);
367         return;
368     }
369 }
370 
com_android_server_connectivity_ClatCoordinator_startClatd(JNIEnv * env,jclass clazz,jobject tunJavaFd,jobject readSockJavaFd,jobject writeSockJavaFd,jstring iface,jstring pfx96,jstring v4,jstring v6)371 static jint com_android_server_connectivity_ClatCoordinator_startClatd(
372         JNIEnv* env, jclass clazz, jobject tunJavaFd, jobject readSockJavaFd,
373         jobject writeSockJavaFd, jstring iface, jstring pfx96, jstring v4, jstring v6) {
374     ScopedUtfChars ifaceStr(env, iface);
375     ScopedUtfChars pfx96Str(env, pfx96);
376     ScopedUtfChars v4Str(env, v4);
377     ScopedUtfChars v6Str(env, v6);
378 
379     int tunFd = netjniutils::GetNativeFileDescriptor(env, tunJavaFd);
380     if (tunFd < 0) {
381         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid tun file descriptor");
382         return -1;
383     }
384 
385     int readSock = netjniutils::GetNativeFileDescriptor(env, readSockJavaFd);
386     if (readSock < 0) {
387         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid read socket");
388         return -1;
389     }
390 
391     int writeSock = netjniutils::GetNativeFileDescriptor(env, writeSockJavaFd);
392     if (writeSock < 0) {
393         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid write socket");
394         return -1;
395     }
396 
397     // 1. these are the FD we'll pass to clatd on the cli, so need it as a string
398     char tunFdStr[INT32_STRLEN];
399     char sockReadStr[INT32_STRLEN];
400     char sockWriteStr[INT32_STRLEN];
401     snprintf(tunFdStr, sizeof(tunFdStr), "%d", tunFd);
402     snprintf(sockReadStr, sizeof(sockReadStr), "%d", readSock);
403     snprintf(sockWriteStr, sizeof(sockWriteStr), "%d", writeSock);
404 
405     // 2. we're going to use this as argv[0] to clatd to make ps output more useful
406     std::string progname("clatd-");
407     progname += ifaceStr.c_str();
408 
409     // clang-format off
410     const char* args[] = {progname.c_str(),
411                           "-i", ifaceStr.c_str(),
412                           "-p", pfx96Str.c_str(),
413                           "-4", v4Str.c_str(),
414                           "-6", v6Str.c_str(),
415                           "-t", tunFdStr,
416                           "-r", sockReadStr,
417                           "-w", sockWriteStr,
418                           nullptr};
419     // clang-format on
420 
421     // 3. register vfork requirement
422     posix_spawnattr_t attr;
423     if (int ret = posix_spawnattr_init(&attr)) {
424         throwIOException(env, "posix_spawnattr_init failed", ret);
425         return -1;
426     }
427 
428     // TODO: use android::base::ScopeGuard.
429     if (int ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK
430                                            | POSIX_SPAWN_CLOEXEC_DEFAULT)) {
431         posix_spawnattr_destroy(&attr);
432         throwIOException(env, "posix_spawnattr_setflags failed", ret);
433         return -1;
434     }
435 
436     // 4. register dup2() action: this is what 'clears' the CLOEXEC flag
437     // on the tun fd that we want the child clatd process to inherit
438     // (this will happen after the vfork, and before the execve).
439     // Note that even though dup2(2) is a no-op if fd == new_fd but O_CLOEXEC flag will be removed.
440     // See implementation of bionic's posix_spawn_file_actions_adddup2().
441     posix_spawn_file_actions_t fa;
442     if (int ret = posix_spawn_file_actions_init(&fa)) {
443         posix_spawnattr_destroy(&attr);
444         throwIOException(env, "posix_spawn_file_actions_init failed", ret);
445         return -1;
446     }
447 
448     if (int ret = posix_spawn_file_actions_adddup2(&fa, tunFd, tunFd)) {
449         posix_spawnattr_destroy(&attr);
450         posix_spawn_file_actions_destroy(&fa);
451         throwIOException(env, "posix_spawn_file_actions_adddup2 for tun fd failed", ret);
452         return -1;
453     }
454     if (int ret = posix_spawn_file_actions_adddup2(&fa, readSock, readSock)) {
455         posix_spawnattr_destroy(&attr);
456         posix_spawn_file_actions_destroy(&fa);
457         throwIOException(env, "posix_spawn_file_actions_adddup2 for read socket failed", ret);
458         return -1;
459     }
460     if (int ret = posix_spawn_file_actions_adddup2(&fa, writeSock, writeSock)) {
461         posix_spawnattr_destroy(&attr);
462         posix_spawn_file_actions_destroy(&fa);
463         throwIOException(env, "posix_spawn_file_actions_adddup2 for write socket failed", ret);
464         return -1;
465     }
466 
467     // 5. actually perform vfork/dup2/execve
468     pid_t pid;
469     if (int ret = posix_spawn(&pid, kClatdBin, &fa, &attr, (char* const*)args, nullptr)) {
470         posix_spawnattr_destroy(&attr);
471         posix_spawn_file_actions_destroy(&fa);
472         throwIOException(env, "posix_spawn failed", ret);
473         return -1;
474     }
475 
476     posix_spawnattr_destroy(&attr);
477     posix_spawn_file_actions_destroy(&fa);
478 
479     return pid;
480 }
481 
482 // Stop clatd process. SIGTERM with timeout first, if fail, SIGKILL.
483 // See stopProcess() in system/netd/server/NetdConstants.cpp.
484 // TODO: have a function stopProcess(int pid, const char *name) in common location and call it.
485 static constexpr int WAITPID_ATTEMPTS = 50;
486 static constexpr int WAITPID_RETRY_INTERVAL_US = 100000;
487 
stopClatdProcess(int pid)488 static void stopClatdProcess(int pid) {
489     int err = kill(pid, SIGTERM);
490     if (err) {
491         err = errno;
492     }
493     if (err == ESRCH) {
494         ALOGE("clatd child process %d unexpectedly disappeared", pid);
495         return;
496     }
497     if (err) {
498         ALOGE("Error killing clatd child process %d: %s", pid, strerror(err));
499     }
500     int status = 0;
501     int ret = 0;
502     for (int count = 0; ret == 0 && count < WAITPID_ATTEMPTS; count++) {
503         usleep(WAITPID_RETRY_INTERVAL_US);
504         ret = waitpid(pid, &status, WNOHANG);
505     }
506     if (ret == 0) {
507         ALOGE("Failed to SIGTERM clatd pid=%d, try SIGKILL", pid);
508         // TODO: fix that kill failed or waitpid doesn't return.
509         if (kill(pid, SIGKILL)) {
510             ALOGE("Failed to SIGKILL clatd pid=%d: %s", pid, strerror(errno));
511         }
512         ret = waitpid(pid, &status, 0);
513     }
514     if (ret == -1) {
515         ALOGE("Error waiting for clatd child process %d: %s", pid, strerror(errno));
516     } else {
517         ALOGD("clatd process %d terminated status=%d", pid, status);
518     }
519 }
520 
com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv * env,jclass clazz,jstring iface,jstring pfx96,jstring v4,jstring v6,jint pid)521 static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jclass clazz,
522                                                                       jstring iface, jstring pfx96,
523                                                                       jstring v4, jstring v6,
524                                                                       jint pid) {
525     ScopedUtfChars ifaceStr(env, iface);
526     ScopedUtfChars pfx96Str(env, pfx96);
527     ScopedUtfChars v4Str(env, v4);
528     ScopedUtfChars v6Str(env, v6);
529 
530     if (pid <= 0) {
531         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid pid");
532         return;
533     }
534 
535     stopClatdProcess(pid);
536 }
537 
com_android_server_connectivity_ClatCoordinator_getSocketCookie(JNIEnv * env,jclass clazz,jobject sockJavaFd)538 static jlong com_android_server_connectivity_ClatCoordinator_getSocketCookie(
539         JNIEnv* env, jclass clazz, jobject sockJavaFd) {
540     int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
541     if (sockFd < 0) {
542         jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket file descriptor");
543         return -1;
544     }
545 
546     uint64_t sock_cookie = bpf::getSocketCookie(sockFd);
547     if (!sock_cookie) {
548         throwIOException(env, "get socket cookie failed", errno);
549         return -1;
550     }
551 
552     ALOGI("Get cookie %" PRIu64 " for socket fd %d", sock_cookie, sockFd);
553     return static_cast<jlong>(sock_cookie);
554 }
555 
556 /*
557  * JNI registration.
558  */
559 static const JNINativeMethod gMethods[] = {
560         /* name, signature, funcPtr */
561         {"native_selectIpv4Address", "(Ljava/lang/String;I)Ljava/lang/String;",
562          (void*)com_android_server_connectivity_ClatCoordinator_selectIpv4Address},
563         {"native_generateIpv6Address",
564          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;",
565          (void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address},
566         {"native_createTunInterface", "(Ljava/lang/String;)I",
567          (void*)com_android_server_connectivity_ClatCoordinator_createTunInterface},
568         {"native_detectMtu", "(Ljava/lang/String;II)I",
569          (void*)com_android_server_connectivity_ClatCoordinator_detectMtu},
570         {"native_openPacketSocket", "()I",
571          (void*)com_android_server_connectivity_ClatCoordinator_openPacketSocket},
572         {"native_openRawSocket6", "(I)I",
573          (void*)com_android_server_connectivity_ClatCoordinator_openRawSocket6},
574         {"native_addAnycastSetsockopt", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
575          (void*)com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt},
576         {"native_configurePacketSocket", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
577          (void*)com_android_server_connectivity_ClatCoordinator_configurePacketSocket},
578         {"native_startClatd",
579          "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/lang/"
580          "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
581          (void*)com_android_server_connectivity_ClatCoordinator_startClatd},
582         {"native_stopClatd",
583          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
584          (void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
585         {"native_getSocketCookie", "(Ljava/io/FileDescriptor;)J",
586          (void*)com_android_server_connectivity_ClatCoordinator_getSocketCookie},
587 };
588 
register_com_android_server_connectivity_ClatCoordinator(JNIEnv * env)589 int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
590     verifyClatPerms();
591     return jniRegisterNativeMethods(env,
592             "android/net/connectivity/com/android/server/connectivity/ClatCoordinator",
593             gMethods, NELEM(gMethods));
594 }
595 
596 };  // namespace android
597