diff --git a/thread/service/java/com/android/server/thread/InfraInterfaceController.java b/thread/service/java/com/android/server/thread/InfraInterfaceController.java index be54cbc28f..e72c9eeb23 100644 --- a/thread/service/java/com/android/server/thread/InfraInterfaceController.java +++ b/thread/service/java/com/android/server/thread/InfraInterfaceController.java @@ -16,14 +16,30 @@ package com.android.server.thread; -import android.os.ParcelFileDescriptor; +import static android.system.OsConstants.IPPROTO_IPV6; +import static android.system.OsConstants.IPPROTO_RAW; +import static android.system.OsConstants.IPV6_CHECKSUM; +import static android.system.OsConstants.IPV6_MULTICAST_HOPS; +import static android.system.OsConstants.IPV6_RECVHOPLIMIT; +import static android.system.OsConstants.IPV6_RECVPKTINFO; +import static android.system.OsConstants.IPV6_UNICAST_HOPS; +import android.net.util.SocketUtils; +import android.os.ParcelFileDescriptor; +import android.system.ErrnoException; +import android.system.Os; + +import java.io.FileDescriptor; import java.io.IOException; /** Controller for the infrastructure network interface. */ public class InfraInterfaceController { private static final String TAG = "InfraIfController"; + private static final int ENABLE = 1; + private static final int IPV6_CHECKSUM_OFFSET = 2; + private static final int HOP_LIMIT = 255; + static { System.loadLibrary("service-thread-jni"); } @@ -37,8 +53,21 @@ public class InfraInterfaceController { * @throws IOException when fails to create the socket. */ public ParcelFileDescriptor createIcmp6Socket(String infraInterfaceName) throws IOException { - return ParcelFileDescriptor.adoptFd(nativeCreateIcmp6Socket(infraInterfaceName)); + ParcelFileDescriptor parcelFd = + ParcelFileDescriptor.adoptFd(nativeCreateFilteredIcmp6Socket()); + FileDescriptor fd = parcelFd.getFileDescriptor(); + try { + Os.setsockoptInt(fd, IPPROTO_RAW, IPV6_CHECKSUM, IPV6_CHECKSUM_OFFSET); + Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, ENABLE); + Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, ENABLE); + Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, HOP_LIMIT); + Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, HOP_LIMIT); + SocketUtils.bindSocketToInterface(fd, infraInterfaceName); + } catch (ErrnoException e) { + throw new IOException("Failed to setsockopt for the ICMPv6 socket", e); + } + return parcelFd; } - private static native int nativeCreateIcmp6Socket(String interfaceName) throws IOException; + private static native int nativeCreateFilteredIcmp6Socket() throws IOException; } diff --git a/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp b/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp index 5d24eabd6b..1f260f236e 100644 --- a/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp +++ b/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp @@ -42,15 +42,8 @@ namespace android { static jint -com_android_server_thread_InfraInterfaceController_createIcmp6Socket(JNIEnv *env, jobject clazz, - jstring interfaceName) { - ScopedUtfChars ifName(env, interfaceName); - - struct icmp6_filter filter; - constexpr int kEnable = 1; - constexpr int kIpv6ChecksumOffset = 2; - constexpr int kHopLimit = 255; - +com_android_server_thread_InfraInterfaceController_createFilteredIcmp6Socket(JNIEnv *env, + jobject clazz) { // Initializes the ICMPv6 socket. int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock == -1) { @@ -59,6 +52,7 @@ com_android_server_thread_InfraInterfaceController_createIcmp6Socket(JNIEnv *env return -1; } + struct icmp6_filter filter; // Only accept Router Advertisements, Router Solicitations and Neighbor // Advertisements. ICMP6_FILTER_SETBLOCKALL(&filter); @@ -73,53 +67,6 @@ com_android_server_thread_InfraInterfaceController_createIcmp6Socket(JNIEnv *env return -1; } - // We want a source address and interface index. - - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kEnable, sizeof(kEnable)) != 0) { - jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_RECVPKTINFO (%s)", - strerror(errno)); - close(sock); - return -1; - } - - if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &kIpv6ChecksumOffset, - sizeof(kIpv6ChecksumOffset)) != 0) { - jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_CHECKSUM (%s)", - strerror(errno)); - close(sock); - return -1; - } - - // We need to be able to reject RAs arriving from off-link. - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kEnable, sizeof(kEnable)) != 0) { - jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_RECVHOPLIMIT (%s)", - strerror(errno)); - close(sock); - return -1; - } - - if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kHopLimit, sizeof(kHopLimit)) != 0) { - jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_UNICAST_HOPS (%s)", - strerror(errno)); - close(sock); - return -1; - } - - if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kHopLimit, sizeof(kHopLimit)) != 0) { - jniThrowExceptionFmt(env, "java/io/IOException", - "failed to create the setsockopt IPV6_MULTICAST_HOPS (%s)", - strerror(errno)); - close(sock); - return -1; - } - - if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifName.c_str(), strlen(ifName.c_str()))) { - jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt SO_BINDTODEVICE (%s)", - strerror(errno)); - close(sock); - return -1; - } - return sock; } @@ -129,8 +76,8 @@ com_android_server_thread_InfraInterfaceController_createIcmp6Socket(JNIEnv *env static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - {"nativeCreateIcmp6Socket", "(Ljava/lang/String;)I", - (void *)com_android_server_thread_InfraInterfaceController_createIcmp6Socket}, + {"nativeCreateFilteredIcmp6Socket", "()I", + (void *)com_android_server_thread_InfraInterfaceController_createFilteredIcmp6Socket}, }; int register_com_android_server_thread_InfraInterfaceController(JNIEnv *env) {