Move TestNetworkService JNI into ServiceConnectivityJni

Test: builds and boots
Change-Id: Ia15833a163604ddbbb9527dff59174f2643daa61
diff --git a/staticlibs/device/com/android/net/module/util/ServiceConnectivityJni.java b/staticlibs/device/com/android/net/module/util/ServiceConnectivityJni.java
index f4529bd..3aaccaf 100644
--- a/staticlibs/device/com/android/net/module/util/ServiceConnectivityJni.java
+++ b/staticlibs/device/com/android/net/module/util/ServiceConnectivityJni.java
@@ -16,6 +16,8 @@
 
 package com.android.net.module.util;
 
+import android.annotation.NonNull;
+
 import java.io.IOException;
 
 /**
@@ -47,4 +49,15 @@
      * @throws IOException if setting expiration time is failed.
      */
     public static native void setTime(int fd, long timeMs) throws IOException;
+
+    /** Create tun/tap interface */
+    public static native int nativeCreateTunTap(boolean isTun, boolean hasCarrier,
+            boolean setIffMulticast, @NonNull String iface);
+
+    /** Enable carrier on tun/tap interface */
+    public static native void nativeSetTunTapCarrierEnabled(@NonNull String iface, int tunFd,
+            boolean enabled);
+
+    /** Bring up tun/tap interface */
+    public static native void nativeBringUpInterface(String iface);
 }
diff --git a/staticlibs/native/timerfdutils/Android.bp b/staticlibs/native/timerfdutils/Android.bp
index 1f5542c..b9298ae 100644
--- a/staticlibs/native/timerfdutils/Android.bp
+++ b/staticlibs/native/timerfdutils/Android.bp
@@ -23,12 +23,15 @@
         "com_android_net_module_util_ServiceConnectivityJni.cpp",
     ],
     header_libs: [
+        "bpf_headers",
         "jni_headers",
+        "libbase_headers",
     ],
     shared_libs: [
         "liblog",
         "libnativehelper_compat_libc++",
     ],
+    stl: "libc++_static",
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/staticlibs/native/timerfdutils/com_android_net_module_util_ServiceConnectivityJni.cpp b/staticlibs/native/timerfdutils/com_android_net_module_util_ServiceConnectivityJni.cpp
index fdefd0e..150f84e 100644
--- a/staticlibs/native/timerfdutils/com_android_net_module_util_ServiceConnectivityJni.cpp
+++ b/staticlibs/native/timerfdutils/com_android_net_module_util_ServiceConnectivityJni.cpp
@@ -14,22 +14,41 @@
  * limitations under the License.
  */
 
+#include <arpa/inet.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/scoped_utf_chars.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/ipv6_route.h>
+#include <linux/route.h>
+#include <netinet/in.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string>
 #include <string.h>
 #include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/timerfd.h>
+#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <android-base/unique_fd.h>
+#include <bpf/KernelUtils.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/scoped_utf_chars.h>
+
 #define MSEC_PER_SEC 1000
 #define NSEC_PER_MSEC 1000000
 
+#ifndef IFF_NO_CARRIER
+#define IFF_NO_CARRIER 0x0040
+#endif
+
 namespace android {
 
 static jint
@@ -60,6 +79,107 @@
   }
 }
 
+static void throwException(JNIEnv* env, int error, const char* action, const char* iface) {
+    const std::string& msg = "Error: " + std::string(action) + " " + std::string(iface) +  ": "
+                + std::string(strerror(error));
+    jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
+}
+
+// enable or disable  carrier on tun / tap interface.
+static void setTunTapCarrierEnabledImpl(JNIEnv* env, const char* iface, int tunFd, bool enabled) {
+    uint32_t carrierOn = enabled;
+    if (ioctl(tunFd, TUNSETCARRIER, &carrierOn)) {
+        throwException(env, errno, "set carrier", iface);
+    }
+}
+
+static int createTunTapImpl(JNIEnv* env, bool isTun, bool hasCarrier, bool setIffMulticast,
+                            const char* iface) {
+    base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
+    ifreq ifr{};
+
+    // Allocate interface.
+    ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
+    if (!hasCarrier) {
+        // Using IFF_NO_CARRIER is supported starting in kernel version >= 6.0
+        // Up until then, unsupported flags are ignored.
+        if (!bpf::isAtLeastKernelVersion(6, 0, 0)) {
+            throwException(env, EOPNOTSUPP, "IFF_NO_CARRIER not supported", ifr.ifr_name);
+            return -1;
+        }
+        ifr.ifr_flags |= IFF_NO_CARRIER;
+    }
+    strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
+    if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
+        throwException(env, errno, "allocating", ifr.ifr_name);
+        return -1;
+    }
+
+    // Mark some TAP interfaces as supporting multicast
+    if (setIffMulticast && !isTun) {
+        base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
+        ifr.ifr_flags = IFF_MULTICAST;
+
+        if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
+            throwException(env, errno, "set IFF_MULTICAST", ifr.ifr_name);
+            return -1;
+        }
+    }
+
+    return tun.release();
+}
+
+static void bringUpInterfaceImpl(JNIEnv* env, const char* iface) {
+    // Activate interface using an unconnected datagram socket.
+    base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
+
+    ifreq ifr{};
+    strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
+    if (ioctl(inet6CtrlSock.get(), SIOCGIFFLAGS, &ifr)) {
+        throwException(env, errno, "read flags", iface);
+        return;
+    }
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
+        throwException(env, errno, "set IFF_UP", iface);
+        return;
+    }
+}
+
+//------------------------------------------------------------------------------
+
+static void setTunTapCarrierEnabled(JNIEnv* env, jclass /* clazz */, jstring
+                                    jIface, jint tunFd, jboolean enabled) {
+    ScopedUtfChars iface(env, jIface);
+    if (!iface.c_str()) {
+        jniThrowNullPointerException(env, "iface");
+        return;
+    }
+    setTunTapCarrierEnabledImpl(env, iface.c_str(), tunFd, enabled);
+}
+
+static jint createTunTap(JNIEnv* env, jclass /* clazz */, jboolean isTun,
+                             jboolean hasCarrier, jboolean setIffMulticast, jstring jIface) {
+    ScopedUtfChars iface(env, jIface);
+    if (!iface.c_str()) {
+        jniThrowNullPointerException(env, "iface");
+        return -1;
+    }
+
+    return createTunTapImpl(env, isTun, hasCarrier, setIffMulticast, iface.c_str());
+}
+
+static void bringUpInterface(JNIEnv* env, jclass /* clazz */, jstring jIface) {
+    ScopedUtfChars iface(env, jIface);
+    if (!iface.c_str()) {
+        jniThrowNullPointerException(env, "iface");
+        return;
+    }
+    bringUpInterfaceImpl(env, iface.c_str());
+}
+
+//------------------------------------------------------------------------------
+
 /*
  * JNI registration.
  */
@@ -69,6 +189,9 @@
      (void *)com_android_net_module_util_ServiceConnectivityJni_createTimerFd},
     {"setTime", "(IJ)V",
      (void *)com_android_net_module_util_ServiceConnectivityJni_setTime},
+    {"nativeSetTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", (void*)setTunTapCarrierEnabled},
+    {"nativeCreateTunTap", "(ZZZLjava/lang/String;)I", (void*)createTunTap},
+    {"nativeBringUpInterface", "(Ljava/lang/String;)V", (void*)bringUpInterface},
 };
 
 int register_com_android_net_module_util_ServiceConnectivityJni(JNIEnv *env,