Snap for 7692221 from a6d779e793804718cfc77a407524b33cdcb0d61b to mainline-art-release

Change-Id: I49169181a169a88d589f8dc98350a58461bb07a0
diff --git a/Android.bp b/Android.bp
index 367c542..0f577a4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -214,8 +214,8 @@
     libs: ["unsupportedappusage"],
     static_libs: [
         "androidx.annotation_annotation",
+        "modules-utils-build_system",
         "netd_aidl_interface-lateststable-java",
-        "netlink-client",
         "networkstack-client",
         "net-utils-framework-common",
         // See note on statsprotos when adding/updating proto build rules
@@ -223,6 +223,7 @@
         "statsprotos",
         "captiveportal-lib",
         "net-utils-device-common",
+        "net-utils-device-common-netlink",
     ],
     plugins: ["java_api_finder"],
 }
@@ -278,6 +279,7 @@
     visibility: [
         "//packages/modules/NetworkStack/tests/unit",
         "//packages/modules/NetworkStack/tests/integration",
+        "//packages/modules/Connectivity/tests:__subpackages__",
         "//packages/modules/Connectivity/Tethering/tests/integration",
     ]
 }
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6a11b2c..8750795 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -21,6 +21,7 @@
   android:sharedUserId="android.uid.networkstack"
   android:versionCode="319999900"
   android:versionName="s_aml_319999900"
+  coreApp="true"
 >
     <!-- Permissions must be defined here, and not in the base manifest, as the network stack
          running in the system server process does not need any permission, and having privileged
diff --git a/AndroidManifest_InProcess.xml b/AndroidManifest_InProcess.xml
index 2cb146a..6c64d87 100644
--- a/AndroidManifest_InProcess.xml
+++ b/AndroidManifest_InProcess.xml
@@ -19,7 +19,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.networkstack.inprocess"
           android:sharedUserId="android.uid.system"
-          android:process="system">
+          android:process="system"
+          coreApp="true">
     <application>
         <service android:name="com.android.server.NetworkStackService"
                  android:process="system"
diff --git a/AndroidManifest_Next.xml b/AndroidManifest_Next.xml
index 9ad69ae..244d465 100644
--- a/AndroidManifest_Next.xml
+++ b/AndroidManifest_Next.xml
@@ -18,5 +18,6 @@
           package="com.android.networkstack"
           android:sharedUserId="android.uid.networkstack"
           android:versionCode="320000000"
-          android:versionName="T-next">
+          android:versionName="T-next"
+          coreApp="true">
 </manifest>
diff --git a/apishim/29/com/android/networkstack/apishim/api29/ConnectivityManagerShimImpl.java b/apishim/29/com/android/networkstack/apishim/api29/ConnectivityManagerShimImpl.java
index 2ac25af..07327be 100644
--- a/apishim/29/com/android/networkstack/apishim/api29/ConnectivityManagerShimImpl.java
+++ b/apishim/29/com/android/networkstack/apishim/api29/ConnectivityManagerShimImpl.java
@@ -16,8 +16,14 @@
 
 package com.android.networkstack.apishim.api29;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Handler;
 
@@ -30,7 +36,10 @@
  * Implementation of {@link ConnectivityManagerShim} for API 29.
  */
 public class ConnectivityManagerShimImpl implements ConnectivityManagerShim {
-    protected ConnectivityManagerShimImpl(Context context) {}
+    protected final ConnectivityManager mCm;
+    protected ConnectivityManagerShimImpl(Context context) {
+        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+    }
 
     /**
      * Get a new instance of {@link ConnectivityManagerShim}.
@@ -52,12 +61,31 @@
 
     /**
      * See android.net.ConnectivityManager#registerSystemDefaultNetworkCallback
-     * @throws UnsupportedApiLevelException if API is not available in this API level.
      */
     @Override
     public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
-            @NonNull Handler handler) throws UnsupportedApiLevelException {
-        // Not supported for API 29.
-        throw new UnsupportedApiLevelException("Not supported in API 29.");
+            @NonNull Handler handler) {
+        // defaultNetworkRequest is not really a "request", just a way of tracking the system
+        // default network. It's guaranteed not to actually bring up any networks because it
+        // should be the same request as the ConnectivityService default request, and thus
+        // shares fate with it.  In API <= R, registerSystemDefaultNetworkCallback is not
+        // available, and registerDefaultNetworkCallback will not track the system default when
+        // a VPN applies to the UID of this process.
+        final NetworkRequest defaultNetworkRequest = makeEmptyCapabilitiesRequest()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build();
+        mCm.requestNetwork(defaultNetworkRequest, networkCallback, handler);
+    }
+
+    @NonNull
+    protected NetworkRequest.Builder makeEmptyCapabilitiesRequest() {
+        // Q does not have clearCapabilities(), so assume the default capabilities are as below
+        return new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                .removeCapability(NET_CAPABILITY_TRUSTED)
+                .removeCapability(NET_CAPABILITY_NOT_VPN);
     }
 }
diff --git a/apishim/30/com/android/networkstack/apishim/api30/ConnectivityManagerShimImpl.java b/apishim/30/com/android/networkstack/apishim/api30/ConnectivityManagerShimImpl.java
index 97f1f60..7c1d786 100644
--- a/apishim/30/com/android/networkstack/apishim/api30/ConnectivityManagerShimImpl.java
+++ b/apishim/30/com/android/networkstack/apishim/api30/ConnectivityManagerShimImpl.java
@@ -16,10 +16,10 @@
 
 package com.android.networkstack.apishim.api30;
 
+import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
+
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
-import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Build;
 import android.os.Handler;
@@ -28,25 +28,24 @@
 import androidx.annotation.RequiresApi;
 
 import com.android.networkstack.apishim.common.ConnectivityManagerShim;
-import com.android.networkstack.apishim.common.ShimUtils;
 import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
 
 /**
  * Implementation of {@link ConnectivityManagerShim} for API 30.
  */
+@RequiresApi(Build.VERSION_CODES.R)
 public class ConnectivityManagerShimImpl
         extends com.android.networkstack.apishim.api29.ConnectivityManagerShimImpl {
-    protected final ConnectivityManager mCm;
     protected ConnectivityManagerShimImpl(Context context) {
         super(context);
-        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
     /**
      * Get a new instance of {@link ConnectivityManagerShim}.
      */
+    @RequiresApi(Build.VERSION_CODES.Q)
     public static ConnectivityManagerShim newInstance(Context context) {
-        if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) {
+        if (!isAtLeastR()) {
             return com.android.networkstack.apishim.api29.ConnectivityManagerShimImpl
                     .newInstance(context);
         }
@@ -65,27 +64,9 @@
         throw new UnsupportedApiLevelException("Not supported in API 30.");
     }
 
-    /**
-     * See android.net.ConnectivityManager#registerSystemDefaultNetworkCallback
-     * @throws UnsupportedApiLevelException if API is not available in this API level.
-     */
+    @NonNull
     @Override
-    @RequiresApi(Build.VERSION_CODES.R)
-    public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
-            @NonNull Handler handler) {
-        // defaultNetworkRequest is not really a "request", just a way of tracking the system
-        // default network. It's guaranteed not to actually bring up any networks because it
-        // should be the same request as the ConnectivityService default request, and thus
-        // shares fate with it.  In API <= R, registerSystemDefaultNetworkCallback is not
-        // available, and registerDefaultNetworkCallback will not track the system default when
-        // a VPN applies to the UID of this process.
-        final NetworkRequest defaultNetworkRequest = new NetworkRequest.Builder()
-                .clearCapabilities()
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build();
-        mCm.requestNetwork(defaultNetworkRequest, networkCallback, handler);
+    protected NetworkRequest.Builder makeEmptyCapabilitiesRequest() {
+        return new NetworkRequest.Builder().clearCapabilities();
     }
 }
diff --git a/apishim/common/com/android/networkstack/apishim/common/ConnectivityManagerShim.java b/apishim/common/com/android/networkstack/apishim/common/ConnectivityManagerShim.java
index 67b3df7..86d785e 100644
--- a/apishim/common/com/android/networkstack/apishim/common/ConnectivityManagerShim.java
+++ b/apishim/common/com/android/networkstack/apishim/common/ConnectivityManagerShim.java
@@ -42,8 +42,7 @@
 
     /** See android.net.ConnectivityManager#registerSystemDefaultNetworkCallback */
     void registerSystemDefaultNetworkCallback(
-            @NonNull NetworkCallback networkCallback, @NonNull Handler handler)
-            throws UnsupportedApiLevelException;
+            @NonNull NetworkCallback networkCallback, @NonNull Handler handler);
 
     /** See android.net.ConnectivityManager#registerDefaultNetworkCallbackForUid */
     default void registerDefaultNetworkCallbackForUid(
diff --git a/common/moduleutils/Android.bp b/common/moduleutils/Android.bp
index 54f4b22..d90c33d 100644
--- a/common/moduleutils/Android.bp
+++ b/common/moduleutils/Android.bp
@@ -21,18 +21,29 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+// TODO: remove this filegroup together with services.net
 filegroup {
     name: "net-module-utils-srcs",
     srcs: [
+        "src/android/net/shared/NetdUtils.java",
+        "src/android/net/shared/RouteUtils.java",
+        "src/android/net/util/InterfaceParams.java",
+        "src/android/net/util/SharedLog.java",
+    ],
+    visibility: [
+        "//frameworks/base/services/net",
+    ]
+}
+
+filegroup {
+    name: "connectivity-module-utils-srcs",
+    srcs: [
         "src/android/net/util/SharedLog.java",
         "src/android/net/shared/NetdUtils.java",
         "src/android/net/shared/NetworkMonitorUtils.java",
         "src/android/net/shared/RouteUtils.java",
-        "src/android/net/util/InterfaceParams.java",
     ],
     visibility: [
-        "//frameworks/base/services/net",
-        "//frameworks/base/packages/Connectivity/service",
         "//packages/modules/Connectivity/service",
     ]
 }
@@ -53,7 +64,6 @@
         "src/android/net/ip/InterfaceController.java",
         "src/android/net/ip/IpNeighborMonitor.java",
         "src/android/net/ip/NetlinkMonitor.java",
-        "src/android/net/netlink/*.java",
         "src/android/net/shared/NetdUtils.java",
         "src/android/net/shared/RouteUtils.java",
         "src/android/net/util/InterfaceParams.java",
diff --git a/common/moduleutils/src/android/net/ip/ConntrackMonitor.java b/common/moduleutils/src/android/net/ip/ConntrackMonitor.java
index 6c72984..43005cd 100644
--- a/common/moduleutils/src/android/net/ip/ConntrackMonitor.java
+++ b/common/moduleutils/src/android/net/ip/ConntrackMonitor.java
@@ -16,12 +16,9 @@
 
 package android.net.ip;
 
-import static android.net.netlink.ConntrackMessage.DYING_MASK;
-import static android.net.netlink.ConntrackMessage.ESTABLISHED_MASK;
+import static com.android.net.module.util.netlink.ConntrackMessage.DYING_MASK;
+import static com.android.net.module.util.netlink.ConntrackMessage.ESTABLISHED_MASK;
 
-import android.net.netlink.ConntrackMessage;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkMessage;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.system.OsConstants;
@@ -29,6 +26,9 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.netlink.ConntrackMessage;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.NetlinkMessage;
 
 import java.util.Objects;
 
diff --git a/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java b/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java
index b45c061..a16fdf2 100644
--- a/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java
+++ b/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java
@@ -16,22 +16,24 @@
 
 package android.net.ip;
 
-import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
-import static android.net.netlink.NetlinkConstants.hexify;
-import static android.net.netlink.NetlinkConstants.stringForNlMsgType;
 import static android.system.OsConstants.NETLINK_ROUTE;
 
+import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH;
+import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
+import static com.android.net.module.util.netlink.NetlinkConstants.stringForNlMsgType;
+
 import android.net.MacAddress;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdMsg;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
 
+import com.android.net.module.util.netlink.NetlinkMessage;
+import com.android.net.module.util.netlink.NetlinkSocket;
+import com.android.net.module.util.netlink.RtNetlinkNeighborMessage;
+import com.android.net.module.util.netlink.StructNdMsg;
+
 import java.net.InetAddress;
 import java.util.StringJoiner;
 
diff --git a/common/moduleutils/src/android/net/ip/NetlinkMonitor.java b/common/moduleutils/src/android/net/ip/NetlinkMonitor.java
index 2025967..17157d8 100644
--- a/common/moduleutils/src/android/net/ip/NetlinkMonitor.java
+++ b/common/moduleutils/src/android/net/ip/NetlinkMonitor.java
@@ -16,7 +16,6 @@
 
 package android.net.ip;
 
-import static android.net.netlink.NetlinkConstants.hexify;
 import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
 import static android.system.OsConstants.AF_NETLINK;
 import static android.system.OsConstants.SOCK_DGRAM;
@@ -24,10 +23,9 @@
 import static android.system.OsConstants.SOL_SOCKET;
 import static android.system.OsConstants.SO_RCVBUF;
 
+import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
+
 import android.annotation.NonNull;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
 import android.net.util.SharedLog;
 import android.net.util.SocketUtils;
 import android.os.Handler;
@@ -37,6 +35,9 @@
 import android.util.Log;
 
 import com.android.net.module.util.PacketReader;
+import com.android.net.module.util.netlink.NetlinkErrorMessage;
+import com.android.net.module.util.netlink.NetlinkMessage;
+import com.android.net.module.util.netlink.NetlinkSocket;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
diff --git a/common/moduleutils/src/android/net/shared/NetworkMonitorUtils.java b/common/moduleutils/src/android/net/shared/NetworkMonitorUtils.java
index 981a576..0cd9f65 100644
--- a/common/moduleutils/src/android/net/shared/NetworkMonitorUtils.java
+++ b/common/moduleutils/src/android/net/shared/NetworkMonitorUtils.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -27,6 +28,8 @@
 
 import android.net.NetworkCapabilities;
 
+import com.android.modules.utils.build.SdkLevel;
+
 /** @hide */
 public class NetworkMonitorUtils {
     // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use
@@ -36,6 +39,14 @@
     // TODO: use NetworkCapabilities.TRANSPORT_TEST once NetworkStack builds against API 31.
     private static final int TRANSPORT_TEST = 7;
 
+    // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use
+    // NetworkStack shims, but at the same time cannot use non-system APIs.
+    // NET_CAPABILITY_NOT_VCN_MANAGED is system API as of S (so it is enforced to always be 28 and
+    // can't be changed).
+    // TODO: use NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED once NetworkStack builds against
+    //       API 31.
+    public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
+
     // Network conditions broadcast constants
     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
             "android.net.conn.NETWORK_CONDITIONS_MEASURED";
@@ -59,11 +70,16 @@
     public static boolean isPrivateDnsValidationRequired(NetworkCapabilities nc) {
         if (nc == null) return false;
 
+        final boolean isVcnManaged = SdkLevel.isAtLeastS()
+                && !nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+        final boolean isOemPaid = nc.hasCapability(NET_CAPABILITY_OEM_PAID)
+                && nc.hasCapability(NET_CAPABILITY_TRUSTED);
+        final boolean isDefaultCapable = nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                && nc.hasCapability(NET_CAPABILITY_TRUSTED);
+
         // TODO: Consider requiring validation for DUN networks.
         if (nc.hasCapability(NET_CAPABILITY_INTERNET)
-                && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
-                && nc.hasCapability(NET_CAPABILITY_TRUSTED)) {
-            // Real networks
+                && (isVcnManaged || isOemPaid || isDefaultCapable)) {
             return true;
         }
 
diff --git a/common/netlinkclient/Android.bp b/common/netlinkclient/Android.bp
deleted file mode 100644
index 9a60e57..0000000
--- a/common/netlinkclient/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_library {
-    name: "netlink-client",
-    srcs: [
-        "src/**/*.java",
-        ":framework-annotations",
-    ],
-    libs: [
-        "androidx.annotation_annotation",
-    ],
-    sdk_version: "system_current",
-    // this is part of updatable modules(NetworkStack) which targets 29(Q)
-    min_sdk_version: "29",
-}
diff --git a/common/netlinkclient/src/android/net/netlink/ConntrackMessage.java b/common/netlinkclient/src/android/net/netlink/ConntrackMessage.java
deleted file mode 100644
index cc8bb7e..0000000
--- a/common/netlinkclient/src/android/net/netlink/ConntrackMessage.java
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlAttr.findNextAttrOfType;
-import static android.net.netlink.StructNlAttr.makeNestedType;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.system.OsConstants;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Objects;
-
-
-/**
- * A NetlinkMessage subclass for netlink conntrack messages.
- *
- * see also: &lt;linux_src&gt;/include/uapi/linux/netfilter/nfnetlink_conntrack.h
- *
- * @hide
- */
-public class ConntrackMessage extends NetlinkMessage {
-    public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
-
-    // enum ctattr_type
-    public static final short CTA_TUPLE_ORIG  = 1;
-    public static final short CTA_TUPLE_REPLY = 2;
-    public static final short CTA_STATUS      = 3;
-    public static final short CTA_TIMEOUT     = 7;
-
-    // enum ctattr_tuple
-    public static final short CTA_TUPLE_IP    = 1;
-    public static final short CTA_TUPLE_PROTO = 2;
-
-    // enum ctattr_ip
-    public static final short CTA_IP_V4_SRC = 1;
-    public static final short CTA_IP_V4_DST = 2;
-
-    // enum ctattr_l4proto
-    public static final short CTA_PROTO_NUM      = 1;
-    public static final short CTA_PROTO_SRC_PORT = 2;
-    public static final short CTA_PROTO_DST_PORT = 3;
-
-    // enum ip_conntrack_status
-    public static final int IPS_EXPECTED      = 0x00000001;
-    public static final int IPS_SEEN_REPLY    = 0x00000002;
-    public static final int IPS_ASSURED       = 0x00000004;
-    public static final int IPS_CONFIRMED     = 0x00000008;
-    public static final int IPS_SRC_NAT       = 0x00000010;
-    public static final int IPS_DST_NAT       = 0x00000020;
-    public static final int IPS_SEQ_ADJUST    = 0x00000040;
-    public static final int IPS_SRC_NAT_DONE  = 0x00000080;
-    public static final int IPS_DST_NAT_DONE  = 0x00000100;
-    public static final int IPS_DYING         = 0x00000200;
-    public static final int IPS_FIXED_TIMEOUT = 0x00000400;
-    public static final int IPS_TEMPLATE      = 0x00000800;
-    public static final int IPS_UNTRACKED     = 0x00001000;
-    public static final int IPS_HELPER        = 0x00002000;
-    public static final int IPS_OFFLOAD       = 0x00004000;
-    public static final int IPS_HW_OFFLOAD    = 0x00008000;
-
-    // ip_conntrack_status mask
-    // Interesting on the NAT conntrack session which has already seen two direction traffic.
-    // TODO: Probably IPS_{SRC, DST}_NAT_DONE are also interesting.
-    public static final int ESTABLISHED_MASK = IPS_CONFIRMED | IPS_ASSURED | IPS_SEEN_REPLY
-            | IPS_SRC_NAT;
-    // Interesting on the established NAT conntrack session which is dying.
-    public static final int DYING_MASK = ESTABLISHED_MASK | IPS_DYING;
-
-    /**
-     * A tuple for the conntrack connection information.
-     *
-     * see also CTA_TUPLE_ORIG and CTA_TUPLE_REPLY.
-     */
-    public static class Tuple {
-        public final Inet4Address srcIp;
-        public final Inet4Address dstIp;
-
-        // Both port and protocol number are unsigned numbers stored in signed integers, and that
-        // callers that want to compare them to integers should either cast those integers, or
-        // convert them to unsigned using Byte.toUnsignedInt() and Short.toUnsignedInt().
-        public final short srcPort;
-        public final short dstPort;
-        public final byte protoNum;
-
-        public Tuple(TupleIpv4 ip, TupleProto proto) {
-            this.srcIp = ip.src;
-            this.dstIp = ip.dst;
-            this.srcPort = proto.srcPort;
-            this.dstPort = proto.dstPort;
-            this.protoNum = proto.protoNum;
-        }
-
-        @Override
-        @VisibleForTesting
-        public boolean equals(Object o) {
-            if (!(o instanceof Tuple)) return false;
-            Tuple that = (Tuple) o;
-            return Objects.equals(this.srcIp, that.srcIp)
-                    && Objects.equals(this.dstIp, that.dstIp)
-                    && this.srcPort == that.srcPort
-                    && this.dstPort == that.dstPort
-                    && this.protoNum == that.protoNum;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(srcIp, dstIp, srcPort, dstPort, protoNum);
-        }
-
-        @Override
-        public String toString() {
-            final String srcIpStr = (srcIp == null) ? "null" : srcIp.getHostAddress();
-            final String dstIpStr = (dstIp == null) ? "null" : dstIp.getHostAddress();
-            final String protoStr = NetlinkConstants.stringForProtocol(protoNum);
-
-            return "Tuple{"
-                    + protoStr + ": "
-                    + srcIpStr + ":" + Short.toUnsignedInt(srcPort) + " -> "
-                    + dstIpStr + ":" + Short.toUnsignedInt(dstPort)
-                    + "}";
-        }
-    }
-
-    /**
-     * A tuple for the conntrack connection address.
-     *
-     * see also CTA_TUPLE_IP.
-     */
-    public static class TupleIpv4 {
-        public final Inet4Address src;
-        public final Inet4Address dst;
-
-        public TupleIpv4(Inet4Address src, Inet4Address dst) {
-            this.src = src;
-            this.dst = dst;
-        }
-    }
-
-    /**
-     * A tuple for the conntrack connection protocol.
-     *
-     * see also CTA_TUPLE_PROTO.
-     */
-    public static class TupleProto {
-        public final byte protoNum;
-        public final short srcPort;
-        public final short dstPort;
-
-        public TupleProto(byte protoNum, short srcPort, short dstPort) {
-            this.protoNum = protoNum;
-            this.srcPort = srcPort;
-            this.dstPort = dstPort;
-        }
-    }
-
-    public static byte[] newIPv4TimeoutUpdateRequest(
-            int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) {
-        // *** STYLE WARNING ***
-        //
-        // Code below this point uses extra block indentation to highlight the
-        // packing of nested tuple netlink attribute types.
-        final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG,
-                new StructNlAttr(CTA_TUPLE_IP,
-                        new StructNlAttr(CTA_IP_V4_SRC, src),
-                        new StructNlAttr(CTA_IP_V4_DST, dst)),
-                new StructNlAttr(CTA_TUPLE_PROTO,
-                        new StructNlAttr(CTA_PROTO_NUM, (byte) proto),
-                        new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN),
-                        new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN)));
-
-        final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN);
-
-        final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength();
-        final byte[] bytes = new byte[STRUCT_SIZE + payloadLength];
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        final ConntrackMessage ctmsg = new ConntrackMessage();
-        ctmsg.mHeader.nlmsg_len = bytes.length;
-        ctmsg.mHeader.nlmsg_type = (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8)
-                | NetlinkConstants.IPCTNL_MSG_CT_NEW;
-        ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
-        ctmsg.mHeader.nlmsg_seq = 1;
-        ctmsg.pack(byteBuffer);
-
-        ctaTupleOrig.pack(byteBuffer);
-        ctaTimeout.pack(byteBuffer);
-
-        return bytes;
-    }
-
-    /**
-     * Parses a netfilter conntrack message from a {@link ByteBuffer}.
-     *
-     * @param header the netlink message header.
-     * @param byteBuffer The buffer from which to parse the netfilter conntrack message.
-     * @return the parsed netfilter conntrack message, or {@code null} if the netfilter conntrack
-     *         message could not be parsed successfully (for example, if it was truncated).
-     */
-    public static ConntrackMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        // Just build the netlink header and netfilter header for now and pretend the whole message
-        // was consumed.
-        // TODO: Parse the conntrack attributes.
-        final StructNfGenMsg nfGenMsg = StructNfGenMsg.parse(byteBuffer);
-        if (nfGenMsg == null) {
-            return null;
-        }
-
-        final int baseOffset = byteBuffer.position();
-        StructNlAttr nlAttr = findNextAttrOfType(CTA_STATUS, byteBuffer);
-        int status = 0;
-        if (nlAttr != null) {
-            status = nlAttr.getValueAsBe32(0);
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(CTA_TIMEOUT, byteBuffer);
-        int timeoutSec = 0;
-        if (nlAttr != null) {
-            timeoutSec = nlAttr.getValueAsBe32(0);
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_ORIG), byteBuffer);
-        Tuple tupleOrig = null;
-        if (nlAttr != null) {
-            tupleOrig = parseTuple(nlAttr.getValueAsByteBuffer());
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_REPLY), byteBuffer);
-        Tuple tupleReply = null;
-        if (nlAttr != null) {
-            tupleReply = parseTuple(nlAttr.getValueAsByteBuffer());
-        }
-
-        // Advance to the end of the message.
-        byteBuffer.position(baseOffset);
-        final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
-        final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
-                header.nlmsg_len - kMinConsumed);
-        if (byteBuffer.remaining() < kAdditionalSpace) {
-            return null;
-        }
-        byteBuffer.position(baseOffset + kAdditionalSpace);
-
-        return new ConntrackMessage(header, nfGenMsg, tupleOrig, tupleReply, status, timeoutSec);
-    }
-
-    /**
-     * Parses a conntrack tuple from a {@link ByteBuffer}.
-     *
-     * The attribute parsing is interesting on:
-     * - CTA_TUPLE_IP
-     *     CTA_IP_V4_SRC
-     *     CTA_IP_V4_DST
-     * - CTA_TUPLE_PROTO
-     *     CTA_PROTO_NUM
-     *     CTA_PROTO_SRC_PORT
-     *     CTA_PROTO_DST_PORT
-     *
-     * Assume that the minimum size is the sum of CTA_TUPLE_IP (size: 20) and CTA_TUPLE_PROTO
-     * (size: 28). Here is an example for an expected CTA_TUPLE_ORIG message in raw data:
-     * +--------------------------------------------------------------------------------------+
-     * | CTA_TUPLE_ORIG                                                                       |
-     * +--------------------------+-----------------------------------------------------------+
-     * | 1400                     | nla_len = 20                                              |
-     * | 0180                     | nla_type = nested CTA_TUPLE_IP                            |
-     * |     0800 0100 C0A8500C   |     nla_type=CTA_IP_V4_SRC, ip=192.168.80.12              |
-     * |     0800 0200 8C700874   |     nla_type=CTA_IP_V4_DST, ip=140.112.8.116              |
-     * | 1C00                     | nla_len = 28                                              |
-     * | 0280                     | nla_type = nested CTA_TUPLE_PROTO                         |
-     * |     0500 0100 06 000000  |     nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6)         |
-     * |     0600 0200 F3F1 0000  |     nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian)  |
-     * |     0600 0300 01BB 0000  |     nla_type=CTA_PROTO_DST_PORT, port=433 (big endian)    |
-     * +--------------------------+-----------------------------------------------------------+
-     *
-     * The position of the byte buffer doesn't set to the end when the function returns. It is okay
-     * because the caller ConntrackMessage#parse has passed a copy which is used for this parser
-     * only. Moreover, the parser behavior is the same as other existing netlink struct class
-     * parser. Ex: StructInetDiagMsg#parse.
-     */
-    @Nullable
-    private static Tuple parseTuple(@Nullable ByteBuffer byteBuffer) {
-        if (byteBuffer == null) return null;
-
-        TupleIpv4 tupleIpv4 = null;
-        TupleProto tupleProto = null;
-
-        final int baseOffset = byteBuffer.position();
-        StructNlAttr nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_IP), byteBuffer);
-        if (nlAttr != null) {
-            tupleIpv4 = parseTupleIpv4(nlAttr.getValueAsByteBuffer());
-        }
-        if (tupleIpv4 == null) return null;
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_PROTO), byteBuffer);
-        if (nlAttr != null) {
-            tupleProto = parseTupleProto(nlAttr.getValueAsByteBuffer());
-        }
-        if (tupleProto == null) return null;
-
-        return new Tuple(tupleIpv4, tupleProto);
-    }
-
-    @Nullable
-    private static Inet4Address castToInet4Address(@Nullable InetAddress address) {
-        if (address == null || !(address instanceof Inet4Address)) return null;
-        return (Inet4Address) address;
-    }
-
-    @Nullable
-    private static TupleIpv4 parseTupleIpv4(@Nullable ByteBuffer byteBuffer) {
-        if (byteBuffer == null) return null;
-
-        Inet4Address src = null;
-        Inet4Address dst = null;
-
-        final int baseOffset = byteBuffer.position();
-        StructNlAttr nlAttr = findNextAttrOfType(CTA_IP_V4_SRC, byteBuffer);
-        if (nlAttr != null) {
-            src = castToInet4Address(nlAttr.getValueAsInetAddress());
-        }
-        if (src == null) return null;
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(CTA_IP_V4_DST, byteBuffer);
-        if (nlAttr != null) {
-            dst = castToInet4Address(nlAttr.getValueAsInetAddress());
-        }
-        if (dst == null) return null;
-
-        return new TupleIpv4(src, dst);
-    }
-
-    @Nullable
-    private static TupleProto parseTupleProto(@Nullable ByteBuffer byteBuffer) {
-        if (byteBuffer == null) return null;
-
-        byte protoNum = 0;
-        short srcPort = 0;
-        short dstPort = 0;
-
-        final int baseOffset = byteBuffer.position();
-        StructNlAttr nlAttr = findNextAttrOfType(CTA_PROTO_NUM, byteBuffer);
-        if (nlAttr != null) {
-            protoNum = nlAttr.getValueAsByte((byte) 0);
-        }
-        if (!(protoNum == IPPROTO_TCP || protoNum == IPPROTO_UDP)) return null;
-
-        byteBuffer.position(baseOffset);
-        nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_SRC_PORT, byteBuffer);
-        if (nlAttr != null) {
-            srcPort = nlAttr.getValueAsBe16((short) 0);
-        }
-        if (srcPort == 0) return null;
-
-        byteBuffer.position(baseOffset);
-        nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_DST_PORT, byteBuffer);
-        if (nlAttr != null) {
-            dstPort = nlAttr.getValueAsBe16((short) 0);
-        }
-        if (dstPort == 0) return null;
-
-        return new TupleProto(protoNum, srcPort, dstPort);
-    }
-
-    /**
-     * Netfilter header.
-     */
-    public final StructNfGenMsg nfGenMsg;
-    /**
-     * Original direction conntrack tuple.
-     *
-     * The tuple is determined by the parsed attribute value CTA_TUPLE_ORIG, or null if the
-     * tuple could not be parsed successfully (for example, if it was truncated or absent).
-     */
-    @Nullable
-    public final Tuple tupleOrig;
-    /**
-     * Reply direction conntrack tuple.
-     *
-     * The tuple is determined by the parsed attribute value CTA_TUPLE_REPLY, or null if the
-     * tuple could not be parsed successfully (for example, if it was truncated or absent).
-     */
-    @Nullable
-    public final Tuple tupleReply;
-    /**
-     * Connection status. A bitmask of ip_conntrack_status enum flags.
-     *
-     * The status is determined by the parsed attribute value CTA_STATUS, or 0 if the status could
-     * not be parsed successfully (for example, if it was truncated or absent). For the message
-     * from kernel, the valid status is non-zero. For the message from user space, the status may
-     * be 0 (absent).
-     */
-    public final int status;
-    /**
-     * Conntrack timeout.
-     *
-     * The timeout is determined by the parsed attribute value CTA_TIMEOUT, or 0 if the timeout
-     * could not be parsed successfully (for example, if it was truncated or absent). For
-     * IPCTNL_MSG_CT_NEW event, the valid timeout is non-zero. For IPCTNL_MSG_CT_DELETE event, the
-     * timeout is 0 (absent).
-     */
-    public final int timeoutSec;
-
-    private ConntrackMessage() {
-        super(new StructNlMsgHdr());
-        nfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET);
-
-        // This constructor is only used by #newIPv4TimeoutUpdateRequest which doesn't use these
-        // data member for packing message. Simply fill them to null or 0.
-        tupleOrig = null;
-        tupleReply = null;
-        status = 0;
-        timeoutSec = 0;
-    }
-
-    private ConntrackMessage(@NonNull StructNlMsgHdr header, @NonNull StructNfGenMsg nfGenMsg,
-            @Nullable Tuple tupleOrig, @Nullable Tuple tupleReply, int status, int timeoutSec) {
-        super(header);
-        this.nfGenMsg = nfGenMsg;
-        this.tupleOrig = tupleOrig;
-        this.tupleReply = tupleReply;
-        this.status = status;
-        this.timeoutSec = timeoutSec;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        mHeader.pack(byteBuffer);
-        nfGenMsg.pack(byteBuffer);
-    }
-
-    public short getMessageType() {
-        return (short) (getHeader().nlmsg_type & ~(NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8));
-    }
-
-    /**
-     * Convert an ip conntrack status to a string.
-     */
-    public static String stringForIpConntrackStatus(int flags) {
-        final StringBuilder sb = new StringBuilder();
-
-        if ((flags & IPS_EXPECTED) != 0) {
-            sb.append("IPS_EXPECTED");
-        }
-        if ((flags & IPS_SEEN_REPLY) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_SEEN_REPLY");
-        }
-        if ((flags & IPS_ASSURED) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_ASSURED");
-        }
-        if ((flags & IPS_CONFIRMED) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_CONFIRMED");
-        }
-        if ((flags & IPS_SRC_NAT) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_SRC_NAT");
-        }
-        if ((flags & IPS_DST_NAT) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_DST_NAT");
-        }
-        if ((flags & IPS_SEQ_ADJUST) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_SEQ_ADJUST");
-        }
-        if ((flags & IPS_SRC_NAT_DONE) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_SRC_NAT_DONE");
-        }
-        if ((flags & IPS_DST_NAT_DONE) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_DST_NAT_DONE");
-        }
-        if ((flags & IPS_DYING) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_DYING");
-        }
-        if ((flags & IPS_FIXED_TIMEOUT) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_FIXED_TIMEOUT");
-        }
-        if ((flags & IPS_TEMPLATE) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_TEMPLATE");
-        }
-        if ((flags & IPS_UNTRACKED) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_UNTRACKED");
-        }
-        if ((flags & IPS_HELPER) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_HELPER");
-        }
-        if ((flags & IPS_OFFLOAD) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_OFFLOAD");
-        }
-        if ((flags & IPS_HW_OFFLOAD) != 0) {
-            if (sb.length() > 0) sb.append("|");
-            sb.append("IPS_HW_OFFLOAD");
-        }
-        return sb.toString();
-    }
-
-    @Override
-    public String toString() {
-        return "ConntrackMessage{"
-                + "nlmsghdr{"
-                + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_NETFILTER))
-                + "}, "
-                + "nfgenmsg{" + nfGenMsg + "}, "
-                + "tuple_orig{" + tupleOrig + "}, "
-                + "tuple_reply{" + tupleReply + "}, "
-                + "status{" + status + "(" + stringForIpConntrackStatus(status) + ")" + "}, "
-                + "timeout_sec{" + Integer.toUnsignedLong(timeoutSec) + "}"
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/InetDiagMessage.java b/common/netlinkclient/src/android/net/netlink/InetDiagMessage.java
deleted file mode 100644
index c085123..0000000
--- a/common/netlinkclient/src/android/net/netlink/InetDiagMessage.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
-import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.NETLINK_INET_DIAG;
-
-import android.annotation.Nullable;
-import android.net.util.SocketUtils;
-import android.system.ErrnoException;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * A NetlinkMessage subclass for netlink inet_diag messages.
- *
- * see also: &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- * @hide
- */
-public class InetDiagMessage extends NetlinkMessage {
-    public static final String TAG = "InetDiagMessage";
-    private static final int TIMEOUT_MS = 500;
-
-    public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
-            InetSocketAddress remote, int family, short flags) {
-        return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */,
-                0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES);
-    }
-
-    /**
-     * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
-     * if local and remote are not both null or both non-null.
-     *
-     * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
-     *                 IPPROTO_UDP, or IPPROTO_UDPLITE.
-     * @param local local socket address of the target socket. This will be packed into a
-     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
-     *              local or remote address is null.
-     * @param remote remote socket address of the target socket. This will be packed into a
-     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
-     *              local or remote address is null.
-     * @param family the ip family of the request message. This should be set to either AF_INET or
-     *               AF_INET6 for IPv4 or IPv6 sockets respectively.
-     * @param flags message flags. See &lt;linux_src&gt;/include/uapi/linux/netlink.h.
-     * @param pad for raw socket protocol specification.
-     * @param idiagExt a set of flags defining what kind of extended information to report.
-     * @param state a bit mask that defines a filter of socket states.
-     *
-     * @return bytes array representation of the message
-     **/
-    public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
-            @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
-            int state) throws NullPointerException {
-        final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
-        nlMsgHdr.nlmsg_len = bytes.length;
-        nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
-        nlMsgHdr.nlmsg_flags = flags;
-        nlMsgHdr.pack(byteBuffer);
-        final StructInetDiagReqV2 inetDiagReqV2 =
-                new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
-
-        inetDiagReqV2.pack(byteBuffer);
-        return bytes;
-    }
-
-    public StructInetDiagMsg mStructInetDiagMsg;
-
-    private InetDiagMessage(StructNlMsgHdr header) {
-        super(header);
-        mStructInetDiagMsg = new StructInetDiagMsg();
-    }
-
-    public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        final InetDiagMessage msg = new InetDiagMessage(header);
-        msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
-        return msg;
-    }
-
-    private static int lookupUidByFamily(int protocol, InetSocketAddress local,
-                                         InetSocketAddress remote, int family, short flags,
-                                         FileDescriptor fd)
-            throws ErrnoException, InterruptedIOException {
-        byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
-        NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
-        ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
-
-        final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG);
-        final StructNlMsgHdr hdr = nlMsg.getHeader();
-        if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
-            return INVALID_UID;
-        }
-        if (nlMsg instanceof InetDiagMessage) {
-            return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
-        }
-        return INVALID_UID;
-    }
-
-    private static final int FAMILY[] = {AF_INET6, AF_INET};
-
-    private static int lookupUid(int protocol, InetSocketAddress local,
-                                 InetSocketAddress remote, FileDescriptor fd)
-            throws ErrnoException, InterruptedIOException {
-        int uid;
-
-        for (int family : FAMILY) {
-            /**
-             * For exact match lookup, swap local and remote for UDP lookups due to kernel
-             * bug which will not be fixed. See aosp/755889 and
-             * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
-             */
-            if (protocol == IPPROTO_UDP) {
-                uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
-            } else {
-                uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
-            }
-            if (uid != INVALID_UID) {
-                return uid;
-            }
-        }
-
-        /**
-         * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
-         * socket is not connected (and even if the socket is connected to a different destination).
-         * If we want this API to work for such packets, then on miss we need to do a second lookup
-         * with only the local address and port filled in.
-         * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
-         */
-        if (protocol == IPPROTO_UDP) {
-            try {
-                InetSocketAddress wildcard = new InetSocketAddress(
-                        Inet6Address.getByName("::"), 0);
-                uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
-                        (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
-                if (uid != INVALID_UID) {
-                    return uid;
-                }
-                wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
-                uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
-                        (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
-                if (uid != INVALID_UID) {
-                    return uid;
-                }
-            } catch (UnknownHostException e) {
-                Log.e(TAG, e.toString());
-            }
-        }
-        return INVALID_UID;
-    }
-
-    /**
-     * Use an inet_diag socket to look up the UID associated with the input local and remote
-     * address/port and protocol of a connection.
-     */
-    public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
-                                            InetSocketAddress remote) {
-        int uid = INVALID_UID;
-        FileDescriptor fd = null;
-        try {
-            fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
-            NetlinkSocket.connectToKernel(fd);
-            uid = lookupUid(protocol, local, remote, fd);
-        } catch (ErrnoException | SocketException | IllegalArgumentException
-                | InterruptedIOException e) {
-            Log.e(TAG, e.toString());
-        } finally {
-            if (fd != null) {
-                try {
-                    SocketUtils.closeSocket(fd);
-                } catch (IOException e) {
-                    Log.e(TAG, e.toString());
-                }
-            }
-        }
-        return uid;
-    }
-
-    @Override
-    public String toString() {
-        return "InetDiagMessage{ "
-                + "nlmsghdr{"
-                + (mHeader == null ? "" : mHeader.toString(NETLINK_INET_DIAG)) + "}, "
-                + "inet_diag_msg{"
-                + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/NdOption.java b/common/netlinkclient/src/android/net/netlink/NdOption.java
deleted file mode 100644
index ab9d2e6..0000000
--- a/common/netlinkclient/src/android/net/netlink/NdOption.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import java.nio.ByteBuffer;
-
-/**
- * Base class for IPv6 neighbour discovery options.
- */
-public class NdOption {
-    public static final int STRUCT_SIZE = 2;
-
-    /** The option type. */
-    public final byte type;
-    /** The length of the option in 8-byte units. Actually an unsigned 8-bit integer */
-    public final int length;
-
-    /** Constructs a new NdOption. */
-    NdOption(byte type, int length) {
-        this.type = type;
-        this.length = length;
-    }
-
-    /**
-     * Parses a neighbour discovery option.
-     *
-     * Parses (and consumes) the option if it is of a known type. If the option is of an unknown
-     * type, advances the buffer (so the caller can continue parsing if desired) and returns
-     * {@link #UNKNOWN}. If the option claims a length of 0, returns null because parsing cannot
-     * continue.
-     *
-     * No checks are performed on the length other than ensuring it is not 0, so if a caller wants
-     * to deal with options that might overflow the structure that contains them, it must explicitly
-     * set the buffer's limit to the position at which that structure ends.
-     *
-     * @param buf the buffer to parse.
-     * @return a subclass of {@link NdOption}, or {@code null} for an unknown or malformed option.
-     */
-    public static NdOption parse(ByteBuffer buf) {
-        if (buf == null || buf.remaining() < STRUCT_SIZE) return null;
-
-        // Peek the type without advancing the buffer.
-        byte type = buf.get(buf.position());
-        int length = Byte.toUnsignedInt(buf.get(buf.position() + 1));
-        if (length == 0) return null;
-
-        switch (type) {
-            case StructNdOptPref64.TYPE:
-                return StructNdOptPref64.parse(buf);
-
-            default:
-                int newPosition = Math.min(buf.limit(), buf.position() + length * 8);
-                buf.position(newPosition);
-                return UNKNOWN;
-        }
-    }
-
-    void writeToByteBuffer(ByteBuffer buf) {
-        buf.put(type);
-        buf.put((byte) length);
-    }
-
-    @Override
-    public String toString() {
-        return String.format("NdOption(%d, %d)", Byte.toUnsignedInt(type), length);
-    }
-
-    public static final NdOption UNKNOWN = new NdOption((byte) 0, 0);
-}
diff --git a/common/netlinkclient/src/android/net/netlink/NduseroptMessage.java b/common/netlinkclient/src/android/net/netlink/NduseroptMessage.java
deleted file mode 100644
index 7b976f1..0000000
--- a/common/netlinkclient/src/android/net/netlink/NduseroptMessage.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.system.OsConstants.AF_INET6;
-
-import androidx.annotation.NonNull;
-
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * A NetlinkMessage subclass for RTM_NEWNDUSEROPT messages.
- */
-public class NduseroptMessage extends NetlinkMessage {
-    public static final int STRUCT_SIZE = 16;
-
-    static final int NDUSEROPT_SRCADDR = 1;
-
-    /** The address family. Presumably always AF_INET6. */
-    public final byte family;
-    /**
-     * The total length in bytes of the options that follow this structure.
-     * Actually a 16-bit unsigned integer.
-     */
-    public final int opts_len;
-    /** The interface index on which the options were received. */
-    public final int ifindex;
-    /** The ICMP type of the packet that contained the options. */
-    public final byte icmp_type;
-    /** The ICMP code of the packet that contained the options. */
-    public final byte icmp_code;
-
-    /**
-     * ND option that was in this message.
-     * Even though the length field is called "opts_len", the kernel only ever sends one option per
-     * message. It is unlikely that this will ever change as it would break existing userspace code.
-     * But if it does, we can simply update this code, since userspace is typically newer than the
-     * kernel.
-     */
-    public final NdOption option;
-
-    /** The IP address that sent the packet containing the option. */
-    public final InetAddress srcaddr;
-
-    NduseroptMessage(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf)
-            throws UnknownHostException {
-        super(header);
-
-        // The structure itself.
-        buf.order(ByteOrder.nativeOrder());  // Restored in the finally clause inside parse().
-        final int start = buf.position();
-        family = buf.get();
-        buf.get();  // Skip 1 byte of padding.
-        opts_len = Short.toUnsignedInt(buf.getShort());
-        ifindex = buf.getInt();
-        icmp_type = buf.get();
-        icmp_code = buf.get();
-        buf.position(buf.position() + 6);  // Skip 6 bytes of padding.
-
-        // The ND option.
-        // Ensure we don't read past opts_len even if the option length is invalid.
-        // Note that this check is not really necessary since if the option length is not valid,
-        // this struct won't be very useful to the caller.
-        buf.order(ByteOrder.BIG_ENDIAN);
-        int oldLimit = buf.limit();
-        buf.limit(start + STRUCT_SIZE + opts_len);
-        try {
-            option = NdOption.parse(buf);
-        } finally {
-            buf.limit(oldLimit);
-        }
-
-        // The source address.
-        int newPosition = start + STRUCT_SIZE + opts_len;
-        if (newPosition >= buf.limit()) {
-            throw new IllegalArgumentException("ND options extend past end of buffer");
-        }
-        buf.position(newPosition);
-
-        StructNlAttr nla = StructNlAttr.parse(buf);
-        if (nla == null || nla.nla_type != NDUSEROPT_SRCADDR || nla.nla_value == null) {
-            throw new IllegalArgumentException("Invalid source address in ND useropt");
-        }
-        if (family == AF_INET6) {
-            // InetAddress.getByAddress only looks at the ifindex if the address type needs one.
-            srcaddr = Inet6Address.getByAddress(null /* hostname */, nla.nla_value, ifindex);
-        } else {
-            srcaddr = InetAddress.getByAddress(nla.nla_value);
-        }
-    }
-
-    /**
-     * Parses a StructNduseroptmsg from a {@link ByteBuffer}.
-     *
-     * @param header the netlink message header.
-     * @param buf The buffer from which to parse the option. The buffer's byte order must be
-     *            {@link java.nio.ByteOrder#BIG_ENDIAN}.
-     * @return the parsed option, or {@code null} if the option could not be parsed successfully
-     *         (for example, if it was truncated, or if the prefix length code was wrong).
-     */
-    public static NduseroptMessage parse(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) {
-        if (buf == null || buf.remaining() < STRUCT_SIZE) return null;
-        ByteOrder oldOrder = buf.order();
-        try {
-            return new NduseroptMessage(header, buf);
-        } catch (IllegalArgumentException | UnknownHostException | BufferUnderflowException e) {
-            // Not great, but better than throwing an exception that might crash the caller.
-            // Convention in this package is that null indicates that the option was truncated, so
-            // callers must already handle it.
-            return null;
-        } finally {
-            buf.order(oldOrder);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return String.format("Nduseroptmsg(%d, %d, %d, %d, %d, %s)",
-                family, opts_len, ifindex, Byte.toUnsignedInt(icmp_type),
-                Byte.toUnsignedInt(icmp_code), srcaddr.getHostAddress());
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java b/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java
deleted file mode 100644
index b4d9cc0..0000000
--- a/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.annotation.NonNull;
-import android.system.OsConstants;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * Various constants and static helper methods for netlink communications.
- *
- * Values taken from:
- *
- *     include/uapi/linux/netfilter/nfnetlink.h
- *     include/uapi/linux/netfilter/nfnetlink_conntrack.h
- *     include/uapi/linux/netlink.h
- *     include/uapi/linux/rtnetlink.h
- *
- * @hide
- */
-public class NetlinkConstants {
-    private NetlinkConstants() {}
-
-    public static final int NLA_ALIGNTO = 4;
-    /**
-     * Flag for dumping struct tcp_info.
-     * Corresponding to enum definition in external/strace/linux/inet_diag.h.
-     */
-    public static final int INET_DIAG_MEMINFO = 1;
-
-    public static final int SOCKDIAG_MSG_HEADER_SIZE =
-            StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE;
-
-    public static final int alignedLengthOf(short length) {
-        final int intLength = (int) length & 0xffff;
-        return alignedLengthOf(intLength);
-    }
-
-    public static final int alignedLengthOf(int length) {
-        if (length <= 0) { return 0; }
-        return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
-    }
-
-    public static String stringForAddressFamily(int family) {
-        if (family == OsConstants.AF_INET) { return "AF_INET"; }
-        if (family == OsConstants.AF_INET6) { return "AF_INET6"; }
-        if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; }
-        return String.valueOf(family);
-    }
-
-    public static String stringForProtocol(int protocol) {
-        if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
-        if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
-        return String.valueOf(protocol);
-    }
-
-    public static String hexify(byte[] bytes) {
-        if (bytes == null) { return "(null)"; }
-        return toHexString(bytes, 0, bytes.length);
-    }
-
-    public static String hexify(ByteBuffer buffer) {
-        if (buffer == null) { return "(null)"; }
-        return toHexString(
-                buffer.array(), buffer.position(), buffer.remaining());
-    }
-
-    // Known values for struct nlmsghdr nlm_type.
-    public static final short NLMSG_NOOP                    = 1;   // Nothing
-    public static final short NLMSG_ERROR                   = 2;   // Error
-    public static final short NLMSG_DONE                    = 3;   // End of a dump
-    public static final short NLMSG_OVERRUN                 = 4;   // Data lost
-    public static final short NLMSG_MAX_RESERVED            = 15;  // Max reserved value
-
-    public static final short RTM_NEWLINK                   = 16;
-    public static final short RTM_DELLINK                   = 17;
-    public static final short RTM_GETLINK                   = 18;
-    public static final short RTM_SETLINK                   = 19;
-    public static final short RTM_NEWADDR                   = 20;
-    public static final short RTM_DELADDR                   = 21;
-    public static final short RTM_GETADDR                   = 22;
-    public static final short RTM_NEWROUTE                  = 24;
-    public static final short RTM_DELROUTE                  = 25;
-    public static final short RTM_GETROUTE                  = 26;
-    public static final short RTM_NEWNEIGH                  = 28;
-    public static final short RTM_DELNEIGH                  = 29;
-    public static final short RTM_GETNEIGH                  = 30;
-    public static final short RTM_NEWRULE                   = 32;
-    public static final short RTM_DELRULE                   = 33;
-    public static final short RTM_GETRULE                   = 34;
-    public static final short RTM_NEWNDUSEROPT              = 68;
-
-    // Netfilter netlink message types are presented by two bytes: high byte subsystem and
-    // low byte operation. See the macro NFNL_SUBSYS_ID and NFNL_MSG_TYPE in
-    // include/uapi/linux/netfilter/nfnetlink.h
-    public static final short NFNL_SUBSYS_CTNETLINK         = 1;
-
-    public static final short IPCTNL_MSG_CT_NEW             = 0;
-    public static final short IPCTNL_MSG_CT_GET             = 1;
-    public static final short IPCTNL_MSG_CT_DELETE          = 2;
-    public static final short IPCTNL_MSG_CT_GET_CTRZERO     = 3;
-    public static final short IPCTNL_MSG_CT_GET_STATS_CPU   = 4;
-    public static final short IPCTNL_MSG_CT_GET_STATS       = 5;
-    public static final short IPCTNL_MSG_CT_GET_DYING       = 6;
-    public static final short IPCTNL_MSG_CT_GET_UNCONFIRMED = 7;
-
-    /* see include/uapi/linux/sock_diag.h */
-    public static final short SOCK_DIAG_BY_FAMILY = 20;
-
-    // Netlink groups.
-    public static final int RTNLGRP_ND_USEROPT = 20;
-    public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1);
-
-    /**
-     * Convert a netlink message type to a string for control message.
-     */
-    @NonNull
-    private static String stringForCtlMsgType(short nlmType) {
-        switch (nlmType) {
-            case NLMSG_NOOP: return "NLMSG_NOOP";
-            case NLMSG_ERROR: return "NLMSG_ERROR";
-            case NLMSG_DONE: return "NLMSG_DONE";
-            case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
-            default: return "unknown control message type: " + String.valueOf(nlmType);
-        }
-    }
-
-    /**
-     * Convert a netlink message type to a string for NETLINK_ROUTE.
-     */
-    @NonNull
-    private static String stringForRtMsgType(short nlmType) {
-        switch (nlmType) {
-            case RTM_NEWLINK: return "RTM_NEWLINK";
-            case RTM_DELLINK: return "RTM_DELLINK";
-            case RTM_GETLINK: return "RTM_GETLINK";
-            case RTM_SETLINK: return "RTM_SETLINK";
-            case RTM_NEWADDR: return "RTM_NEWADDR";
-            case RTM_DELADDR: return "RTM_DELADDR";
-            case RTM_GETADDR: return "RTM_GETADDR";
-            case RTM_NEWROUTE: return "RTM_NEWROUTE";
-            case RTM_DELROUTE: return "RTM_DELROUTE";
-            case RTM_GETROUTE: return "RTM_GETROUTE";
-            case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
-            case RTM_DELNEIGH: return "RTM_DELNEIGH";
-            case RTM_GETNEIGH: return "RTM_GETNEIGH";
-            case RTM_NEWRULE: return "RTM_NEWRULE";
-            case RTM_DELRULE: return "RTM_DELRULE";
-            case RTM_GETRULE: return "RTM_GETRULE";
-            case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
-            default: return "unknown RTM type: " + String.valueOf(nlmType);
-        }
-    }
-
-    /**
-     * Convert a netlink message type to a string for NETLINK_INET_DIAG.
-     */
-    @NonNull
-    private static String stringForInetDiagMsgType(short nlmType) {
-        switch (nlmType) {
-            case SOCK_DIAG_BY_FAMILY: return "SOCK_DIAG_BY_FAMILY";
-            default: return "unknown SOCK_DIAG type: " + String.valueOf(nlmType);
-        }
-    }
-
-    /**
-     * Convert a netlink message type to a string for NETLINK_NETFILTER.
-     */
-    @NonNull
-    private static String stringForNfMsgType(short nlmType) {
-        final byte subsysId = (byte) (nlmType >> 8);
-        final byte msgType = (byte) nlmType;
-        switch (subsysId) {
-            case NFNL_SUBSYS_CTNETLINK:
-                switch (msgType) {
-                    case IPCTNL_MSG_CT_NEW: return "IPCTNL_MSG_CT_NEW";
-                    case IPCTNL_MSG_CT_GET: return "IPCTNL_MSG_CT_GET";
-                    case IPCTNL_MSG_CT_DELETE: return "IPCTNL_MSG_CT_DELETE";
-                    case IPCTNL_MSG_CT_GET_CTRZERO: return "IPCTNL_MSG_CT_GET_CTRZERO";
-                    case IPCTNL_MSG_CT_GET_STATS_CPU: return "IPCTNL_MSG_CT_GET_STATS_CPU";
-                    case IPCTNL_MSG_CT_GET_STATS: return "IPCTNL_MSG_CT_GET_STATS";
-                    case IPCTNL_MSG_CT_GET_DYING: return "IPCTNL_MSG_CT_GET_DYING";
-                    case IPCTNL_MSG_CT_GET_UNCONFIRMED: return "IPCTNL_MSG_CT_GET_UNCONFIRMED";
-                }
-                break;
-        }
-        return "unknown NETFILTER type: " + String.valueOf(nlmType);
-    }
-
-    /**
-     * Convert a netlink message type to a string by netlink family.
-     */
-    @NonNull
-    public static String stringForNlMsgType(short nlmType, int nlFamily) {
-        // Reserved control messages. The netlink family is ignored.
-        // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h.
-        if (nlmType <= NLMSG_MAX_RESERVED) return stringForCtlMsgType(nlmType);
-
-        // Netlink family messages. The netlink family is required. Note that the reason for using
-        // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are
-        // not constant.
-        if (nlFamily == OsConstants.NETLINK_ROUTE) return stringForRtMsgType(nlmType);
-        if (nlFamily == OsConstants.NETLINK_INET_DIAG) return stringForInetDiagMsgType(nlmType);
-        if (nlFamily == OsConstants.NETLINK_NETFILTER) return stringForNfMsgType(nlmType);
-
-        return "unknown type: " + String.valueOf(nlmType);
-    }
-
-    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-            'A', 'B', 'C', 'D', 'E', 'F' };
-    /**
-     * Convert a byte array to a hexadecimal string.
-     */
-    public static String toHexString(byte[] array, int offset, int length) {
-        char[] buf = new char[length * 2];
-
-        int bufIndex = 0;
-        for (int i = offset; i < offset + length; i++) {
-            byte b = array[i];
-            buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
-            buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
-        }
-
-        return new String(buf);
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/NetlinkErrorMessage.java b/common/netlinkclient/src/android/net/netlink/NetlinkErrorMessage.java
deleted file mode 100644
index 36b02c6..0000000
--- a/common/netlinkclient/src/android/net/netlink/NetlinkErrorMessage.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * A NetlinkMessage subclass for netlink error messages.
- *
- * @hide
- */
-public class NetlinkErrorMessage extends NetlinkMessage {
-
-    public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header);
-
-        errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer);
-        if (errorMsg.mNlMsgErr == null) {
-            return null;
-        }
-
-        return errorMsg;
-    }
-
-    private StructNlMsgErr mNlMsgErr;
-
-    NetlinkErrorMessage(StructNlMsgHdr header) {
-        super(header);
-        mNlMsgErr = null;
-    }
-
-    public StructNlMsgErr getNlMsgError() {
-        return mNlMsgErr;
-    }
-
-    @Override
-    public String toString() {
-        return "NetlinkErrorMessage{ "
-                + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
-                + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/NetlinkMessage.java b/common/netlinkclient/src/android/net/netlink/NetlinkMessage.java
deleted file mode 100644
index ab2c223..0000000
--- a/common/netlinkclient/src/android/net/netlink/NetlinkMessage.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.system.OsConstants;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * NetlinkMessage base class for other, more specific netlink message types.
- *
- * Classes that extend NetlinkMessage should:
- *     - implement a public static parse(StructNlMsgHdr, ByteBuffer) method
- *     - returning either null (parse errors) or a new object of the subclass
- *       type (cast-able to NetlinkMessage)
- *
- * NetlinkMessage.parse() should be updated to know which nlmsg_type values
- * correspond with which message subclasses.
- *
- * @hide
- */
-public class NetlinkMessage {
-    private final static String TAG = "NetlinkMessage";
-
-    /**
-     * Parsing netlink messages for reserved control message or specific netlink message. The
-     * netlink family is required for parsing specific netlink message. See man-pages/netlink.
-     */
-    @Nullable
-    public static NetlinkMessage parse(@NonNull ByteBuffer byteBuffer, int nlFamily) {
-        final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
-        final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
-        if (nlmsghdr == null) {
-            return null;
-        }
-
-        int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
-        payloadLength -= StructNlMsgHdr.STRUCT_SIZE;
-        if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) {
-            // Malformed message or runt buffer.  Pretend the buffer was consumed.
-            byteBuffer.position(byteBuffer.limit());
-            return null;
-        }
-
-        // Reserved control messages. The netlink family is ignored.
-        // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h.
-        if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
-            return parseCtlMessage(nlmsghdr, byteBuffer, payloadLength);
-        }
-
-        // Netlink family messages. The netlink family is required. Note that the reason for using
-        // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are
-        // not constant.
-        if (nlFamily == OsConstants.NETLINK_ROUTE) {
-            return parseRtMessage(nlmsghdr, byteBuffer);
-        } else if (nlFamily == OsConstants.NETLINK_INET_DIAG) {
-            return parseInetDiagMessage(nlmsghdr, byteBuffer);
-        } else if (nlFamily == OsConstants.NETLINK_NETFILTER) {
-            return parseNfMessage(nlmsghdr, byteBuffer);
-        }
-
-        return null;
-    }
-
-    protected StructNlMsgHdr mHeader;
-
-    public NetlinkMessage(StructNlMsgHdr nlmsghdr) {
-        mHeader = nlmsghdr;
-    }
-
-    public StructNlMsgHdr getHeader() {
-        return mHeader;
-    }
-
-    @Override
-    public String toString() {
-        // The netlink family is not provided to StructNlMsgHdr#toString because NetlinkMessage
-        // doesn't store the information. So the netlink message type can't be transformed into
-        // a string by StructNlMsgHdr#toString and just keep as an integer. The specific message
-        // which inherits NetlinkMessage could override NetlinkMessage#toString and provide the
-        // specific netlink family to StructNlMsgHdr#toString.
-        return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
-    }
-
-    @NonNull
-    private static NetlinkMessage parseCtlMessage(@NonNull StructNlMsgHdr nlmsghdr,
-            @NonNull ByteBuffer byteBuffer, int payloadLength) {
-        switch (nlmsghdr.nlmsg_type) {
-            case NetlinkConstants.NLMSG_ERROR:
-                return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
-            default: {
-                // Other netlink control messages. Just parse the header for now,
-                // pretending the whole message was consumed.
-                byteBuffer.position(byteBuffer.position() + payloadLength);
-                return new NetlinkMessage(nlmsghdr);
-            }
-        }
-    }
-
-    @Nullable
-    private static NetlinkMessage parseRtMessage(@NonNull StructNlMsgHdr nlmsghdr,
-            @NonNull ByteBuffer byteBuffer) {
-        switch (nlmsghdr.nlmsg_type) {
-            case NetlinkConstants.RTM_NEWNEIGH:
-            case NetlinkConstants.RTM_DELNEIGH:
-            case NetlinkConstants.RTM_GETNEIGH:
-                return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
-            case NetlinkConstants.RTM_NEWNDUSEROPT:
-                return (NetlinkMessage) NduseroptMessage.parse(nlmsghdr, byteBuffer);
-            default: return null;
-        }
-    }
-
-    @Nullable
-    private static NetlinkMessage parseInetDiagMessage(@NonNull StructNlMsgHdr nlmsghdr,
-            @NonNull ByteBuffer byteBuffer) {
-        switch (nlmsghdr.nlmsg_type) {
-            case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
-                return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
-            default: return null;
-        }
-    }
-
-    @Nullable
-    private static NetlinkMessage parseNfMessage(@NonNull StructNlMsgHdr nlmsghdr,
-            @NonNull ByteBuffer byteBuffer) {
-        switch (nlmsghdr.nlmsg_type) {
-            case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
-                    | NetlinkConstants.IPCTNL_MSG_CT_NEW:
-            case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
-                    | NetlinkConstants.IPCTNL_MSG_CT_DELETE:
-                return (NetlinkMessage) ConntrackMessage.parse(nlmsghdr, byteBuffer);
-            default: return null;
-        }
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/NetlinkSocket.java b/common/netlinkclient/src/android/net/netlink/NetlinkSocket.java
deleted file mode 100644
index ab4c052..0000000
--- a/common/netlinkclient/src/android/net/netlink/NetlinkSocket.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
-import static android.system.OsConstants.AF_NETLINK;
-import static android.system.OsConstants.EIO;
-import static android.system.OsConstants.EPROTO;
-import static android.system.OsConstants.ETIMEDOUT;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_RCVBUF;
-import static android.system.OsConstants.SO_RCVTIMEO;
-import static android.system.OsConstants.SO_SNDTIMEO;
-
-import android.net.util.SocketUtils;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * NetlinkSocket
- *
- * A small static class to assist with AF_NETLINK socket operations.
- *
- * @hide
- */
-public class NetlinkSocket {
-    private static final String TAG = "NetlinkSocket";
-
-    public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
-    public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
-
-    public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
-        final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
-        final long IO_TIMEOUT = 300L;
-
-        final FileDescriptor fd = forProto(nlProto);
-
-        try {
-            connectToKernel(fd);
-            sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
-            final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
-            // recvMessage() guaranteed to not return null if it did not throw.
-            final NetlinkMessage response = NetlinkMessage.parse(bytes, nlProto);
-            if (response != null && response instanceof NetlinkErrorMessage &&
-                    (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
-                final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
-                if (errno != 0) {
-                    // TODO: consider ignoring EINVAL (-22), which appears to be
-                    // normal when probing a neighbor for which the kernel does
-                    // not already have / no longer has a link layer address.
-                    Log.e(TAG, errPrefix + ", errmsg=" + response.toString());
-                    // Note: convert kernel errnos (negative) into userspace errnos (positive).
-                    throw new ErrnoException(response.toString(), Math.abs(errno));
-                }
-            } else {
-                final String errmsg;
-                if (response == null) {
-                    bytes.position(0);
-                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
-                } else {
-                    errmsg = response.toString();
-                }
-                Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
-                throw new ErrnoException(errmsg, EPROTO);
-            }
-        } catch (InterruptedIOException e) {
-            Log.e(TAG, errPrefix, e);
-            throw new ErrnoException(errPrefix, ETIMEDOUT, e);
-        } catch (SocketException e) {
-            Log.e(TAG, errPrefix, e);
-            throw new ErrnoException(errPrefix, EIO, e);
-        } finally {
-            try {
-                SocketUtils.closeSocket(fd);
-            } catch (IOException e) {
-                // Nothing we can do here
-            }
-        }
-    }
-
-    public static FileDescriptor forProto(int nlProto) throws ErrnoException {
-        final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
-        Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
-        return fd;
-    }
-
-    public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
-        Os.connect(fd, makeNetlinkSocketAddress(0, 0));
-    }
-
-    private static void checkTimeout(long timeoutMs) {
-        if (timeoutMs < 0) {
-            throw new IllegalArgumentException("Negative timeouts not permitted");
-        }
-    }
-
-    /**
-     * Wait up to |timeoutMs| (or until underlying socket error) for a
-     * netlink message of at most |bufsize| size.
-     *
-     * Multi-threaded calls with different timeouts will cause unexpected results.
-     */
-    public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
-            throws ErrnoException, IllegalArgumentException, InterruptedIOException {
-        checkTimeout(timeoutMs);
-
-        Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
-
-        ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
-        int length = Os.read(fd, byteBuffer);
-        if (length == bufsize) {
-            Log.w(TAG, "maximum read");
-        }
-        byteBuffer.position(0);
-        byteBuffer.limit(length);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        return byteBuffer;
-    }
-
-    /**
-     * Send a message to a peer to which this socket has previously connected,
-     * waiting at most |timeoutMs| milliseconds for the send to complete.
-     *
-     * Multi-threaded calls with different timeouts will cause unexpected results.
-     */
-    public static int sendMessage(
-            FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
-            throws ErrnoException, IllegalArgumentException, InterruptedIOException {
-        checkTimeout(timeoutMs);
-        Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
-        return Os.write(fd, bytes, offset, count);
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/RtNetlinkNeighborMessage.java b/common/netlinkclient/src/android/net/netlink/RtNetlinkNeighborMessage.java
deleted file mode 100644
index 099ff07..0000000
--- a/common/netlinkclient/src/android/net/netlink/RtNetlinkNeighborMessage.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import android.system.OsConstants;
-
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * A NetlinkMessage subclass for rtnetlink neighbor messages.
- *
- * see also: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class RtNetlinkNeighborMessage extends NetlinkMessage {
-    public static final short NDA_UNSPEC    = 0;
-    public static final short NDA_DST       = 1;
-    public static final short NDA_LLADDR    = 2;
-    public static final short NDA_CACHEINFO = 3;
-    public static final short NDA_PROBES    = 4;
-    public static final short NDA_VLAN      = 5;
-    public static final short NDA_PORT      = 6;
-    public static final short NDA_VNI       = 7;
-    public static final short NDA_IFINDEX   = 8;
-    public static final short NDA_MASTER    = 9;
-
-    public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
-
-        neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
-        if (neighMsg.mNdmsg == null) {
-            return null;
-        }
-
-        // Some of these are message-type dependent, and not always present.
-        final int baseOffset = byteBuffer.position();
-        StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(NDA_DST, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mDestination = nlAttr.getValueAsInetAddress();
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = StructNlAttr.findNextAttrOfType(NDA_LLADDR, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mLinkLayerAddr = nlAttr.nla_value;
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = StructNlAttr.findNextAttrOfType(NDA_PROBES, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = StructNlAttr.findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
-        }
-
-        final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
-        final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
-                neighMsg.mHeader.nlmsg_len - kMinConsumed);
-        if (byteBuffer.remaining() < kAdditionalSpace) {
-            byteBuffer.position(byteBuffer.limit());
-        } else {
-            byteBuffer.position(baseOffset + kAdditionalSpace);
-        }
-
-        return neighMsg;
-    }
-
-    /**
-     * A convenience method to create an RTM_GETNEIGH request message.
-     */
-    public static byte[] newGetNeighborsRequest(int seqNo) {
-        final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
-        final byte[] bytes = new byte[length];
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
-        nlmsghdr.nlmsg_len = length;
-        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
-        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-        nlmsghdr.nlmsg_seq = seqNo;
-        nlmsghdr.pack(byteBuffer);
-
-        final StructNdMsg ndmsg = new StructNdMsg();
-        ndmsg.pack(byteBuffer);
-
-        return bytes;
-    }
-
-    /**
-     * A convenience method to create an RTM_NEWNEIGH message, to modify
-     * the kernel's state information for a specific neighbor.
-     */
-    public static byte[] newNewNeighborMessage(
-            int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
-        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
-        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
-        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
-        nlmsghdr.nlmsg_seq = seqNo;
-
-        final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
-        msg.mNdmsg = new StructNdMsg();
-        msg.mNdmsg.ndm_family =
-                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
-        msg.mNdmsg.ndm_ifindex = ifIndex;
-        msg.mNdmsg.ndm_state = nudState;
-        msg.mDestination = ip;
-        msg.mLinkLayerAddr = llAddr;  // might be null
-
-        final byte[] bytes = new byte[msg.getRequiredSpace()];
-        nlmsghdr.nlmsg_len = bytes.length;
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        msg.pack(byteBuffer);
-        return bytes;
-    }
-
-    private StructNdMsg mNdmsg;
-    private InetAddress mDestination;
-    private byte[] mLinkLayerAddr;
-    private int mNumProbes;
-    private StructNdaCacheInfo mCacheInfo;
-
-    private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
-        super(header);
-        mNdmsg = null;
-        mDestination = null;
-        mLinkLayerAddr = null;
-        mNumProbes = 0;
-        mCacheInfo = null;
-    }
-
-    public StructNdMsg getNdHeader() {
-        return mNdmsg;
-    }
-
-    public InetAddress getDestination() {
-        return mDestination;
-    }
-
-    public byte[] getLinkLayerAddress() {
-        return mLinkLayerAddr;
-    }
-
-    public int getProbes() {
-        return mNumProbes;
-    }
-
-    public StructNdaCacheInfo getCacheInfo() {
-        return mCacheInfo;
-    }
-
-    public int getRequiredSpace() {
-        int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
-        if (mDestination != null) {
-            spaceRequired += NetlinkConstants.alignedLengthOf(
-                    StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
-        }
-        if (mLinkLayerAddr != null) {
-            spaceRequired += NetlinkConstants.alignedLengthOf(
-                    StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
-        }
-        // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
-        // attributes appended.  Fix later, if necessary.
-        return spaceRequired;
-    }
-
-    private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
-        final StructNlAttr nlAttr = new StructNlAttr();
-        nlAttr.nla_type = nlType;
-        nlAttr.nla_value = nlValue;
-        nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
-        nlAttr.pack(byteBuffer);
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        getHeader().pack(byteBuffer) ;
-        mNdmsg.pack(byteBuffer);
-
-        if (mDestination != null) {
-            packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
-        }
-        if (mLinkLayerAddr != null) {
-            packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
-        }
-    }
-
-    @Override
-    public String toString() {
-        final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
-        return "RtNetlinkNeighborMessage{ "
-                + "nlmsghdr{"
-                + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_ROUTE)) + "}, "
-                + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
-                + "destination{" + ipLiteral + "} "
-                + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
-                + "probes{" + mNumProbes + "} "
-                + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructInetDiagMsg.java b/common/netlinkclient/src/android/net/netlink/StructInetDiagMsg.java
deleted file mode 100644
index 5772a94..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructInetDiagMsg.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import java.nio.ByteBuffer;
-
-/**
- * struct inet_diag_msg
- *
- * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_msg {
- *      __u8    idiag_family;
- *      __u8    idiag_state;
- *      __u8    idiag_timer;
- *      __u8    idiag_retrans;
- *      struct  inet_diag_sockid id;
- *      __u32   idiag_expires;
- *      __u32   idiag_rqueue;
- *      __u32   idiag_wqueue;
- *      __u32   idiag_uid;
- *      __u32   idiag_inode;
- * };
- *
- * @hide
- */
-public class StructInetDiagMsg {
-    public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
-    private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
-            StructInetDiagSockId.STRUCT_SIZE + 12;
-    public int idiag_uid;
-
-    public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
-        StructInetDiagMsg struct = new StructInetDiagMsg();
-        struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
-        return struct;
-    }
-
-    @Override
-    public String toString() {
-        return "StructInetDiagMsg{ "
-                + "idiag_uid{" + idiag_uid + "}, "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructInetDiagReqV2.java b/common/netlinkclient/src/android/net/netlink/StructInetDiagReqV2.java
deleted file mode 100644
index 520f0ef..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructInetDiagReqV2.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.annotation.Nullable;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-
-/**
- * struct inet_diag_req_v2
- *
- * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- *      struct inet_diag_req_v2 {
- *          __u8    sdiag_family;
- *          __u8    sdiag_protocol;
- *          __u8    idiag_ext;
- *          __u8    pad;
- *          __u32   idiag_states;
- *          struct  inet_diag_sockid id;
- *      };
- *
- * @hide
- */
-public class StructInetDiagReqV2 {
-    public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
-
-    private final byte mSdiagFamily;
-    private final byte mSdiagProtocol;
-    private final byte mIdiagExt;
-    private final byte mPad;
-    private final StructInetDiagSockId mId;
-    private final int mState;
-    public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
-
-    public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
-            int family) {
-        this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
-                INET_DIAG_REQ_V2_ALL_STATES);
-    }
-
-    public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
-            @Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
-            throws NullPointerException {
-        mSdiagFamily = (byte) family;
-        mSdiagProtocol = (byte) protocol;
-        // Request for all sockets if no specific socket is requested. Specify the local and remote
-        // socket address information for target request socket.
-        if ((local == null) != (remote == null)) {
-            throw new NullPointerException("Local and remote must be both null or both non-null");
-        }
-        mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
-        mPad = (byte) pad;
-        mIdiagExt = (byte) extension;
-        mState = state;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.
-        byteBuffer.put((byte) mSdiagFamily);
-        byteBuffer.put((byte) mSdiagProtocol);
-        byteBuffer.put((byte) mIdiagExt);
-        byteBuffer.put((byte) mPad);
-        byteBuffer.putInt(mState);
-        if (mId != null) mId.pack(byteBuffer);
-    }
-
-    @Override
-    public String toString() {
-        final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily);
-        final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol);
-
-        return "StructInetDiagReqV2{ "
-                + "sdiag_family{" + familyStr + "}, "
-                + "sdiag_protocol{" + protocolStr + "}, "
-                + "idiag_ext{" + mIdiagExt + ")}, "
-                + "pad{" + mPad + "}, "
-                + "idiag_states{" + Integer.toHexString(mState) + "}, "
-                + ((mId != null) ? mId.toString() : "inet_diag_sockid=null")
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructInetDiagSockId.java b/common/netlinkclient/src/android/net/netlink/StructInetDiagSockId.java
deleted file mode 100644
index 2e9fa25..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructInetDiagSockId.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * struct inet_diag_req_v2
- *
- * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_sockid {
- *        __be16    idiag_sport;
- *        __be16    idiag_dport;
- *        __be32    idiag_src[4];
- *        __be32    idiag_dst[4];
- *        __u32     idiag_if;
- *        __u32     idiag_cookie[2];
- * #define INET_DIAG_NOCOOKIE (~0U)
- * };
- *
- * @hide
- */
-public class StructInetDiagSockId {
-    public static final int STRUCT_SIZE = 48;
-
-    private final InetSocketAddress mLocSocketAddress;
-    private final InetSocketAddress mRemSocketAddress;
-    private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
-    private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-    public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
-        mLocSocketAddress = loc;
-        mRemSocketAddress = rem;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        byteBuffer.order(BIG_ENDIAN);
-        byteBuffer.putShort((short) mLocSocketAddress.getPort());
-        byteBuffer.putShort((short) mRemSocketAddress.getPort());
-        byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
-        if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
-            byteBuffer.put(IPV4_PADDING);
-        }
-        byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
-        if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
-            byteBuffer.put(IPV4_PADDING);
-        }
-        byteBuffer.order(ByteOrder.nativeOrder());
-        byteBuffer.putInt(0);
-        byteBuffer.put(INET_DIAG_NOCOOKIE);
-    }
-
-    @Override
-    public String toString() {
-        return "StructInetDiagSockId{ "
-                + "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
-                + "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
-                + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
-                + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
-                + "idiag_if{" + 0 + "} "
-                + "idiag_cookie{INET_DIAG_NOCOOKIE}"
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNdMsg.java b/common/netlinkclient/src/android/net/netlink/StructNdMsg.java
deleted file mode 100644
index 64364df..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNdMsg.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import android.system.OsConstants;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct ndmsg
- *
- * see: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class StructNdMsg {
-    // Already aligned.
-    public static final int STRUCT_SIZE = 12;
-
-    // Neighbor Cache Entry States
-    public static final short NUD_NONE        = 0x00;
-    public static final short NUD_INCOMPLETE  = 0x01;
-    public static final short NUD_REACHABLE   = 0x02;
-    public static final short NUD_STALE       = 0x04;
-    public static final short NUD_DELAY       = 0x08;
-    public static final short NUD_PROBE       = 0x10;
-    public static final short NUD_FAILED      = 0x20;
-    public static final short NUD_NOARP       = 0x40;
-    public static final short NUD_PERMANENT   = 0x80;
-
-    public static String stringForNudState(short nudState) {
-        switch (nudState) {
-            case NUD_NONE: return "NUD_NONE";
-            case NUD_INCOMPLETE: return "NUD_INCOMPLETE";
-            case NUD_REACHABLE: return "NUD_REACHABLE";
-            case NUD_STALE: return "NUD_STALE";
-            case NUD_DELAY: return "NUD_DELAY";
-            case NUD_PROBE: return "NUD_PROBE";
-            case NUD_FAILED: return "NUD_FAILED";
-            case NUD_NOARP: return "NUD_NOARP";
-            case NUD_PERMANENT: return "NUD_PERMANENT";
-            default:
-                return "unknown NUD state: " + String.valueOf(nudState);
-        }
-    }
-
-    public static boolean isNudStateConnected(short nudState) {
-        return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
-    }
-
-    public static boolean isNudStateValid(short nudState) {
-        return (isNudStateConnected(nudState) ||
-                ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
-    }
-
-    // Neighbor Cache Entry Flags
-    public static byte NTF_USE       = (byte) 0x01;
-    public static byte NTF_SELF      = (byte) 0x02;
-    public static byte NTF_MASTER    = (byte) 0x04;
-    public static byte NTF_PROXY     = (byte) 0x08;
-    public static byte NTF_ROUTER    = (byte) 0x80;
-
-    public static String stringForNudFlags(byte flags) {
-        final StringBuilder sb = new StringBuilder();
-        if ((flags & NTF_USE) != 0) {
-            sb.append("NTF_USE");
-        }
-        if ((flags & NTF_SELF) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NTF_SELF");
-        }
-        if ((flags & NTF_MASTER) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NTF_MASTER");
-        }
-        if ((flags & NTF_PROXY) != 0) {
-            if (sb.length() > 0) { sb.append("|");
-        }
-            sb.append("NTF_PROXY"); }
-        if ((flags & NTF_ROUTER) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NTF_ROUTER");
-        }
-        return sb.toString();
-    }
-
-    private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNdMsg parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        final StructNdMsg struct = new StructNdMsg();
-        struct.ndm_family = byteBuffer.get();
-        final byte pad1 = byteBuffer.get();
-        final short pad2 = byteBuffer.getShort();
-        struct.ndm_ifindex = byteBuffer.getInt();
-        struct.ndm_state = byteBuffer.getShort();
-        struct.ndm_flags = byteBuffer.get();
-        struct.ndm_type = byteBuffer.get();
-        return struct;
-    }
-
-    public byte ndm_family;
-    public int ndm_ifindex;
-    public short ndm_state;
-    public byte ndm_flags;
-    public byte ndm_type;
-
-    public StructNdMsg() {
-        ndm_family = (byte) OsConstants.AF_UNSPEC;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the exception
-        // of usage within unittests.
-        byteBuffer.put(ndm_family);
-        byteBuffer.put((byte) 0);         // pad1
-        byteBuffer.putShort((short) 0);   // pad2
-        byteBuffer.putInt(ndm_ifindex);
-        byteBuffer.putShort(ndm_state);
-        byteBuffer.put(ndm_flags);
-        byteBuffer.put(ndm_type);
-    }
-
-    public boolean nudConnected() {
-        return isNudStateConnected(ndm_state);
-    }
-
-    public boolean nudValid() {
-        return isNudStateValid(ndm_state);
-    }
-
-    @Override
-    public String toString() {
-        final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")";
-        final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")";
-        return "StructNdMsg{ "
-                + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, "
-                + "ifindex{" + ndm_ifindex + "}, "
-                + "state{" + stateStr + "}, "
-                + "flags{" + flagsStr + "}, "
-                + "type{" + ndm_type + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNdOptPref64.java b/common/netlinkclient/src/android/net/netlink/StructNdOptPref64.java
deleted file mode 100644
index 607aaba..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNdOptPref64.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.IpPrefix;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.Objects;
-
-/**
- * The PREF64 router advertisement option. RFC 8781.
- *
- * 0                   1                   2                   3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |     Type      |    Length     |     Scaled Lifetime     | PLC |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |                                                               |
- * +                                                               +
- * |              Highest 96 bits of the Prefix                    |
- * +                                                               +
- * |                                                               |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- */
-public class StructNdOptPref64 extends NdOption {
-    public static final int STRUCT_SIZE = 16;
-    public static final int TYPE = 38;
-    public static final byte LENGTH = 2;
-
-    private static final String TAG = StructNdOptPref64.class.getSimpleName();
-
-    /**
-     * How many seconds the prefix is expected to remain valid.
-     * Valid values are from 0 to 65528 in multiples of 8.
-     */
-    public final int lifetime;
-    /** The NAT64 prefix. */
-    @NonNull public final IpPrefix prefix;
-
-    static int plcToPrefixLength(int plc) {
-        switch (plc) {
-            case 0: return 96;
-            case 1: return 64;
-            case 2: return 56;
-            case 3: return 48;
-            case 4: return 40;
-            case 5: return 32;
-            default:
-                throw new IllegalArgumentException("Invalid prefix length code " + plc);
-        }
-    }
-
-    static int prefixLengthToPlc(int prefixLength) {
-        switch (prefixLength) {
-            case 96: return 0;
-            case 64: return 1;
-            case 56: return 2;
-            case 48: return 3;
-            case 40: return 4;
-            case 32: return 5;
-            default:
-                throw new IllegalArgumentException("Invalid prefix length " + prefixLength);
-        }
-    }
-
-    /**
-     * Returns the 2-byte "scaled lifetime and prefix length code" field: 13-bit lifetime, 3-bit PLC
-     */
-    static short getScaledLifetimePlc(int lifetime, int prefixLengthCode) {
-        return (short) ((lifetime & 0xfff8) | (prefixLengthCode & 0x7));
-    }
-
-    public StructNdOptPref64(@NonNull IpPrefix prefix, int lifetime) {
-        super((byte) TYPE, LENGTH);
-
-        Objects.requireNonNull(prefix, "prefix must not be null");
-        if (!(prefix.getAddress() instanceof Inet6Address)) {
-            throw new IllegalArgumentException("Must be an IPv6 prefix: " + prefix);
-        }
-        prefixLengthToPlc(prefix.getPrefixLength());  // Throw if the prefix length is invalid.
-        this.prefix = prefix;
-
-        if (lifetime < 0 || lifetime > 0xfff8) {
-            throw new IllegalArgumentException("Invalid lifetime " + lifetime);
-        }
-        this.lifetime = lifetime & 0xfff8;
-    }
-
-    private StructNdOptPref64(@NonNull ByteBuffer buf) {
-        super(buf.get(), Byte.toUnsignedInt(buf.get()));
-        if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type);
-        if (length != LENGTH) throw new IllegalArgumentException("Invalid length " + length);
-
-        int scaledLifetimePlc = Short.toUnsignedInt(buf.getShort());
-        lifetime = scaledLifetimePlc & 0xfff8;
-
-        byte[] addressBytes = new byte[16];
-        buf.get(addressBytes, 0, 12);
-        InetAddress addr;
-        try {
-            addr = InetAddress.getByAddress(addressBytes);
-        } catch (UnknownHostException e) {
-            throw new AssertionError("16-byte array not valid InetAddress?");
-        }
-        prefix = new IpPrefix(addr, plcToPrefixLength(scaledLifetimePlc & 7));
-    }
-
-    /**
-     * Parses an option from a {@link ByteBuffer}.
-     *
-     * @param buf The buffer from which to parse the option. The buffer's byte order must be
-     *            {@link java.nio.ByteOrder#BIG_ENDIAN}.
-     * @return the parsed option, or {@code null} if the option could not be parsed successfully
-     *         (for example, if it was truncated, or if the prefix length code was wrong).
-     */
-    public static StructNdOptPref64 parse(@NonNull ByteBuffer buf) {
-        if (buf == null || buf.remaining() < STRUCT_SIZE) return null;
-        try {
-            return new StructNdOptPref64(buf);
-        } catch (IllegalArgumentException e) {
-            // Not great, but better than throwing an exception that might crash the caller.
-            // Convention in this package is that null indicates that the option was truncated, so
-            // callers must already handle it.
-            Log.d(TAG, "Invalid PREF64 option: " + e);
-            return null;
-        }
-    }
-
-    protected void writeToByteBuffer(ByteBuffer buf) {
-        super.writeToByteBuffer(buf);
-        buf.putShort(getScaledLifetimePlc(lifetime,  prefixLengthToPlc(prefix.getPrefixLength())));
-        buf.put(prefix.getRawAddress(), 0, 12);
-    }
-
-    /** Outputs the wire format of the option to a new big-endian ByteBuffer. */
-    public ByteBuffer toByteBuffer() {
-        ByteBuffer buf = ByteBuffer.allocate(STRUCT_SIZE);
-        writeToByteBuffer(buf);
-        buf.flip();
-        return buf;
-    }
-
-    @Override
-    @NonNull
-    public String toString() {
-        return String.format("NdOptPref64(%s, %d)", prefix, lifetime);
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNdaCacheInfo.java b/common/netlinkclient/src/android/net/netlink/StructNdaCacheInfo.java
deleted file mode 100644
index 16cf563..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNdaCacheInfo.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.system.Os;
-import android.system.OsConstants;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nda_cacheinfo
- *
- * see: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class StructNdaCacheInfo {
-    // Already aligned.
-    public static final int STRUCT_SIZE = 16;
-
-    private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        final StructNdaCacheInfo struct = new StructNdaCacheInfo();
-        struct.ndm_used = byteBuffer.getInt();
-        struct.ndm_confirmed = byteBuffer.getInt();
-        struct.ndm_updated = byteBuffer.getInt();
-        struct.ndm_refcnt = byteBuffer.getInt();
-        return struct;
-    }
-
-    // TODO: investigate whether this can change during device runtime and
-    // decide what (if anything) should be done about that.
-    private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);
-
-    private static long ticksToMilliSeconds(int intClockTicks) {
-        final long longClockTicks = (long) intClockTicks & 0xffffffff;
-        return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
-    }
-
-    /**
-     * Explanatory notes, for reference.
-     *
-     * Before being returned to user space, the neighbor entry times are
-     * converted to clock_t's like so:
-     *
-     *     ndm_used      = jiffies_to_clock_t(now - neigh->used);
-     *     ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
-     *     ndm_updated   = jiffies_to_clock_t(now - neigh->updated);
-     *
-     * meaning that these values are expressed as "clock ticks ago".  To
-     * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
-     * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
-     * in centiseconds.
-     *
-     * These values are unsigned, but fortunately being expressed as "some
-     * clock ticks ago", these values are typically very small (and 
-     * 2^31 centiseconds = 248 days).
-     *
-     * By observation, it appears that:
-     *     ndm_used: the last time ARP/ND took place for this neighbor
-     *     ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR
-     *                    higher layer confirmation (TCP or MSG_CONFIRM)
-     *                    was received
-     *     ndm_updated: the time when the current NUD state was entered
-     */
-    public int ndm_used;
-    public int ndm_confirmed;
-    public int ndm_updated;
-    public int ndm_refcnt;
-
-    public StructNdaCacheInfo() {}
-
-    public long lastUsed() {
-        return ticksToMilliSeconds(ndm_used);
-    }
-
-    public long lastConfirmed() {
-        return ticksToMilliSeconds(ndm_confirmed);
-    }
-
-    public long lastUpdated() {
-        return ticksToMilliSeconds(ndm_updated);
-    }
-
-    @Override
-    public String toString() {
-        return "NdaCacheInfo{ "
-                + "ndm_used{" + lastUsed() + "}, "
-                + "ndm_confirmed{" + lastConfirmed() + "}, "
-                + "ndm_updated{" + lastUpdated() + "}, "
-                + "ndm_refcnt{" + ndm_refcnt + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNfGenMsg.java b/common/netlinkclient/src/android/net/netlink/StructNfGenMsg.java
deleted file mode 100644
index 7f247f5..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNfGenMsg.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Objects;
-
-
-/**
- * struct nfgenmsg
- *
- * see &lt;linux_src&gt;/include/uapi/linux/netfilter/nfnetlink.h
- *
- * @hide
- */
-public class StructNfGenMsg {
-    public static final int STRUCT_SIZE = 2 + Short.BYTES;
-
-    public static final int NFNETLINK_V0 = 0;
-
-    final public byte nfgen_family;
-    final public byte version;
-    final public short res_id;  // N.B.: this is big endian in the kernel
-
-    /**
-     * Parses a netfilter netlink header from a {@link ByteBuffer}.
-     *
-     * @param byteBuffer The buffer from which to parse the netfilter netlink header.
-     * @return the parsed netfilter netlink header, or {@code null} if the netfilter netlink header
-     *         could not be parsed successfully (for example, if it was truncated).
-     */
-    @Nullable
-    public static StructNfGenMsg parse(@NonNull ByteBuffer byteBuffer) {
-        Objects.requireNonNull(byteBuffer);
-
-        if (!hasAvailableSpace(byteBuffer)) return null;
-
-        final byte nfgen_family = byteBuffer.get();
-        final byte version = byteBuffer.get();
-
-        final ByteOrder originalOrder = byteBuffer.order();
-        byteBuffer.order(ByteOrder.BIG_ENDIAN);
-        final short res_id = byteBuffer.getShort();
-        byteBuffer.order(originalOrder);
-
-        return new StructNfGenMsg(nfgen_family, version, res_id);
-    }
-
-    public StructNfGenMsg(byte family, byte ver, short id) {
-        nfgen_family = family;
-        version = ver;
-        res_id = id;
-    }
-
-    public StructNfGenMsg(byte family) {
-        nfgen_family = family;
-        version = (byte) NFNETLINK_V0;
-        res_id = (short) 0;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        byteBuffer.put(nfgen_family);
-        byteBuffer.put(version);
-
-        final ByteOrder originalOrder = byteBuffer.order();
-        byteBuffer.order(ByteOrder.BIG_ENDIAN);
-        byteBuffer.putShort(res_id);
-        byteBuffer.order(originalOrder);
-    }
-
-    private static boolean hasAvailableSpace(@NonNull ByteBuffer byteBuffer) {
-        return byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    @Override
-    public String toString() {
-        final String familyStr = NetlinkConstants.stringForAddressFamily(nfgen_family);
-
-        return "NfGenMsg{ "
-                + "nfgen_family{" + familyStr + "}, "
-                + "version{" + Byte.toUnsignedInt(version) + "}, "
-                + "res_id{" + Short.toUnsignedInt(res_id) + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNlAttr.java b/common/netlinkclient/src/android/net/netlink/StructNlAttr.java
deleted file mode 100644
index b6e1d3f..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNlAttr.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import androidx.annotation.Nullable;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * struct nlattr
- *
- * see: &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlAttr {
-    // Already aligned.
-    public static final int NLA_HEADERLEN  = 4;
-    public static final int NLA_F_NESTED   = (1 << 15);
-
-    public static short makeNestedType(short type) {
-        return (short) (type | NLA_F_NESTED);
-    }
-
-    // Return a (length, type) object only, without consuming any bytes in
-    // |byteBuffer| and without copying or interpreting any value bytes.
-    // This is used for scanning over a packed set of struct nlattr's,
-    // looking for instances of a particular type.
-    public static StructNlAttr peek(ByteBuffer byteBuffer) {
-        if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
-            return null;
-        }
-        final int baseOffset = byteBuffer.position();
-
-        final StructNlAttr struct = new StructNlAttr();
-        final ByteOrder originalOrder = byteBuffer.order();
-        byteBuffer.order(ByteOrder.nativeOrder());
-        try {
-            struct.nla_len = byteBuffer.getShort();
-            struct.nla_type = byteBuffer.getShort();
-        } finally {
-            byteBuffer.order(originalOrder);
-        }
-
-        byteBuffer.position(baseOffset);
-        if (struct.nla_len < NLA_HEADERLEN) {
-            // Malformed.
-            return null;
-        }
-        return struct;
-    }
-
-    public static StructNlAttr parse(ByteBuffer byteBuffer) {
-        final StructNlAttr struct = peek(byteBuffer);
-        if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
-            return null;
-        }
-
-        final int baseOffset = byteBuffer.position();
-        byteBuffer.position(baseOffset + NLA_HEADERLEN);
-
-        int valueLen = ((int) struct.nla_len) & 0xffff;
-        valueLen -= NLA_HEADERLEN;
-        if (valueLen > 0) {
-            struct.nla_value = new byte[valueLen];
-            byteBuffer.get(struct.nla_value, 0, valueLen);
-            byteBuffer.position(baseOffset + struct.getAlignedLength());
-        }
-        return struct;
-    }
-
-    /**
-     * Find next netlink attribute with a given type from {@link ByteBuffer}.
-     *
-     * @param attrType The given netlink attribute type is requested for.
-     * @param byteBuffer The buffer from which to find the netlink attribute.
-     * @return the found netlink attribute, or {@code null} if the netlink attribute could not be
-     *         found or parsed successfully (for example, if it was truncated).
-     */
-    @Nullable
-    public static StructNlAttr findNextAttrOfType(short attrType,
-            @Nullable ByteBuffer byteBuffer) {
-        while (byteBuffer != null && byteBuffer.remaining() > 0) {
-            final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
-            if (nlAttr == null) {
-                break;
-            }
-            if (nlAttr.nla_type == attrType) {
-                return StructNlAttr.parse(byteBuffer);
-            }
-            if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
-                break;
-            }
-            byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
-        }
-        return null;
-    }
-
-    public short nla_len = (short) NLA_HEADERLEN;
-    public short nla_type;
-    public byte[] nla_value;
-
-    public StructNlAttr() {}
-
-    public StructNlAttr(short type, byte value) {
-        nla_type = type;
-        setValue(new byte[1]);
-        nla_value[0] = value;
-    }
-
-    public StructNlAttr(short type, short value) {
-        this(type, value, ByteOrder.nativeOrder());
-    }
-
-    public StructNlAttr(short type, short value, ByteOrder order) {
-        nla_type = type;
-        setValue(new byte[Short.BYTES]);
-        final ByteBuffer buf = getValueAsByteBuffer();
-        final ByteOrder originalOrder = buf.order();
-        try {
-            buf.order(order);
-            buf.putShort(value);
-        } finally {
-            buf.order(originalOrder);
-        }
-    }
-
-    public StructNlAttr(short type, int value) {
-        this(type, value, ByteOrder.nativeOrder());
-    }
-
-    public StructNlAttr(short type, int value, ByteOrder order) {
-        nla_type = type;
-        setValue(new byte[Integer.BYTES]);
-        final ByteBuffer buf = getValueAsByteBuffer();
-        final ByteOrder originalOrder = buf.order();
-        try {
-            buf.order(order);
-            buf.putInt(value);
-        } finally {
-            buf.order(originalOrder);
-        }
-    }
-
-    public StructNlAttr(short type, InetAddress ip) {
-        nla_type = type;
-        setValue(ip.getAddress());
-    }
-
-    public StructNlAttr(short type, StructNlAttr... nested) {
-        this();
-        nla_type = makeNestedType(type);
-
-        int payloadLength = 0;
-        for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength();
-        setValue(new byte[payloadLength]);
-
-        final ByteBuffer buf = getValueAsByteBuffer();
-        for (StructNlAttr nla : nested) {
-            nla.pack(buf);
-        }
-    }
-
-    public int getAlignedLength() {
-        return NetlinkConstants.alignedLengthOf(nla_len);
-    }
-
-    /**
-     * Get attribute value as BE16.
-     */
-    public short getValueAsBe16(short defaultValue) {
-        final ByteBuffer byteBuffer = getValueAsByteBuffer();
-        if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) {
-            return defaultValue;
-        }
-        final ByteOrder originalOrder = byteBuffer.order();
-        try {
-            byteBuffer.order(ByteOrder.BIG_ENDIAN);
-            return byteBuffer.getShort();
-        } finally {
-            byteBuffer.order(originalOrder);
-        }
-    }
-
-    public int getValueAsBe32(int defaultValue) {
-        final ByteBuffer byteBuffer = getValueAsByteBuffer();
-        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
-            return defaultValue;
-        }
-        final ByteOrder originalOrder = byteBuffer.order();
-        try {
-            byteBuffer.order(ByteOrder.BIG_ENDIAN);
-            return byteBuffer.getInt();
-        } finally {
-            byteBuffer.order(originalOrder);
-        }
-    }
-
-    public ByteBuffer getValueAsByteBuffer() {
-        if (nla_value == null) { return null; }
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
-        // By convention, all buffers in this library are in native byte order because netlink is in
-        // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only
-        // order accepted by NetlinkMessage.parse.
-        byteBuffer.order(ByteOrder.nativeOrder());
-        return byteBuffer;
-    }
-
-    /**
-     * Get attribute value as byte.
-     */
-    public byte getValueAsByte(byte defaultValue) {
-        final ByteBuffer byteBuffer = getValueAsByteBuffer();
-        if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) {
-            return defaultValue;
-        }
-        return getValueAsByteBuffer().get();
-    }
-
-    public int getValueAsInt(int defaultValue) {
-        final ByteBuffer byteBuffer = getValueAsByteBuffer();
-        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
-            return defaultValue;
-        }
-        return getValueAsByteBuffer().getInt();
-    }
-
-    public InetAddress getValueAsInetAddress() {
-        if (nla_value == null) { return null; }
-
-        try {
-            return InetAddress.getByAddress(nla_value);
-        } catch (UnknownHostException ignored) {
-            return null;
-        }
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        final ByteOrder originalOrder = byteBuffer.order();
-        final int originalPosition = byteBuffer.position();
-
-        byteBuffer.order(ByteOrder.nativeOrder());
-        try {
-            byteBuffer.putShort(nla_len);
-            byteBuffer.putShort(nla_type);
-            if (nla_value != null) byteBuffer.put(nla_value);
-        } finally {
-            byteBuffer.order(originalOrder);
-        }
-        byteBuffer.position(originalPosition + getAlignedLength());
-    }
-
-    private void setValue(byte[] value) {
-        nla_value = value;
-        nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0));
-    }
-
-    @Override
-    public String toString() {
-        return "StructNlAttr{ "
-                + "nla_len{" + nla_len + "}, "
-                + "nla_type{" + nla_type + "}, "
-                + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNlMsgErr.java b/common/netlinkclient/src/android/net/netlink/StructNlMsgErr.java
deleted file mode 100644
index 9ea4364..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNlMsgErr.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlmsgerr
- *
- * see &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlMsgErr {
-    public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE;
-
-    public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNlMsgErr parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the exception
-        // of usage within unittests.
-        final StructNlMsgErr struct = new StructNlMsgErr();
-        struct.error = byteBuffer.getInt();
-        struct.msg = StructNlMsgHdr.parse(byteBuffer);
-        return struct;
-    }
-
-    public int error;
-    public StructNlMsgHdr msg;
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        byteBuffer.putInt(error);
-        if (msg != null) {
-            msg.pack(byteBuffer);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "StructNlMsgErr{ "
-                + "error{" + error + "}, "
-                + "msg{" + (msg == null ? "" : msg.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/common/netlinkclient/src/android/net/netlink/StructNlMsgHdr.java b/common/netlinkclient/src/android/net/netlink/StructNlMsgHdr.java
deleted file mode 100644
index 55a649d..0000000
--- a/common/netlinkclient/src/android/net/netlink/StructNlMsgHdr.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlmsghdr
- *
- * see &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlMsgHdr {
-    // Already aligned.
-    public static final int STRUCT_SIZE = 16;
-
-    public static final short NLM_F_REQUEST = 0x0001;
-    public static final short NLM_F_MULTI   = 0x0002;
-    public static final short NLM_F_ACK     = 0x0004;
-    public static final short NLM_F_ECHO    = 0x0008;
-    // Flags for a GET request.
-    public static final short NLM_F_ROOT    = 0x0100;
-    public static final short NLM_F_MATCH   = 0x0200;
-    public static final short NLM_F_DUMP    = NLM_F_ROOT|NLM_F_MATCH;
-    // Flags for a NEW request.
-    public static final short NLM_F_REPLACE   = 0x100;
-    public static final short NLM_F_EXCL      = 0x200;
-    public static final short NLM_F_CREATE    = 0x400;
-    public static final short NLM_F_APPEND    = 0x800;
-
-    // TODO: Probably need to distinguish the flags which have the same value. For example,
-    // NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200).
-    public static String stringForNlMsgFlags(short flags) {
-        final StringBuilder sb = new StringBuilder();
-        if ((flags & NLM_F_REQUEST) != 0) {
-            sb.append("NLM_F_REQUEST");
-        }
-        if ((flags & NLM_F_MULTI) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_MULTI");
-        }
-        if ((flags & NLM_F_ACK) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_ACK");
-        }
-        if ((flags & NLM_F_ECHO) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_ECHO");
-        }
-        if ((flags & NLM_F_ROOT) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_ROOT");
-        }
-        if ((flags & NLM_F_MATCH) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_MATCH");
-        }
-        return sb.toString();
-    }
-
-    public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNlMsgHdr parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the exception
-        // of usage within unittests.
-        final StructNlMsgHdr struct = new StructNlMsgHdr();
-        struct.nlmsg_len = byteBuffer.getInt();
-        struct.nlmsg_type = byteBuffer.getShort();
-        struct.nlmsg_flags = byteBuffer.getShort();
-        struct.nlmsg_seq = byteBuffer.getInt();
-        struct.nlmsg_pid = byteBuffer.getInt();
-
-        if (struct.nlmsg_len < STRUCT_SIZE) {
-            // Malformed.
-            return null;
-        }
-        return struct;
-    }
-
-    public int nlmsg_len;
-    public short nlmsg_type;
-    public short nlmsg_flags;
-    public int nlmsg_seq;
-    public int nlmsg_pid;
-
-    public StructNlMsgHdr() {
-        nlmsg_len = 0;
-        nlmsg_type = 0;
-        nlmsg_flags = 0;
-        nlmsg_seq = 0;
-        nlmsg_pid = 0;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        byteBuffer.putInt(nlmsg_len);
-        byteBuffer.putShort(nlmsg_type);
-        byteBuffer.putShort(nlmsg_flags);
-        byteBuffer.putInt(nlmsg_seq);
-        byteBuffer.putInt(nlmsg_pid);
-    }
-
-    @Override
-    public String toString() {
-        return toString(null /* unknown netlink family */);
-    }
-
-    /**
-     * Transform a netlink header into a string. The netlink family is required for transforming
-     * a netlink type integer into a string.
-     * @param nlFamily netlink family. Using Integer will not incur autoboxing penalties because
-     *                 family values are small, and all Integer objects between -128 and 127 are
-     *                 statically cached. See Integer.IntegerCache.
-     * @return A list of header elements.
-     */
-    @NonNull
-    public String toString(@Nullable Integer nlFamily) {
-        final String typeStr = "" + nlmsg_type
-                + "(" + (nlFamily == null
-                ? "" : NetlinkConstants.stringForNlMsgType(nlmsg_type, nlFamily))
-                + ")";
-        final String flagsStr = "" + nlmsg_flags
-                + "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
-        return "StructNlMsgHdr{ "
-                + "nlmsg_len{" + nlmsg_len + "}, "
-                + "nlmsg_type{" + typeStr + "}, "
-                + "nlmsg_flags{" + flagsStr + ")}, "
-                + "nlmsg_seq{" + nlmsg_seq + "}, "
-                + "nlmsg_pid{" + nlmsg_pid + "} "
-                + "}";
-    }
-}
diff --git a/common/networkstackclient/Android.bp b/common/networkstackclient/Android.bp
index 376ff89..02a39f6 100644
--- a/common/networkstackclient/Android.bp
+++ b/common/networkstackclient/Android.bp
@@ -133,6 +133,8 @@
         "8",
         "9",
         "10",
+        "11",
+        "12",
     ],
     // TODO: have tethering depend on networkstack-client and set visibility to private
     visibility: [
@@ -160,11 +162,11 @@
         "src/android/net/util/**/*.java",
     ],
     libs: [
-        "net-utils-framework-common",  // XXX for IpUtils.java only
+        "net-utils-framework-common", // XXX for IpUtils.java only
     ],
     static_libs: [
         "ipmemorystore-aidl-interfaces-V10-java",
-        "networkstack-aidl-interfaces-V10-java",
+        "networkstack-aidl-interfaces-V12-java",
     ],
     visibility: [
         "//frameworks/base/packages/Connectivity/service",
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl
index bf7a26d..048e84c 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStoreCallbacks.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStoreCallbacks.aidl
index 2024391..7dbbc98 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStoreCallbacks.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStoreCallbacks.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/Blob.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/Blob.aidl
index 8a1b57e..4300c83 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/Blob.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/Blob.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
index e711272..3a263e2 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
index 4abecb9..c663ccf 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl
index 05c48b3..3740e15 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl
index 0bc8c5e..9d87fbb 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusAndCountListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusAndCountListener.aidl
index cf30fa1..1e6a41c 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusAndCountListener.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusAndCountListener.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusListener.aidl
index e71de47..dccdf27 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusListener.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnStatusListener.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
index 2ac7644..227785d 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
index 42a1feb..377a3ec 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/StatusParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/StatusParcelable.aidl
index 1bea082..59b96cd 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/StatusParcelable.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/StatusParcelable.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl
index e2ecbb4..c01564b 100644
--- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl
+++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
 //
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
 // with the aidl_interface module type with versions property set. The module
 // type is used to build AIDL files in a way that they can be used across
 // independently updatable components of the system. If a device is shipped
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/.hash b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/.hash
new file mode 100644
index 0000000..2914d2a
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/.hash
@@ -0,0 +1 @@
+7fecd0a7a6d978705afad88c5e492613cc46e2cb
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/DataStallReportParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/DataStallReportParcelable.aidl
new file mode 100644
index 0000000..771deda
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/DataStallReportParcelable.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable DataStallReportParcelable {
+  long timestampMillis = 0;
+  int detectionMethod = 1;
+  int tcpPacketFailRate = 2;
+  int tcpMetricsCollectionPeriodMillis = 3;
+  int dnsConsecutiveTimeouts = 4;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/DhcpResultsParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/DhcpResultsParcelable.aidl
new file mode 100644
index 0000000..31f2194
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/DhcpResultsParcelable.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable DhcpResultsParcelable {
+  android.net.StaticIpConfiguration baseConfiguration;
+  int leaseDuration;
+  int mtu;
+  String serverAddress;
+  String vendorInfo;
+  @nullable String serverHostName;
+  @nullable String captivePortalApiUrl;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkMonitor.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkMonitor.aidl
new file mode 100644
index 0000000..d92196d
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkMonitor.aidl
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkMonitor {
+  oneway void start();
+  oneway void launchCaptivePortalApp();
+  oneway void notifyCaptivePortalAppFinished(int response);
+  oneway void setAcceptPartialConnectivity();
+  oneway void forceReevaluation(int uid);
+  oneway void notifyPrivateDnsChanged(in android.net.PrivateDnsConfigParcel config);
+  oneway void notifyDnsResponse(int returnCode);
+  oneway void notifyNetworkConnected(in android.net.LinkProperties lp, in android.net.NetworkCapabilities nc);
+  oneway void notifyNetworkDisconnected();
+  oneway void notifyLinkPropertiesChanged(in android.net.LinkProperties lp);
+  oneway void notifyNetworkCapabilitiesChanged(in android.net.NetworkCapabilities nc);
+  const int NETWORK_TEST_RESULT_VALID = 0;
+  const int NETWORK_TEST_RESULT_INVALID = 1;
+  const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2;
+  const int NETWORK_VALIDATION_RESULT_VALID = 1;
+  const int NETWORK_VALIDATION_RESULT_PARTIAL = 2;
+  const int NETWORK_VALIDATION_RESULT_SKIPPED = 4;
+  const int NETWORK_VALIDATION_PROBE_DNS = 4;
+  const int NETWORK_VALIDATION_PROBE_HTTP = 8;
+  const int NETWORK_VALIDATION_PROBE_HTTPS = 16;
+  const int NETWORK_VALIDATION_PROBE_FALLBACK = 32;
+  const int NETWORK_VALIDATION_PROBE_PRIVDNS = 64;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkMonitorCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkMonitorCallbacks.aidl
new file mode 100644
index 0000000..36eda8e
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkMonitorCallbacks.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkMonitorCallbacks {
+  oneway void onNetworkMonitorCreated(in android.net.INetworkMonitor networkMonitor) = 0;
+  oneway void notifyNetworkTested(int testResult, @nullable String redirectUrl) = 1;
+  oneway void notifyPrivateDnsConfigResolved(in android.net.PrivateDnsConfigParcel config) = 2;
+  oneway void showProvisioningNotification(String action, String packageName) = 3;
+  oneway void hideProvisioningNotification() = 4;
+  oneway void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) = 5;
+  oneway void notifyNetworkTestedWithExtras(in android.net.NetworkTestResultParcelable result) = 6;
+  oneway void notifyDataStallSuspected(in android.net.DataStallReportParcelable report) = 7;
+  oneway void notifyCaptivePortalDataChanged(in android.net.CaptivePortalData data) = 8;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkStackConnector.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkStackConnector.aidl
new file mode 100644
index 0000000..8120ffc
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkStackConnector.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkStackConnector {
+  oneway void makeDhcpServer(in String ifName, in android.net.dhcp.DhcpServingParamsParcel params, in android.net.dhcp.IDhcpServerCallbacks cb);
+  oneway void makeNetworkMonitor(in android.net.Network network, String name, in android.net.INetworkMonitorCallbacks cb);
+  oneway void makeIpClient(in String ifName, in android.net.ip.IIpClientCallbacks callbacks);
+  oneway void fetchIpMemoryStore(in android.net.IIpMemoryStoreCallbacks cb);
+  oneway void allowTestUid(int uid, in android.net.INetworkStackStatusCallback cb);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkStackStatusCallback.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkStackStatusCallback.aidl
new file mode 100644
index 0000000..0b6b778
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/INetworkStackStatusCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkStackStatusCallback {
+  oneway void onStatusAvailable(int statusCode);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/InformationElementParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/InformationElementParcelable.aidl
new file mode 100644
index 0000000..6103774
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/InformationElementParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable InformationElementParcelable {
+  int id;
+  byte[] payload;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/InitialConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/InitialConfigurationParcelable.aidl
new file mode 100644
index 0000000..6a597e6
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/InitialConfigurationParcelable.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable InitialConfigurationParcelable {
+  android.net.LinkAddress[] ipAddresses;
+  android.net.IpPrefix[] directlyConnectedRoutes;
+  String[] dnsServers;
+  String gateway;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/Layer2InformationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/Layer2InformationParcelable.aidl
new file mode 100644
index 0000000..83796ee
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/Layer2InformationParcelable.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable Layer2InformationParcelable {
+  String l2Key;
+  String cluster;
+  android.net.MacAddress bssid;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/Layer2PacketParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/Layer2PacketParcelable.aidl
new file mode 100644
index 0000000..4b3fff5
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/Layer2PacketParcelable.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable Layer2PacketParcelable {
+  android.net.MacAddress dstMacAddress;
+  byte[] payload;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/NattKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/NattKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..18cf954
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/NattKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable NattKeepalivePacketDataParcelable {
+  byte[] srcAddress;
+  int srcPort;
+  byte[] dstAddress;
+  int dstPort;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/NetworkTestResultParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/NetworkTestResultParcelable.aidl
new file mode 100644
index 0000000..4d6d5a2
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/NetworkTestResultParcelable.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable NetworkTestResultParcelable {
+  long timestampMillis;
+  int result;
+  int probesSucceeded;
+  int probesAttempted;
+  String redirectUrl;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/PrivateDnsConfigParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/PrivateDnsConfigParcel.aidl
new file mode 100644
index 0000000..1457caf
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/PrivateDnsConfigParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable PrivateDnsConfigParcel {
+  String hostname;
+  String[] ips;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ProvisioningConfigurationParcelable.aidl
new file mode 100644
index 0000000..0b7a7a1
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ProvisioningConfigurationParcelable.aidl
@@ -0,0 +1,54 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable ProvisioningConfigurationParcelable {
+  boolean enableIPv4;
+  boolean enableIPv6;
+  boolean usingMultinetworkPolicyTracker;
+  boolean usingIpReachabilityMonitor;
+  int requestedPreDhcpActionMs;
+  android.net.InitialConfigurationParcelable initialConfig;
+  android.net.StaticIpConfiguration staticIpConfig;
+  android.net.apf.ApfCapabilities apfCapabilities;
+  int provisioningTimeoutMs;
+  int ipv6AddrGenMode;
+  android.net.Network network;
+  String displayName;
+  boolean enablePreconnection;
+  @nullable android.net.ScanResultInfoParcelable scanResultInfo;
+  @nullable android.net.Layer2InformationParcelable layer2Info;
+  @nullable List<android.net.networkstack.aidl.dhcp.DhcpOption> options;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ScanResultInfoParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ScanResultInfoParcelable.aidl
new file mode 100644
index 0000000..94fc27f
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ScanResultInfoParcelable.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable ScanResultInfoParcelable {
+  String ssid;
+  String bssid;
+  android.net.InformationElementParcelable[] informationElements;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/TcpKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/TcpKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..0e1c21c
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable TcpKeepalivePacketDataParcelable {
+  byte[] srcAddress;
+  int srcPort;
+  byte[] dstAddress;
+  int dstPort;
+  int seq;
+  int ack;
+  int rcvWnd;
+  int rcvWndScale;
+  int tos;
+  int ttl;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/DhcpLeaseParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/DhcpLeaseParcelable.aidl
new file mode 100644
index 0000000..3cd8860
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/DhcpLeaseParcelable.aidl
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+@JavaDerive(toString=true)
+parcelable DhcpLeaseParcelable {
+  byte[] clientId;
+  byte[] hwAddr;
+  int netAddr;
+  int prefixLength;
+  long expTime;
+  String hostname;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/DhcpServingParamsParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/DhcpServingParamsParcel.aidl
new file mode 100644
index 0000000..fa412cb
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,48 @@
+/**
+ *
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+@JavaDerive(toString=true)
+parcelable DhcpServingParamsParcel {
+  int serverAddr;
+  int serverAddrPrefixLength;
+  int[] defaultRouters;
+  int[] dnsServers;
+  int[] excludedAddrs;
+  long dhcpLeaseTimeSecs;
+  int linkMtu;
+  boolean metered;
+  int singleClientAddr = 0;
+  boolean changePrefixOnDecline = false;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpEventCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpEventCallbacks.aidl
new file mode 100644
index 0000000..9312f47
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpEventCallbacks.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+interface IDhcpEventCallbacks {
+  oneway void onLeasesChanged(in List<android.net.dhcp.DhcpLeaseParcelable> newLeases);
+  oneway void onNewPrefixRequest(in android.net.IpPrefix currentPrefix);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpServer.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpServer.aidl
new file mode 100644
index 0000000..1109f35
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpServer.aidl
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+/* @hide */
+interface IDhcpServer {
+  oneway void start(in android.net.INetworkStackStatusCallback cb) = 0;
+  oneway void startWithCallbacks(in android.net.INetworkStackStatusCallback statusCb, in android.net.dhcp.IDhcpEventCallbacks eventCb) = 3;
+  oneway void updateParams(in android.net.dhcp.DhcpServingParamsParcel params, in android.net.INetworkStackStatusCallback cb) = 1;
+  oneway void stop(in android.net.INetworkStackStatusCallback cb) = 2;
+  const int STATUS_UNKNOWN = 0;
+  const int STATUS_SUCCESS = 1;
+  const int STATUS_INVALID_ARGUMENT = 2;
+  const int STATUS_UNKNOWN_ERROR = 3;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpServerCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpServerCallbacks.aidl
new file mode 100644
index 0000000..ab8577c
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/dhcp/IDhcpServerCallbacks.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+/* @hide */
+interface IDhcpServerCallbacks {
+  oneway void onDhcpServerCreated(int statusCode, in android.net.dhcp.IDhcpServer server);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ip/IIpClient.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ip/IIpClient.aidl
new file mode 100644
index 0000000..1fe4c4c
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ip/IIpClient.aidl
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.ip;
+/* @hide */
+interface IIpClient {
+  oneway void completedPreDhcpAction();
+  oneway void confirmConfiguration();
+  oneway void readPacketFilterComplete(in byte[] data);
+  oneway void shutdown();
+  oneway void startProvisioning(in android.net.ProvisioningConfigurationParcelable req);
+  oneway void stop();
+  oneway void setTcpBufferSizes(in String tcpBufferSizes);
+  oneway void setHttpProxy(in android.net.ProxyInfo proxyInfo);
+  oneway void setMulticastFilter(boolean enabled);
+  oneway void addKeepalivePacketFilter(int slot, in android.net.TcpKeepalivePacketDataParcelable pkt);
+  oneway void removeKeepalivePacketFilter(int slot);
+  oneway void setL2KeyAndGroupHint(in String l2Key, in String cluster);
+  oneway void addNattKeepalivePacketFilter(int slot, in android.net.NattKeepalivePacketDataParcelable pkt);
+  oneway void notifyPreconnectionComplete(boolean success);
+  oneway void updateLayer2Information(in android.net.Layer2InformationParcelable info);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ip/IIpClientCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ip/IIpClientCallbacks.aidl
new file mode 100644
index 0000000..488510d
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/ip/IIpClientCallbacks.aidl
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.ip;
+/* @hide */
+interface IIpClientCallbacks {
+  oneway void onIpClientCreated(in android.net.ip.IIpClient ipClient);
+  oneway void onPreDhcpAction();
+  oneway void onPostDhcpAction();
+  oneway void onNewDhcpResults(in android.net.DhcpResultsParcelable dhcpResults);
+  oneway void onProvisioningSuccess(in android.net.LinkProperties newLp);
+  oneway void onProvisioningFailure(in android.net.LinkProperties newLp);
+  oneway void onLinkPropertiesChange(in android.net.LinkProperties newLp);
+  oneway void onReachabilityLost(in String logMsg);
+  oneway void onQuit();
+  oneway void installPacketFilter(in byte[] filter);
+  oneway void startReadPacketFilter();
+  oneway void setFallbackMulticastFilter(boolean enabled);
+  oneway void setNeighborDiscoveryOffload(boolean enable);
+  oneway void onPreconnectionStart(in List<android.net.Layer2PacketParcelable> packets);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/networkstack/aidl/dhcp/DhcpOption.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
new file mode 100644
index 0000000..eea3e0d
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/11/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.networkstack.aidl.dhcp;
+@JavaDerive(toString=true)
+parcelable DhcpOption {
+  byte type;
+  @nullable byte[] value;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/.hash b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/.hash
new file mode 100644
index 0000000..e96fe34
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/.hash
@@ -0,0 +1 @@
+ca534b24b8f1e946a36977f391a156016ea7ef4a
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/DataStallReportParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/DataStallReportParcelable.aidl
new file mode 100644
index 0000000..771deda
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/DataStallReportParcelable.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable DataStallReportParcelable {
+  long timestampMillis = 0;
+  int detectionMethod = 1;
+  int tcpPacketFailRate = 2;
+  int tcpMetricsCollectionPeriodMillis = 3;
+  int dnsConsecutiveTimeouts = 4;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/DhcpResultsParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/DhcpResultsParcelable.aidl
new file mode 100644
index 0000000..31f2194
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/DhcpResultsParcelable.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable DhcpResultsParcelable {
+  android.net.StaticIpConfiguration baseConfiguration;
+  int leaseDuration;
+  int mtu;
+  String serverAddress;
+  String vendorInfo;
+  @nullable String serverHostName;
+  @nullable String captivePortalApiUrl;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkMonitor.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkMonitor.aidl
new file mode 100644
index 0000000..d92196d
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkMonitor.aidl
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkMonitor {
+  oneway void start();
+  oneway void launchCaptivePortalApp();
+  oneway void notifyCaptivePortalAppFinished(int response);
+  oneway void setAcceptPartialConnectivity();
+  oneway void forceReevaluation(int uid);
+  oneway void notifyPrivateDnsChanged(in android.net.PrivateDnsConfigParcel config);
+  oneway void notifyDnsResponse(int returnCode);
+  oneway void notifyNetworkConnected(in android.net.LinkProperties lp, in android.net.NetworkCapabilities nc);
+  oneway void notifyNetworkDisconnected();
+  oneway void notifyLinkPropertiesChanged(in android.net.LinkProperties lp);
+  oneway void notifyNetworkCapabilitiesChanged(in android.net.NetworkCapabilities nc);
+  const int NETWORK_TEST_RESULT_VALID = 0;
+  const int NETWORK_TEST_RESULT_INVALID = 1;
+  const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2;
+  const int NETWORK_VALIDATION_RESULT_VALID = 1;
+  const int NETWORK_VALIDATION_RESULT_PARTIAL = 2;
+  const int NETWORK_VALIDATION_RESULT_SKIPPED = 4;
+  const int NETWORK_VALIDATION_PROBE_DNS = 4;
+  const int NETWORK_VALIDATION_PROBE_HTTP = 8;
+  const int NETWORK_VALIDATION_PROBE_HTTPS = 16;
+  const int NETWORK_VALIDATION_PROBE_FALLBACK = 32;
+  const int NETWORK_VALIDATION_PROBE_PRIVDNS = 64;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkMonitorCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkMonitorCallbacks.aidl
new file mode 100644
index 0000000..36eda8e
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkMonitorCallbacks.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkMonitorCallbacks {
+  oneway void onNetworkMonitorCreated(in android.net.INetworkMonitor networkMonitor) = 0;
+  oneway void notifyNetworkTested(int testResult, @nullable String redirectUrl) = 1;
+  oneway void notifyPrivateDnsConfigResolved(in android.net.PrivateDnsConfigParcel config) = 2;
+  oneway void showProvisioningNotification(String action, String packageName) = 3;
+  oneway void hideProvisioningNotification() = 4;
+  oneway void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) = 5;
+  oneway void notifyNetworkTestedWithExtras(in android.net.NetworkTestResultParcelable result) = 6;
+  oneway void notifyDataStallSuspected(in android.net.DataStallReportParcelable report) = 7;
+  oneway void notifyCaptivePortalDataChanged(in android.net.CaptivePortalData data) = 8;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkStackConnector.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkStackConnector.aidl
new file mode 100644
index 0000000..8120ffc
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkStackConnector.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkStackConnector {
+  oneway void makeDhcpServer(in String ifName, in android.net.dhcp.DhcpServingParamsParcel params, in android.net.dhcp.IDhcpServerCallbacks cb);
+  oneway void makeNetworkMonitor(in android.net.Network network, String name, in android.net.INetworkMonitorCallbacks cb);
+  oneway void makeIpClient(in String ifName, in android.net.ip.IIpClientCallbacks callbacks);
+  oneway void fetchIpMemoryStore(in android.net.IIpMemoryStoreCallbacks cb);
+  oneway void allowTestUid(int uid, in android.net.INetworkStackStatusCallback cb);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkStackStatusCallback.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkStackStatusCallback.aidl
new file mode 100644
index 0000000..0b6b778
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/INetworkStackStatusCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetworkStackStatusCallback {
+  oneway void onStatusAvailable(int statusCode);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/InformationElementParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/InformationElementParcelable.aidl
new file mode 100644
index 0000000..6103774
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/InformationElementParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable InformationElementParcelable {
+  int id;
+  byte[] payload;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/InitialConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/InitialConfigurationParcelable.aidl
new file mode 100644
index 0000000..6a597e6
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/InitialConfigurationParcelable.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable InitialConfigurationParcelable {
+  android.net.LinkAddress[] ipAddresses;
+  android.net.IpPrefix[] directlyConnectedRoutes;
+  String[] dnsServers;
+  String gateway;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/Layer2InformationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/Layer2InformationParcelable.aidl
new file mode 100644
index 0000000..83796ee
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/Layer2InformationParcelable.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable Layer2InformationParcelable {
+  String l2Key;
+  String cluster;
+  android.net.MacAddress bssid;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/Layer2PacketParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/Layer2PacketParcelable.aidl
new file mode 100644
index 0000000..4b3fff5
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/Layer2PacketParcelable.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable Layer2PacketParcelable {
+  android.net.MacAddress dstMacAddress;
+  byte[] payload;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/NattKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/NattKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..18cf954
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/NattKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable NattKeepalivePacketDataParcelable {
+  byte[] srcAddress;
+  int srcPort;
+  byte[] dstAddress;
+  int dstPort;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/NetworkTestResultParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/NetworkTestResultParcelable.aidl
new file mode 100644
index 0000000..4d6d5a2
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/NetworkTestResultParcelable.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable NetworkTestResultParcelable {
+  long timestampMillis;
+  int result;
+  int probesSucceeded;
+  int probesAttempted;
+  String redirectUrl;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/PrivateDnsConfigParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/PrivateDnsConfigParcel.aidl
new file mode 100644
index 0000000..1457caf
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/PrivateDnsConfigParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable PrivateDnsConfigParcel {
+  String hostname;
+  String[] ips;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ProvisioningConfigurationParcelable.aidl
new file mode 100644
index 0000000..9ecd110
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ProvisioningConfigurationParcelable.aidl
@@ -0,0 +1,62 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable ProvisioningConfigurationParcelable {
+  /**
+   * @deprecated use ipv4ProvisioningMode instead.
+   */
+  boolean enableIPv4;
+  /**
+   * @deprecated use ipv6ProvisioningMode instead.
+   */
+  boolean enableIPv6;
+  boolean usingMultinetworkPolicyTracker;
+  boolean usingIpReachabilityMonitor;
+  int requestedPreDhcpActionMs;
+  android.net.InitialConfigurationParcelable initialConfig;
+  android.net.StaticIpConfiguration staticIpConfig;
+  android.net.apf.ApfCapabilities apfCapabilities;
+  int provisioningTimeoutMs;
+  int ipv6AddrGenMode;
+  android.net.Network network;
+  String displayName;
+  boolean enablePreconnection;
+  @nullable android.net.ScanResultInfoParcelable scanResultInfo;
+  @nullable android.net.Layer2InformationParcelable layer2Info;
+  @nullable List<android.net.networkstack.aidl.dhcp.DhcpOption> options;
+  int ipv4ProvisioningMode;
+  int ipv6ProvisioningMode;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ScanResultInfoParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ScanResultInfoParcelable.aidl
new file mode 100644
index 0000000..94fc27f
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ScanResultInfoParcelable.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable ScanResultInfoParcelable {
+  String ssid;
+  String bssid;
+  android.net.InformationElementParcelable[] informationElements;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/TcpKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/TcpKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..0e1c21c
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaDerive(toString=true)
+parcelable TcpKeepalivePacketDataParcelable {
+  byte[] srcAddress;
+  int srcPort;
+  byte[] dstAddress;
+  int dstPort;
+  int seq;
+  int ack;
+  int rcvWnd;
+  int rcvWndScale;
+  int tos;
+  int ttl;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/DhcpLeaseParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/DhcpLeaseParcelable.aidl
new file mode 100644
index 0000000..3cd8860
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/DhcpLeaseParcelable.aidl
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+@JavaDerive(toString=true)
+parcelable DhcpLeaseParcelable {
+  byte[] clientId;
+  byte[] hwAddr;
+  int netAddr;
+  int prefixLength;
+  long expTime;
+  String hostname;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/DhcpServingParamsParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/DhcpServingParamsParcel.aidl
new file mode 100644
index 0000000..fa412cb
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,48 @@
+/**
+ *
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+@JavaDerive(toString=true)
+parcelable DhcpServingParamsParcel {
+  int serverAddr;
+  int serverAddrPrefixLength;
+  int[] defaultRouters;
+  int[] dnsServers;
+  int[] excludedAddrs;
+  long dhcpLeaseTimeSecs;
+  int linkMtu;
+  boolean metered;
+  int singleClientAddr = 0;
+  boolean changePrefixOnDecline = false;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpEventCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpEventCallbacks.aidl
new file mode 100644
index 0000000..9312f47
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpEventCallbacks.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+interface IDhcpEventCallbacks {
+  oneway void onLeasesChanged(in List<android.net.dhcp.DhcpLeaseParcelable> newLeases);
+  oneway void onNewPrefixRequest(in android.net.IpPrefix currentPrefix);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpServer.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpServer.aidl
new file mode 100644
index 0000000..1109f35
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpServer.aidl
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+/* @hide */
+interface IDhcpServer {
+  oneway void start(in android.net.INetworkStackStatusCallback cb) = 0;
+  oneway void startWithCallbacks(in android.net.INetworkStackStatusCallback statusCb, in android.net.dhcp.IDhcpEventCallbacks eventCb) = 3;
+  oneway void updateParams(in android.net.dhcp.DhcpServingParamsParcel params, in android.net.INetworkStackStatusCallback cb) = 1;
+  oneway void stop(in android.net.INetworkStackStatusCallback cb) = 2;
+  const int STATUS_UNKNOWN = 0;
+  const int STATUS_SUCCESS = 1;
+  const int STATUS_INVALID_ARGUMENT = 2;
+  const int STATUS_UNKNOWN_ERROR = 3;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpServerCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpServerCallbacks.aidl
new file mode 100644
index 0000000..ab8577c
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/dhcp/IDhcpServerCallbacks.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.dhcp;
+/* @hide */
+interface IDhcpServerCallbacks {
+  oneway void onDhcpServerCreated(int statusCode, in android.net.dhcp.IDhcpServer server);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ip/IIpClient.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ip/IIpClient.aidl
new file mode 100644
index 0000000..a97511e
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ip/IIpClient.aidl
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.ip;
+/* @hide */
+interface IIpClient {
+  oneway void completedPreDhcpAction();
+  oneway void confirmConfiguration();
+  oneway void readPacketFilterComplete(in byte[] data);
+  oneway void shutdown();
+  oneway void startProvisioning(in android.net.ProvisioningConfigurationParcelable req);
+  oneway void stop();
+  oneway void setTcpBufferSizes(in String tcpBufferSizes);
+  oneway void setHttpProxy(in android.net.ProxyInfo proxyInfo);
+  oneway void setMulticastFilter(boolean enabled);
+  oneway void addKeepalivePacketFilter(int slot, in android.net.TcpKeepalivePacketDataParcelable pkt);
+  oneway void removeKeepalivePacketFilter(int slot);
+  oneway void setL2KeyAndGroupHint(in String l2Key, in String cluster);
+  oneway void addNattKeepalivePacketFilter(int slot, in android.net.NattKeepalivePacketDataParcelable pkt);
+  oneway void notifyPreconnectionComplete(boolean success);
+  oneway void updateLayer2Information(in android.net.Layer2InformationParcelable info);
+  const int PROV_IPV4_DISABLED = 0;
+  const int PROV_IPV4_STATIC = 1;
+  const int PROV_IPV4_DHCP = 2;
+  const int PROV_IPV6_DISABLED = 0;
+  const int PROV_IPV6_SLAAC = 1;
+  const int PROV_IPV6_LINKLOCAL = 2;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ip/IIpClientCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ip/IIpClientCallbacks.aidl
new file mode 100644
index 0000000..488510d
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/ip/IIpClientCallbacks.aidl
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.ip;
+/* @hide */
+interface IIpClientCallbacks {
+  oneway void onIpClientCreated(in android.net.ip.IIpClient ipClient);
+  oneway void onPreDhcpAction();
+  oneway void onPostDhcpAction();
+  oneway void onNewDhcpResults(in android.net.DhcpResultsParcelable dhcpResults);
+  oneway void onProvisioningSuccess(in android.net.LinkProperties newLp);
+  oneway void onProvisioningFailure(in android.net.LinkProperties newLp);
+  oneway void onLinkPropertiesChange(in android.net.LinkProperties newLp);
+  oneway void onReachabilityLost(in String logMsg);
+  oneway void onQuit();
+  oneway void installPacketFilter(in byte[] filter);
+  oneway void startReadPacketFilter();
+  oneway void setFallbackMulticastFilter(boolean enabled);
+  oneway void setNeighborDiscoveryOffload(boolean enable);
+  oneway void onPreconnectionStart(in List<android.net.Layer2PacketParcelable> packets);
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/networkstack/aidl/dhcp/DhcpOption.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
new file mode 100644
index 0000000..eea3e0d
--- /dev/null
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/12/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.networkstack.aidl.dhcp;
+@JavaDerive(toString=true)
+parcelable DhcpOption {
+  byte type;
+  @nullable byte[] value;
+}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DataStallReportParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DataStallReportParcelable.aidl
index 0f860a5..771deda 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DataStallReportParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DataStallReportParcelable.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DhcpResultsParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DhcpResultsParcelable.aidl
index 4445be7..31f2194 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DhcpResultsParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/DhcpResultsParcelable.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitor.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitor.aidl
index db9145f..d92196d 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitor.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitor.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -35,6 +50,7 @@
   const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2;
   const int NETWORK_VALIDATION_RESULT_VALID = 1;
   const int NETWORK_VALIDATION_RESULT_PARTIAL = 2;
+  const int NETWORK_VALIDATION_RESULT_SKIPPED = 4;
   const int NETWORK_VALIDATION_PROBE_DNS = 4;
   const int NETWORK_VALIDATION_PROBE_HTTP = 8;
   const int NETWORK_VALIDATION_PROBE_HTTPS = 16;
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitorCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitorCallbacks.aidl
index b2685ad..36eda8e 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitorCallbacks.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkMonitorCallbacks.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackConnector.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackConnector.aidl
index 396b42a..8120ffc 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackConnector.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackConnector.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackStatusCallback.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackStatusCallback.aidl
index 97c9970..0b6b778 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackStatusCallback.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/INetworkStackStatusCallback.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InformationElementParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InformationElementParcelable.aidl
index 77fca83..6103774 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InformationElementParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InformationElementParcelable.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InitialConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InitialConfigurationParcelable.aidl
index 6137305..6a597e6 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InitialConfigurationParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/InitialConfigurationParcelable.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2InformationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2InformationParcelable.aidl
index d3adbb3..83796ee 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2InformationParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2InformationParcelable.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2PacketParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2PacketParcelable.aidl
index b45f6da..4b3fff5 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2PacketParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/Layer2PacketParcelable.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NattKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NattKeepalivePacketDataParcelable.aidl
index 7634ac9..18cf954 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NattKeepalivePacketDataParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NattKeepalivePacketDataParcelable.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NetworkTestResultParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NetworkTestResultParcelable.aidl
index 1d0bbbe..4d6d5a2 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NetworkTestResultParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/NetworkTestResultParcelable.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl
index c6d6361..1457caf 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ProvisioningConfigurationParcelable.aidl
index 171817c..9ecd110 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ProvisioningConfigurationParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ProvisioningConfigurationParcelable.aidl
@@ -1,3 +1,19 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -19,7 +35,13 @@
 package android.net;
 @JavaDerive(toString=true)
 parcelable ProvisioningConfigurationParcelable {
+  /**
+   * @deprecated use ipv4ProvisioningMode instead.
+   */
   boolean enableIPv4;
+  /**
+   * @deprecated use ipv6ProvisioningMode instead.
+   */
   boolean enableIPv6;
   boolean usingMultinetworkPolicyTracker;
   boolean usingIpReachabilityMonitor;
@@ -35,4 +57,6 @@
   @nullable android.net.ScanResultInfoParcelable scanResultInfo;
   @nullable android.net.Layer2InformationParcelable layer2Info;
   @nullable List<android.net.networkstack.aidl.dhcp.DhcpOption> options;
+  int ipv4ProvisioningMode;
+  int ipv6ProvisioningMode;
 }
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ScanResultInfoParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ScanResultInfoParcelable.aidl
index 4646ede..94fc27f 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ScanResultInfoParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ScanResultInfoParcelable.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/TcpKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/TcpKeepalivePacketDataParcelable.aidl
index 00f15da..0e1c21c 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/TcpKeepalivePacketDataParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpLeaseParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpLeaseParcelable.aidl
index b0a0f0f..3cd8860 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpLeaseParcelable.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpLeaseParcelable.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpServingParamsParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpServingParamsParcel.aidl
index d56ef8e..fa412cb 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpServingParamsParcel.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -1,3 +1,19 @@
+/**
+ *
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpEventCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpEventCallbacks.aidl
index 8f3288e..9312f47 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpEventCallbacks.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpEventCallbacks.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServer.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServer.aidl
index 83cebdf..1109f35 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServer.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServer.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServerCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServerCallbacks.aidl
index 35da06c..ab8577c 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServerCallbacks.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/dhcp/IDhcpServerCallbacks.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClient.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClient.aidl
index 5607b2a..a97511e 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClient.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClient.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -34,4 +49,10 @@
   oneway void addNattKeepalivePacketFilter(int slot, in android.net.NattKeepalivePacketDataParcelable pkt);
   oneway void notifyPreconnectionComplete(boolean success);
   oneway void updateLayer2Information(in android.net.Layer2InformationParcelable info);
+  const int PROV_IPV4_DISABLED = 0;
+  const int PROV_IPV4_STATIC = 1;
+  const int PROV_IPV4_DHCP = 2;
+  const int PROV_IPV6_DISABLED = 0;
+  const int PROV_IPV6_SLAAC = 1;
+  const int PROV_IPV6_LINKLOCAL = 2;
 }
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClientCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClientCallbacks.aidl
index 9a84784..488510d 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClientCallbacks.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/ip/IIpClientCallbacks.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/networkstack/aidl/dhcp/DhcpOption.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
index c97212b..eea3e0d 100644
--- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
+++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/src/android/net/INetworkMonitor.aidl b/common/networkstackclient/src/android/net/INetworkMonitor.aidl
index 3fc81a3..b124734 100644
--- a/common/networkstackclient/src/android/net/INetworkMonitor.aidl
+++ b/common/networkstackclient/src/android/net/INetworkMonitor.aidl
@@ -44,10 +44,16 @@
     // are set, then it's equal to NETWORK_TEST_RESULT_INVALID. If NETWORK_VALIDATION_RESULT_VALID
     // is set, then the network validates and equal to NETWORK_TEST_RESULT_VALID. If
     // NETWORK_VALIDATION_RESULT_PARTIAL is set, then the network has partial connectivity which
-    // is equal to NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY. NETWORK_VALIDATION_PROBE_* is set
-    // when the specific probe result of the network is resolved.
+    // is equal to NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY. Networks receiving validation that both
+    // do not require validation and are not validated will have NETWORK_VALIDATION_RESULT_SKIPPED
+    // set. NETWORK_VALIDATION_PROBE_* is set when the specific probe result of the network is
+    // resolved.
     const int NETWORK_VALIDATION_RESULT_VALID = 0x01;
     const int NETWORK_VALIDATION_RESULT_PARTIAL = 0x02;
+    const int NETWORK_VALIDATION_RESULT_SKIPPED = 0x04;
+
+    // NETWORK_VALIDATION_RESULT_* and NETWORK_VALIDATION_PROBE_* are independent values sent in
+    // different ints.
     const int NETWORK_VALIDATION_PROBE_DNS = 0x04;
     const int NETWORK_VALIDATION_PROBE_HTTP = 0x08;
     const int NETWORK_VALIDATION_PROBE_HTTPS = 0x10;
diff --git a/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
index 0aeebcb..54a5729 100644
--- a/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
+++ b/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
@@ -29,7 +29,9 @@
 
 @JavaDerive(toString=true)
 parcelable ProvisioningConfigurationParcelable {
+    /** @deprecated use ipv4ProvisioningMode instead. */
     boolean enableIPv4;
+    /** @deprecated use ipv6ProvisioningMode instead. */
     boolean enableIPv6;
     boolean usingMultinetworkPolicyTracker;
     boolean usingIpReachabilityMonitor;
@@ -45,4 +47,6 @@
     @nullable ScanResultInfoParcelable scanResultInfo;
     @nullable Layer2InformationParcelable layer2Info;
     @nullable List<DhcpOption> options;
+    int ipv4ProvisioningMode;
+    int ipv6ProvisioningMode;
 }
diff --git a/common/networkstackclient/src/android/net/ip/IIpClient.aidl b/common/networkstackclient/src/android/net/ip/IIpClient.aidl
index 029bdb3..f76a230 100644
--- a/common/networkstackclient/src/android/net/ip/IIpClient.aidl
+++ b/common/networkstackclient/src/android/net/ip/IIpClient.aidl
@@ -23,6 +23,36 @@
 
 /** @hide */
 oneway interface IIpClient {
+    /**
+     * Disable IPv4 provisioning.
+     */
+    const int PROV_IPV4_DISABLED = 0x00;
+
+    /**
+     * Enable IPv4 provisioning using static IP addresses.
+     */
+    const int PROV_IPV4_STATIC = 0x01;
+
+    /**
+     * Enable IPv4 provisioning using DHCP.
+     */
+    const int PROV_IPV4_DHCP = 0x02;
+
+    /**
+     * Disable IPv6 provisioning.
+     */
+    const int PROV_IPV6_DISABLED = 0x00;
+
+    /**
+     * Enable IPv6 provisioning via SLAAC.
+     */
+    const int PROV_IPV6_SLAAC = 0x01;
+
+    /**
+     * Enable IPv6 Link-local only.
+     */
+    const int PROV_IPV6_LINKLOCAL = 0x02;
+
     void completedPreDhcpAction();
     void confirmConfiguration();
     void readPacketFilterComplete(in byte[] data);
diff --git a/common/networkstackclient/src/android/net/shared/ProvisioningConfiguration.java b/common/networkstackclient/src/android/net/shared/ProvisioningConfiguration.java
index 6ee9b73..3bf6744 100644
--- a/common/networkstackclient/src/android/net/shared/ProvisioningConfiguration.java
+++ b/common/networkstackclient/src/android/net/shared/ProvisioningConfiguration.java
@@ -16,6 +16,12 @@
 
 package android.net.shared;
 
+import static android.net.ip.IIpClient.PROV_IPV4_DHCP;
+import static android.net.ip.IIpClient.PROV_IPV4_DISABLED;
+import static android.net.ip.IIpClient.PROV_IPV4_STATIC;
+import static android.net.ip.IIpClient.PROV_IPV6_DISABLED;
+import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL;
+import static android.net.ip.IIpClient.PROV_IPV6_SLAAC;
 import static android.net.shared.ParcelableUtil.fromParcelableArray;
 import static android.net.shared.ParcelableUtil.toParcelableArray;
 
@@ -31,6 +37,8 @@
 import android.net.networkstack.aidl.dhcp.DhcpOption;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -82,6 +90,10 @@
     public static final int IPV6_ADDR_GEN_MODE_EUI64 = 0;
     public static final int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
 
+    // ipv4ProvisioningMode and ipv6ProvisioningMode members are introduced since
+    // networkstack-aidl-interfaces-v12.
+    public static final int VERSION_ADDED_PROVISIONING_ENUM = 12;
+
     /**
      * Builder to create a {@link ProvisioningConfiguration}.
      */
@@ -92,7 +104,7 @@
          * Specify that the configuration should not enable IPv4. It is enabled by default.
          */
         public Builder withoutIPv4() {
-            mConfig.mEnableIPv4 = false;
+            mConfig.mIPv4ProvisioningMode = PROV_IPV4_DISABLED;
             return this;
         }
 
@@ -100,7 +112,7 @@
          * Specify that the configuration should not enable IPv6. It is enabled by default.
          */
         public Builder withoutIPv6() {
-            mConfig.mEnableIPv6 = false;
+            mConfig.mIPv6ProvisioningMode = PROV_IPV6_DISABLED;
             return this;
         }
 
@@ -162,6 +174,7 @@
          * Specify a static configuration for provisioning.
          */
         public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+            mConfig.mIPv4ProvisioningMode = PROV_IPV4_STATIC;
             mConfig.mStaticIpConfig = staticConfig;
             return this;
         }
@@ -239,15 +252,32 @@
          *
          * @param: options customized DHCP option stable parcelable list.
          */
-        public Builder withDhcpOptions(List<DhcpOption> options) {
+        public Builder withDhcpOptions(@Nullable List<DhcpOption> options) {
             mConfig.mDhcpOptions = options;
             return this;
         }
 
         /**
+         * Specify that the configuration should enable IPv6 link-local only mode used for
+         * WiFi Neighbor Aware Networking and other link-local-only technologies. It's not
+         * used by default, and IPv4 must be disabled when this mode is enabled.
+         *
+         * @note This API is only supported since Android T.
+         */
+        public Builder withIpv6LinkLocalOnly() {
+            mConfig.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL;
+            return this;
+        }
+
+        /**
          * Build the configuration using previously specified parameters.
          */
         public ProvisioningConfiguration build() {
+            if (mConfig.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL
+                    && mConfig.mIPv4ProvisioningMode != PROV_IPV4_DISABLED) {
+                throw new IllegalArgumentException("IPv4 must be disabled in IPv6 link-local"
+                        + "only mode.");
+            }
             return new ProvisioningConfiguration(mConfig);
         }
     }
@@ -433,8 +463,6 @@
         }
     }
 
-    public boolean mEnableIPv4 = true;
-    public boolean mEnableIPv6 = true;
     public boolean mEnablePreconnection = false;
     public boolean mUsingMultinetworkPolicyTracker = true;
     public boolean mUsingIpReachabilityMonitor = true;
@@ -449,12 +477,12 @@
     public ScanResultInfo mScanResultInfo;
     public Layer2Information mLayer2Info;
     public List<DhcpOption> mDhcpOptions;
+    public int mIPv4ProvisioningMode = PROV_IPV4_DHCP;
+    public int mIPv6ProvisioningMode = PROV_IPV6_SLAAC;
 
     public ProvisioningConfiguration() {} // used by Builder
 
     public ProvisioningConfiguration(ProvisioningConfiguration other) {
-        mEnableIPv4 = other.mEnableIPv4;
-        mEnableIPv6 = other.mEnableIPv6;
         mEnablePreconnection = other.mEnablePreconnection;
         mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
         mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
@@ -471,6 +499,8 @@
         mScanResultInfo = other.mScanResultInfo;
         mLayer2Info = other.mLayer2Info;
         mDhcpOptions = other.mDhcpOptions;
+        mIPv4ProvisioningMode = other.mIPv4ProvisioningMode;
+        mIPv6ProvisioningMode = other.mIPv6ProvisioningMode;
     }
 
     /**
@@ -478,8 +508,10 @@
      */
     public ProvisioningConfigurationParcelable toStableParcelable() {
         final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
-        p.enableIPv4 = mEnableIPv4;
-        p.enableIPv6 = mEnableIPv6;
+        p.enableIPv4 = (mIPv4ProvisioningMode != PROV_IPV4_DISABLED);
+        p.ipv4ProvisioningMode = mIPv4ProvisioningMode;
+        p.enableIPv6 = (mIPv6ProvisioningMode != PROV_IPV6_DISABLED);
+        p.ipv6ProvisioningMode = mIPv6ProvisioningMode;
         p.enablePreconnection = mEnablePreconnection;
         p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
         p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
@@ -501,13 +533,16 @@
 
     /**
      * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
+     *
+     * @param p stable parcelable instance to be converted to a {@link ProvisioningConfiguration}.
+     * @param interfaceVersion IIpClientCallbacks interface version called by the remote peer,
+     *                         which is used to determine the appropriate parcelable members for
+     *                         backwards compatibility.
      */
     public static ProvisioningConfiguration fromStableParcelable(
-            @Nullable ProvisioningConfigurationParcelable p) {
+            @Nullable ProvisioningConfigurationParcelable p, int interfaceVersion) {
         if (p == null) return null;
         final ProvisioningConfiguration config = new ProvisioningConfiguration();
-        config.mEnableIPv4 = p.enableIPv4;
-        config.mEnableIPv6 = p.enableIPv6;
         config.mEnablePreconnection = p.enablePreconnection;
         config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
         config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
@@ -524,14 +559,49 @@
         config.mScanResultInfo = ScanResultInfo.fromStableParcelable(p.scanResultInfo);
         config.mLayer2Info = Layer2Information.fromStableParcelable(p.layer2Info);
         config.mDhcpOptions = (p.options == null) ? null : new ArrayList<>(p.options);
+        if (interfaceVersion < VERSION_ADDED_PROVISIONING_ENUM) {
+            config.mIPv4ProvisioningMode = p.enableIPv4 ? PROV_IPV4_DHCP : PROV_IPV4_DISABLED;
+            config.mIPv6ProvisioningMode = p.enableIPv6 ? PROV_IPV6_SLAAC : PROV_IPV6_DISABLED;
+        } else {
+            config.mIPv4ProvisioningMode = p.ipv4ProvisioningMode;
+            config.mIPv6ProvisioningMode = p.ipv6ProvisioningMode;
+        }
         return config;
     }
 
+    @VisibleForTesting
+    static String ipv4ProvisioningModeToString(int mode) {
+        switch (mode) {
+            case PROV_IPV4_DISABLED:
+                return "disabled";
+            case PROV_IPV4_STATIC:
+                return "static";
+            case PROV_IPV4_DHCP:
+                return "dhcp";
+            default:
+                return "unknown";
+        }
+    }
+
+    @VisibleForTesting
+    static String ipv6ProvisioningModeToString(int mode) {
+        switch (mode) {
+            case PROV_IPV6_DISABLED:
+                return "disabled";
+            case PROV_IPV6_SLAAC:
+                return "slaac";
+            case PROV_IPV6_LINKLOCAL:
+                return "link-local";
+            default:
+                return "unknown";
+        }
+    }
+
     @Override
     public String toString() {
+        final String ipv4ProvisioningMode = ipv4ProvisioningModeToString(mIPv4ProvisioningMode);
+        final String ipv6ProvisioningMode = ipv6ProvisioningModeToString(mIPv6ProvisioningMode);
         return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
-                .add("mEnableIPv4: " + mEnableIPv4)
-                .add("mEnableIPv6: " + mEnableIPv6)
                 .add("mEnablePreconnection: " + mEnablePreconnection)
                 .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
                 .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
@@ -546,6 +616,8 @@
                 .add("mScanResultInfo: " + mScanResultInfo)
                 .add("mLayer2Info: " + mLayer2Info)
                 .add("mDhcpOptions: " + mDhcpOptions)
+                .add("mIPv4ProvisioningMode: " + ipv4ProvisioningMode)
+                .add("mIPv6ProvisioningMode: " + ipv6ProvisioningMode)
                 .toString();
     }
 
@@ -575,9 +647,7 @@
     public boolean equals(Object obj) {
         if (!(obj instanceof ProvisioningConfiguration)) return false;
         final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
-        return mEnableIPv4 == other.mEnableIPv4
-                && mEnableIPv6 == other.mEnableIPv6
-                && mEnablePreconnection == other.mEnablePreconnection
+        return mEnablePreconnection == other.mEnablePreconnection
                 && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
                 && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
                 && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
@@ -590,7 +660,9 @@
                 && Objects.equals(mDisplayName, other.mDisplayName)
                 && Objects.equals(mScanResultInfo, other.mScanResultInfo)
                 && Objects.equals(mLayer2Info, other.mLayer2Info)
-                && dhcpOptionListEquals(mDhcpOptions, other.mDhcpOptions);
+                && dhcpOptionListEquals(mDhcpOptions, other.mDhcpOptions)
+                && mIPv4ProvisioningMode == other.mIPv4ProvisioningMode
+                && mIPv6ProvisioningMode == other.mIPv6ProvisioningMode;
     }
 
     public boolean isValid() {
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 9aec881..bed0ea7 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -17,9 +17,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="notification_channel_name_connected" msgid="1795068343200033922">"Кирүү бетинин аутентификациясы"</string>
-    <string name="notification_channel_description_connected" msgid="7239184168268014518">"Түзмөк тармактын кирүү бети аркылуу аутентификациядан ийгиликтүү өткөндө билдирмелер көрсөтүлөт"</string>
+    <string name="notification_channel_description_connected" msgid="7239184168268014518">"Түзмөк тармактын кирүү бети аркылуу аутентификациядан ийгиликтүү өткөндө билдирмелер көрүнөт"</string>
     <string name="notification_channel_name_network_venue_info" msgid="6526543187249265733">"Тармактын жайгашуусу жөнүндө маалымат"</string>
-    <string name="notification_channel_description_network_venue_info" msgid="5131499595382733605">"Тармак маалымат барагына киргенде билдирме көрсөтүлөт"</string>
+    <string name="notification_channel_description_network_venue_info" msgid="5131499595382733605">"Тармак маалымат барагына киргенде билдирме көрүнөт"</string>
     <string name="connected" msgid="4563643884927480998">"Туташты"</string>
     <string name="tap_for_info" msgid="6849746325626883711">"Туташты / Вебсайтты көрүү үчүн таптаңыз"</string>
     <string name="application_label" msgid="1322847171305285454">"Тармактарды башкаргыч"</string>
diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java
index 1331a24..76dc807 100644
--- a/src/android/net/dhcp/DhcpPacket.java
+++ b/src/android/net/dhcp/DhcpPacket.java
@@ -403,7 +403,7 @@
 
     // Set in unit tests, to ensure that the test does not break when run on different devices and
     // on different releases.
-    static String testOverrideVendorId = null;
+    static String sTestOverrideVendorId = null;
 
     protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                          Inet4Address nextIp, Inet4Address relayIp,
@@ -779,7 +779,7 @@
      * with the customized option value if any.
      */
     private static String getVendorId(@Nullable List<DhcpOption> customizedClientOptions) {
-        if (testOverrideVendorId != null) return testOverrideVendorId;
+        if (sTestOverrideVendorId != null) return sTestOverrideVendorId;
 
         String vendorId = "android-dhcp-" + Build.VERSION.RELEASE;
         if (customizedClientOptions != null) {
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java
index 445f915..4de9393 100644
--- a/src/android/net/ip/IpClient.java
+++ b/src/android/net/ip/IpClient.java
@@ -18,6 +18,9 @@
 
 import static android.net.RouteInfo.RTN_UNICAST;
 import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable;
+import static android.net.ip.IIpClient.PROV_IPV4_DISABLED;
+import static android.net.ip.IIpClient.PROV_IPV6_DISABLED;
+import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL;
 import static android.net.util.NetworkStackUtils.IPCLIENT_DISABLE_ACCEPT_RA_VERSION;
 import static android.net.util.NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION;
 import static android.net.util.NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION;
@@ -70,6 +73,7 @@
 import android.net.util.SharedLog;
 import android.os.Build;
 import android.os.ConditionVariable;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
@@ -396,6 +400,24 @@
                 log("Failed to call onPreconnectionStart", e);
             }
         }
+
+        /**
+         * Get the version of the IIpClientCallbacks AIDL interface.
+         */
+        public int getInterfaceVersion() {
+            log("getInterfaceVersion");
+            try {
+                return mCallback.getInterfaceVersion();
+            } catch (RemoteException e) {
+                // This can never happen for callers in the system server, because if the
+                // system server crashes, then the networkstack will crash as well. But it can
+                // happen for other callers such as bluetooth or telephony (if it starts to use
+                // IpClient). 0 will generally work but will assume an old client and disable
+                // all new features.
+                log("Failed to call getInterfaceVersion", e);
+                return 0;
+            }
+        }
     }
 
     public static final String DUMP_ARG_CONFIRM = "confirm";
@@ -596,11 +618,33 @@
             return new IpConnectivityLog();
         }
 
+        /**
+         * Get a NetworkQuirkMetrics instance.
+         */
         public NetworkQuirkMetrics getNetworkQuirkMetrics() {
             return new NetworkQuirkMetrics();
         }
 
         /**
+         * Get a IpReachabilityMonitor instance.
+         */
+        public IpReachabilityMonitor getIpReachabilityMonitor(Context context,
+                InterfaceParams ifParams, Handler h, SharedLog log,
+                IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker,
+                IpReachabilityMonitor.Dependencies deps, final INetd netd) {
+            return new IpReachabilityMonitor(context, ifParams, h, log, callback,
+                    usingMultinetworkPolicyTracker, deps, netd);
+        }
+
+        /**
+         * Get a IpReachabilityMonitor dependencies instance.
+         */
+        public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context,
+                String name) {
+            return IpReachabilityMonitor.Dependencies.makeDefault(context, name);
+        }
+
+        /**
          * Return whether a feature guarded by a feature flag is enabled.
          * @see NetworkStackUtils#isFeatureEnabled(Context, String, String)
          */
@@ -772,7 +816,8 @@
         @Override
         public void startProvisioning(ProvisioningConfigurationParcelable req) {
             enforceNetworkStackCallingPermission();
-            IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req));
+            IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req,
+                    mCallback.getInterfaceVersion()));
         }
         @Override
         public void stop() {
@@ -1204,12 +1249,41 @@
         transitionTo(mStoppingState);
     }
 
+    private static boolean hasIpv6LinkLocalInterfaceRoute(final LinkProperties lp) {
+        for (RouteInfo r : lp.getRoutes()) {
+            if (r.getDestination().equals(new IpPrefix("fe80::/64"))
+                    && r.getGateway().isAnyLocalAddress()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasIpv6LinkLocalAddress(final LinkProperties lp) {
+        for (LinkAddress address : lp.getLinkAddresses()) {
+            if (address.isIpv6() && address.getAddress().isLinkLocalAddress()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // LinkProperties has a link-local (fe80::xxx) IPv6 address and route to fe80::/64 destination.
+    private boolean isIpv6LinkLocalProvisioned(final LinkProperties lp) {
+        if (mConfiguration == null
+                || mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_LINKLOCAL) return false;
+        if (hasIpv6LinkLocalAddress(lp) && hasIpv6LinkLocalInterfaceRoute(lp)) return true;
+        return false;
+    }
+
     // For now: use WifiStateMachine's historical notion of provisioned.
     @VisibleForTesting
-    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
-        // For historical reasons, we should connect even if all we have is
-        // an IPv4 address and nothing else.
-        if (lp.hasIpv4Address() || lp.isProvisioned()) {
+    boolean isProvisioned(final LinkProperties lp, final InitialConfiguration config) {
+        // For historical reasons, we should connect even if all we have is an IPv4
+        // address and nothing else. If IPv6 link-local only mode is enabled and
+        // it's provisioned without IPv4, then still connecting once IPv6 link-local
+        // address is ready to use and route to fe80::/64 destination is up.
+        if (lp.hasIpv4Address() || lp.isProvisioned() || isIpv6LinkLocalProvisioned(lp)) {
             return true;
         }
         if (config == null) {
@@ -1776,7 +1850,7 @@
 
     private boolean startIpReachabilityMonitor() {
         try {
-            mIpReachabilityMonitor = new IpReachabilityMonitor(
+            mIpReachabilityMonitor = mDependencies.getIpReachabilityMonitor(
                     mContext,
                     mInterfaceParams,
                     getHandler(),
@@ -1788,6 +1862,7 @@
                         }
                     },
                     mConfiguration.mUsingMultinetworkPolicyTracker,
+                    mDependencies.getIpReachabilityMonitorDeps(mContext, mInterfaceParams.name),
                     mNetd);
         } catch (IllegalArgumentException iae) {
             // Failed to start IpReachabilityMonitor. Log it and call
@@ -1869,7 +1944,7 @@
         }
 
         if (mIpReachabilityMonitor != null) {
-            mIpReachabilityMonitor.probeAll();
+            mIpReachabilityMonitor.probeAll(true /* dueToRoam */);
         }
 
         // Check whether to refresh previous IP lease on L2 roaming happened.
@@ -1966,6 +2041,9 @@
             if (mDhcpClient == null) {
                 // There's no DHCPv4 for which to wait; proceed to stopped.
                 deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
+            } else {
+                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
+                mDhcpClient.doQuit();
             }
 
             // Restore the interface MTU to initial value if it has changed.
@@ -2202,6 +2280,14 @@
         }
     }
 
+    private boolean isIpv6Enabled() {
+        return mConfiguration.mIPv6ProvisioningMode != PROV_IPV6_DISABLED;
+    }
+
+    private boolean isIpv4Enabled() {
+        return mConfiguration.mIPv4ProvisioningMode != PROV_IPV4_DISABLED;
+    }
+
     class RunningState extends State {
         private ConnectivityPacketTracker mPacketTracker;
         private boolean mDhcpActionInFlight;
@@ -2234,13 +2320,13 @@
             mPacketTracker = createPacketTracker();
             if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
 
-            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+            if (isIpv6Enabled() && !startIPv6()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
                 return;
             }
 
-            if (mConfiguration.mEnableIPv4 && !isUsingPreconnection() && !startIPv4()) {
+            if (isIpv4Enabled() && !isUsingPreconnection() && !startIPv4()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
                 enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV4);
                 return;
@@ -2271,11 +2357,6 @@
                 mIpReachabilityMonitor = null;
             }
 
-            if (mDhcpClient != null) {
-                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
-                mDhcpClient.doQuit();
-            }
-
             if (mPacketTracker != null) {
                 mPacketTracker.stop();
                 mPacketTracker = null;
@@ -2338,7 +2419,7 @@
                     // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
                     // roams.
                     if (mIpReachabilityMonitor != null) {
-                        mIpReachabilityMonitor.probeAll();
+                        mIpReachabilityMonitor.probeAll(false /* dueToRoam */);
                     }
                     break;
 
diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java
index cc4a851..3702674 100644
--- a/src/android/net/ip/IpClientLinkObserver.java
+++ b/src/android/net/ip/IpClientLinkObserver.java
@@ -27,16 +27,16 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.RouteInfo;
-import android.net.netlink.NduseroptMessage;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.StructNdOptPref64;
 import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.system.OsConstants;
 import android.util.Log;
 
+import com.android.net.module.util.netlink.NduseroptMessage;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.NetlinkMessage;
+import com.android.net.module.util.netlink.StructNdOptPref64;
 import com.android.networkstack.apishim.NetworkInformationShimImpl;
 import com.android.networkstack.apishim.common.NetworkInformationShim;
 import com.android.server.NetworkObserver;
diff --git a/src/android/net/ip/IpReachabilityMonitor.java b/src/android/net/ip/IpReachabilityMonitor.java
index 3dbe662..0f199e2 100644
--- a/src/android/net/ip/IpReachabilityMonitor.java
+++ b/src/android/net/ip/IpReachabilityMonitor.java
@@ -20,6 +20,8 @@
 import static android.net.metrics.IpReachabilityEvent.NUD_FAILED_ORGANIC;
 import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST;
 import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST_ORGANIC;
+import static android.net.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION;
+import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -30,7 +32,6 @@
 import android.net.ip.IpNeighborMonitor.NeighborEventConsumer;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpReachabilityEvent;
-import android.net.netlink.StructNdMsg;
 import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.ConditionVariable;
@@ -40,12 +41,21 @@
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.stats.connectivity.IpType;
+import android.stats.connectivity.NudEventType;
+import android.stats.connectivity.NudNeighborType;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.net.module.util.DeviceConfigUtils;
+import com.android.net.module.util.netlink.StructNdMsg;
 import com.android.networkstack.R;
+import com.android.networkstack.metrics.IpReachabilityMonitorMetrics;
 
 import java.io.PrintWriter;
 import java.net.Inet6Address;
@@ -143,6 +153,10 @@
     protected static final int MIN_NUD_SOLICIT_NUM = 5;
     protected static final int MAX_NUD_SOLICIT_INTERVAL_MS = 1000;
     protected static final int MIN_NUD_SOLICIT_INTERVAL_MS = 750;
+    protected static final int NUD_MCAST_RESOLICIT_NUM = 3;
+    private static final int INVALID_NUD_MCAST_RESOLICIT_NUM = -1;
+
+    private static final int INVALID_LEGACY_NUD_FAILURE_TYPE = -1;
 
     public interface Callback {
         /**
@@ -161,6 +175,8 @@
     interface Dependencies {
         void acquireWakeLock(long durationMs);
         IpNeighborMonitor makeIpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb);
+        boolean isFeatureEnabled(Context context, String name, boolean defaultEnabled);
+        IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics();
 
         static Dependencies makeDefault(Context context, String iface) {
             final String lockName = TAG + "." + iface;
@@ -176,6 +192,16 @@
                         NeighborEventConsumer cb) {
                     return new IpNeighborMonitor(h, log, cb);
                 }
+
+                public boolean isFeatureEnabled(final Context context, final String name,
+                        boolean defaultEnabled) {
+                    return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name,
+                            defaultEnabled);
+                }
+
+                public IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics() {
+                    return new IpReachabilityMonitorMetrics();
+                }
             };
         }
     }
@@ -183,25 +209,30 @@
     private final InterfaceParams mInterfaceParams;
     private final IpNeighborMonitor mIpNeighborMonitor;
     private final SharedLog mLog;
-    private final Callback mCallback;
     private final Dependencies mDependencies;
     private final boolean mUsingMultinetworkPolicyTracker;
     private final ConnectivityManager mCm;
     private final IpConnectivityLog mMetricsLog;
     private final Context mContext;
     private final INetd mNetd;
+    private final IpReachabilityMonitorMetrics mIpReachabilityMetrics;
     private LinkProperties mLinkProperties = new LinkProperties();
     private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
     // Time in milliseconds of the last forced probe request.
     private volatile long mLastProbeTimeMs;
+    // Time in milliseconds of the last forced probe request due to roam or CMD_CONFIRM.
+    private long mLastProbeDueToRoamMs;
+    private long mLastProbeDueToConfirmMs;
     private int mNumSolicits;
     private int mInterSolicitIntervalMs;
+    @NonNull
+    private final Callback mCallback;
 
     public IpReachabilityMonitor(
             Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
-            boolean usingMultinetworkPolicyTracker, final INetd netd) {
-        this(context, ifParams, h, log, callback, usingMultinetworkPolicyTracker,
-                Dependencies.makeDefault(context, ifParams.name), new IpConnectivityLog(), netd);
+            boolean usingMultinetworkPolicyTracker, Dependencies dependencies, final INetd netd) {
+        this(context, ifParams, h, log, callback, usingMultinetworkPolicyTracker, dependencies,
+                new IpConnectivityLog(), netd);
     }
 
     @VisibleForTesting
@@ -225,7 +256,10 @@
         // In case the overylaid parameters specify an invalid configuration, set the parameters
         // to the hardcoded defaults first, then set them to the values used in the steady state.
         try {
-            setNeighborParameters(MIN_NUD_SOLICIT_NUM, MIN_NUD_SOLICIT_INTERVAL_MS);
+            int numResolicits = isMulticastResolicitEnabled()
+                    ? NUD_MCAST_RESOLICIT_NUM
+                    : INVALID_NUD_MCAST_RESOLICIT_NUM;
+            setNeighborParameters(MIN_NUD_SOLICIT_NUM, MIN_NUD_SOLICIT_INTERVAL_MS, numResolicits);
         } catch (Exception e) {
             Log.e(TAG, "Failed to adjust neighbor parameters with hardcoded defaults");
         }
@@ -241,13 +275,16 @@
                     // TODO: Consider what to do with other states that are not within
                     // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
                     if (event.nudState == StructNdMsg.NUD_FAILED) {
+                        // After both unicast probe and multicast probe(if mcast_resolicit is not 0)
+                        // attempts fail, trigger the neighbor lost event and disconnect.
                         mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
                         handleNeighborLost(event);
                     } else if (event.nudState == StructNdMsg.NUD_REACHABLE) {
-                        maybeRestoreNeighborParameters();
+                        handleNeighborReachable(prev, event);
                     }
                 });
         mIpNeighborMonitor.start();
+        mIpReachabilityMetrics = dependencies.getIpReachabilityMonitorMetrics();
     }
 
     public void stop() {
@@ -296,6 +333,33 @@
         return false;
     }
 
+    private boolean hasDefaultRouterNeighborMacAddressChanged(
+            @Nullable final NeighborEvent prev, @NonNull final NeighborEvent event) {
+        if (prev == null || !isNeighborDefaultRouter(event)) return false;
+        return !event.macAddr.equals(prev.macAddr);
+    }
+
+    private boolean isNeighborDefaultRouter(@NonNull final NeighborEvent event) {
+        // For the IPv6 link-local scoped address, equals() works because the NeighborEvent.ip
+        // doesn't have a scope id and Inet6Address#equals doesn't consider scope id neither.
+        for (RouteInfo route : mLinkProperties.getRoutes()) {
+            if (route.isDefaultRoute() && event.ip.equals(route.getGateway())) return true;
+        }
+        return false;
+    }
+
+    private boolean isNeighborDnsServer(@NonNull final NeighborEvent event) {
+        for (InetAddress dns : mLinkProperties.getDnsServers()) {
+            if (event.ip.equals(dns)) return true;
+        }
+        return false;
+    }
+
+    private boolean isMulticastResolicitEnabled() {
+        return mDependencies.isFeatureEnabled(mContext, IP_REACHABILITY_MCAST_RESOLICIT_VERSION,
+                false /* defaultEnabled */);
+    }
+
     public void updateLinkProperties(LinkProperties lp) {
         if (!mInterfaceParams.name.equals(lp.getInterfaceName())) {
             // TODO: figure out whether / how to cope with interface changes.
@@ -333,6 +397,25 @@
         if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
     }
 
+    private void handleNeighborReachable(@Nullable final NeighborEvent prev,
+            @NonNull final NeighborEvent event) {
+        if (isMulticastResolicitEnabled()
+                && hasDefaultRouterNeighborMacAddressChanged(prev, event)) {
+            // This implies device has confirmed the neighbor's reachability from
+            // other states(e.g., NUD_PROBE or NUD_STALE), checking if the mac
+            // address hasn't changed is required. If Mac address does change, then
+            // trigger a new neighbor lost event and disconnect.
+            final String logMsg = "ALERT neighbor: " + event.ip
+                    + " MAC address changed from: " + prev.macAddr
+                    + " to: " + event.macAddr;
+            mLog.w(logMsg);
+            mCallback.notifyLost(event.ip, logMsg);
+            logNudFailed(event, NudEventType.NUD_MAC_ADDRESS_CHANGED);
+            return;
+        }
+        maybeRestoreNeighborParameters();
+    }
+
     private void handleNeighborLost(NeighborEvent event) {
         final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
 
@@ -366,17 +449,17 @@
         final boolean lostProvisioning =
                 (mLinkProperties.isIpv4Provisioned() && !whatIfLp.isIpv4Provisioned())
                 || (mLinkProperties.isIpv6Provisioned() && !whatIfLp.isIpv6Provisioned());
+        final NudEventType type = getNudFailureEventType(isFromProbe(),
+                isNudFailureDueToRoam(), lostProvisioning);
 
         if (lostProvisioning) {
             final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
             Log.w(TAG, logMsg);
-            if (mCallback != null) {
-                // TODO: remove |ip| when the callback signature no longer has
-                // an InetAddress argument.
-                mCallback.notifyLost(ip, logMsg);
-            }
+            // TODO: remove |ip| when the callback signature no longer has
+            // an InetAddress argument.
+            mCallback.notifyLost(ip, logMsg);
         }
-        logNudFailed(lostProvisioning);
+        logNudFailed(event, type);
     }
 
     private void maybeRestoreNeighborParameters() {
@@ -400,7 +483,13 @@
         return !mUsingMultinetworkPolicyTracker || mCm.shouldAvoidBadWifi();
     }
 
-    public void probeAll() {
+    /**
+     * Force probe to verify whether or not the critical on-link neighbours are still reachable.
+     *
+     * @param dueToRoam indicate on which situation forced probe has been sent, e.g., on post
+     *                  roaming or receiving CMD_CONFIRM from IpClient.
+     */
+    public void probeAll(boolean dueToRoam) {
         setNeighbourParametersPostRoaming();
 
         final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
@@ -421,6 +510,11 @@
             logEvent(IpReachabilityEvent.PROBE, rval);
         }
         mLastProbeTimeMs = SystemClock.elapsedRealtime();
+        if (dueToRoam) {
+            mLastProbeDueToRoamMs = mLastProbeTimeMs;
+        } else {
+            mLastProbeDueToConfirmMs = mLastProbeTimeMs;
+        }
     }
 
     private long getProbeWakeLockDuration() {
@@ -450,6 +544,12 @@
 
     private void setNeighborParameters(int numSolicits, int interSolicitIntervalMs)
             throws RemoteException, IllegalArgumentException {
+        // Do not set mcast_resolicit param by default.
+        setNeighborParameters(numSolicits, interSolicitIntervalMs, INVALID_NUD_MCAST_RESOLICIT_NUM);
+    }
+
+    private void setNeighborParameters(int numSolicits, int interSolicitIntervalMs,
+            int numResolicits) throws RemoteException, IllegalArgumentException {
         Preconditions.checkArgument(numSolicits >= MIN_NUD_SOLICIT_NUM,
                 "numSolicits must be at least " + MIN_NUD_SOLICIT_NUM);
         Preconditions.checkArgument(numSolicits <= MAX_NUD_SOLICIT_NUM,
@@ -464,32 +564,117 @@
                     Integer.toString(interSolicitIntervalMs));
             mNetd.setProcSysNet(family, INetd.NEIGH, mInterfaceParams.name, "ucast_solicit",
                     Integer.toString(numSolicits));
+            if (numResolicits != INVALID_NUD_MCAST_RESOLICIT_NUM) {
+                mNetd.setProcSysNet(family, INetd.NEIGH, mInterfaceParams.name, "mcast_resolicit",
+                        Integer.toString(numResolicits));
+            }
         }
 
         mNumSolicits = numSolicits;
         mInterSolicitIntervalMs = interSolicitIntervalMs;
     }
 
+    private boolean isFromProbe() {
+        final long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
+        return duration < getProbeWakeLockDuration();
+    }
+
+    private boolean isNudFailureDueToRoam() {
+        if (!isFromProbe()) return false;
+
+        // Check to which probe expiry the curren timestamp gets close when NUD failure event
+        // happens, theoretically that indicates which probe event(due to roam or CMD_CONFIRM)
+        // was triggered eariler.
+        //
+        // Note that this would be incorrect if the probe or confirm was so long ago that the
+        // probe duration has already expired. That cannot happen because isFromProbe would return
+        // false.
+        final long probeExpiryAfterRoam = mLastProbeDueToRoamMs + getProbeWakeLockDuration();
+        final long probeExpiryAfterConfirm =
+                mLastProbeDueToConfirmMs + getProbeWakeLockDuration();
+        final long currentTime = SystemClock.elapsedRealtime();
+        return Math.abs(probeExpiryAfterRoam - currentTime)
+                < Math.abs(probeExpiryAfterConfirm - currentTime);
+    }
+
     private void logEvent(int probeType, int errorCode) {
         int eventType = probeType | (errorCode & 0xff);
         mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
     }
 
-    private void logNudFailed(boolean lostProvisioning) {
-        long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
-        boolean isFromProbe = (duration < getProbeWakeLockDuration());
-        int eventType = nudFailureEventType(isFromProbe, lostProvisioning);
+    private void logNudFailed(final NeighborEvent event, final NudEventType type) {
+        logNeighborLostEvent(event, type);
+
+        // The legacy metrics only record whether the failure came from a probe and whether
+        // the network is still provisioned. They do not record provisioning failures due to
+        // multicast resolicits finding that the MAC address has changed.
+        final int eventType = legacyNudFailureType(type);
+        if (eventType == INVALID_LEGACY_NUD_FAILURE_TYPE) return;
         mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
     }
 
     /**
+     * Returns the neighbor type code corresponding to the given conditions.
+     */
+    private NudNeighborType getNeighborType(final NeighborEvent event) {
+        final boolean isGateway = isNeighborDefaultRouter(event);
+        final boolean isDnsServer = isNeighborDnsServer(event);
+
+        if (isGateway && isDnsServer) return NudNeighborType.NUD_NEIGHBOR_BOTH;
+        if (isGateway && !isDnsServer) return NudNeighborType.NUD_NEIGHBOR_GATEWAY;
+        if (!isGateway && isDnsServer) return NudNeighborType.NUD_NEIGHBOR_DNS;
+        return NudNeighborType.NUD_NEIGHBOR_UNKNOWN;
+    }
+
+    /**
      * Returns the NUD failure event type code corresponding to the given conditions.
      */
-    private static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
-        if (isFromProbe) {
-            return isProvisioningLost ? PROVISIONING_LOST : NUD_FAILED;
-        } else {
-            return isProvisioningLost ? PROVISIONING_LOST_ORGANIC : NUD_FAILED_ORGANIC;
+    private static NudEventType getNudFailureEventType(boolean isFromProbe, boolean isDueToRoam,
+            boolean isProvisioningLost) {
+        if (!isFromProbe) {
+            return isProvisioningLost
+                    ? NudEventType.NUD_ORGANIC_FAILED_CRITICAL
+                    : NudEventType.NUD_ORGANIC_FAILED;
+        }
+        return isProvisioningLost
+                ? isDueToRoam
+                        ? NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL
+                        : NudEventType.NUD_CONFIRM_FAILED_CRITICAL
+                : isDueToRoam
+                        ? NudEventType.NUD_POST_ROAMING_FAILED
+                        : NudEventType.NUD_CONFIRM_FAILED;
+    }
+
+    /**
+     * Log NUD failure metrics with new Westworld APIs while the function using mMetricsLog API
+     * still sends the legacy metrics, @see #logNudFailed.
+     */
+    private void logNeighborLostEvent(final NeighborEvent event, final NudEventType type) {
+        final IpType ipType = (event.ip instanceof Inet6Address) ? IpType.IPV6 : IpType.IPV4;
+        mIpReachabilityMetrics.setNudIpType(ipType);
+        mIpReachabilityMetrics.setNudNeighborType(getNeighborType(event));
+        mIpReachabilityMetrics.setNudEventType(type);
+        mIpReachabilityMetrics.statsWrite();
+    }
+
+    /**
+     * Returns the NUD failure event type code corresponding to the given conditions.
+     */
+    private static int legacyNudFailureType(final NudEventType type) {
+        switch (type) {
+            case NUD_POST_ROAMING_FAILED:
+            case NUD_CONFIRM_FAILED:
+                return NUD_FAILED;
+            case NUD_POST_ROAMING_FAILED_CRITICAL:
+            case NUD_CONFIRM_FAILED_CRITICAL:
+                return PROVISIONING_LOST;
+            case NUD_ORGANIC_FAILED:
+                return NUD_FAILED_ORGANIC;
+            case NUD_ORGANIC_FAILED_CRITICAL:
+                return PROVISIONING_LOST_ORGANIC;
+            default:
+                // Do not log legacy event
+                return INVALID_LEGACY_NUD_FAILURE_TYPE;
         }
     }
 }
diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java
index 81d0c08..e06cdca 100755
--- a/src/android/net/util/NetworkStackUtils.java
+++ b/src/android/net/util/NetworkStackUtils.java
@@ -255,6 +255,13 @@
      */
     public static final String IPCLIENT_DISABLE_ACCEPT_RA_VERSION = "ipclient_disable_accept_ra";
 
+    /**
+     * Experiment flag to enable "mcast_resolicit" neighbor parameter in IpReachabilityMonitor,
+     * set it to 3 by default.
+     */
+    public static final String IP_REACHABILITY_MCAST_RESOLICIT_VERSION =
+            "ip_reachability_mcast_resolicit_version";
+
     static {
         System.loadLibrary("networkstackutilsjni");
     }
diff --git a/src/com/android/networkstack/metrics/IpProvisioningMetrics.java b/src/com/android/networkstack/metrics/IpProvisioningMetrics.java
index b015a51..5ca996e 100644
--- a/src/com/android/networkstack/metrics/IpProvisioningMetrics.java
+++ b/src/com/android/networkstack/metrics/IpProvisioningMetrics.java
@@ -157,17 +157,17 @@
         mStatsBuilder.setDhcpSession(mDhcpSessionBuilder);
         mStatsBuilder.setProvisioningDurationMicros(mWatch.stop());
         mStatsBuilder.setRandomNumber((int) (Math.random() * 1000));
-        final NetworkIpProvisioningReported Stats = mStatsBuilder.build();
-        final byte[] DhcpSession = Stats.getDhcpSession().toByteArray();
+        final NetworkIpProvisioningReported stats = mStatsBuilder.build();
+        final byte[] DhcpSession = stats.getDhcpSession().toByteArray();
         NetworkStackStatsLog.write(NetworkStackStatsLog.NETWORK_IP_PROVISIONING_REPORTED,
-                Stats.getTransportType().getNumber(),
-                Stats.getIpv4LatencyMicros(),
-                Stats.getIpv6LatencyMicros(),
-                Stats.getProvisioningDurationMicros(),
-                Stats.getDisconnectCode().getNumber(),
+                stats.getTransportType().getNumber(),
+                stats.getIpv4LatencyMicros(),
+                stats.getIpv6LatencyMicros(),
+                stats.getProvisioningDurationMicros(),
+                stats.getDisconnectCode().getNumber(),
                 DhcpSession,
-                Stats.getRandomNumber());
+                stats.getRandomNumber());
         mWatch.reset();
-        return Stats;
+        return stats;
     }
 }
diff --git a/src/com/android/networkstack/metrics/IpReachabilityMonitorMetrics.java b/src/com/android/networkstack/metrics/IpReachabilityMonitorMetrics.java
new file mode 100644
index 0000000..401de4a
--- /dev/null
+++ b/src/com/android/networkstack/metrics/IpReachabilityMonitorMetrics.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.networkstack.metrics;
+
+import android.stats.connectivity.IpType;
+import android.stats.connectivity.NudEventType;
+import android.stats.connectivity.NudNeighborType;
+
+/**
+ * Class to record the network stack IpReachabilityMonitor metrics into statsd.
+ *
+ * This class is not thread-safe, and should always be accessed from the same thread.
+ *
+ * @hide
+ */
+public class IpReachabilityMonitorMetrics {
+    private final NetworkIpReachabilityMonitorReported.Builder mStatsBuilder =
+            NetworkIpReachabilityMonitorReported.newBuilder();
+
+    /**
+     * Write the NUD event type into mStatsBuilder.
+     */
+    public void setNudEventType(final NudEventType type) {
+        mStatsBuilder.setEventType(type);
+    }
+
+    /**
+     * Write the NUD probe type(IPv4 or IPv6) into mStatsBuilder.
+     */
+    public void setNudIpType(final IpType type) {
+        mStatsBuilder.setIpType(type);
+    }
+
+    /**
+     * Write the NUD probe neighbor type into mStatsBuilder.
+     */
+    public void setNudNeighborType(final NudNeighborType type) {
+        mStatsBuilder.setNeighborType(type);
+    }
+
+    /**
+     * Write the NetworkIpReachabilityMonitorReported proto into statsd.
+     */
+    public NetworkIpReachabilityMonitorReported statsWrite() {
+        final NetworkIpReachabilityMonitorReported stats = mStatsBuilder.build();
+        NetworkStackStatsLog.write(NetworkStackStatsLog.NETWORK_IP_REACHABILITY_MONITOR_REPORTED,
+                stats.getEventType().getNumber(),
+                stats.getIpType().getNumber(),
+                stats.getNeighborType().getNumber());
+        return stats;
+    }
+}
diff --git a/src/com/android/networkstack/metrics/stats.proto b/src/com/android/networkstack/metrics/stats.proto
index 2b0a704..c09f082 100644
--- a/src/com/android/networkstack/metrics/stats.proto
+++ b/src/com/android/networkstack/metrics/stats.proto
@@ -172,3 +172,19 @@
     // Record each Quirk event
     optional .android.stats.connectivity.NetworkQuirkEvent event = 2;
 }
+
+/**
+ * Logs Neighbor Unreachability Detection probe event.
+ * Logged from:
+ * src/com/android/networkstack/metrics/IpReachabilityMonitorMetrics.java
+ */
+message NetworkIpReachabilityMonitorReported {
+    // Neighbor Unreachability Detection event.
+    optional .android.stats.connectivity.NudEventType event_type = 1;
+
+    // NUD probe based on IPv4 ARP or IPv6 ND packet.
+    optional .android.stats.connectivity.IpType ip_type = 2;
+
+    // NUD neighbor type, default gateway, DNS server or both.
+    optional .android.stats.connectivity.NudNeighborType neighbor_type = 3;
+}
diff --git a/src/com/android/networkstack/netlink/TcpSocketTracker.java b/src/com/android/networkstack/netlink/TcpSocketTracker.java
index 770e85a..b5eafd6 100644
--- a/src/com/android/networkstack/netlink/TcpSocketTracker.java
+++ b/src/com/android/networkstack/netlink/TcpSocketTracker.java
@@ -15,13 +15,6 @@
  */
 package com.android.networkstack.netlink;
 
-import static android.net.netlink.InetDiagMessage.InetDiagReqV2;
-import static android.net.netlink.NetlinkConstants.INET_DIAG_MEMINFO;
-import static android.net.netlink.NetlinkConstants.NLMSG_DONE;
-import static android.net.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE;
-import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
 import static android.net.util.DataStallUtils.CONFIG_MIN_PACKETS_THRESHOLD;
 import static android.net.util.DataStallUtils.CONFIG_TCP_PACKETS_FAIL_PERCENTAGE;
 import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_PACKETS_THRESHOLD;
@@ -38,14 +31,18 @@
 import static android.system.OsConstants.SOL_SOCKET;
 import static android.system.OsConstants.SO_SNDTIMEO;
 
+import static com.android.net.module.util.netlink.InetDiagMessage.inetDiagReqV2;
+import static com.android.net.module.util.netlink.NetlinkConstants.INET_DIAG_MEMINFO;
+import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
+import static com.android.net.module.util.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE;
+import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+
 import android.content.Context;
 import android.net.INetd;
 import android.net.MarkMaskParcel;
 import android.net.Network;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.StructInetDiagMsg;
-import android.net.netlink.StructNlMsgHdr;
 import android.net.util.NetworkStackUtils;
 import android.net.util.SocketUtils;
 import android.os.AsyncTask;
@@ -66,6 +63,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.DeviceConfigUtils;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.NetlinkSocket;
+import com.android.net.module.util.netlink.StructInetDiagMsg;
+import com.android.net.module.util.netlink.StructNlMsgHdr;
 import com.android.networkstack.apishim.NetworkShimImpl;
 import com.android.networkstack.apishim.common.ShimUtils;
 import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
@@ -114,7 +115,7 @@
      * Request to send to kernel to request tcp info.
      *
      *   Key: Ip family type.
-     * Value: Bytes array represent the {@Code InetDiagReqV2}.
+     * Value: Bytes array represent the {@Code inetDiagReqV2}.
      */
     private final SparseArray<byte[]> mSockDiagMsg = new SparseArray<>();
     private final Dependencies mDependencies;
@@ -160,7 +161,7 @@
         for (final int family : ADDRESS_FAMILIES) {
             mSockDiagMsg.put(
                     family,
-                    InetDiagReqV2(IPPROTO_TCP,
+                    inetDiagReqV2(IPPROTO_TCP,
                             null /* local addr */,
                             null /* remote addr */,
                             family,
diff --git a/src/com/android/networkstack/packets/NeighborAdvertisement.java b/src/com/android/networkstack/packets/NeighborAdvertisement.java
index e6cdfc8..ef38314 100644
--- a/src/com/android/networkstack/packets/NeighborAdvertisement.java
+++ b/src/com/android/networkstack/packets/NeighborAdvertisement.java
@@ -17,13 +17,14 @@
 package com.android.networkstack.packets;
 
 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
-import static com.android.net.module.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
 
 import android.net.MacAddress;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.net.module.util.Ipv6Utils;
 import com.android.net.module.util.Struct;
@@ -50,12 +51,12 @@
     public final Icmpv6Header icmpv6Hdr;
     @NonNull
     public final NaHeader naHdr;
-    @NonNull
+    @Nullable
     public final LlaOption tlla;
 
     public NeighborAdvertisement(@NonNull final EthernetHeader ethHdr,
             @NonNull final Ipv6Header ipv6Hdr, @NonNull final Icmpv6Header icmpv6Hdr,
-            @NonNull final NaHeader naHdr, @NonNull final LlaOption tlla) {
+            @NonNull final NaHeader naHdr, @Nullable final LlaOption tlla) {
         this.ethHdr = ethHdr;
         this.ipv6Hdr = ipv6Hdr;
         this.icmpv6Hdr = icmpv6Hdr;
@@ -71,7 +72,7 @@
         final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class);
         final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class);
         final int naHeaderLen = Struct.getSize(NaHeader.class);
-        final int tllaOptionLen = Struct.getSize(LlaOption.class);
+        final int tllaOptionLen = (tlla == null) ? 0 : Struct.getSize(LlaOption.class);
         final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen
                 + icmpv6HeaderLen + naHeaderLen + tllaOptionLen);
 
@@ -79,7 +80,9 @@
         ipv6Hdr.writeToByteBuffer(packet);
         icmpv6Hdr.writeToByteBuffer(packet);
         naHdr.writeToByteBuffer(packet);
-        tlla.writeToByteBuffer(packet);
+        if (tlla != null) {
+            tlla.writeToByteBuffer(packet);
+        }
         packet.flip();
 
         return packet;
@@ -100,7 +103,7 @@
      */
     public static NeighborAdvertisement parse(@NonNull final byte[] recvbuf, final int length)
             throws ParseException {
-        if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_MIN_LEN
+        if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NA_HEADER_LEN
                 || recvbuf.length < length) {
             throw new ParseException("Invalid packet length: " + length);
         }
@@ -111,7 +114,9 @@
         final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, packet);
         final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, packet);
         final NaHeader naHdr = Struct.parse(NaHeader.class, packet);
-        final LlaOption tlla = Struct.parse(LlaOption.class, packet);
+        final LlaOption tlla = (packet.remaining() == 0)
+                ? null
+                : Struct.parse(LlaOption.class, packet);
 
         return new NeighborAdvertisement(ethHdr, ipv6Hdr, icmpv6Hdr, naHdr, tlla);
     }
diff --git a/src/com/android/networkstack/packets/NeighborSolicitation.java b/src/com/android/networkstack/packets/NeighborSolicitation.java
index e743209..5c3e40a 100644
--- a/src/com/android/networkstack/packets/NeighborSolicitation.java
+++ b/src/com/android/networkstack/packets/NeighborSolicitation.java
@@ -17,8 +17,8 @@
 package com.android.networkstack.packets;
 
 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
-import static com.android.net.module.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NS_HEADER_LEN;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
 
 import android.net.MacAddress;
@@ -43,8 +43,6 @@
  * @hide
  */
 public class NeighborSolicitation {
-    private static final int NS_HEADER_LEN = Struct.getSize(NsHeader.class);
-
     @NonNull
     public final EthernetHeader ethHdr;
     @NonNull
@@ -105,7 +103,7 @@
      */
     public static NeighborSolicitation parse(@NonNull final byte[] recvbuf, final int length)
             throws ParseException {
-        if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_MIN_LEN + NS_HEADER_LEN
+        if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NS_HEADER_LEN
                 || recvbuf.length < length) {
             throw new ParseException("Invalid packet length: " + length);
         }
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index af21851..131b3b2 100755
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -31,8 +31,10 @@
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_SKIPPED;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.captiveportal.CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs;
 import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
 import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
@@ -386,7 +388,7 @@
     private static final int CMD_BANDWIDTH_CHECK_COMPLETE = 23;
 
     /**
-     * Message to self to know the bandwidth check is timeouted.
+     * Message to self to know the bandwidth check has timed out.
      */
     private static final int CMD_BANDWIDTH_CHECK_TIMEOUT = 24;
 
@@ -634,6 +636,13 @@
 
     /**
      * Request the NetworkMonitor to reevaluate the network.
+     *
+     * TODO : refactor reevaluation to introduce rate limiting. If the system finds a network is
+     * validated but some app can't access their server, or the network is behind a captive portal
+     * that only lets the validation URL through, apps may be calling reportNetworkConnectivity
+     * often, causing many revalidation attempts. Meanwhile, reevaluation attempts that result
+     * from actions that may affect the validation status (e.g. the user just logged in through
+     * the captive portal app) should never be skipped because of the rate limitation.
      */
     public void forceReevaluation(int responsibleUid) {
         sendMessage(CMD_FORCE_REEVALUATION, responsibleUid, 0);
@@ -671,6 +680,7 @@
                 (Pair<LinkProperties, NetworkCapabilities>) connectedMsg.obj;
         mLinkProperties = attrs.first;
         mNetworkCapabilities = attrs.second;
+        suppressNotificationIfNetworkRestricted();
     }
 
     /**
@@ -735,6 +745,12 @@
         return NetworkMonitorUtils.isPrivateDnsValidationRequired(mNetworkCapabilities);
     }
 
+    private void suppressNotificationIfNetworkRestricted() {
+        if (!mNetworkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+            mDontDisplaySigninNotification = true;
+        }
+    }
+
     private void notifyNetworkTested(NetworkTestResultParcelable result) {
         try {
             if (mCallbackVersion <= 5) {
@@ -907,6 +923,18 @@
                             // If the user wants to use this network anyway, there is no need to
                             // perform the bandwidth check even if configured.
                             mIsBandwidthCheckPassedOrIgnored = true;
+                            // If the user wants to use this network anyway, it should always
+                            // be reported as validated, but other checks still need to be
+                            // done. For example, it should still validate strict private DNS and
+                            // show a notification if not available, because the network will
+                            // be unusable for this additional reason.
+                            mEvaluationState.setCaptivePortalWantedAsIs();
+                            // A successful evaluation result should be reported immediately, so
+                            // that the network stack may immediately use the validation in ranking
+                            // without waiting for a possibly long private DNS or bandwidth eval
+                            // step.
+                            mEvaluationState.reportEvaluationResult(NETWORK_VALIDATION_RESULT_VALID,
+                                    null);
                             // TODO: Distinguish this from a network that actually validates.
                             // Displaying the "x" on the system UI icon may still be a good idea.
                             transitionTo(mEvaluatingPrivateDnsState);
@@ -984,6 +1012,7 @@
                     break;
                 case EVENT_NETWORK_CAPABILITIES_CHANGED:
                     mNetworkCapabilities = (NetworkCapabilities) message.obj;
+                    suppressNotificationIfNetworkRestricted();
                     break;
                 default:
                     break;
@@ -1280,11 +1309,19 @@
                     //    the network so don't bother validating here.  Furthermore sending HTTP
                     //    packets over the network may be undesirable, for example an extremely
                     //    expensive metered network, or unwanted leaking of the User Agent string.
+                    // Also don't bother validating networks that the user already said they
+                    // wanted as-is.
                     //
                     // On networks that need to support private DNS in strict mode (e.g., VPNs, but
                     // not networks that don't provide Internet access), we still need to perform
                     // private DNS server resolution.
-                    if (!isValidationRequired()) {
+                    if (mEvaluationState.isCaptivePortalWantedAsIs()
+                            && isPrivateDnsValidationRequired()) {
+                        // Captive portals can only be detected on networks that validate both
+                        // validation and private DNS validation.
+                        validationLog("Captive portal is used as is, resolving private DNS");
+                        transitionTo(mEvaluatingPrivateDnsState);
+                    } else if (!isValidationRequired()) {
                         if (isPrivateDnsValidationRequired()) {
                             validationLog("Network would not satisfy default request, "
                                     + "resolving private DNS");
@@ -3170,7 +3207,7 @@
          * data to statsd pipeline.
          * @param stats a {@link DataStallDetectionStats} that contains the detection level
          *              information.
-         * @para result the network reevaluation result.
+         * @param result the network reevaluation result.
          */
         public void writeDataStallDetectionStats(@NonNull final DataStallDetectionStats stats,
                 @NonNull final CaptivePortalProbeResult result) {
@@ -3380,18 +3417,28 @@
     // NETWORK_VALIDATION_RESULT_VALID. But with this scheme, the first two or three validation
     // reports are all failures, because they are "HTTP succeeded but validation not yet passed",
     // "HTTP and HTTPS succeeded but validation not yet passed", etc.
+    // TODO : rename EvaluationState to not contain "State" in the name, as it makes this class
+    // sound like one of the states of the state machine, which it's not.
     @VisibleForTesting
     protected class EvaluationState {
         // The latest validation result for this network. This is a bitmask of
         // INetworkMonitor.NETWORK_VALIDATION_RESULT_* constants.
         private int mEvaluationResult = NETWORK_VALIDATION_RESULT_INVALID;
+
+
+        // Set when the captive portal app said this network should be used as is as a result
+        // of user interaction. The valid bit represents the user's decision to override automatic
+        // determination of whether the network has access to Internet, so in this case the
+        // network is always reported as validated.
+        // TODO : Make ConnectivityService aware of this state, so that it can use the network as
+        // the default without setting the VALIDATED bit, as it's a bit of a lie. This can't be
+        // done on Android <= R where CS can't be updated, but it is doable on S+.
+        private boolean mCaptivePortalWantedAsIs = false;
         // Indicates which probes have succeeded since clearProbeResults was called.
         // This is a bitmask of INetworkMonitor.NETWORK_VALIDATION_PROBE_* constants.
         private int mProbeResults = 0;
         // A bitmask to record which probes are completed.
         private int mProbeCompleted = 0;
-        // The latest redirect URL.
-        private String mRedirectUrl;
 
         protected void clearProbeResults() {
             mProbeResults = 0;
@@ -3425,9 +3472,26 @@
             });
         }
 
+        protected void setCaptivePortalWantedAsIs() {
+            mCaptivePortalWantedAsIs = true;
+        }
+
+        protected boolean isCaptivePortalWantedAsIs() {
+            return mCaptivePortalWantedAsIs;
+        }
+
         protected void reportEvaluationResult(int result, @Nullable String redirectUrl) {
+            if (mCaptivePortalWantedAsIs) {
+                result = NETWORK_VALIDATION_RESULT_VALID;
+            } else if (!isValidationRequired() && mProbeCompleted == 0 && mCallbackVersion >= 11) {
+                // If validation is not required AND no probes were attempted, the validation was
+                // skipped. Report this to ConnectivityService for ConnectivityDiagnostics, but only
+                // if the platform has callback version 11+, as ConnectivityService must also know
+                // how to understand this bit.
+                result |= NETWORK_VALIDATION_RESULT_SKIPPED;
+            }
+
             mEvaluationResult = result;
-            mRedirectUrl = redirectUrl;
             final NetworkTestResultParcelable p = new NetworkTestResultParcelable();
             p.result = result;
             p.probesSucceeded = mProbeResults;
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp
index 3842b50..9137c5c 100644
--- a/tests/integration/Android.bp
+++ b/tests/integration/Android.bp
@@ -50,7 +50,6 @@
         "android.test.base",
         "android.test.mock",
     ],
-    jarjar_rules: ":NetworkStackJarJarRules",
     visibility: ["//visibility:private"],
 }
 
@@ -73,6 +72,7 @@
     test_suites: ["device-tests"],
     min_sdk_version: "29",
     target_sdk_version: "30",
+    jarjar_rules: ":NetworkStackJarJarRules",
 }
 
 // Network stack next integration tests.
@@ -88,21 +88,7 @@
     certificate: "networkstack",
     platform_apis: true,
     test_suites: ["device-tests"],
-}
-
-// The static lib needs to be jarjared by each module so they do not conflict with each other
-// (e.g. wifi, system server, network stack need to use different package names when including it).
-// Apply NetworkStack jarjar rules to the tests as well so classes in NetworkStaticLibTests have the
-// same package names as in module code.
-android_library {
-    name: "NetworkStackStaticLibTestsLib",
-    platform_apis: true,
-    min_sdk_version: "29",
     jarjar_rules: ":NetworkStackJarJarRules",
-    static_libs: [
-        "NetworkStaticLibTestsLib",
-        "NetdStaticLibTestsLib",
-    ],
 }
 
 // Special version of the network stack tests that includes all tests necessary for code coverage
@@ -120,8 +106,10 @@
         "modules-utils-native-coverage-listener",
         "NetworkStackTestsLib",
         "NetworkStackIntegrationTestsLib",
-        "NetworkStackStaticLibTestsLib",
+        "NetworkStaticLibTestsLib",
+        "NetdStaticLibTestsLib",
     ],
     compile_multilib: "both",
     manifest: "AndroidManifest_coverage.xml",
+    jarjar_rules: ":NetworkStackJarJarRules",
 }
diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.kt b/tests/integration/src/android/net/ip/IpClientIntegrationTest.kt
index eb0a799..748ee5a 100644
--- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.kt
+++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.kt
@@ -17,8 +17,14 @@
 package android.net.ip
 
 import android.net.ipmemorystore.NetworkAttributes
+import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener
+import android.net.ipmemorystore.Status
+import android.net.ipmemorystore.Status.SUCCESS
 import android.util.ArrayMap
+import java.net.Inet6Address
+import kotlin.test.assertEquals
 import org.mockito.Mockito.any
+import org.mockito.Mockito.doAnswer
 import org.mockito.ArgumentCaptor
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.never
@@ -56,4 +62,23 @@
     override fun assertIpMemoryNeverStoreNetworkAttributes(l2Key: String, timeout: Long) {
         verify(mIpMemoryStore, never()).storeNetworkAttributes(eq(l2Key), any(), any())
     }
+
+    override fun assertNotifyNeighborLost(targetIp: Inet6Address) {
+        val target = ArgumentCaptor.forClass(Inet6Address::class.java)
+
+        verify(mCallback, timeout(TEST_TIMEOUT_MS)).notifyLost(target.capture(), any())
+        assertEquals(targetIp, target.getValue())
+    }
+
+    override fun assertNeverNotifyNeighborLost() {
+        verify(mCallback, never()).notifyLost(any(), any())
+    }
+
+    override fun storeNetworkAttributes(l2Key: String, na: NetworkAttributes) {
+        doAnswer { inv ->
+            val listener = inv.getArgument<OnNetworkAttributesRetrievedListener>(1)
+            listener.onNetworkAttributesRetrieved(Status(SUCCESS), l2Key, na)
+            true
+        }.`when`(mIpMemoryStore).retrieveNetworkAttributes(eq(l2Key), any())
+    }
 }
diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
index e40db77..bbbe0ba 100644
--- a/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
+++ b/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
@@ -27,7 +27,10 @@
 import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
 import static android.net.dhcp.DhcpPacket.MIN_V6ONLY_WAIT_MS;
 import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable;
+import static android.net.ip.IpReachabilityMonitor.MIN_NUD_SOLICIT_NUM;
+import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM;
 import static android.net.ipmemorystore.Status.SUCCESS;
+import static android.net.shared.ProvisioningConfiguration.VERSION_ADDED_PROVISIONING_ENUM;
 import static android.system.OsConstants.ETH_P_IPV6;
 import static android.system.OsConstants.IFA_F_TEMPORARY;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
@@ -40,15 +43,21 @@
 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_OFFSET;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET;
+import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE;
+import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER;
+import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS;
 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK;
+import static com.android.testutils.MiscAsserts.assertThrows;
 
 import static junit.framework.Assert.fail;
 
@@ -99,6 +108,7 @@
 import android.net.LinkProperties;
 import android.net.MacAddress;
 import android.net.NetworkStackIpMemoryStore;
+import android.net.RouteInfo;
 import android.net.TestNetworkInterface;
 import android.net.TestNetworkManager;
 import android.net.Uri;
@@ -108,10 +118,10 @@
 import android.net.dhcp.DhcpPacket;
 import android.net.dhcp.DhcpPacket.ParseException;
 import android.net.dhcp.DhcpRequestPacket;
+import android.net.ip.IpNeighborMonitor.NeighborEventConsumer;
 import android.net.ipmemorystore.NetworkAttributes;
 import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener;
 import android.net.ipmemorystore.Status;
-import android.net.netlink.StructNdOptPref64;
 import android.net.networkstack.TestNetworkStackServiceClient;
 import android.net.networkstack.aidl.dhcp.DhcpOption;
 import android.net.shared.Layer2Information;
@@ -119,6 +129,7 @@
 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
 import android.net.util.InterfaceParams;
 import android.net.util.NetworkStackUtils;
+import android.net.util.SharedLog;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -141,6 +152,8 @@
 import com.android.internal.util.StateMachine;
 import com.android.net.module.util.ArrayTrackRecord;
 import com.android.net.module.util.Ipv6Utils;
+import com.android.net.module.util.netlink.StructNdOptPref64;
+import com.android.net.module.util.structs.LlaOption;
 import com.android.net.module.util.structs.PrefixInformationOption;
 import com.android.net.module.util.structs.RdnssOption;
 import com.android.networkstack.apishim.CaptivePortalDataShimImpl;
@@ -148,8 +161,10 @@
 import com.android.networkstack.apishim.common.ShimUtils;
 import com.android.networkstack.arp.ArpPacket;
 import com.android.networkstack.metrics.IpProvisioningMetrics;
+import com.android.networkstack.metrics.IpReachabilityMonitorMetrics;
 import com.android.networkstack.metrics.NetworkQuirkMetrics;
 import com.android.networkstack.packets.NeighborAdvertisement;
+import com.android.networkstack.packets.NeighborSolicitation;
 import com.android.server.NetworkObserver;
 import com.android.server.NetworkObserverRegistry;
 import com.android.server.NetworkStackService.NetworkStackServiceManager;
@@ -263,6 +278,8 @@
     @Mock private PowerManager.WakeLock mTimeoutWakeLock;
     @Mock protected NetworkStackIpMemoryStore mIpMemoryStore;
     @Mock private NetworkQuirkMetrics.Dependencies mNetworkQuirkMetricsDeps;
+    @Mock private IpReachabilityMonitorMetrics mIpReachabilityMonitorMetrics;
+    @Mock protected IpReachabilityMonitor.Callback mCallback;
 
     @Spy private INetd mNetd;
     private NetworkObserverRegistry mNetworkObserverRegistry;
@@ -272,7 +289,7 @@
 
     /***** END signature required test members *****/
 
-    private IIpClientCallbacks mCb;
+    protected IIpClientCallbacks mCb;
     private IIpClient mIIpClient;
     private String mIfaceName;
     private HandlerThread mPacketReaderThread;
@@ -327,7 +344,10 @@
     private static final String HOSTNAME = "testhostname";
     private static final int TEST_DEFAULT_MTU = 1500;
     private static final int TEST_MIN_MTU = 1280;
-    private static final byte[] SERVER_MAC = new byte[] { 0x00, 0x1A, 0x11, 0x22, 0x33, 0x44 };
+    private static final MacAddress ROUTER_MAC = MacAddress.fromString("00:1A:11:22:33:44");
+    private static final byte[] ROUTER_MAC_BYTES = ROUTER_MAC.toByteArray();
+    private static final Inet6Address ROUTER_LINK_LOCAL =
+                (Inet6Address) InetAddresses.parseNumericAddress("fe80::1");
     private static final String TEST_HOST_NAME = "AOSP on Crosshatch";
     private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch";
     private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi";
@@ -401,6 +421,15 @@
         }
 
         @Override
+        public IpReachabilityMonitor getIpReachabilityMonitor(Context context,
+                InterfaceParams ifParams, Handler h, SharedLog log,
+                IpReachabilityMonitor.Callback callback, boolean usingMultinetworkPolicyTracker,
+                IpReachabilityMonitor.Dependencies deps, final INetd netd) {
+            return new IpReachabilityMonitor(context, ifParams, h, log, mCallback,
+                    usingMultinetworkPolicyTracker, deps, netd);
+        }
+
+        @Override
         public boolean isFeatureEnabled(final Context context, final String name,
                 final boolean defaultEnabled) {
             return IpClientIntegrationTestCommon.this.isFeatureEnabled(name, defaultEnabled);
@@ -440,6 +469,32 @@
         }
 
         @Override
+        public IpReachabilityMonitor.Dependencies getIpReachabilityMonitorDeps(Context context,
+                String name) {
+            return new IpReachabilityMonitor.Dependencies() {
+                public void acquireWakeLock(long durationMs) {
+                    // It doesn't matter for the integration test app on whether the wake lock
+                    // is acquired or not.
+                    return;
+                }
+
+                public IpNeighborMonitor makeIpNeighborMonitor(Handler h, SharedLog log,
+                        NeighborEventConsumer cb) {
+                    return new IpNeighborMonitor(h, log, cb);
+                }
+
+                public boolean isFeatureEnabled(final Context context, final String name,
+                        boolean defaultEnabled) {
+                    return Dependencies.this.isFeatureEnabled(context, name, defaultEnabled);
+                }
+
+                public IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics() {
+                    return mIpReachabilityMonitorMetrics;
+                }
+            };
+        }
+
+        @Override
         public int getDeviceConfigPropertyInt(String name, int defaultValue) {
             Integer value = mIntConfigProperties.get(name);
             if (value == null) {
@@ -470,8 +525,14 @@
 
     protected abstract NetworkAttributes getStoredNetworkAttributes(String l2Key, long timeout);
 
+    protected abstract void storeNetworkAttributes(String l2Key, NetworkAttributes na);
+
     protected abstract void assertIpMemoryNeverStoreNetworkAttributes(String l2Key, long timeout);
 
+    protected abstract void assertNotifyNeighborLost(Inet6Address targetIp);
+
+    protected abstract void assertNeverNotifyNeighborLost();
+
     protected final boolean testSkipped() {
         // TODO: split out a test suite for root tests, and fail hard instead of skipping the test
         // if it is run on devices where TestNetworkStackServiceClient is not supported
@@ -518,6 +579,7 @@
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
         when(mNetworkStackServiceManager.getIpMemoryStoreService())
                 .thenReturn(mIpMemoryStoreService);
+        when(mCb.getInterfaceVersion()).thenReturn(VERSION_ADDED_PROVISIONING_ENUM);
 
         mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67);
         mDependencies.setDeviceConfigProperty(DhcpClient.DHCP_RESTART_CONFIG_DELAY, 10);
@@ -712,6 +774,14 @@
         }
     }
 
+    private NeighborSolicitation parseNeighborSolicitationOrNull(final byte[] packet) {
+        try {
+            return NeighborSolicitation.parse(packet, packet.length);
+        } catch (NeighborSolicitation.ParseException e) {
+            return null;
+        }
+    }
+
     private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
             final Inet4Address clientAddress, final Integer leaseTimeSec, final short mtu,
             final String captivePortalUrl, final Integer ipv6OnlyWaitTime) {
@@ -761,7 +831,7 @@
 
     private void sendArpReply(final byte[] clientMac) throws IOException {
         final ByteBuffer packet = ArpPacket.buildArpPacket(clientMac /* dst */,
-                SERVER_MAC /* src */, INADDR_ANY.getAddress() /* target IP */,
+                ROUTER_MAC_BYTES /* srcMac */, INADDR_ANY.getAddress() /* target IP */,
                 clientMac /* target HW address */, CLIENT_ADDR.getAddress() /* sender IP */,
                 (short) ARP_REPLY);
         mPacketReader.sendResponse(packet);
@@ -769,7 +839,7 @@
 
     private void sendArpProbe() throws IOException {
         final ByteBuffer packet = ArpPacket.buildArpPacket(DhcpPacket.ETHER_BROADCAST /* dst */,
-                SERVER_MAC /* src */, CLIENT_ADDR.getAddress() /* target IP */,
+                ROUTER_MAC_BYTES /* srcMac */, CLIENT_ADDR.getAddress() /* target IP */,
                 new byte[ETHER_ADDR_LEN] /* target HW address */,
                 INADDR_ANY.getAddress() /* sender IP */, (short) ARP_REQUEST);
         mPacketReader.sendResponse(packet);
@@ -1458,20 +1528,23 @@
         HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
     }
 
-    private boolean isRouterSolicitation(final byte[] packetBytes) {
+    private boolean isIcmpv6PacketOfType(final byte[] packetBytes, int type) {
         ByteBuffer packet = ByteBuffer.wrap(packetBytes);
         return packet.getShort(ETHER_TYPE_OFFSET) == (short) ETH_P_IPV6
                 && packet.get(ETHER_HEADER_LEN + IPV6_PROTOCOL_OFFSET) == (byte) IPPROTO_ICMPV6
-                && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN)
-                        == (byte) ICMPV6_ROUTER_SOLICITATION;
+                && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN) == (byte) type;
+    }
+
+    private boolean isRouterSolicitation(final byte[] packetBytes) {
+        return isIcmpv6PacketOfType(packetBytes, ICMPV6_ROUTER_SOLICITATION);
     }
 
     private boolean isNeighborAdvertisement(final byte[] packetBytes) {
-        ByteBuffer packet = ByteBuffer.wrap(packetBytes);
-        return packet.getShort(ETHER_TYPE_OFFSET) == (short) ETH_P_IPV6
-                && packet.get(ETHER_HEADER_LEN + IPV6_PROTOCOL_OFFSET) == (byte) IPPROTO_ICMPV6
-                && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN)
-                        == (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT;
+        return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_ADVERTISEMENT);
+    }
+
+    private boolean isNeighborSolicitation(final byte[] packetBytes) {
+        return isIcmpv6PacketOfType(packetBytes, ICMPV6_NEIGHBOR_SOLICITATION);
     }
 
     private NeighborAdvertisement getNextNeighborAdvertisement() throws ParseException {
@@ -1484,6 +1557,16 @@
         return na;
     }
 
+    private NeighborSolicitation getNextNeighborSolicitation() throws ParseException {
+        final byte[] packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS,
+                this::isNeighborSolicitation);
+        if (packet == null) return null;
+
+        final NeighborSolicitation ns = parseNeighborSolicitationOrNull(packet);
+        assertNotNull("Invalid neighbour solicitation received", ns);
+        return ns;
+    }
+
     private void waitForRouterSolicitation() throws ParseException {
         assertNotNull("No router solicitation received on interface within timeout",
                 mPacketReader.popPacket(PACKET_TIMEOUT_MS, this::isRouterSolicitation));
@@ -1521,17 +1604,18 @@
         return RdnssOption.build(lifetime, servers);
     }
 
+    private static ByteBuffer buildSllaOption() throws Exception {
+        return LlaOption.build((byte) ICMPV6_ND_OPTION_SLLA, ROUTER_MAC);
+    }
+
     private static ByteBuffer buildRaPacket(short lifetime, ByteBuffer... options)
             throws Exception {
-        final MacAddress dstMac = MacAddress.fromString("33:33:00:00:00:01");
-        final MacAddress srcMac = MacAddress.fromString("01:02:03:04:05:06");
-        final Inet6Address routerLinkLocal =
-                (Inet6Address) InetAddresses.parseNumericAddress("fe80::1");
-
-        return Ipv6Utils.buildRaPacket(srcMac, dstMac, routerLinkLocal,
-                IPV6_ADDR_ALL_NODES_MULTICAST, (byte) 0 /* M=0, O=0 */, lifetime,
-                0 /* Reachable time, unspecified */, 100 /* Retrans time 100ms */,
-                options);
+        final MacAddress dstMac =
+                NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST);
+        return Ipv6Utils.buildRaPacket(ROUTER_MAC /* srcMac */, dstMac,
+                ROUTER_LINK_LOCAL /* srcIp */, IPV6_ADDR_ALL_NODES_MULTICAST /* dstIp */,
+                (byte) 0 /* M=0, O=0 */, lifetime, 0 /* Reachable time, unspecified */,
+                100 /* Retrans time 100ms */, options);
     }
 
     private static ByteBuffer buildRaPacket(ByteBuffer... options) throws Exception {
@@ -1575,7 +1659,8 @@
         final String dnsServer = "2001:4860:4860::64";
         final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
         final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
-        final ByteBuffer ra = buildRaPacket(pio, rdnss);
+        final ByteBuffer slla = buildSllaOption();
+        final ByteBuffer ra = buildRaPacket(pio, rdnss, slla);
 
         return doIpv6OnlyProvisioning(inOrder, ra);
     }
@@ -2000,6 +2085,52 @@
     }
 
     @Test
+    @SignatureRequiredTest(reason = "needs mocked alarm and access to IpClient handler thread")
+    public void testDhcpClientPreconnection_DelayedAbortAndTransitToStoppedState()
+            throws Exception {
+        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+                .withoutIpReachabilityMonitor()
+                .withPreconnection()
+                .build();
+        setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, false /* shouldReplyRapidCommitAck */,
+                false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
+        startIpClientProvisioning(config);
+        assertDiscoverPacketOnPreconnectionStart();
+
+        // IpClient is in the PreconnectingState, simulate provisioning timeout event
+        // and force IpClient state machine transit to StoppingState.
+        final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
+        final OnAlarmListener alarm = expectAlarmSet(null /* inOrder */, "TIMEOUT", 18,
+                mIpc.getHandler());
+        mIpc.getHandler().post(() -> alarm.onAlarm());
+
+        verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
+        final LinkProperties lp = captor.getValue();
+        assertNotNull(lp);
+        assertEquals(mIfaceName, lp.getInterfaceName());
+        assertEquals(0, lp.getLinkAddresses().size());
+        assertEquals(0, lp.getRoutes().size());
+        assertEquals(0, lp.getMtu());
+        assertEquals(0, lp.getDnsServers().size());
+
+        // Send preconnection abort message, but IpClient should ignore it at this moment and
+        // transit to StoppedState finally.
+        mIpc.notifyPreconnectionComplete(false /* abort */);
+        mIpc.stop();
+        HandlerUtils.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS);
+
+        reset(mCb);
+
+        // Start provisioning again to verify IpClient can process CMD_START correctly at
+        // StoppedState.
+        startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
+                false /* shouldReplyRapidCommitAck */, false /* isPreConnectionEnabled */,
+                false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
+        final DhcpPacket discover = getNextDhcpPacket();
+        assertTrue(discover instanceof DhcpDiscoverPacket);
+    }
+
+    @Test
     public void testDhcpDecline_conflictByArpReply() throws Exception {
         doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */,
                 false /* shouldReplyRapidCommitAck */, true /* isDhcpIpConflictDetectEnabled */,
@@ -2383,7 +2514,8 @@
         final String dnsServer = "2001:4860:4860::64";
         final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
         final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
-        final ByteBuffer ra = buildRaPacket(pio, rdnss);
+        final ByteBuffer slla = buildSllaOption();
+        final ByteBuffer ra = buildRaPacket(pio, rdnss, slla);
 
         doIpv6OnlyProvisioning(inOrder, ra);
 
@@ -2607,20 +2739,20 @@
         verifyDhcpPacketRequestsIPv6OnlyPreferredOption(DhcpRequestPacket.class);
     }
 
+    private void setUpRetrievedNetworkAttributesForInitRebootState() {
+        final NetworkAttributes na = new NetworkAttributes.Builder()
+                .setAssignedV4Address(CLIENT_ADDR)
+                .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
+                .setMtu(new Integer(TEST_DEFAULT_MTU))
+                .setCluster(TEST_CLUSTER)
+                .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
+                .build();
+        storeNetworkAttributes(TEST_L2KEY, na);
+    }
+
     private void startFromInitRebootStateWithIPv6OnlyPreferredOption(final Integer ipv6OnlyWaitTime,
             final long expectedWaitSecs) throws Exception {
-        doAnswer(invocation -> {
-            ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1))
-                    .onNetworkAttributesRetrieved(new Status(SUCCESS), TEST_L2KEY,
-                            new NetworkAttributes.Builder()
-                                .setAssignedV4Address(CLIENT_ADDR)
-                                .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid
-                                .setMtu(new Integer(TEST_DEFAULT_MTU))
-                                .setCluster(TEST_CLUSTER)
-                                .setDnsAddresses(Collections.singletonList(SERVER_ADDR))
-                                .build());
-            return null;
-        }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any());
+        setUpRetrievedNetworkAttributesForInitRebootState();
 
         final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
                 .withoutIpReachabilityMonitor()
@@ -2747,7 +2879,7 @@
     );
 
     private DhcpPacket doCustomizedDhcpOptionsTest(final List<DhcpOption> options,
-             final ScanResultInfo info) throws Exception {
+             final ScanResultInfo info, boolean isDhcpLeaseCacheEnabled) throws Exception {
         ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
                 .withoutIpReachabilityMonitor()
                 .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
@@ -2756,7 +2888,7 @@
                 .withDhcpOptions(options)
                 .withoutIPv6();
 
-        setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, false /* isRapidCommitEnabled */,
+        setDhcpFeatures(isDhcpLeaseCacheEnabled, false /* isRapidCommitEnabled */,
                 false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
 
         startIpClientProvisioning(prov.build());
@@ -2767,10 +2899,11 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions() throws Exception {
         final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
                 (byte) 0x17 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
@@ -2778,10 +2911,11 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
         final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
                 (byte) 0x17 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
@@ -2789,9 +2923,9 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
         final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS,
-                null /* scanResultInfo */);
+                null /* scanResultInfo */, false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
@@ -2799,10 +2933,11 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_disallowedOui() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions_disallowedOui() throws Exception {
         final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */,
                 new byte[]{ 0x00, 0x11, 0x22} /* oui */, (byte) 0x17 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
@@ -2810,10 +2945,11 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_invalidIeId() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions_invalidIeId() throws Exception {
         final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specificIE */, TEST_OEM_OUI,
                 (byte) 0x17 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
@@ -2821,10 +2957,11 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
         final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
                 (byte) 0x10 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
@@ -2832,7 +2969,7 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_disallowedOption() throws Exception {
+    public void testDisoverCustomizedDhcpOptions_disallowedOption() throws Exception {
         final List<DhcpOption> options = Arrays.asList(
                 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
                 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
@@ -2840,7 +2977,8 @@
                 makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU)));
         final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
                 (byte) 0x17 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
@@ -2849,7 +2987,7 @@
     }
 
     @Test
-    public void testCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
+    public void testDiscoverCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
         final List<DhcpOption> options = Arrays.asList(
                 makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
                 makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
@@ -2857,7 +2995,8 @@
                 makeDhcpOption((byte) 42, null));
         final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
                 (byte) 0x17 /* vendor-specific IE type */);
-        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
+                false /* isDhcpLeaseCacheEnabled */);
 
         assertTrue(packet instanceof DhcpDiscoverPacket);
         assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
@@ -2865,6 +3004,160 @@
         assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */));
     }
 
+    @Test
+    public void testDiscoverCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception {
+        final List<DhcpOption> options = Arrays.asList(
+                // DHCP_USER_CLASS
+                makeDhcpOption((byte) 77, null));
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
+                false /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpDiscoverPacket);
+        assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */));
+        assertNull(packet.mUserClass);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
+        assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_nullDhcpOptions() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(null /* options */, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
+        assertNull(packet.mUserClass);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_nullScanResultInfo() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS,
+                null /* scanResultInfo */, true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
+        assertNull(packet.mUserClass);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_disallowedOui() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */,
+                new byte[]{ 0x00, 0x11, 0x22} /* oui */, (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
+        assertNull(packet.mUserClass);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_invalidIeId() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final ScanResultInfo info = makeScanResultInfo(0xde /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
+        assertNull(packet.mUserClass);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_invalidVendorSpecificType() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x10 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(TEST_OEM_DHCP_OPTIONS, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, new String("android-dhcp-" + Build.VERSION.RELEASE));
+        assertNull(packet.mUserClass);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_disallowedOption() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final List<DhcpOption> options = Arrays.asList(
+                makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
+                makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
+                // Option 26: MTU
+                makeDhcpOption((byte) 26, HexDump.toByteArray(TEST_DEFAULT_MTU)));
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
+        assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
+        assertNull(packet.mMtu);
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_disallowedParamRequestOption() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final List<DhcpOption> options = Arrays.asList(
+                makeDhcpOption((byte) 60, TEST_OEM_VENDOR_ID.getBytes()),
+                makeDhcpOption((byte) 77, TEST_OEM_USER_CLASS_INFO),
+                // NTP_SERVER
+                makeDhcpOption((byte) 42, null));
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertEquals(packet.mVendorId, TEST_OEM_VENDOR_ID);
+        assertArrayEquals(packet.mUserClass, TEST_OEM_USER_CLASS_INFO);
+        assertFalse(packet.hasRequestedParam((byte) 42 /* NTP_SERVER */));
+    }
+
+    @Test
+    public void testRequestCustomizedDhcpOptions_ParameterRequestListOnly() throws Exception {
+        setUpRetrievedNetworkAttributesForInitRebootState();
+
+        final List<DhcpOption> options = Arrays.asList(
+                // DHCP_USER_CLASS
+                makeDhcpOption((byte) 77, null));
+        final ScanResultInfo info = makeScanResultInfo(0xdd /* vendor-specificIE */, TEST_OEM_OUI,
+                (byte) 0x17 /* vendor-specific IE type */);
+        final DhcpPacket packet = doCustomizedDhcpOptionsTest(options, info,
+                true /* isDhcpLeaseCacheEnabled */);
+
+        assertTrue(packet instanceof DhcpRequestPacket);
+        assertTrue(packet.hasRequestedParam((byte) 77 /* DHCP_USER_CLASS */));
+        assertNull(packet.mUserClass);
+    }
+
     private void assertGratuitousNa(final NeighborAdvertisement na) throws Exception {
         final MacAddress etherMulticast =
                 NetworkStackUtils.ipv6MulticastToEthernetMulticast(IPV6_ADDR_ALL_ROUTERS_MULTICAST);
@@ -2965,7 +3258,7 @@
     @Test
     public void testGratuitousArpAndNaAfterRoaming_disableExpFlag() throws Exception {
         startGratuitousArpAndNaAfterRoamingTest(false /* isGratuitousArpNaRoamingEnabled */,
-                true /* hasIpv6 */, true /* hasIpv6 */);
+                true /* hasIpv4 */, true /* hasIpv6 */);
         performDualStackProvisioning();
         forceLayer2Roaming();
 
@@ -3007,4 +3300,207 @@
         assertEquals(0, naList.size());
         assertEquals(1, arpList.size());
     }
+
+    private void assertNeighborSolicitation(final NeighborSolicitation ns,
+            final Inet6Address target) {
+        assertEquals(ETH_P_IPV6, ns.ethHdr.etherType);
+        assertEquals(IPPROTO_ICMPV6, ns.ipv6Hdr.nextHeader);
+        assertEquals(0xff, ns.ipv6Hdr.hopLimit);
+        assertTrue(ns.ipv6Hdr.srcIp.isLinkLocalAddress());
+        assertEquals(ICMPV6_NEIGHBOR_SOLICITATION, ns.icmpv6Hdr.type);
+        assertEquals(0, ns.icmpv6Hdr.code);
+        assertEquals(0, ns.nsHdr.reserved);
+        assertEquals(target, ns.nsHdr.target);
+        assertEquals(ns.slla.linkLayerAddress, ns.ethHdr.srcMac);
+    }
+
+    private void assertUnicastNeighborSolicitation(final NeighborSolicitation ns,
+            final MacAddress dstMac, final Inet6Address dstIp, final Inet6Address target) {
+        assertEquals(dstMac, ns.ethHdr.dstMac);
+        assertEquals(dstIp, ns.ipv6Hdr.dstIp);
+        assertNeighborSolicitation(ns, target);
+    }
+
+    private void assertMulticastNeighborSolicitation(final NeighborSolicitation ns,
+            final Inet6Address target) {
+        final MacAddress etherMulticast =
+                NetworkStackUtils.ipv6MulticastToEthernetMulticast(ns.ipv6Hdr.dstIp);
+        assertEquals(etherMulticast, ns.ethHdr.dstMac);
+        assertTrue(ns.ipv6Hdr.dstIp.isMulticastAddress());
+        assertNeighborSolicitation(ns, target);
+    }
+
+    private NeighborSolicitation waitForUnicastNeighborSolicitation(final MacAddress dstMac,
+            final Inet6Address dstIp, final Inet6Address targetIp) throws Exception {
+        NeighborSolicitation ns;
+        while ((ns = getNextNeighborSolicitation()) != null) {
+            // Filter out the NSes used for duplicate address detetction, the target address
+            // is the global IPv6 address inside these NSes.
+            if (ns.nsHdr.target.isLinkLocalAddress()) break;
+        }
+        assertNotNull("No unicast Neighbor solicitation received on interface within timeout", ns);
+        assertUnicastNeighborSolicitation(ns, dstMac, dstIp, targetIp);
+        return ns;
+    }
+
+    private List<NeighborSolicitation> waitForMultipleNeighborSolicitations() throws Exception {
+        NeighborSolicitation ns;
+        final List<NeighborSolicitation> nsList = new ArrayList<NeighborSolicitation>();
+        while ((ns = getNextNeighborSolicitation()) != null) {
+            // Filter out the NSes used for duplicate address detetction, the target address
+            // is the global IPv6 address inside these NSes.
+            if (ns.nsHdr.target.isLinkLocalAddress()) {
+                nsList.add(ns);
+            }
+        }
+        assertFalse(nsList.isEmpty());
+        return nsList;
+    }
+
+    // Override this function with disabled experiment flag by default, in order not to
+    // affect those tests which are just related to basic IpReachabilityMonitor infra.
+    private void prepareIpReachabilityMonitorTest() throws Exception {
+        prepareIpReachabilityMonitorTest(false /* isMulticastResolicitEnabled */);
+    }
+
+    private void prepareIpReachabilityMonitorTest(boolean isMulticastResolicitEnabled)
+            throws Exception {
+        final ScanResultInfo info = makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID);
+        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+                .withLayer2Information(new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
+                       MacAddress.fromString(TEST_DEFAULT_BSSID)))
+                .withScanResultInfo(info)
+                .withDisplayName(TEST_DEFAULT_SSID)
+                .withoutIPv4()
+                .build();
+        setFeatureEnabled(NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION,
+                isMulticastResolicitEnabled);
+        startIpClientProvisioning(config);
+        verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false);
+        doIpv6OnlyProvisioning();
+
+        // Simulate the roaming.
+        forceLayer2Roaming();
+    }
+
+    @Test
+    public void testIpReachabilityMonitor_probeFailed() throws Exception {
+        prepareIpReachabilityMonitorTest();
+
+        final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
+        assertEquals(MIN_NUD_SOLICIT_NUM, nsList.size());
+        for (NeighborSolicitation ns : nsList) {
+            assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
+                    ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
+        }
+        assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */);
+    }
+
+    @Test
+    public void testIpReachabilityMonitor_probeReachable() throws Exception {
+        prepareIpReachabilityMonitorTest();
+
+        final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
+                ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
+
+        // Reply Neighbor Advertisement and check notifyLost callback won't be triggered.
+        int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
+        final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */,
+                ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
+                ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
+        mPacketReader.sendResponse(na);
+        assertNeverNotifyNeighborLost();
+    }
+
+    @Test
+    public void testIpReachabilityMonitor_mcastResoclicitProbeFailed() throws Exception {
+        prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
+
+        final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
+        int expectedSize = MIN_NUD_SOLICIT_NUM + NUD_MCAST_RESOLICIT_NUM;
+        assertEquals(expectedSize, nsList.size()); // 5 unicast NSes + 3 multicast NSes
+        for (NeighborSolicitation ns : nsList.subList(0, MIN_NUD_SOLICIT_NUM)) {
+            assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
+                    ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
+        }
+        for (NeighborSolicitation ns : nsList.subList(MIN_NUD_SOLICIT_NUM, nsList.size())) {
+            assertMulticastNeighborSolicitation(ns, ROUTER_LINK_LOCAL /* targetIp */);
+        }
+        assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */);
+    }
+
+    @Test
+    public void testIpReachabilityMonitor_mcastResoclicitProbeReachableWithSameLinkLayerAddress()
+            throws Exception {
+        prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
+
+        final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
+                ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
+
+        // Reply Neighbor Advertisement and check notifyLost callback won't be triggered.
+        int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
+        final ByteBuffer na = NeighborAdvertisement.build(ROUTER_MAC /* srcMac */,
+                ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
+                ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
+        mPacketReader.sendResponse(na);
+        assertNeverNotifyNeighborLost();
+    }
+
+    @Test
+    public void testIpReachabilityMonitor_mcastResoclicitProbeReachableWithDiffLinkLayerAddress()
+            throws Exception {
+        prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */);
+
+        final NeighborSolicitation ns = waitForUnicastNeighborSolicitation(ROUTER_MAC /* dstMac */,
+                ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
+
+        // Reply Neighbor Advertisement with a different link-layer address and check notifyLost
+        // callback will be triggered. Override flag must be set, which indicates that the
+        // advertisement should override an existing cache entry and update the cached link-layer
+        // address, otherwise, kernel won't transit to REACHABLE state with a different link-layer
+        // address.
+        int flag = NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER | NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
+                | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE;
+        final MacAddress newMac = MacAddress.fromString("00:1a:11:22:33:55");
+        final ByteBuffer na = NeighborAdvertisement.build(newMac /* srcMac */,
+                ns.ethHdr.srcMac /* dstMac */, ROUTER_LINK_LOCAL /* srcIp */,
+                ns.ipv6Hdr.srcIp /* dstIp */, flag, ROUTER_LINK_LOCAL /* target */);
+        mPacketReader.sendResponse(na);
+        assertNotifyNeighborLost(ROUTER_LINK_LOCAL /* targetIp */);
+    }
+
+    @Test
+    public void testIPv6LinkLocalOnly() throws Exception {
+        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+                .withoutIPv4()
+                .withIpv6LinkLocalOnly()
+                .withRandomMacAddress()
+                .build();
+        startIpClientProvisioning(config);
+
+        final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
+        verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
+        final LinkProperties lp = captor.getValue();
+        assertNotNull(lp);
+        assertEquals(0, lp.getDnsServers().size());
+        final List<LinkAddress> addresses = lp.getLinkAddresses();
+        assertEquals(1, addresses.size());
+        assertTrue(addresses.get(0).getAddress().isLinkLocalAddress());
+        assertEquals(1, lp.getRoutes().size());
+        final RouteInfo route = lp.getRoutes().get(0);
+        assertNotNull(route);
+        assertTrue(route.getDestination().equals(new IpPrefix("fe80::/64")));
+        assertTrue(route.getGateway().isAnyLocalAddress());
+    }
+
+    @Test
+    public void testIPv6LinkLocalOnly_enableBothIPv4andIPv6LinkLocalOnly() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> new ProvisioningConfiguration.Builder()
+                        .withoutIpReachabilityMonitor()
+                        .withIpv6LinkLocalOnly()
+                        .withRandomMacAddress()
+                        .build()
+        );
+    }
 }
diff --git a/tests/integration/src/android/net/ip/IpClientRootTest.kt b/tests/integration/src/android/net/ip/IpClientRootTest.kt
index 68d8aab..d861639 100644
--- a/tests/integration/src/android/net/ip/IpClientRootTest.kt
+++ b/tests/integration/src/android/net/ip/IpClientRootTest.kt
@@ -33,6 +33,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.net.module.util.DeviceConfigUtils
 import java.lang.System.currentTimeMillis
+import java.net.Inet6Address
 import java.util.concurrent.CompletableFuture
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
@@ -45,6 +46,8 @@
 import org.junit.AfterClass
 import org.junit.BeforeClass
 import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.never
 import org.mockito.Mockito.timeout
 import org.mockito.Mockito.verify
 
@@ -150,6 +153,7 @@
             IIpClientCallbacks.Stub(), IIpClientCallbacks by base {
         // asBinder is implemented by both base class and delegate: specify explicitly
         override fun asBinder() = super.asBinder()
+        override fun getInterfaceVersion() = IIpClientCallbacks.VERSION
     }
 
     @After
@@ -260,4 +264,16 @@
         mStore.retrieveNetworkAttributes(l2Key, listener)
         assertNull(listener.getBlockingNetworkAttributes(timeout))
     }
+
+    override fun assertNotifyNeighborLost(targetIp: Inet6Address) {
+        verify(mCb, timeout(TEST_TIMEOUT_MS)).onReachabilityLost(anyString())
+    }
+
+    override fun assertNeverNotifyNeighborLost() {
+        verify(mCb, never()).onReachabilityLost(anyString())
+    }
+
+    override fun storeNetworkAttributes(l2Key: String, na: NetworkAttributes) {
+        mStore.storeNetworkAttributes(l2Key, na, null /* listener */)
+    }
 }
diff --git a/tests/integration/src/android/net/netlink/InetDiagSocketIntegrationTest.java b/tests/integration/src/android/net/netlink/InetDiagSocketIntegrationTest.java
index e474d8a..0329fab 100644
--- a/tests/integration/src/android/net/netlink/InetDiagSocketIntegrationTest.java
+++ b/tests/integration/src/android/net/netlink/InetDiagSocketIntegrationTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.netlink;
+package com.android.net.module.util.netlink;
 
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 64da600..a74d018 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -47,7 +47,6 @@
         "libnetworkstackutilsjni",
     ],
     jni_uses_sdk_apis: true,
-    jarjar_rules: ":NetworkStackJarJarRules",
 }
 
 // Tests for NetworkStackNext.
@@ -64,6 +63,7 @@
     defaults: ["NetworkStackTestsDefaults"],
     static_libs: ["NetworkStackApiCurrentLib"],
     compile_multilib: "both", // Workaround for b/147785146 for mainline-presubmit
+    jarjar_rules: ":NetworkStackJarJarRules",
 }
 
 // Library containing the unit tests. This is used by the coverage test target to pull in the
@@ -93,6 +93,7 @@
     defaults: ["NetworkStackTestsDefaults"],
     static_libs: ["NetworkStackApiStableLib"],
     compile_multilib: "both",
+    jarjar_rules: ":NetworkStackJarJarRules",
 }
 
 // Additional dependencies of libnetworkstackutilsjni that are not provided by the system when
diff --git a/tests/unit/lint-baseline.xml b/tests/unit/lint-baseline.xml
index ededbea..0bfcaa9 100644
--- a/tests/unit/lint-baseline.xml
+++ b/tests/unit/lint-baseline.xml
@@ -3,105 +3,6 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="    private static final NetworkCapabilities CELL_METERED_CAPABILITIES = new NetworkCapabilities()"
-        errorLine2="                                                                         ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="297"
-            column="74"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="            new NetworkCapabilities()"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="302"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="            new NetworkCapabilities()"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="308"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="            new NetworkCapabilities().addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="314"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="        final NetworkCapabilities nc = new NetworkCapabilities()"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="670"
-            column="40"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="        final NetworkCapabilities nc = new NetworkCapabilities()"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="690"
-            column="40"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="        final NetworkCapabilities meteredCap = new NetworkCapabilities()"
-        errorLine2="                                               ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="726"
-            column="48"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="        final NetworkCapabilities nonMeteredCap = new NetworkCapabilities()"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="746"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.net.NetworkCapabilities`"
-        errorLine1="        final NetworkCapabilities nc = new NetworkCapabilities()"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java"
-            line="2149"
-            column="40"/>
-    </issue>
-
-    <issue
-        id="NewApi"
         message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
         errorLine1="    private val EMPTY_CAPABILITIES = NetworkCapabilities()"
         errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~">
@@ -177,81 +78,4 @@
             column="14"/>
     </issue>
 
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="        mCallback.onCapabilitiesChanged(net2097, NetworkCapabilities())"
-        errorLine2="                                                 ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="59"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="        mCallback.onCapabilitiesChanged(net2098, NetworkCapabilities())"
-        errorLine2="                                                 ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="71"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="        val meteredNc = NetworkCapabilities()"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="108"
-            column="25"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="        val unmeteredNc = NetworkCapabilities().addCapability(NOT_METERED)"
-        errorLine2="                          ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="109"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="        val netCaps = NetworkCapabilities().addTransportType(CELLULAR)"
-        errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="130"
-            column="23"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="        val netCaps = NetworkCapabilities().addCapability(NOT_METERED).addTransportType(WIFI)"
-        errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="152"
-            column="23"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`"
-        errorLine1="            &quot;CapabilitiesChanged&quot; -> cb.onCapabilitiesChanged(net, NetworkCapabilities())"
-        errorLine2="                                                                   ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/modules/NetworkStack/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt"
-            line="279"
-            column="68"/>
-    </issue>
-
 </issues>
diff --git a/tests/unit/src/android/net/dhcp/DhcpPacketTest.java b/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
index d0c49d3..1a1f6c3 100644
--- a/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
@@ -96,12 +96,12 @@
 
     @Before
     public void setUp() {
-        DhcpPacket.testOverrideVendorId = "android-dhcp-???";
+        DhcpPacket.sTestOverrideVendorId = "android-dhcp-???";
     }
 
     @After
     public void tearDown() {
-        DhcpPacket.testOverrideVendorId = null;
+        DhcpPacket.sTestOverrideVendorId = null;
     }
 
     class TestDhcpPacket extends DhcpPacket {
diff --git a/tests/unit/src/android/net/ip/ConntrackMonitorTest.java b/tests/unit/src/android/net/ip/ConntrackMonitorTest.java
index 6e9078e..fc0d52b 100644
--- a/tests/unit/src/android/net/ip/ConntrackMonitorTest.java
+++ b/tests/unit/src/android/net/ip/ConntrackMonitorTest.java
@@ -16,15 +16,16 @@
 package android.net.ip;
 
 import static android.net.ip.ConntrackMonitor.ConntrackEvent;
-import static android.net.netlink.ConntrackMessage.Tuple;
-import static android.net.netlink.ConntrackMessage.TupleIpv4;
-import static android.net.netlink.ConntrackMessage.TupleProto;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_DELETE;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW;
 import static android.system.OsConstants.AF_UNIX;
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.SOCK_DGRAM;
 
+import static com.android.net.module.util.netlink.ConntrackMessage.Tuple;
+import static com.android.net.module.util.netlink.ConntrackMessage.TupleIpv4;
+import static com.android.net.module.util.netlink.ConntrackMessage.TupleProto;
+import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_DELETE;
+import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
@@ -33,8 +34,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.net.InetAddresses;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkSocket;
 import android.net.util.SharedLog;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -46,6 +45,9 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.NetlinkSocket;
+
 import libcore.util.HexEncoding;
 
 import org.junit.After;
diff --git a/tests/unit/src/android/net/ip/IpClientTest.java b/tests/unit/src/android/net/ip/IpClientTest.java
index c9e486b..95fe93a 100644
--- a/tests/unit/src/android/net/ip/IpClientTest.java
+++ b/tests/unit/src/android/net/ip/IpClientTest.java
@@ -115,6 +115,7 @@
     private static final String TEST_CLUSTER = "some cluster";
     private static final String TEST_SSID = "test_ssid";
     private static final String TEST_BSSID = "00:11:22:33:44:55";
+    private static final String TEST_BSSID2 = "00:1A:11:22:33:44";
 
     private static final String TEST_GLOBAL_ADDRESS = "1234:4321::548d:2db2:4fcf:ef75/64";
     private static final String[] TEST_LOCAL_ADDRESSES = {
@@ -430,6 +431,7 @@
 
     @Test
     public void testIsProvisioned() throws Exception {
+        final IpClient ipc = makeIpClient(TEST_IFNAME);
         InitialConfiguration empty = conf(links(), prefixes());
         IsProvisionedTestCase[] testcases = {
             // nothing
@@ -461,7 +463,7 @@
         };
 
         for (IsProvisionedTestCase testcase : testcases) {
-            if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
+            if (ipc.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
                 fail(testcase.errorMessage());
             }
         }
@@ -735,7 +737,18 @@
         final IpClient ipc = makeIpClient(TEST_IFNAME);
         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
                 MacAddress.fromString(TEST_BSSID));
-        final MacAddress bssid = ipc.getInitialBssid(layer2Info, null /* ScanReqsultInfo */,
+        final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID2);
+        final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
+                true /* isAtLeastS */);
+        assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
+    }
+
+    @Test
+    public void testGetInitialBssidOnSOrAbove_NullScanReqsultInfo() throws Exception {
+        final IpClient ipc = makeIpClient(TEST_IFNAME);
+        final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
+                MacAddress.fromString(TEST_BSSID));
+        final MacAddress bssid = ipc.getInitialBssid(layer2Info, null /* ScanResultInfo */,
                 true /* isAtLeastS */);
         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
     }
@@ -764,7 +777,7 @@
     public void testGetInitialBssidBeforeS() throws Exception {
         final IpClient ipc = makeIpClient(TEST_IFNAME);
         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
-                MacAddress.fromString(TEST_BSSID));
+                MacAddress.fromString(TEST_BSSID2));
         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
                 false /* isAtLeastS */);
diff --git a/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.kt b/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.kt
index 863e268..ea8f1da 100644
--- a/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.kt
+++ b/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.kt
@@ -16,6 +16,7 @@
 package android.net.ip
 
 import android.content.Context
+import android.net.ip.IpNeighborMonitor.NeighborEventConsumer
 import android.net.INetd
 import android.net.InetAddresses.parseNumericAddress
 import android.net.IpPrefix
@@ -23,19 +24,37 @@
 import android.net.LinkProperties
 import android.net.RouteInfo
 import android.net.metrics.IpConnectivityLog
-import android.net.netlink.StructNdMsg.NUD_FAILED
-import android.net.netlink.StructNdMsg.NUD_STALE
-import android.net.netlink.makeNewNeighMessage
 import android.net.util.InterfaceParams
+import android.net.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION
 import android.net.util.SharedLog
 import android.os.Handler
 import android.os.HandlerThread
 import android.os.MessageQueue
 import android.os.MessageQueue.OnFileDescriptorEventListener
+import android.stats.connectivity.IpType
+import android.stats.connectivity.IpType.IPV4
+import android.stats.connectivity.IpType.IPV6
+import android.stats.connectivity.NudEventType
+import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED
+import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED_CRITICAL
+import android.stats.connectivity.NudEventType.NUD_MAC_ADDRESS_CHANGED
+import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED
+import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL
+import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED
+import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED_CRITICAL
+import android.stats.connectivity.NudNeighborType
+import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_BOTH
+import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_DNS
+import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_GATEWAY
 import android.system.ErrnoException
 import android.system.OsConstants.EAGAIN
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
+import com.android.networkstack.metrics.IpReachabilityMonitorMetrics
+import com.android.net.module.util.netlink.StructNdMsg.NUD_FAILED
+import com.android.net.module.util.netlink.StructNdMsg.NUD_REACHABLE
+import com.android.net.module.util.netlink.StructNdMsg.NUD_STALE
+import com.android.testutils.makeNewNeighMessage
 import com.android.testutils.waitForIdle
 import org.junit.After
 import org.junit.Before
@@ -43,12 +62,15 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyObject
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.timeout
 import org.mockito.Mockito.verify
 import java.io.FileDescriptor
@@ -66,12 +88,20 @@
 private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
 private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
 
+// IPv4 gateway is also DNS server.
+private val TEST_IPV4_GATEWAY_DNS = parseNumericAddress("192.168.222.100") as Inet4Address
+
 private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
 private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
 
+private val TEST_IPV6_LINKLOCAL_LINKADDR = LinkAddress("fe80::123/64")
+private val TEST_IPV6_LINKLOCAL_GATEWAY = parseNumericAddress("fe80::1") as Inet6Address
+private val TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY = parseNumericAddress("fe80::1%21") as Inet6Address
+
 // DNSes inside IP prefix
 private val TEST_IPV4_DNS = parseNumericAddress("192.168.222.1") as Inet4Address
 private val TEST_IPV6_DNS = parseNumericAddress("2001:db8::321") as Inet6Address
+private val TEST_IPV6_DNS2 = parseNumericAddress("2001:db8::456") as Inet6Address
 
 private val TEST_IFACE = InterfaceParams("fake0", 21, null)
 private val TEST_LINK_PROPERTIES = LinkProperties().apply {
@@ -91,6 +121,54 @@
     addDnsServer(TEST_IPV6_DNS)
 }
 
+private val TEST_IPV4_ONLY_LINK_PROPERTIES = LinkProperties().apply {
+    interfaceName = TEST_IFACE.name
+    addLinkAddress(TEST_IPV4_LINKADDR)
+
+    // Add on link routes
+    addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
+
+    // Add default routes
+    addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY_DNS))
+
+    addDnsServer(TEST_IPV4_GATEWAY_DNS)
+}
+
+private val TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES = LinkProperties().apply {
+    interfaceName = TEST_IFACE.name
+    addLinkAddress(TEST_IPV6_LINKADDR)
+    addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
+
+    // Add on link routes
+    addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
+    addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
+
+    // Add default routes
+    addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
+
+    addDnsServer(TEST_IPV6_DNS)
+}
+
+private val TEST_DUAL_LINK_PROPERTIES = LinkProperties().apply {
+    interfaceName = TEST_IFACE.name
+    addLinkAddress(TEST_IPV4_LINKADDR)
+    addLinkAddress(TEST_IPV6_LINKADDR)
+    addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
+
+    // Add on link routes
+    addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
+    addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
+    addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
+
+    // Add default routes
+    addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
+    addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
+
+    addDnsServer(TEST_IPV4_DNS)
+    addDnsServer(TEST_IPV6_DNS)
+    addDnsServer(TEST_IPV6_DNS2)
+}
+
 /**
  * Tests for IpReachabilityMonitor.
  */
@@ -104,6 +182,7 @@
     private val netd = mock(INetd::class.java)
     private val fd = mock(FileDescriptor::class.java)
     private val metricsLog = mock(IpConnectivityLog::class.java)
+    private val mIpReachabilityMonitorMetrics = mock(IpReachabilityMonitorMetrics::class.java)
 
     private val handlerThread = HandlerThread(IpReachabilityMonitorTest::class.simpleName)
     private val handler by lazy { Handler(handlerThread.looper) }
@@ -171,6 +250,8 @@
             neighborMonitor = TestIpNeighborMonitor(handler, log, cb, fd)
             neighborMonitor
         }.`when`(dependencies).makeIpNeighborMonitor(any(), any(), any())
+        doReturn(mIpReachabilityMonitorMetrics)
+                .`when`(dependencies).getIpReachabilityMonitorMetrics()
 
         val monitorFuture = CompletableFuture<IpReachabilityMonitor>()
         // IpReachabilityMonitor needs to be started from the handler thread
@@ -207,8 +288,8 @@
         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(TEST_IPV4_DNS), anyString())
     }
 
-    private fun runLoseProvisioningTest(lostNeighbor: InetAddress) {
-        reachabilityMonitor.updateLinkProperties(TEST_LINK_PROPERTIES)
+    private fun runLoseProvisioningTest(newLp: LinkProperties, lostNeighbor: InetAddress) {
+        reachabilityMonitor.updateLinkProperties(newLp)
 
         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_STALE))
         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_STALE))
@@ -219,23 +300,261 @@
         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(lostNeighbor), anyString())
     }
 
+    private fun verifyNudFailureMetrics(
+        eventType: NudEventType,
+        ipType: IpType,
+        lostNeighborType: NudNeighborType
+    ) {
+        verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS)).setNudIpType(eq(ipType))
+        verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
+                .setNudEventType(eq(eventType))
+        verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
+                .setNudNeighborType(eq(lostNeighborType))
+    }
+
+    // Verify if the notifyLost will be called when one neighbor has lost but it's still
+    // provisioned.
+    private fun runLoseNeighborStillProvisionedTest(
+        newLp: LinkProperties,
+        lostNeighbor: InetAddress,
+        eventType: NudEventType,
+        ipType: IpType,
+        lostNeighborType: NudNeighborType
+    ) {
+        reachabilityMonitor.updateLinkProperties(newLp)
+
+        neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
+        handlerThread.waitForIdle(TEST_TIMEOUT_MS)
+        verify(callback, never()).notifyLost(any(), anyString())
+        verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
+    }
+
+    private fun runNeighborReachableButMacAddrChangedTest(
+        newLp: LinkProperties,
+        neighbor: InetAddress,
+        ipType: IpType
+    ) {
+        doReturn(true).`when`(dependencies).isFeatureEnabled(anyObject(),
+                eq(IP_REACHABILITY_MCAST_RESOLICIT_VERSION), anyBoolean())
+
+        reachabilityMonitor.updateLinkProperties(newLp)
+
+        neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE,
+                "001122334455" /* oldMac */))
+        handlerThread.waitForIdle(TEST_TIMEOUT_MS)
+        verify(callback, never()).notifyLost(eq(neighbor), anyString())
+
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+
+        neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE,
+                "1122334455aa" /* newMac */))
+        verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(neighbor), anyString())
+        verifyNudFailureMetrics(NUD_MAC_ADDRESS_CHANGED, ipType, NUD_NEIGHBOR_GATEWAY)
+    }
+
     @Test
     fun testLoseProvisioning_Ipv4DnsLost() {
-        runLoseProvisioningTest(TEST_IPV4_DNS)
+        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS)
     }
 
     @Test
     fun testLoseProvisioning_Ipv6DnsLost() {
-        runLoseProvisioningTest(TEST_IPV6_DNS)
+        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS)
     }
 
     @Test
     fun testLoseProvisioning_Ipv4GatewayLost() {
-        runLoseProvisioningTest(TEST_IPV4_GATEWAY)
+        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY)
     }
 
     @Test
     fun testLoseProvisioning_Ipv6GatewayLost() {
-        runLoseProvisioningTest(TEST_IPV6_GATEWAY)
+        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY)
     }
-}
\ No newline at end of file
+
+    private fun runNudProbeFailureMetricsTest(
+        lp: LinkProperties,
+        lostNeighbor: InetAddress,
+        eventType: NudEventType,
+        ipType: IpType,
+        lostNeighborType: NudNeighborType
+    ) {
+        runLoseProvisioningTest(lp, lostNeighbor)
+        verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv6GatewayLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
+                NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv4GatewayLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
+                NUD_POST_ROAMING_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv6DnsLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS,
+                NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv4DnsLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS,
+                NUD_POST_ROAMING_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_IPV4_ONLY_LINK_PROPERTIES, TEST_IPV4_GATEWAY_DNS,
+                NUD_POST_ROAMING_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_BOTH)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
+                TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_POST_ROAMING_FAILED_CRITICAL, IPV6,
+                NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
+                NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
+                NUD_CONFIRM_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS,
+                NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS,
+                NUD_CONFIRM_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_IPV4_ONLY_LINK_PROPERTIES, TEST_IPV4_GATEWAY_DNS,
+                NUD_CONFIRM_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_BOTH)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runNudProbeFailureMetricsTest(TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
+                TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_CONFIRM_FAILED_CRITICAL, IPV6,
+                NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6GatewayLostOrganic() {
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
+                NUD_ORGANIC_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv4GatewayLostOrganic() {
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
+                NUD_ORGANIC_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6DnsLostOrganic() {
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS,
+                NUD_ORGANIC_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv4DnsLostOrganic() {
+        runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS,
+                NUD_ORGANIC_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganic() {
+        runNudProbeFailureMetricsTest(TEST_IPV4_ONLY_LINK_PROPERTIES, TEST_IPV4_GATEWAY_DNS,
+                NUD_ORGANIC_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_BOTH)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganic() {
+        runNudProbeFailureMetricsTest(TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
+                TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_ORGANIC_FAILED_CRITICAL, IPV6,
+                NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoaming() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runLoseNeighborStillProvisionedTest(TEST_DUAL_LINK_PROPERTIES, TEST_IPV6_DNS,
+                NUD_POST_ROAMING_FAILED, IPV6, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirm() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runLoseNeighborStillProvisionedTest(TEST_DUAL_LINK_PROPERTIES, TEST_IPV6_DNS,
+                NUD_CONFIRM_FAILED, IPV6, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganic() {
+        runLoseNeighborStillProvisionedTest(TEST_DUAL_LINK_PROPERTIES, TEST_IPV6_DNS,
+                NUD_ORGANIC_FAILED, IPV6, NUD_NEIGHBOR_DNS)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_multipleProbesFromRoamFirst() {
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        handlerThread.waitForIdle(TEST_TIMEOUT_MS)
+        Thread.sleep(2)
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY)
+
+        verifyNudFailureMetrics(NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_multipleProbesFromConfirmFirst() {
+        reachabilityMonitor.probeAll(false /* dueToRoam */)
+        handlerThread.waitForIdle(TEST_TIMEOUT_MS)
+        Thread.sleep(2)
+        reachabilityMonitor.probeAll(true /* dueToRoam */)
+        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY)
+
+        verifyNudFailureMetrics(NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChanged() {
+        runNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY, IPV6)
+    }
+
+    @Test
+    fun testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChanged() {
+        runNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY, IPV4)
+    }
+}
diff --git a/tests/unit/src/android/net/netlink/ConntrackMessageTest.java b/tests/unit/src/android/net/netlink/ConntrackMessageTest.java
deleted file mode 100644
index 2e8d184..0000000
--- a/tests/unit/src/android/net/netlink/ConntrackMessageTest.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW;
-import static android.net.netlink.NetlinkConstants.NFNL_SUBSYS_CTNETLINK;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConntrackMessageTest {
-    private static final boolean USING_LE = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
-
-    private short makeCtType(short msgType) {
-        return (short) (NFNL_SUBSYS_CTNETLINK << 8 | (byte) msgType);
-    }
-
-    // Example 1: TCP (192.168.43.209, 44333) -> (23.211.13.26, 443)
-    public static final String CT_V4UPDATE_TCP_HEX =
-            // struct nlmsghdr
-            "50000000" +      // length = 80
-            "0001" +          // type = (1 << 8) | 0
-            "0501" +          // flags
-            "01000000" +      // seqno = 1
-            "00000000" +      // pid = 0
-            // struct nfgenmsg
-            "02" +            // nfgen_family  = AF_INET
-            "00" +            // version = NFNETLINK_V0
-            "0000" +          // res_id
-            // struct nlattr
-            "3400" +          // nla_len = 52
-            "0180" +          // nla_type = nested CTA_TUPLE_ORIG
-                // struct nlattr
-                "1400" +      // nla_len = 20
-                "0180" +      // nla_type = nested CTA_TUPLE_IP
-                    "0800 0100 C0A82BD1" +  // nla_type=CTA_IP_V4_SRC, ip=192.168.43.209
-                    "0800 0200 17D30D1A" +  // nla_type=CTA_IP_V4_DST, ip=23.211.13.26
-                // struct nlattr
-                "1C00" +      // nla_len = 28
-                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
-                    "0500 0100 06 000000" +  // nla_type=CTA_PROTO_NUM, proto=6
-                    "0600 0200 AD2D 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=44333 (big endian)
-                    "0600 0300 01BB 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
-            // struct nlattr
-            "0800" +          // nla_len = 8
-            "0700" +          // nla_type = CTA_TIMEOUT
-            "00069780";       // nla_value = 432000 (big endian)
-    public static final byte[] CT_V4UPDATE_TCP_BYTES =
-            HexEncoding.decode(CT_V4UPDATE_TCP_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    private byte[] makeIPv4TimeoutUpdateRequestTcp() throws Exception {
-        return ConntrackMessage.newIPv4TimeoutUpdateRequest(
-                OsConstants.IPPROTO_TCP,
-                (Inet4Address) InetAddress.getByName("192.168.43.209"), 44333,
-                (Inet4Address) InetAddress.getByName("23.211.13.26"), 443,
-                432000);
-    }
-
-    // Example 2: UDP (100.96.167.146, 37069) -> (216.58.197.10, 443)
-    public static final String CT_V4UPDATE_UDP_HEX =
-            // struct nlmsghdr
-            "50000000" +      // length = 80
-            "0001" +          // type = (1 << 8) | 0
-            "0501" +          // flags
-            "01000000" +      // seqno = 1
-            "00000000" +      // pid = 0
-            // struct nfgenmsg
-            "02" +            // nfgen_family  = AF_INET
-            "00" +            // version = NFNETLINK_V0
-            "0000" +          // res_id
-            // struct nlattr
-            "3400" +          // nla_len = 52
-            "0180" +          // nla_type = nested CTA_TUPLE_ORIG
-                // struct nlattr
-                "1400" +      // nla_len = 20
-                "0180" +      // nla_type = nested CTA_TUPLE_IP
-                    "0800 0100 6460A792" +  // nla_type=CTA_IP_V4_SRC, ip=100.96.167.146
-                    "0800 0200 D83AC50A" +  // nla_type=CTA_IP_V4_DST, ip=216.58.197.10
-                // struct nlattr
-                "1C00" +      // nla_len = 28
-                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
-                    "0500 0100 11 000000" +  // nla_type=CTA_PROTO_NUM, proto=17
-                    "0600 0200 90CD 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=37069 (big endian)
-                    "0600 0300 01BB 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
-            // struct nlattr
-            "0800" +          // nla_len = 8
-            "0700" +          // nla_type = CTA_TIMEOUT
-            "000000B4";       // nla_value = 180 (big endian)
-    public static final byte[] CT_V4UPDATE_UDP_BYTES =
-            HexEncoding.decode(CT_V4UPDATE_UDP_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    private byte[] makeIPv4TimeoutUpdateRequestUdp() throws Exception {
-        return ConntrackMessage.newIPv4TimeoutUpdateRequest(
-                OsConstants.IPPROTO_UDP,
-                (Inet4Address) InetAddress.getByName("100.96.167.146"), 37069,
-                (Inet4Address) InetAddress.getByName("216.58.197.10"), 443,
-                180);
-    }
-
-    @Test
-    public void testConntrackMakeIPv4TcpTimeoutUpdate() throws Exception {
-        assumeTrue(USING_LE);
-
-        final byte[] tcp = makeIPv4TimeoutUpdateRequestTcp();
-        assertArrayEquals(CT_V4UPDATE_TCP_BYTES, tcp);
-    }
-
-    @Test
-    public void testConntrackParseIPv4TcpTimeoutUpdate() throws Exception {
-        assumeTrue(USING_LE);
-
-        final byte[] tcp = makeIPv4TimeoutUpdateRequestTcp();
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(tcp);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER);
-        assertNotNull(msg);
-        assertTrue(msg instanceof ConntrackMessage);
-        final ConntrackMessage conntrackMessage = (ConntrackMessage) msg;
-
-        final StructNlMsgHdr hdr = conntrackMessage.getHeader();
-        assertNotNull(hdr);
-        assertEquals(80, hdr.nlmsg_len);
-        assertEquals(makeCtType(IPCTNL_MSG_CT_NEW), hdr.nlmsg_type);
-        assertEquals((short) (StructNlMsgHdr.NLM_F_REPLACE | StructNlMsgHdr.NLM_F_REQUEST
-                | StructNlMsgHdr.NLM_F_ACK), hdr.nlmsg_flags);
-        assertEquals(1, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNfGenMsg nfmsgHdr = conntrackMessage.nfGenMsg;
-        assertNotNull(nfmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET, nfmsgHdr.nfgen_family);
-        assertEquals((byte) StructNfGenMsg.NFNETLINK_V0, nfmsgHdr.version);
-        assertEquals((short) 0, nfmsgHdr.res_id);
-
-        assertEquals(InetAddress.parseNumericAddress("192.168.43.209"),
-                conntrackMessage.tupleOrig.srcIp);
-        assertEquals(InetAddress.parseNumericAddress("23.211.13.26"),
-                conntrackMessage.tupleOrig.dstIp);
-        assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleOrig.protoNum);
-        assertEquals((short) 44333, conntrackMessage.tupleOrig.srcPort);
-        assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort);
-
-        assertNull(conntrackMessage.tupleReply);
-
-        assertEquals(0 /* absent */, conntrackMessage.status);
-        assertEquals(432000, conntrackMessage.timeoutSec);
-    }
-
-    @Test
-    public void testConntrackMakeIPv4UdpTimeoutUpdate() throws Exception {
-        assumeTrue(USING_LE);
-
-        final byte[] udp = makeIPv4TimeoutUpdateRequestUdp();
-        assertArrayEquals(CT_V4UPDATE_UDP_BYTES, udp);
-    }
-
-    @Test
-    public void testConntrackParseIPv4UdpTimeoutUpdate() throws Exception {
-        assumeTrue(USING_LE);
-
-        final byte[] udp = makeIPv4TimeoutUpdateRequestUdp();
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(udp);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER);
-        assertNotNull(msg);
-        assertTrue(msg instanceof ConntrackMessage);
-        final ConntrackMessage conntrackMessage = (ConntrackMessage) msg;
-
-        final StructNlMsgHdr hdr = conntrackMessage.getHeader();
-        assertNotNull(hdr);
-        assertEquals(80, hdr.nlmsg_len);
-        assertEquals(makeCtType(IPCTNL_MSG_CT_NEW), hdr.nlmsg_type);
-        assertEquals((short) (StructNlMsgHdr.NLM_F_REPLACE | StructNlMsgHdr.NLM_F_REQUEST
-                | StructNlMsgHdr.NLM_F_ACK), hdr.nlmsg_flags);
-        assertEquals(1, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNfGenMsg nfmsgHdr = conntrackMessage.nfGenMsg;
-        assertNotNull(nfmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET, nfmsgHdr.nfgen_family);
-        assertEquals((byte) StructNfGenMsg.NFNETLINK_V0, nfmsgHdr.version);
-        assertEquals((short) 0, nfmsgHdr.res_id);
-
-        assertEquals(InetAddress.parseNumericAddress("100.96.167.146"),
-                conntrackMessage.tupleOrig.srcIp);
-        assertEquals(InetAddress.parseNumericAddress("216.58.197.10"),
-                conntrackMessage.tupleOrig.dstIp);
-        assertEquals((byte) OsConstants.IPPROTO_UDP, conntrackMessage.tupleOrig.protoNum);
-        assertEquals((short) 37069, conntrackMessage.tupleOrig.srcPort);
-        assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort);
-
-        assertNull(conntrackMessage.tupleReply);
-
-        assertEquals(0 /* absent */, conntrackMessage.status);
-        assertEquals(180, conntrackMessage.timeoutSec);
-    }
-
-    public static final String CT_V4NEW_TCP_HEX =
-            // CHECKSTYLE:OFF IndentationCheck
-            // struct nlmsghdr
-            "8C000000" +      // length = 140
-            "0001" +          // type = NFNL_SUBSYS_CTNETLINK (1) << 8 | IPCTNL_MSG_CT_NEW (0)
-            "0006" +          // flags = NLM_F_CREATE (1 << 10) | NLM_F_EXCL (1 << 9)
-            "00000000" +      // seqno = 0
-            "00000000" +      // pid = 0
-            // struct nfgenmsg
-            "02" +            // nfgen_family = AF_INET
-            "00" +            // version = NFNETLINK_V0
-            "1234" +          // res_id = 0x1234 (big endian)
-             // struct nlattr
-            "3400" +          // nla_len = 52
-            "0180" +          // nla_type = nested CTA_TUPLE_ORIG
-                // struct nlattr
-                "1400" +      // nla_len = 20
-                "0180" +      // nla_type = nested CTA_TUPLE_IP
-                    "0800 0100 C0A8500C" +  // nla_type=CTA_IP_V4_SRC, ip=192.168.80.12
-                    "0800 0200 8C700874" +  // nla_type=CTA_IP_V4_DST, ip=140.112.8.116
-                // struct nlattr
-                "1C00" +      // nla_len = 28
-                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
-                    "0500 0100 06 000000" +  // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6)
-                    "0600 0200 F3F1 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian)
-                    "0600 0300 01BB 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
-            // struct nlattr
-            "3400" +          // nla_len = 52
-            "0280" +          // nla_type = nested CTA_TUPLE_REPLY
-                // struct nlattr
-                "1400" +      // nla_len = 20
-                "0180" +      // nla_type = nested CTA_TUPLE_IP
-                    "0800 0100 8C700874" +  // nla_type=CTA_IP_V4_SRC, ip=140.112.8.116
-                    "0800 0200 6451B301" +  // nla_type=CTA_IP_V4_DST, ip=100.81.179.1
-                // struct nlattr
-                "1C00" +      // nla_len = 28
-                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
-                    "0500 0100 06 000000" +  // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6)
-                    "0600 0200 01BB 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=443 (big endian)
-                    "0600 0300 F3F1 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=62449 (big endian)
-            // struct nlattr
-            "0800" +          // nla_len = 8
-            "0300" +          // nla_type = CTA_STATUS
-            "00000198" +      // nla_value = 0b110011000 (big endian)
-                              // IPS_CONFIRMED (1 << 3) | IPS_SRC_NAT (1 << 4) |
-                              // IPS_SRC_NAT_DONE (1 << 7) | IPS_DST_NAT_DONE (1 << 8)
-            // struct nlattr
-            "0800" +          // nla_len = 8
-            "0700" +          // nla_type = CTA_TIMEOUT
-            "00000078";       // nla_value = 120 (big endian)
-            // CHECKSTYLE:ON IndentationCheck
-    public static final byte[] CT_V4NEW_TCP_BYTES =
-            HexEncoding.decode(CT_V4NEW_TCP_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    @Test
-    public void testParseCtNew() {
-        assumeTrue(USING_LE);
-
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(CT_V4NEW_TCP_BYTES);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER);
-        assertNotNull(msg);
-        assertTrue(msg instanceof ConntrackMessage);
-        final ConntrackMessage conntrackMessage = (ConntrackMessage) msg;
-
-        final StructNlMsgHdr hdr = conntrackMessage.getHeader();
-        assertNotNull(hdr);
-        assertEquals(140, hdr.nlmsg_len);
-        assertEquals(makeCtType(IPCTNL_MSG_CT_NEW), hdr.nlmsg_type);
-        assertEquals((short) (StructNlMsgHdr.NLM_F_CREATE | StructNlMsgHdr.NLM_F_EXCL),
-                hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNfGenMsg nfmsgHdr = conntrackMessage.nfGenMsg;
-        assertNotNull(nfmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET, nfmsgHdr.nfgen_family);
-        assertEquals((byte) StructNfGenMsg.NFNETLINK_V0, nfmsgHdr.version);
-        assertEquals((short) 0x1234, nfmsgHdr.res_id);
-
-        assertEquals(InetAddress.parseNumericAddress("192.168.80.12"),
-                conntrackMessage.tupleOrig.srcIp);
-        assertEquals(InetAddress.parseNumericAddress("140.112.8.116"),
-                conntrackMessage.tupleOrig.dstIp);
-        assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleOrig.protoNum);
-        assertEquals((short) 62449, conntrackMessage.tupleOrig.srcPort);
-        assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort);
-
-        assertEquals(InetAddress.parseNumericAddress("140.112.8.116"),
-                conntrackMessage.tupleReply.srcIp);
-        assertEquals(InetAddress.parseNumericAddress("100.81.179.1"),
-                conntrackMessage.tupleReply.dstIp);
-        assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleReply.protoNum);
-        assertEquals((short) 443, conntrackMessage.tupleReply.srcPort);
-        assertEquals((short) 62449, conntrackMessage.tupleReply.dstPort);
-
-        assertEquals(0x198, conntrackMessage.status);
-        assertEquals(120, conntrackMessage.timeoutSec);
-    }
-
-    @Test
-    public void testParseTruncation() {
-        assumeTrue(USING_LE);
-
-        // Expect no crash while parsing the truncated message which has been truncated to every
-        // length between 0 and its full length - 1.
-        for (int len = 0; len < CT_V4NEW_TCP_BYTES.length; len++) {
-            final byte[] truncated = Arrays.copyOfRange(CT_V4NEW_TCP_BYTES, 0, len);
-
-            final ByteBuffer byteBuffer = ByteBuffer.wrap(truncated);
-            byteBuffer.order(ByteOrder.nativeOrder());
-            final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer,
-                    OsConstants.NETLINK_NETFILTER);
-        }
-    }
-
-    @Test
-    public void testParseTruncationWithInvalidByte() {
-        assumeTrue(USING_LE);
-
-        // Expect no crash while parsing the message which is truncated by invalid bytes. The
-        // message has been truncated to every length between 0 and its full length - 1.
-        for (byte invalid : new byte[]{(byte) 0x00, (byte) 0xff}) {
-            for (int len = 0; len < CT_V4NEW_TCP_BYTES.length; len++) {
-                final byte[] truncated = new byte[CT_V4NEW_TCP_BYTES.length];
-                Arrays.fill(truncated, (byte) invalid);
-                System.arraycopy(CT_V4NEW_TCP_BYTES, 0, truncated, 0, len);
-
-                final ByteBuffer byteBuffer = ByteBuffer.wrap(truncated);
-                byteBuffer.order(ByteOrder.nativeOrder());
-                final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer,
-                        OsConstants.NETLINK_NETFILTER);
-            }
-        }
-    }
-
-    // Malformed conntrack messages.
-    public static final String CT_MALFORMED_HEX =
-            // CHECKSTYLE:OFF IndentationCheck
-            // <--           nlmsghr           -->|<-nfgenmsg->|<--    CTA_TUPLE_ORIG     -->|
-            // CTA_TUPLE_ORIG has no nla_value.
-            "18000000 0001 0006 00000000 00000000   02 00 0000 0400 0180"
-            // nested CTA_TUPLE_IP has no nla_value.
-            + "1C000000 0001 0006 00000000 00000000 02 00 0000 0800 0180 0400 0180"
-            // nested CTA_IP_V4_SRC has no nla_value.
-            + "20000000 0001 0006 00000000 00000000 02 00 0000 0C00 0180 0800 0180 0400 0100"
-            // nested CTA_TUPLE_PROTO has no nla_value.
-            // <--           nlmsghr           -->|<-nfgenmsg->|<--    CTA_TUPLE_ORIG
-            + "30000000 0001 0006 00000000 00000000 02 00 0000 1C00 0180 1400 0180 0800 0100"
-            //                                  -->|
-            + "C0A8500C 0800 0200 8C700874 0400 0280";
-            // CHECKSTYLE:ON IndentationCheck
-    public static final byte[] CT_MALFORMED_BYTES =
-            HexEncoding.decode(CT_MALFORMED_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    @Test
-    public void testParseMalformation() {
-        assumeTrue(USING_LE);
-
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(CT_MALFORMED_BYTES);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        // Expect no crash while parsing the malformed message.
-        int messageCount = 0;
-        while (byteBuffer.remaining() > 0) {
-            final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer,
-                    OsConstants.NETLINK_NETFILTER);
-            messageCount++;
-        }
-        assertEquals(4, messageCount);
-    }
-
-    @Test
-    public void testToString() {
-        assumeTrue(USING_LE);
-
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(CT_V4NEW_TCP_BYTES);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER);
-        assertNotNull(msg);
-        assertTrue(msg instanceof ConntrackMessage);
-        final ConntrackMessage conntrackMessage = (ConntrackMessage) msg;
-
-        // Bug: "nlmsg_flags{1536(NLM_F_MATCH))" is not correct because StructNlMsgHdr
-        // #stringForNlMsgFlags can't convert all flags (ex: NLM_F_CREATE) and can't distinguish
-        // the flags which have the same value (ex: NLM_F_MATCH <0x200> and NLM_F_EXCL <0x200>).
-        // The flags output string should be "NLM_F_CREATE|NLM_F_EXCL" in this case.
-        // TODO: correct the flag converted string once #stringForNlMsgFlags does.
-        final String expected = ""
-                + "ConntrackMessage{"
-                + "nlmsghdr{StructNlMsgHdr{ nlmsg_len{140}, nlmsg_type{256(IPCTNL_MSG_CT_NEW)}, "
-                + "nlmsg_flags{1536(NLM_F_MATCH))}, nlmsg_seq{0}, nlmsg_pid{0} }}, "
-                + "nfgenmsg{NfGenMsg{ nfgen_family{AF_INET}, version{0}, res_id{4660} }}, "
-                + "tuple_orig{Tuple{IPPROTO_TCP: 192.168.80.12:62449 -> 140.112.8.116:443}}, "
-                + "tuple_reply{Tuple{IPPROTO_TCP: 140.112.8.116:443 -> 100.81.179.1:62449}}, "
-                + "status{408(IPS_CONFIRMED|IPS_SRC_NAT|IPS_SRC_NAT_DONE|IPS_DST_NAT_DONE)}, "
-                + "timeout_sec{120}}";
-        assertEquals(expected, conntrackMessage.toString());
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/InetDiagSocketTest.java b/tests/unit/src/android/net/netlink/InetDiagSocketTest.java
deleted file mode 100644
index fcc85a2..0000000
--- a/tests/unit/src/android/net/netlink/InetDiagSocketTest.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.NETLINK_INET_DIAG;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InetDiagSocketTest {
-    // Hexadecimal representation of InetDiagReqV2 request.
-    private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0103" +         // flags = NLM_F_REQUEST | NLM_F_DUMP
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "02" +           // family = AF_INET
-            "11" +           // protcol = IPPROTO_UDP
-            "00" +           // idiag_ext
-            "00" +           // pad
-            "ffffffff" +     // idiag_states
-            // inet_diag_sockid
-            "a5de" +         // idiag_sport = 42462
-            "b971" +         // idiag_dport = 47473
-            "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
-            "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
-            "00000000" +     // idiag_if
-            "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-    private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
-
-    @Test
-    public void testInetDiagReqV2UdpInet4() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
-                42462);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
-                47473);
-        final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
-                (short) (NLM_F_REQUEST | NLM_F_DUMP));
-        assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request.
-    private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0100" +         // flags = NLM_F_REQUEST
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "0a" +           // family = AF_INET6
-            "06" +           // protcol = IPPROTO_TCP
-            "00" +           // idiag_ext
-            "00" +           // pad
-            "ffffffff" +     // idiag_states
-                // inet_diag_sockid
-                "a5de" +         // idiag_sport = 42462
-                "b971" +         // idiag_dport = 47473
-                "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
-                "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
-                "00000000" +     // idiag_if
-                "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
-
-    @Test
-    public void testInetDiagReqV2TcpInet6() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(
-                InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
-                47473);
-        byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
-                NLM_F_REQUEST);
-
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO.
-    private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0100" +         // flags = NLM_F_REQUEST
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "02" +           // family = AF_INET
-            "06" +           // protcol = IPPROTO_TCP
-            "02" +           // idiag_ext = INET_DIAG_INFO
-            "00" +           // pad
-            "ffffffff" +   // idiag_states
-            // inet_diag_sockid
-            "3039" +         // idiag_sport = 12345
-            "d431" +         // idiag_dport = 54321
-            "01020304000000000000000000000000" + // idiag_src = 1.2.3.4
-            "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4
-            "00000000" +     // idiag_if
-            "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-
-    private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false);
-    private static final int TCP_ALL_STATES = 0xffffffff;
-    @Test
-    public void testInetDiagReqV2TcpInetWithExt() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(
-                InetAddress.getByName("1.2.3.4"), 12345);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
-                54321);
-        byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET,
-                NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES);
-
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg);
-
-        local = new InetSocketAddress(
-                InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
-        remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
-                47473);
-        msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
-                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request with no socket specified.
-    private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0100" +         // flags = NLM_F_REQUEST
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "0a" +           // family = AF_INET6
-            "06" +           // protcol = IPPROTO_TCP
-            "00" +           // idiag_ext
-            "00" +           // pad
-            "ffffffff" +     // idiag_states
-            // inet_diag_sockid
-            "0000" +         // idiag_sport
-            "0000" +         // idiag_dport
-            "00000000000000000000000000000000" + // idiag_src
-            "00000000000000000000000000000000" + // idiag_dst
-            "00000000" +     // idiag_if
-            "0000000000000000"; // idiag_cookie
-
-    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false);
-
-    @Test
-    public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(
-                InetAddress.getByName("fe80::fe6a:ed4b"), 12345);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
-                54321);
-        // Verify no socket specified if either local or remote socket address is null.
-        byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
-                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-        byte[] msg;
-        try {
-            msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
-                    NLM_F_REQUEST);
-            fail("Both remote and local should be null, expected UnknownHostException");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
-                    NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-            fail("Both remote and local should be null, expected UnknownHostException");
-        } catch (NullPointerException e) {
-        }
-
-        msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
-                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg);
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request.
-    private static final String INET_DIAG_MSG_HEX =
-            // struct nlmsghdr
-            "58000000" +     // length = 88
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0200" +         // flags = NLM_F_MULTI
-            "00000000" +     // seqno
-            "f5220000" +     // pid (0 == kernel)
-            // struct inet_diag_msg
-            "0a" +           // family = AF_INET6
-            "01" +           // idiag_state
-            "00" +           // idiag_timer
-            "00" +           // idiag_retrans
-                // inet_diag_sockid
-                "a817" +     // idiag_sport = 43031
-                "960f" +     // idiag_dport = 38415
-                "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
-                "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
-                "00000000" + // idiag_if
-                "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
-            "00000000" +     // idiag_expires
-            "00000000" +     // idiag_rqueue
-            "00000000" +     // idiag_wqueue
-            "a3270000" +     // idiag_uid
-            "A57E1900";      // idiag_inode
-    private static final byte[] INET_DIAG_MSG_BYTES =
-            HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
-
-    @Test
-    public void testParseInetDiagResponse() throws Exception {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG);
-        assertNotNull(msg);
-
-        assertTrue(msg instanceof InetDiagMessage);
-        final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
-        assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
-
-        final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
-        assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(8949, hdr.nlmsg_pid);
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/NduseroptMessageTest.java b/tests/unit/src/android/net/netlink/NduseroptMessageTest.java
deleted file mode 100644
index b070d61..0000000
--- a/tests/unit/src/android/net/netlink/NduseroptMessageTest.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.IpPrefix;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NduseroptMessageTest {
-
-    private static final byte ICMP_TYPE_RA = (byte) 134;
-
-    private static final int IFINDEX1 = 15715755;
-    private static final int IFINDEX2 = 1431655765;
-
-    // IPv6, 0 bytes of options, interface index 15715755, type 134 (RA), code 0, padding.
-    private static final String HDR_EMPTY = "0a00" + "0000" + "abcdef00" + "8600000000000000";
-
-    // IPv6, 16 bytes of options, interface index 1431655765, type 134 (RA), code 0, padding.
-    private static final String HDR_16BYTE = "0a00" + "1000" + "55555555" + "8600000000000000";
-
-    // IPv6, 32 bytes of options, interface index 1431655765, type 134 (RA), code 0, padding.
-    private static final String HDR_32BYTE = "0a00" + "2000" + "55555555" + "8600000000000000";
-
-    // PREF64 option, 2001:db8:3:4:5:6::/96, lifetime=10064
-    private static final String OPT_PREF64 = "2602" + "2750" + "20010db80003000400050006";
-
-    // Length 20, NDUSEROPT_SRCADDR, fe80:2:3:4:5:6:7:8
-    private static final String NLA_SRCADDR = "1400" + "0100" + "fe800002000300040005000600070008";
-
-    private static final InetAddress SADDR1 = parseNumericAddress("fe80:2:3:4:5:6:7:8%" + IFINDEX1);
-    private static final InetAddress SADDR2 = parseNumericAddress("fe80:2:3:4:5:6:7:8%" + IFINDEX2);
-
-    private static final String MSG_EMPTY = HDR_EMPTY + NLA_SRCADDR;
-    private static final String MSG_PREF64 = HDR_16BYTE + OPT_PREF64 + NLA_SRCADDR;
-
-    @Test
-    public void testParsing() {
-        NduseroptMessage msg = parseNduseroptMessage(toBuffer(MSG_EMPTY));
-        assertMatches(AF_INET6, 0, IFINDEX1, ICMP_TYPE_RA, (byte) 0, SADDR1, msg);
-        assertNull(msg.option);
-
-        msg = parseNduseroptMessage(toBuffer(MSG_PREF64));
-        assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg);
-        assertPref64Option("2001:db8:3:4:5:6::/96", msg.option);
-    }
-
-    @Test
-    public void testParseWithinNetlinkMessage() throws Exception {
-        // A NduseroptMessage inside a netlink message. Ensure that it parses the same way both by
-        // parsing the netlink message via NetlinkMessage.parse() and by parsing the option itself
-        // with NduseroptMessage.parse().
-        final String hexBytes =
-                "44000000440000000000000000000000"             // len=68, RTM_NEWNDUSEROPT
-                + "0A0010001E0000008600000000000000"           // IPv6, opt_bytes=16, ifindex=30, RA
-                + "260202580064FF9B0000000000000000"           // pref64, prefix=64:ff9b::/96, 600
-                + "14000100FE800000000000000250B6FFFEB7C499";  // srcaddr=fe80::250:b6ff:feb7:c499
-
-        ByteBuffer buf = toBuffer(hexBytes);
-        assertEquals(68, buf.limit());
-        buf.order(ByteOrder.nativeOrder());
-
-        NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_ROUTE);
-        assertNotNull(nlMsg);
-        assertTrue(nlMsg instanceof NduseroptMessage);
-
-        NduseroptMessage msg = (NduseroptMessage) nlMsg;
-        InetAddress srcaddr = InetAddress.getByName("fe80::250:b6ff:feb7:c499%30");
-        assertMatches(AF_INET6, 16, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg);
-        assertPref64Option("64:ff9b::/96", msg.option);
-
-        final String hexBytesWithoutHeader = hexBytes.substring(StructNlMsgHdr.STRUCT_SIZE * 2);
-        ByteBuffer bufWithoutHeader = toBuffer(hexBytesWithoutHeader);
-        assertEquals(52, bufWithoutHeader.limit());
-        msg = parseNduseroptMessage(bufWithoutHeader);
-        assertMatches(AF_INET6, 16, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg);
-        assertPref64Option("64:ff9b::/96", msg.option);
-    }
-
-    @Test
-    public void testParseUnknownOptionWithinNetlinkMessage() throws Exception {
-        final String hexBytes =
-                "4C0000004400000000000000000000000"
-                + "A0018001E0000008600000000000000"
-                + "1903000000001770FD123456789000000000000000000001"  // RDNSS option
-                + "14000100FE800000000000000250B6FFFEB7C499";
-
-        ByteBuffer buf = toBuffer(hexBytes);
-        assertEquals(76, buf.limit());
-        buf.order(ByteOrder.nativeOrder());
-
-        NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_ROUTE);
-        assertNotNull(nlMsg);
-        assertTrue(nlMsg instanceof NduseroptMessage);
-
-        NduseroptMessage msg = (NduseroptMessage) nlMsg;
-        InetAddress srcaddr = InetAddress.getByName("fe80::250:b6ff:feb7:c499%30");
-        assertMatches(AF_INET6, 24, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg);
-        assertEquals(NdOption.UNKNOWN, msg.option);
-    }
-
-    @Test
-    public void testUnknownOption() {
-        ByteBuffer buf = toBuffer(MSG_PREF64);
-        // Replace the PREF64 option type (38) with an unknown option number.
-        final int optionStart = NduseroptMessage.STRUCT_SIZE;
-        assertEquals(38, buf.get(optionStart));
-        buf.put(optionStart, (byte) 42);
-
-        NduseroptMessage msg = parseNduseroptMessage(buf);
-        assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg);
-        assertEquals(NdOption.UNKNOWN, msg.option);
-
-        buf.flip();
-        assertEquals(42, buf.get(optionStart));
-        buf.put(optionStart, (byte) 38);
-
-        msg = parseNduseroptMessage(buf);
-        assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg);
-        assertPref64Option("2001:db8:3:4:5:6::/96", msg.option);
-    }
-
-    @Test
-    public void testZeroLengthOption() {
-        // Make sure an unknown option with a 0-byte length is ignored and parsing continues with
-        // the address, which comes after it.
-        final String hexString = HDR_16BYTE + "00000000000000000000000000000000" + NLA_SRCADDR;
-        ByteBuffer buf = toBuffer(hexString);
-        assertEquals(52, buf.limit());
-        NduseroptMessage msg = parseNduseroptMessage(buf);
-        assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg);
-        assertNull(msg.option);
-    }
-
-    @Test
-    public void testTooLongOption() {
-        // Make sure that if an option's length is too long, it's ignored and parsing continues with
-        // the address, which comes after it.
-        final String hexString = HDR_16BYTE + "26030000000000000000000000000000" + NLA_SRCADDR;
-        ByteBuffer buf = toBuffer(hexString);
-        assertEquals(52, buf.limit());
-        NduseroptMessage msg = parseNduseroptMessage(buf);
-        assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg);
-        assertNull(msg.option);
-    }
-
-    @Test
-    public void testOptionsTooLong() {
-        // Header claims 32 bytes of options. Buffer ends before options end.
-        String hexString = HDR_32BYTE + OPT_PREF64;
-        ByteBuffer buf = toBuffer(hexString);
-        assertEquals(32, buf.limit());
-        assertNull(NduseroptMessage.parse(toBuffer(hexString), NETLINK_ROUTE));
-
-        // Header claims 32 bytes of options. Buffer ends at end of options with no source address.
-        hexString = HDR_32BYTE + OPT_PREF64 + OPT_PREF64;
-        buf = toBuffer(hexString);
-        assertEquals(48, buf.limit());
-        assertNull(NduseroptMessage.parse(toBuffer(hexString), NETLINK_ROUTE));
-    }
-
-    @Test
-    public void testTruncation() {
-        final int optLen = MSG_PREF64.length() / 2;  // 1 byte = 2 hex chars
-        for (int len = 0; len < optLen; len++) {
-            ByteBuffer buf = toBuffer(MSG_PREF64.substring(0, len * 2));
-            NduseroptMessage msg = parseNduseroptMessage(buf);
-            if (len < optLen) {
-                assertNull(msg);
-            } else {
-                assertNotNull(msg);
-                assertPref64Option("2001:db8:3:4:5:6::/96", msg.option);
-            }
-        }
-    }
-
-    @Test
-    public void testToString() {
-        NduseroptMessage msg = parseNduseroptMessage(toBuffer(MSG_PREF64));
-        assertNotNull(msg);
-        assertEquals("Nduseroptmsg(10, 16, 1431655765, 134, 0, fe80:2:3:4:5:6:7:8%1431655765)",
-                msg.toString());
-    }
-
-    // Convenience method to parse a NduseroptMessage that's not part of a netlink message.
-    private NduseroptMessage parseNduseroptMessage(ByteBuffer buf) {
-        return NduseroptMessage.parse(null, buf);
-    }
-
-    private ByteBuffer toBuffer(String hexString) {
-        return ByteBuffer.wrap(HexEncoding.decode(hexString));
-    }
-
-    private void assertMatches(int family, int optsLen, int ifindex, byte icmpType,
-            byte icmpCode, InetAddress srcaddr, NduseroptMessage msg) {
-        assertNotNull(msg);
-        assertEquals(family, msg.family);
-        assertEquals(ifindex, msg.ifindex);
-        assertEquals(optsLen, msg.opts_len);
-        assertEquals(icmpType, msg.icmp_type);
-        assertEquals(icmpCode, msg.icmp_code);
-        assertEquals(srcaddr, msg.srcaddr);
-    }
-
-    private void assertPref64Option(String prefix, NdOption opt) {
-        assertNotNull(opt);
-        assertTrue(opt instanceof StructNdOptPref64);
-        StructNdOptPref64 pref64Opt = (StructNdOptPref64) opt;
-        assertEquals(new IpPrefix(prefix), pref64Opt.prefix);
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/NetlinkConstantsTest.java b/tests/unit/src/android/net/netlink/NetlinkConstantsTest.java
deleted file mode 100644
index 131feeb..0000000
--- a/tests/unit/src/android/net/netlink/NetlinkConstantsTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_DELETE;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_CTRZERO;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_DYING;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_STATS;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_STATS_CPU;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_UNCONFIRMED;
-import static android.net.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW;
-import static android.net.netlink.NetlinkConstants.NFNL_SUBSYS_CTNETLINK;
-import static android.net.netlink.NetlinkConstants.NLMSG_DONE;
-import static android.net.netlink.NetlinkConstants.NLMSG_ERROR;
-import static android.net.netlink.NetlinkConstants.NLMSG_NOOP;
-import static android.net.netlink.NetlinkConstants.NLMSG_OVERRUN;
-import static android.net.netlink.NetlinkConstants.RTM_DELADDR;
-import static android.net.netlink.NetlinkConstants.RTM_DELLINK;
-import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
-import static android.net.netlink.NetlinkConstants.RTM_DELROUTE;
-import static android.net.netlink.NetlinkConstants.RTM_DELRULE;
-import static android.net.netlink.NetlinkConstants.RTM_GETADDR;
-import static android.net.netlink.NetlinkConstants.RTM_GETLINK;
-import static android.net.netlink.NetlinkConstants.RTM_GETNEIGH;
-import static android.net.netlink.NetlinkConstants.RTM_GETROUTE;
-import static android.net.netlink.NetlinkConstants.RTM_GETRULE;
-import static android.net.netlink.NetlinkConstants.RTM_NEWADDR;
-import static android.net.netlink.NetlinkConstants.RTM_NEWLINK;
-import static android.net.netlink.NetlinkConstants.RTM_NEWNDUSEROPT;
-import static android.net.netlink.NetlinkConstants.RTM_NEWNEIGH;
-import static android.net.netlink.NetlinkConstants.RTM_NEWROUTE;
-import static android.net.netlink.NetlinkConstants.RTM_NEWRULE;
-import static android.net.netlink.NetlinkConstants.RTM_SETLINK;
-import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
-import static android.net.netlink.NetlinkConstants.stringForNlMsgType;
-import static android.system.OsConstants.NETLINK_INET_DIAG;
-import static android.system.OsConstants.NETLINK_NETFILTER;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkConstantsTest {
-    private static final short UNKNOWN_FAMILY = 1234;
-
-    private short makeCtType(short msgType) {
-        return (short) (NFNL_SUBSYS_CTNETLINK << 8 | (byte) msgType);
-    }
-
-    @Test
-    public void testStringForNlMsgType() {
-        assertEquals("RTM_NEWLINK", stringForNlMsgType(RTM_NEWLINK, NETLINK_ROUTE));
-        assertEquals("RTM_DELLINK", stringForNlMsgType(RTM_DELLINK, NETLINK_ROUTE));
-        assertEquals("RTM_GETLINK", stringForNlMsgType(RTM_GETLINK, NETLINK_ROUTE));
-        assertEquals("RTM_SETLINK", stringForNlMsgType(RTM_SETLINK, NETLINK_ROUTE));
-        assertEquals("RTM_NEWADDR", stringForNlMsgType(RTM_NEWADDR, NETLINK_ROUTE));
-        assertEquals("RTM_DELADDR", stringForNlMsgType(RTM_DELADDR, NETLINK_ROUTE));
-        assertEquals("RTM_GETADDR", stringForNlMsgType(RTM_GETADDR, NETLINK_ROUTE));
-        assertEquals("RTM_NEWROUTE", stringForNlMsgType(RTM_NEWROUTE, NETLINK_ROUTE));
-        assertEquals("RTM_DELROUTE", stringForNlMsgType(RTM_DELROUTE, NETLINK_ROUTE));
-        assertEquals("RTM_GETROUTE", stringForNlMsgType(RTM_GETROUTE, NETLINK_ROUTE));
-        assertEquals("RTM_NEWNEIGH", stringForNlMsgType(RTM_NEWNEIGH, NETLINK_ROUTE));
-        assertEquals("RTM_DELNEIGH", stringForNlMsgType(RTM_DELNEIGH, NETLINK_ROUTE));
-        assertEquals("RTM_GETNEIGH", stringForNlMsgType(RTM_GETNEIGH, NETLINK_ROUTE));
-        assertEquals("RTM_NEWRULE", stringForNlMsgType(RTM_NEWRULE, NETLINK_ROUTE));
-        assertEquals("RTM_DELRULE", stringForNlMsgType(RTM_DELRULE, NETLINK_ROUTE));
-        assertEquals("RTM_GETRULE", stringForNlMsgType(RTM_GETRULE, NETLINK_ROUTE));
-        assertEquals("RTM_NEWNDUSEROPT", stringForNlMsgType(RTM_NEWNDUSEROPT, NETLINK_ROUTE));
-
-        assertEquals("SOCK_DIAG_BY_FAMILY",
-                stringForNlMsgType(SOCK_DIAG_BY_FAMILY, NETLINK_INET_DIAG));
-
-        assertEquals("IPCTNL_MSG_CT_NEW",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_NEW), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_GET",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_DELETE",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_DELETE), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_GET_CTRZERO",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_CTRZERO), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_GET_STATS_CPU",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_STATS_CPU), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_GET_STATS",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_STATS), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_GET_DYING",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_DYING), NETLINK_NETFILTER));
-        assertEquals("IPCTNL_MSG_CT_GET_UNCONFIRMED",
-                stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_UNCONFIRMED), NETLINK_NETFILTER));
-    }
-
-    @Test
-    public void testStringForNlMsgType_ControlMessage() {
-        for (int family : new int[]{NETLINK_ROUTE, NETLINK_INET_DIAG, NETLINK_NETFILTER}) {
-            assertEquals("NLMSG_NOOP", stringForNlMsgType(NLMSG_NOOP, family));
-            assertEquals("NLMSG_ERROR", stringForNlMsgType(NLMSG_ERROR, family));
-            assertEquals("NLMSG_DONE", stringForNlMsgType(NLMSG_DONE, family));
-            assertEquals("NLMSG_OVERRUN", stringForNlMsgType(NLMSG_OVERRUN, family));
-        }
-    }
-
-    @Test
-    public void testStringForNlMsgType_UnknownFamily() {
-        assertTrue(stringForNlMsgType(RTM_NEWLINK, UNKNOWN_FAMILY).startsWith("unknown"));
-        assertTrue(stringForNlMsgType(SOCK_DIAG_BY_FAMILY, UNKNOWN_FAMILY).startsWith("unknown"));
-        assertTrue(stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_NEW), UNKNOWN_FAMILY)
-                .startsWith("unknown"));
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/NetlinkErrorMessageTest.java b/tests/unit/src/android/net/netlink/NetlinkErrorMessageTest.java
deleted file mode 100644
index 345622f..0000000
--- a/tests/unit/src/android/net/netlink/NetlinkErrorMessageTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.StructNlMsgErr;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkErrorMessageTest {
-    private final String TAG = "NetlinkErrorMessageTest";
-
-    // Hexadecimal representation of packet capture.
-    public static final String NLM_ERROR_OK_HEX =
-            // struct nlmsghdr
-            "24000000" +     // length = 36
-            "0200"     +     // type = 2 (NLMSG_ERROR)
-            "0000"     +     // flags
-            "26350000" +     // seqno
-            "64100000" +     // pid = userspace process
-            // error integer
-            "00000000" +     // "errno" (0 == OK)
-            // struct nlmsghdr
-            "30000000" +     // length (48) of original request
-            "1C00"     +     // type = 28 (RTM_NEWNEIGH)
-            "0501"     +     // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
-            "26350000" +     // seqno
-            "00000000";      // pid = kernel
-    public static final byte[] NLM_ERROR_OK =
-            HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
-
-    @Test
-    public void testParseNlmErrorOk() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
-        assertNotNull(msg);
-        assertTrue(msg instanceof NetlinkErrorMessage);
-        final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg;
-
-        final StructNlMsgHdr hdr = errorMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(36, hdr.nlmsg_len);
-        assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type);
-        assertEquals(0, hdr.nlmsg_flags);
-        assertEquals(13606, hdr.nlmsg_seq);
-        assertEquals(4196, hdr.nlmsg_pid);
-
-        final StructNlMsgErr err = errorMsg.getNlMsgError();
-        assertNotNull(err);
-        assertEquals(0, err.error);
-        assertNotNull(err.msg);
-        assertEquals(48, err.msg.nlmsg_len);
-        assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type);
-        assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags);
-        assertEquals(13606, err.msg.nlmsg_seq);
-        assertEquals(0, err.msg.nlmsg_pid);
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/NetlinkSocketTest.java b/tests/unit/src/android/net/netlink/NetlinkSocketTest.java
deleted file mode 100644
index 5716803..0000000
--- a/tests/unit/src/android/net/netlink/NetlinkSocketTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNlMsgHdr;
-import android.system.NetlinkSocketAddress;
-import android.system.Os;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.io.IoUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkSocketTest {
-    private final String TAG = "NetlinkSocketTest";
-
-    @Test
-    public void testBasicWorkingGetNeighborsQuery() throws Exception {
-        final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
-        assertNotNull(fd);
-
-        NetlinkSocket.connectToKernel(fd);
-
-        final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
-        assertNotNull(localAddr);
-        assertEquals(0, localAddr.getGroupsMask());
-        assertTrue(0 != localAddr.getPortId());
-
-        final int TEST_SEQNO = 5;
-        final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
-        assertNotNull(req);
-
-        final long TIMEOUT = 500;
-        assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
-
-        int neighMessageCount = 0;
-        int doneMessageCount = 0;
-
-        while (doneMessageCount == 0) {
-            ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
-            assertNotNull(response);
-            assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
-            assertEquals(0, response.position());
-            assertEquals(ByteOrder.nativeOrder(), response.order());
-
-            // Verify the messages at least appears minimally reasonable.
-            while (response.remaining() > 0) {
-                final NetlinkMessage msg = NetlinkMessage.parse(response, NETLINK_ROUTE);
-                assertNotNull(msg);
-                final StructNlMsgHdr hdr = msg.getHeader();
-                assertNotNull(hdr);
-
-                if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
-                    doneMessageCount++;
-                    continue;
-                }
-
-                assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
-                assertTrue(msg instanceof RtNetlinkNeighborMessage);
-                assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0);
-                assertEquals(TEST_SEQNO, hdr.nlmsg_seq);
-                assertEquals(localAddr.getPortId(), hdr.nlmsg_pid);
-
-                neighMessageCount++;
-            }
-        }
-
-        assertEquals(1, doneMessageCount);
-        // TODO: make sure this test passes sanely in airplane mode.
-        assertTrue(neighMessageCount > 0);
-
-        IoUtils.closeQuietly(fd);
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/NetlinkTestUtils.kt b/tests/unit/src/android/net/netlink/NetlinkTestUtils.kt
deleted file mode 100644
index 3b485eb..0000000
--- a/tests/unit/src/android/net/netlink/NetlinkTestUtils.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@file:JvmName("NetlinkTestUtils")
-
-package android.net.netlink
-
-import android.net.netlink.NetlinkConstants.RTM_DELNEIGH
-import android.net.netlink.NetlinkConstants.RTM_NEWNEIGH
-import libcore.util.HexEncoding
-import libcore.util.HexEncoding.encodeToString
-import java.net.Inet6Address
-import java.net.InetAddress
-
-/**
- * Make a RTM_NEWNEIGH netlink message.
- */
-fun makeNewNeighMessage(
-    neighAddr: InetAddress,
-    nudState: Short
-) = makeNeighborMessage(
-        neighAddr = neighAddr,
-        type = RTM_NEWNEIGH,
-        nudState = nudState
-)
-
-/**
- * Make a RTM_DELNEIGH netlink message.
- */
-fun makeDelNeighMessage(
-    neighAddr: InetAddress,
-    nudState: Short
-) = makeNeighborMessage(
-        neighAddr = neighAddr,
-        type = RTM_DELNEIGH,
-        nudState = nudState
-)
-
-private fun makeNeighborMessage(
-    neighAddr: InetAddress,
-    type: Short,
-    nudState: Short
-) = HexEncoding.decode(
-    /* ktlint-disable indent */
-    // -- struct nlmsghdr --
-                         // length = 88 or 76:
-    (if (neighAddr is Inet6Address) "58000000" else "4c000000") +
-    type.toLEHex() +     // type
-    "0000" +             // flags
-    "00000000" +         // seqno
-    "00000000" +         // pid (0 == kernel)
-    // struct ndmsg
-                         // family (AF_INET6 or AF_INET)
-    (if (neighAddr is Inet6Address) "0a" else "02") +
-    "00" +               // pad1
-    "0000" +             // pad2
-    "15000000" +         // interface index (21 == wlan0, on test device)
-    nudState.toLEHex() + // NUD state
-    "00" +               // flags
-    "01" +               // type
-    // -- struct nlattr: NDA_DST --
-                         // length = 20 or 8:
-    (if (neighAddr is Inet6Address) "1400" else "0800") +
-    "0100" +             // type (1 == NDA_DST, for neighbor messages)
-                         // IP address:
-    encodeToString(neighAddr.address) +
-    // -- struct nlattr: NDA_LLADDR --
-    "0a00" +             // length = 10
-    "0200" +             // type (2 == NDA_LLADDR, for neighbor messages)
-    "00005e000164" +     // MAC Address (== 00:00:5e:00:01:64)
-    "0000" +             // padding, for 4 byte alignment
-    // -- struct nlattr: NDA_PROBES --
-    "0800" +             // length = 8
-    "0400" +             // type (4 == NDA_PROBES, for neighbor messages)
-    "01000000" +         // number of probes
-    // -- struct nlattr: NDA_CACHEINFO --
-    "1400" +             // length = 20
-    "0300" +             // type (3 == NDA_CACHEINFO, for neighbor messages)
-    "05190000" +         // ndm_used, as "clock ticks ago"
-    "05190000" +         // ndm_confirmed, as "clock ticks ago"
-    "190d0000" +         // ndm_updated, as "clock ticks ago"
-    "00000000",          // ndm_refcnt
-    false /* allowSingleChar */)
-    /* ktlint-enable indent */
-
-/**
- * Convert a [Short] to a little-endian hex string.
- */
-private fun Short.toLEHex() = String.format("%04x", java.lang.Short.reverseBytes(this))
diff --git a/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
deleted file mode 100644
index a1f1d44..0000000
--- a/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkTestUtils.makeDelNeighMessage;
-import static android.net.netlink.NetlinkTestUtils.makeNewNeighMessage;
-import static android.net.netlink.StructNdMsg.NUD_STALE;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.InetAddresses;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNlMsgHdr;
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class RtNetlinkNeighborMessageTest {
-    private final String TAG = "RtNetlinkNeighborMessageTest";
-
-    public static final byte[] RTM_DELNEIGH = makeDelNeighMessage(
-            InetAddresses.parseNumericAddress("192.168.159.254"), NUD_STALE);
-
-    public static final byte[] RTM_NEWNEIGH = makeNewNeighMessage(
-            InetAddresses.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), NUD_STALE);
-
-    // An example of the full response from an RTM_GETNEIGH query.
-    private static final String RTM_GETNEIGH_RESPONSE_HEX =
-            // <-- struct nlmsghr             -->|<-- struct ndmsg           -->|<-- struct nlattr: NDA_DST             -->|<-- NDA_LLADDR          -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO                         -->|
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" +
-            "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000                         0400 0200                   0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000";
-    public static final byte[] RTM_GETNEIGH_RESPONSE =
-            HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    @Test
-    public void testParseRtmDelNeigh() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
-        assertNotNull(msg);
-        assertTrue(msg instanceof RtNetlinkNeighborMessage);
-        final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
-        final StructNlMsgHdr hdr = neighMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(76, hdr.nlmsg_len);
-        assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type);
-        assertEquals(0, hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
-        assertNotNull(ndmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family);
-        assertEquals(21, ndmsgHdr.ndm_ifindex);
-        assertEquals(NUD_STALE, ndmsgHdr.ndm_state);
-        final InetAddress destination = neighMsg.getDestination();
-        assertNotNull(destination);
-        assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
-    }
-
-    @Test
-    public void testParseRtmNewNeigh() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
-        assertNotNull(msg);
-        assertTrue(msg instanceof RtNetlinkNeighborMessage);
-        final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
-        final StructNlMsgHdr hdr = neighMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(88, hdr.nlmsg_len);
-        assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
-        assertEquals(0, hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
-        assertNotNull(ndmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family);
-        assertEquals(21, ndmsgHdr.ndm_ifindex);
-        assertEquals(NUD_STALE, ndmsgHdr.ndm_state);
-        final InetAddress destination = neighMsg.getDestination();
-        assertNotNull(destination);
-        assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
-    }
-
-    @Test
-    public void testParseRtmGetNeighResponse() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-
-        int messageCount = 0;
-        while (byteBuffer.remaining() > 0) {
-            final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
-            assertNotNull(msg);
-            assertTrue(msg instanceof RtNetlinkNeighborMessage);
-            final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
-            final StructNlMsgHdr hdr = neighMsg.getHeader();
-            assertNotNull(hdr);
-            assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
-            assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
-            assertEquals(0, hdr.nlmsg_seq);
-            assertEquals(11070, hdr.nlmsg_pid);
-
-            final int probes = neighMsg.getProbes();
-            assertTrue("Unexpected number of probes. Got " +  probes + ", max=5",
-                    probes < 5);
-            final int ndm_refcnt = neighMsg.getCacheInfo().ndm_refcnt;
-            assertTrue("nda_cacheinfo has unexpectedly high ndm_refcnt: " + ndm_refcnt,
-                    ndm_refcnt < 0x100);
-
-            messageCount++;
-        }
-        // TODO: add more detailed spot checks.
-        assertEquals(14, messageCount);
-    }
-
-    @Test
-    public void testCreateRtmNewNeighMessage() {
-        final int seqNo = 2635;
-        final int ifIndex = 14;
-        final byte[] llAddr =
-                new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
-
-        // Hexadecimal representation of our created packet.
-        final String expectedNewNeighHex =
-                // struct nlmsghdr
-                "30000000" +     // length = 48
-                "1c00" +         // type = 28 (RTM_NEWNEIGH)
-                "0501" +         // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
-                "4b0a0000" +     // seqno
-                "00000000" +     // pid (0 == kernel)
-                // struct ndmsg
-                "02" +           // family
-                "00" +           // pad1
-                "0000" +         // pad2
-                "0e000000" +     // interface index (14)
-                "0800" +         // NUD state (0x08 == NUD_DELAY)
-                "00" +           // flags
-                "00" +           // type
-                // struct nlattr: NDA_DST
-                "0800" +         // length = 8
-                "0100" +         // type (1 == NDA_DST, for neighbor messages)
-                "7f000001" +     // IPv4 address (== 127.0.0.1)
-                // struct nlattr: NDA_LLADDR
-                "0a00" +         // length = 10
-                "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
-                "010203040506" + // MAC Address (== 01:02:03:04:05:06)
-                "0000";          // padding, for 4 byte alignment
-        final byte[] expectedNewNeigh =
-                HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
-
-        final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
-            seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
-        if (!Arrays.equals(expectedNewNeigh, bytes)) {
-            assertEquals(expectedNewNeigh.length, bytes.length);
-            for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
-                assertEquals(expectedNewNeigh[i], bytes[i]);
-            }
-        }
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/StructNdOptPref64Test.java b/tests/unit/src/android/net/netlink/StructNdOptPref64Test.java
deleted file mode 100644
index 0f3020d..0000000
--- a/tests/unit/src/android/net/netlink/StructNdOptPref64Test.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNdOptPref64.getScaledLifetimePlc;
-import static android.net.netlink.StructNdOptPref64.plcToPrefixLength;
-import static android.net.netlink.StructNdOptPref64.prefixLengthToPlc;
-
-import static com.android.testutils.MiscAsserts.assertThrows;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import android.net.IpPrefix;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class StructNdOptPref64Test {
-
-    private static final String PREFIX1 = "64:ff9b::";
-    private static final String PREFIX2 = "2001:db8:1:2:3:64::";
-
-    private static byte[] prefixBytes(String addrString) throws Exception {
-        InetAddress addr = InetAddress.getByName(addrString);
-        byte[] prefixBytes = new byte[12];
-        System.arraycopy(addr.getAddress(), 0, prefixBytes, 0, 12);
-        return prefixBytes;
-    }
-
-    private static IpPrefix prefix(String addrString, int prefixLength) throws Exception {
-        return new IpPrefix(InetAddress.getByName(addrString), prefixLength);
-    }
-
-    private void assertPref64OptMatches(int lifetime, IpPrefix prefix, StructNdOptPref64 opt) {
-        assertEquals(StructNdOptPref64.TYPE, opt.type);
-        assertEquals(2, opt.length);
-        assertEquals(lifetime, opt.lifetime);
-        assertEquals(prefix, opt.prefix);
-    }
-
-    private void assertToByteBufferMatches(StructNdOptPref64 opt, String expected) {
-        String actual = HexEncoding.encodeToString(opt.toByteBuffer().array());
-        assertEquals(expected, actual);
-    }
-
-    private ByteBuffer makeNdOptPref64(int lifetime, byte[] prefix, int prefixLengthCode) {
-        if (prefix.length != 12) throw new IllegalArgumentException("Prefix must be 12 bytes");
-
-        ByteBuffer buf = ByteBuffer.allocate(16)
-                .put((byte) StructNdOptPref64.TYPE)
-                .put((byte) StructNdOptPref64.LENGTH)
-                .putShort(getScaledLifetimePlc(lifetime, prefixLengthCode))
-                .put(prefix, 0, 12);
-
-        buf.flip();
-        return buf;
-    }
-
-    @Test
-    public void testParseCannedOption() throws Exception {
-        String hexBytes = "2602"               // type=38, len=2 (16 bytes)
-                + "0088"                       // lifetime=136, PLC=0 (/96)
-                + "20010DB80003000400050006";  // 2001:db8:3:4:5:6/96
-        byte[] rawBytes = HexEncoding.decode(hexBytes);
-        StructNdOptPref64 opt = StructNdOptPref64.parse(ByteBuffer.wrap(rawBytes));
-        assertPref64OptMatches(136, prefix("2001:DB8:3:4:5:6::", 96), opt);
-        assertToByteBufferMatches(opt, hexBytes);
-
-        hexBytes = "2602"                      // type=38, len=2 (16 bytes)
-                + "2752"                       // lifetime=10064, PLC=2 (/56)
-                + "0064FF9B0000000000000000";  // 64:ff9b::/56
-        rawBytes = HexEncoding.decode(hexBytes);
-        opt = StructNdOptPref64.parse(ByteBuffer.wrap(rawBytes));
-        assertPref64OptMatches(10064, prefix("64:FF9B::", 56), opt);
-        assertToByteBufferMatches(opt, hexBytes);
-    }
-
-    @Test
-    public void testParsing() throws Exception {
-        // Valid.
-        ByteBuffer buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 0);
-        StructNdOptPref64 opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(600, prefix(PREFIX1, 96), opt);
-
-        // Valid, zero lifetime, /64.
-        buf = makeNdOptPref64(0, prefixBytes(PREFIX1), 1);
-        opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(0, prefix(PREFIX1, 64), opt);
-
-        // Valid, low lifetime, /56.
-        buf = makeNdOptPref64(8, prefixBytes(PREFIX2), 2);
-        opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(8, prefix(PREFIX2, 56), opt);
-        assertEquals(new IpPrefix("2001:db8:1::/56"), opt.prefix);  // Prefix is truncated.
-
-        // Valid, maximum lifetime, /32.
-        buf = makeNdOptPref64(65528, prefixBytes(PREFIX2), 5);
-        opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(65528, prefix(PREFIX2, 32), opt);
-        assertEquals(new IpPrefix("2001:db8::/32"), opt.prefix);  // Prefix is truncated.
-
-        // Lifetime not divisible by 8.
-        buf = makeNdOptPref64(300, prefixBytes(PREFIX2), 0);
-        opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(296, prefix(PREFIX2, 96), opt);
-
-        // Invalid prefix length codes.
-        buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 6);
-        assertNull(StructNdOptPref64.parse(buf));
-        buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 7);
-        assertNull(StructNdOptPref64.parse(buf));
-
-        // Truncated to varying lengths...
-        buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 3);
-        final int len = buf.limit();
-        for (int i = 0; i < buf.limit() - 1; i++) {
-            buf.flip();
-            buf.limit(i);
-            assertNull("Option truncated to " + i + " bytes, should have returned null",
-                    StructNdOptPref64.parse(buf));
-        }
-        buf.flip();
-        buf.limit(len);
-        // ... but otherwise OK.
-        opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(600, prefix(PREFIX1, 48), opt);
-    }
-
-    @Test
-    public void testToString() throws Exception {
-        ByteBuffer buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 4);
-        StructNdOptPref64 opt = StructNdOptPref64.parse(buf);
-        assertPref64OptMatches(600, prefix(PREFIX1, 40), opt);
-        assertEquals("NdOptPref64(64:ff9b::/40, 600)", opt.toString());
-    }
-
-    private void assertInvalidPlc(int plc) {
-        assertThrows(IllegalArgumentException.class, () -> plcToPrefixLength(plc));
-    }
-
-    @Test
-    public void testPrefixLengthToPlc() {
-        for (int i = 0; i < 6; i++) {
-            assertEquals(i, prefixLengthToPlc(plcToPrefixLength(i)));
-        }
-        assertInvalidPlc(-1);
-        assertInvalidPlc(6);
-        assertInvalidPlc(7);
-        assertEquals(0, prefixLengthToPlc(96));
-    }
-
-
-    private void assertInvalidParameters(IpPrefix prefix, int lifetime) {
-        assertThrows(IllegalArgumentException.class, () -> new StructNdOptPref64(prefix, lifetime));
-    }
-
-    @Test
-    public void testToByteBuffer() throws Exception {
-        final IpPrefix prefix1 = prefix(PREFIX1, 56);
-        final IpPrefix prefix2 = prefix(PREFIX2, 96);
-
-        StructNdOptPref64 opt = new StructNdOptPref64(prefix1, 600);
-        assertToByteBufferMatches(opt, "2602025A0064FF9B0000000000000000");
-        assertEquals(new IpPrefix("64:ff9b::/56"), opt.prefix);
-        assertEquals(600, opt.lifetime);
-
-        opt = new StructNdOptPref64(prefix2, 65519);
-        assertToByteBufferMatches(opt, "2602FFE820010DB80001000200030064");
-        assertEquals(new IpPrefix("2001:db8:1:2:3:64::/96"), opt.prefix);
-        assertEquals(65512, opt.lifetime);
-
-        assertInvalidParameters(prefix1, 65535);
-        assertInvalidParameters(prefix2, -1);
-        assertInvalidParameters(prefix("1.2.3.4", 32), 600);
-    }
-}
diff --git a/tests/unit/src/android/net/netlink/StructNlMsgHdrTest.java b/tests/unit/src/android/net/netlink/StructNlMsgHdrTest.java
deleted file mode 100644
index b44b31d..0000000
--- a/tests/unit/src/android/net/netlink/StructNlMsgHdrTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static org.junit.Assert.fail;
-
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class StructNlMsgHdrTest {
-
-    public static final short TEST_NLMSG_LEN = 16;
-    public static final short TEST_NLMSG_FLAGS = StructNlMsgHdr.NLM_F_REQUEST
-            | StructNlMsgHdr.NLM_F_MULTI | StructNlMsgHdr.NLM_F_ACK | StructNlMsgHdr.NLM_F_ECHO;
-    public static final short TEST_NLMSG_SEQ = 1234;
-    public static final short TEST_NLMSG_PID = 5678;
-
-    // Checking the header string nlmsg_{len, ..} of the number can make sure that the checking
-    // number comes from the expected element.
-    // TODO: Verify more flags once StructNlMsgHdr can distinguish the flags which have the same
-    // value. For example, NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200) can't be distinguished.
-    // See StructNlMsgHdrTest#stringForNlMsgFlags.
-    public static final String TEST_NLMSG_LEN_STR = "nlmsg_len{16}";
-    public static final String TEST_NLMSG_FLAGS_STR =
-            "NLM_F_REQUEST|NLM_F_MULTI|NLM_F_ACK|NLM_F_ECHO";
-    public static final String TEST_NLMSG_SEQ_STR = "nlmsg_seq{1234}";
-    public static final String TEST_NLMSG_PID_STR = "nlmsg_pid{5678}";
-
-    private StructNlMsgHdr makeStructNlMsgHdr(short type) {
-        final StructNlMsgHdr struct = new StructNlMsgHdr();
-        struct.nlmsg_len = TEST_NLMSG_LEN;
-        struct.nlmsg_type = type;
-        struct.nlmsg_flags = TEST_NLMSG_FLAGS;
-        struct.nlmsg_seq = TEST_NLMSG_SEQ;
-        struct.nlmsg_pid = TEST_NLMSG_PID;
-        return struct;
-    }
-
-    private static void assertContains(String actualValue, String expectedSubstring) {
-        if (actualValue.contains(expectedSubstring)) return;
-        fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\"");
-    }
-
-    @Test
-    public void testToString() {
-        StructNlMsgHdr struct = makeStructNlMsgHdr(NetlinkConstants.RTM_NEWADDR);
-        String s = struct.toString();
-        assertContains(s, TEST_NLMSG_LEN_STR);
-        assertContains(s, TEST_NLMSG_FLAGS_STR);
-        assertContains(s, TEST_NLMSG_SEQ_STR);
-        assertContains(s, TEST_NLMSG_PID_STR);
-        assertContains(s, "nlmsg_type{20()}");
-
-        struct = makeStructNlMsgHdr(NetlinkConstants.SOCK_DIAG_BY_FAMILY);
-        s = struct.toString();
-        assertContains(s, TEST_NLMSG_LEN_STR);
-        assertContains(s, TEST_NLMSG_FLAGS_STR);
-        assertContains(s, TEST_NLMSG_SEQ_STR);
-        assertContains(s, TEST_NLMSG_PID_STR);
-        assertContains(s, "nlmsg_type{20()}");
-    }
-
-    @Test
-    public void testToStringWithNetlinkFamily() {
-        StructNlMsgHdr struct = makeStructNlMsgHdr(NetlinkConstants.RTM_NEWADDR);
-        String s = struct.toString(OsConstants.NETLINK_ROUTE);
-        assertContains(s, TEST_NLMSG_LEN_STR);
-        assertContains(s, TEST_NLMSG_FLAGS_STR);
-        assertContains(s, TEST_NLMSG_SEQ_STR);
-        assertContains(s, TEST_NLMSG_PID_STR);
-        assertContains(s, "nlmsg_type{20(RTM_NEWADDR)}");
-
-        struct = makeStructNlMsgHdr(NetlinkConstants.SOCK_DIAG_BY_FAMILY);
-        s = struct.toString(OsConstants.NETLINK_INET_DIAG);
-        assertContains(s, TEST_NLMSG_LEN_STR);
-        assertContains(s, TEST_NLMSG_FLAGS_STR);
-        assertContains(s, TEST_NLMSG_SEQ_STR);
-        assertContains(s, TEST_NLMSG_PID_STR);
-        assertContains(s, "nlmsg_type{20(SOCK_DIAG_BY_FAMILY)}");
-    }
-}
diff --git a/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java b/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
index 436b81a..716abaa 100644
--- a/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
+++ b/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
@@ -17,12 +17,22 @@
 package android.net.shared;
 
 import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.ip.IIpClient.PROV_IPV4_DHCP;
+import static android.net.ip.IIpClient.PROV_IPV4_DISABLED;
+import static android.net.ip.IIpClient.PROV_IPV4_STATIC;
+import static android.net.ip.IIpClient.PROV_IPV6_DISABLED;
+import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL;
+import static android.net.ip.IIpClient.PROV_IPV6_SLAAC;
 import static android.net.shared.ProvisioningConfiguration.fromStableParcelable;
+import static android.net.shared.ProvisioningConfiguration.ipv4ProvisioningModeToString;
+import static android.net.shared.ProvisioningConfiguration.ipv6ProvisioningModeToString;
 
 import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.net.LinkAddress;
 import android.net.MacAddress;
@@ -76,32 +86,66 @@
         return options;
     }
 
-    @Before
-    public void setUp() {
-        mConfig = new ProvisioningConfiguration();
-        mConfig.mEnableIPv4 = true;
-        mConfig.mEnableIPv6 = true;
-        mConfig.mUsingMultinetworkPolicyTracker = true;
-        mConfig.mUsingIpReachabilityMonitor = true;
-        mConfig.mRequestedPreDhcpActionMs = 42;
-        mConfig.mInitialConfig = new InitialConfiguration();
-        mConfig.mInitialConfig.ipAddresses.add(
+    private ProvisioningConfiguration makeTestProvisioningConfiguration() {
+        final ProvisioningConfiguration config = new ProvisioningConfiguration();
+        config.mUsingMultinetworkPolicyTracker = true;
+        config.mUsingIpReachabilityMonitor = true;
+        config.mRequestedPreDhcpActionMs = 42;
+        config.mInitialConfig = new InitialConfiguration();
+        config.mInitialConfig.ipAddresses.add(
                 new LinkAddress(parseNumericAddress("192.168.42.42"), 24));
-        mConfig.mStaticIpConfig = new StaticIpConfiguration();
-        mConfig.mStaticIpConfig.ipAddress =
+        config.mStaticIpConfig = new StaticIpConfiguration();
+        config.mStaticIpConfig.ipAddress =
                 new LinkAddress(parseNumericAddress("2001:db8::42"), 90);
         // Not testing other InitialConfig or StaticIpConfig members: they have their own unit tests
-        mConfig.mApfCapabilities = new ApfCapabilities(1, 2, 3);
-        mConfig.mProvisioningTimeoutMs = 4200;
-        mConfig.mIPv6AddrGenMode = 123;
-        mConfig.mNetwork = new Network(321);
-        mConfig.mDisplayName = "test_config";
-        mConfig.mEnablePreconnection = false;
-        mConfig.mScanResultInfo = makeScanResultInfo("ssid");
-        mConfig.mLayer2Info = new Layer2Information("some l2key", "some cluster",
+        config.mApfCapabilities = new ApfCapabilities(1, 2, 3);
+        config.mProvisioningTimeoutMs = 4200;
+        config.mIPv6AddrGenMode = 123;
+        config.mNetwork = new Network(321);
+        config.mDisplayName = "test_config";
+        config.mEnablePreconnection = false;
+        config.mScanResultInfo = makeScanResultInfo("ssid");
+        config.mLayer2Info = new Layer2Information("some l2key", "some cluster",
                 MacAddress.fromString("00:01:02:03:04:05"));
-        mConfig.mDhcpOptions = makeCustomizedDhcpOptions((byte) 60,
+        config.mDhcpOptions = makeCustomizedDhcpOptions((byte) 60,
                 new String("android-dhcp-11").getBytes());
+        config.mIPv4ProvisioningMode = PROV_IPV4_DHCP;
+        config.mIPv6ProvisioningMode = PROV_IPV6_SLAAC;
+        return config;
+    }
+
+    private ProvisioningConfigurationParcelable makeTestProvisioningConfigurationParcelable() {
+        final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
+        p.enableIPv4 = true;
+        p.enableIPv6 = true;
+        p.usingMultinetworkPolicyTracker = true;
+        p.usingIpReachabilityMonitor = true;
+        p.requestedPreDhcpActionMs = 42;
+        final InitialConfiguration initialConfig = new InitialConfiguration();
+        initialConfig.ipAddresses.add(
+                new LinkAddress(parseNumericAddress("192.168.42.42"), 24));
+        p.initialConfig = initialConfig.toStableParcelable();
+        p.staticIpConfig = new StaticIpConfiguration();
+        p.staticIpConfig.ipAddress =
+                new LinkAddress(parseNumericAddress("2001:db8::42"), 90);
+        p.apfCapabilities = new ApfCapabilities(1, 2, 3);
+        p.provisioningTimeoutMs = 4200;
+        p.ipv6AddrGenMode = 123;
+        p.network = new Network(321);
+        p.displayName = "test_config";
+        p.enablePreconnection = false;
+        final ScanResultInfo scanResultInfo = makeScanResultInfo("ssid");
+        p.scanResultInfo = scanResultInfo.toStableParcelable();
+        final Layer2Information layer2Info = new Layer2Information("some l2key", "some cluster",
+                MacAddress.fromString("00:01:02:03:04:05"));
+        p.layer2Info = layer2Info.toStableParcelable();
+        p.options = makeCustomizedDhcpOptions((byte) 60, new String("android-dhcp-11").getBytes());
+        return p;
+    }
+
+    @Before
+    public void setUp() {
+        mConfig = makeTestProvisioningConfiguration();
         // Any added field must be included in equals() to be tested properly
         assertFieldCountEquals(16, ProvisioningConfiguration.class);
     }
@@ -153,9 +197,43 @@
         doParcelUnparcelTest();
     }
 
+    @Test
+    public void testParcelUnparcel_DisabledIpProvisioningMode() {
+        mConfig.mIPv4ProvisioningMode = PROV_IPV4_DISABLED;
+        mConfig.mIPv6ProvisioningMode = PROV_IPV6_DISABLED;
+        doParcelUnparcelTest();
+
+        assertFalse(mConfig.toStableParcelable().enableIPv4);
+        assertFalse(mConfig.toStableParcelable().enableIPv6);
+    }
+
+    @Test
+    public void testParcelUnparcel_enabledIpProvisioningMode() {
+        mConfig.mIPv4ProvisioningMode = PROV_IPV4_DHCP;
+        mConfig.mIPv6ProvisioningMode = PROV_IPV6_SLAAC;
+        doParcelUnparcelTest();
+
+        assertTrue(mConfig.toStableParcelable().enableIPv4);
+        assertTrue(mConfig.toStableParcelable().enableIPv6);
+    }
+
+    @Test
+    public void testParcelUnparcel_IpProvisioningModefromOldStableParcelable() {
+        final ProvisioningConfigurationParcelable p = makeTestProvisioningConfigurationParcelable();
+        final ProvisioningConfiguration unparceled = fromStableParcelable(p,
+                11 /* interface version */);
+        assertEquals(mConfig, unparceled);
+    }
+
+    @Test
+    public void testParcelUnparcel_WithIpv6LinkLocalOnly() {
+        mConfig.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL;
+        doParcelUnparcelTest();
+    }
+
     private void doParcelUnparcelTest() {
         final ProvisioningConfiguration unparceled =
-                fromStableParcelable(mConfig.toStableParcelable());
+                fromStableParcelable(mConfig.toStableParcelable(), 12 /* interface version */);
         assertEquals(mConfig, unparceled);
     }
 
@@ -163,8 +241,6 @@
     public void testEquals() {
         assertEquals(mConfig, new ProvisioningConfiguration(mConfig));
 
-        assertNotEqualsAfterChange(c -> c.mEnableIPv4 = false);
-        assertNotEqualsAfterChange(c -> c.mEnableIPv6 = false);
         assertNotEqualsAfterChange(c -> c.mUsingMultinetworkPolicyTracker = false);
         assertNotEqualsAfterChange(c -> c.mUsingIpReachabilityMonitor = false);
         assertNotEqualsAfterChange(c -> c.mRequestedPreDhcpActionMs++);
@@ -198,6 +274,10 @@
                   new String("vendor-class-identifier").getBytes()));
         assertNotEqualsAfterChange(c -> c.mDhcpOptions = makeCustomizedDhcpOptions((byte) 77,
                   new String("vendor-class-identifier").getBytes()));
+        assertNotEqualsAfterChange(c -> c.mIPv4ProvisioningMode = PROV_IPV4_DISABLED);
+        assertNotEqualsAfterChange(c -> c.mIPv4ProvisioningMode = PROV_IPV4_STATIC);
+        assertNotEqualsAfterChange(c -> c.mIPv6ProvisioningMode = PROV_IPV6_DISABLED);
+        assertNotEqualsAfterChange(c -> c.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL);
         assertFieldCountEquals(16, ProvisioningConfiguration.class);
     }
 
@@ -223,7 +303,8 @@
             + " android.net.Layer2InformationParcelable{l2Key: some l2key,"
             + " cluster: some cluster, bssid: %s},"
             + " options: [android.net.networkstack.aidl.dhcp.DhcpOption{type: 60,"
-            + " value: [97, 110, 100, 114, 111, 105, 100, 45, 100, 104, 99, 112, 45, 49, 49]}]}";
+            + " value: [97, 110, 100, 114, 111, 105, 100, 45, 100, 104, 99, 112, 45, 49, 49]}],"
+            + " ipv4ProvisioningMode: 2, ipv6ProvisioningMode: 1}";
 
     @Test
     public void testParcelableToString() {
@@ -235,4 +316,17 @@
         expected = String.format(TEMPLATE, "null");
         assertEquals(expected, parcelWithNull.toString());
     }
+
+    @Test
+    public void testIpProvisioningModeToString() {
+        assertEquals("disabled", ipv4ProvisioningModeToString(PROV_IPV4_DISABLED));
+        assertEquals("static", ipv4ProvisioningModeToString(PROV_IPV4_STATIC));
+        assertEquals("dhcp", ipv4ProvisioningModeToString(PROV_IPV4_DHCP));
+        assertEquals("unknown", ipv4ProvisioningModeToString(0x03 /* unknown mode */));
+
+        assertEquals("disabled", ipv6ProvisioningModeToString(PROV_IPV6_DISABLED));
+        assertEquals("slaac", ipv6ProvisioningModeToString(PROV_IPV6_SLAAC));
+        assertEquals("link-local", ipv6ProvisioningModeToString(PROV_IPV6_LINKLOCAL));
+        assertEquals("unknown", ipv6ProvisioningModeToString(0x03 /* unknown mode */));
+    }
 }
diff --git a/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt b/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt
index 5b91985..5ca20d8 100644
--- a/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt
+++ b/tests/unit/src/android/net/testutils/TestableNetworkCallbackTest.kt
@@ -1,5 +1,6 @@
 package android.net.testutils
 
+import android.annotation.SuppressLint
 import android.net.LinkAddress
 import android.net.LinkProperties
 import android.net.Network
@@ -7,6 +8,15 @@
 import com.android.testutils.ConcurrentInterpreter
 import com.android.testutils.InterpretMatcher
 import com.android.testutils.RecorderCallback.CallbackEntry
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.AVAILABLE
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.BLOCKED_STATUS
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LINK_PROPERTIES_CHANGED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOSING
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CAPS_UPDATED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOST
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.RESUMED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.SUSPENDED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.UNAVAILABLE
 import com.android.testutils.RecorderCallback.CallbackEntry.Available
 import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus
 import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
@@ -33,6 +43,7 @@
 const val TEST_INTERFACE_NAME = "testInterfaceName"
 
 @RunWith(JUnit4::class)
+@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs.
 class TestableNetworkCallbackTest {
     private lateinit var mCallback: TestableNetworkCallback
 
@@ -102,6 +113,20 @@
     }
 
     @Test
+    fun testAssertNoCallbackThat() {
+        val net = Network(101)
+        mCallback.assertNoCallbackThat { it is Available }
+        mCallback.onAvailable(net)
+        // Expect no blocked status change. Receive other callback does not fail the test.
+        mCallback.assertNoCallbackThat { it is BlockedStatus }
+        mCallback.onBlockedStatusChanged(net, true)
+        assertFails { mCallback.assertNoCallbackThat { it is BlockedStatus } }
+        mCallback.onBlockedStatusChanged(net, false)
+        mCallback.onCapabilitiesChanged(net, NetworkCapabilities())
+        assertFails { mCallback.assertNoCallbackThat { it is CapabilitiesChanged } }
+    }
+
+    @Test
     fun testCapabilitiesWithAndWithout() {
         val net = Network(101)
         val matcher = makeHasNetwork(101)
@@ -245,6 +270,41 @@
             onBlockedStatus(199)       | poll(1) = BlockedStatus(199) time 0..3
         """)
     }
+
+    @Test
+    fun testEventuallyExpect() {
+        // TODO: Current test does not verify the inline one. Also verify the behavior after
+        // aligning two eventuallyExpect()
+        val net1 = Network(100)
+        val net2 = Network(101)
+        mCallback.onAvailable(net1)
+        mCallback.onCapabilitiesChanged(net1, NetworkCapabilities())
+        mCallback.onLinkPropertiesChanged(net1, LinkProperties())
+        mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) {
+            net1.equals(it.network)
+        }
+        // No further new callback. Expect no callback.
+        assertFails { mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) }
+
+        // Verify no predicate set.
+        mCallback.onAvailable(net2)
+        mCallback.onLinkPropertiesChanged(net2, LinkProperties())
+        mCallback.onBlockedStatusChanged(net1, false)
+        mCallback.eventuallyExpect(BLOCKED_STATUS) { net1.equals(it.network) }
+        // Verify no callback received if the callback does not happen.
+        assertFails { mCallback.eventuallyExpect(LOSING) }
+    }
+
+    @Test
+    fun testEventuallyExpectOnMultiThreads() {
+        TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1,
+                threadTransform = { cb -> cb.createLinkedCopy() }, spec = """
+                onAvailable(100)                   | eventually(CapabilitiesChanged(100), 1) fails
+                sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 2)
+                onAvailable(101) ; onBlockedStatus(101) | eventually(BlockedStatus(100), 2) fails
+                onSuspended(100) ; sleep ; onLost(100)  | eventually(Lost(100), 2)
+        """)
+    }
 }
 
 private object TNCInterpreter : ConcurrentInterpreter<TestableNetworkCallback>(interpretTable)
@@ -254,6 +314,7 @@
     return CallbackEntry::class.sealedSubclasses.first { it.simpleName == name }
 }
 
+@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs.
 private val interpretTable = listOf<InterpretMatcher<TestableNetworkCallback>>(
     // Interpret "Available(xx)" as "call to onAvailable with netId xx", and likewise for
     // all callback types. This is implemented above by enumerating the subclasses of
@@ -289,5 +350,26 @@
     },
     Regex("""poll\((\d+)\)""") to { i, cb, t ->
         cb.pollForNextCallback(t.timeArg(1))
+    },
+    // Interpret "eventually(Available(xx), timeout)" as calling eventuallyExpect that expects
+    // CallbackEntry.AVAILABLE with netId of xx within timeout*INTERPRET_TIME_UNIT timeout, and
+    // likewise for all callback types.
+    Regex("""eventually\(($EntryList)\((\d+)\),\s+(\d+)\)""") to { i, cb, t ->
+        val net = Network(t.intArg(2))
+        val timeout = t.timeArg(3)
+        when (t.strArg(1)) {
+            "Available" -> cb.eventuallyExpect(AVAILABLE, timeout) { net == it.network }
+            "Suspended" -> cb.eventuallyExpect(SUSPENDED, timeout) { net == it.network }
+            "Resumed" -> cb.eventuallyExpect(RESUMED, timeout) { net == it.network }
+            "Losing" -> cb.eventuallyExpect(LOSING, timeout) { net == it.network }
+            "Lost" -> cb.eventuallyExpect(LOST, timeout) { net == it.network }
+            "Unavailable" -> cb.eventuallyExpect(UNAVAILABLE, timeout) { net == it.network }
+            "BlockedStatus" -> cb.eventuallyExpect(BLOCKED_STATUS, timeout) { net == it.network }
+            "CapabilitiesChanged" ->
+                cb.eventuallyExpect(NETWORK_CAPS_UPDATED, timeout) { net == it.network }
+            "LinkPropertiesChanged" ->
+                cb.eventuallyExpect(LINK_PROPERTIES_CHANGED, timeout) { net == it.network }
+            else -> fail("Unknown callback type")
+        }
     }
 )
diff --git a/tests/unit/src/com/android/networkstack/metrics/NetworkIpReachabilityMonitorMetricsTest.java b/tests/unit/src/com/android/networkstack/metrics/NetworkIpReachabilityMonitorMetricsTest.java
new file mode 100644
index 0000000..45592aa
--- /dev/null
+++ b/tests/unit/src/com/android/networkstack/metrics/NetworkIpReachabilityMonitorMetricsTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.networkstack.metrics;
+
+import android.stats.connectivity.IpType;
+import android.stats.connectivity.NudEventType;
+import android.stats.connectivity.NudNeighborType;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for IpReachabilityMonitorMetrics.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkIpReachabilityMonitorMetricsTest {
+    @Test
+    public void testIpReachabilityMonitorMetrics_setIpType() throws Exception {
+        NetworkIpReachabilityMonitorReported mStats;
+        final IpReachabilityMonitorMetrics mMetrics = new IpReachabilityMonitorMetrics();
+
+        for (IpType ip : IpType.values()) {
+            mMetrics.setNudIpType(ip);
+            mStats = mMetrics.statsWrite();
+            assertEquals(ip, mStats.getIpType());
+        }
+    }
+
+    @Test
+    public void testIpReachabilityMonitorMetrics_setNeighborType() throws Exception {
+        NetworkIpReachabilityMonitorReported mStats;
+        final IpReachabilityMonitorMetrics mMetrics = new IpReachabilityMonitorMetrics();
+
+        for (NudNeighborType neighborType : NudNeighborType.values()) {
+            mMetrics.setNudNeighborType(neighborType);
+            mStats = mMetrics.statsWrite();
+            assertEquals(neighborType, mStats.getNeighborType());
+        }
+    }
+
+    @Test
+    public void testIpReachabilityMonitorMetrics_setEventType() {
+        NetworkIpReachabilityMonitorReported mStats;
+        final IpReachabilityMonitorMetrics mMetrics = new IpReachabilityMonitorMetrics();
+
+        for (NudEventType type : NudEventType.values()) {
+            mMetrics.setNudEventType(type);
+            mStats = mMetrics.statsWrite();
+            assertEquals(type, mStats.getEventType());
+        }
+    }
+}
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
index 8fbe0c4..198ac99 100644
--- a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
+++ b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.networkstack.netlink;
 
-import static android.net.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE;
 import static android.net.util.DataStallUtils.CONFIG_TCP_PACKETS_FAIL_PERCENTAGE;
 import static android.net.util.DataStallUtils.DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE;
 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -26,6 +25,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.net.module.util.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -43,7 +43,6 @@
 import android.net.INetd;
 import android.net.MarkMaskParcel;
 import android.net.Network;
-import android.net.netlink.StructNlMsgHdr;
 import android.os.Build;
 import android.util.Log;
 import android.util.Log.TerribleFailureHandler;
@@ -51,6 +50,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.net.module.util.netlink.StructNlMsgHdr;
 import com.android.networkstack.apishim.ConstantsShim;
 import com.android.networkstack.apishim.NetworkShimImpl;
 import com.android.testutils.DevSdkIgnoreRule;
diff --git a/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java b/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java
index 3317b2b..c689d7b 100644
--- a/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java
+++ b/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java
@@ -19,6 +19,7 @@
 import static android.system.OsConstants.ETH_P_IPV6;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
 
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
 import static com.android.testutils.MiscAsserts.assertThrows;
@@ -90,6 +91,41 @@
         // Link-Layer address
         (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25,
     };
+    private static final byte[] TEST_GRATUITOUS_NA_WITHOUT_TLLA = new byte[] {
+        // dst mac address
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        // src mac address
+        (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25,
+        // ether type
+        (byte) 0x86, (byte) 0xdd,
+        // version, priority and flow label
+        (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        // length
+        (byte) 0x00, (byte) 0x20,
+        // next header
+        (byte) 0x3a,
+        // hop limit
+        (byte) 0xff,
+        // source address
+        (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0,
+        (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d,
+        // destination address
+        (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+        // ICMP type, code, checksum
+        (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c,
+        // flags
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        // target address
+        (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
+        (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+        (byte) 0xc9, (byte) 0x28, (byte) 0x25, (byte) 0x0d,
+        (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78,
+    };
     private static final byte[] TEST_GRATUITOUS_NA_LESS_LENGTH = new byte[] {
         // dst mac address
         (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
@@ -115,6 +151,10 @@
         (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
         (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
         (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+        // ICMP type, code, checksum
+        (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c,
+        // flags
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     };
     private static final byte[] TEST_GRATUITOUS_NA_TRUNCATED = new byte[] {
         // dst mac address
@@ -152,7 +192,7 @@
         (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78,
         // TLLA option
         (byte) 0x02, (byte) 0x01,
-        // Link-Layer address
+        // truncatd Link-Layer address: 4bytes
         (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25,
     };
 
@@ -165,11 +205,8 @@
         assertArrayEquals(na.array(), TEST_GRATUITOUS_NA);
     }
 
-    @Test
-    public void testGratuitousNa_parse() throws Exception {
-        final NeighborAdvertisement na = NeighborAdvertisement.parse(TEST_GRATUITOUS_NA,
-                TEST_GRATUITOUS_NA.length);
-
+    private void assertNeighborAdvertisement(final NeighborAdvertisement na,
+            boolean hasTllaOption) {
         assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.ethHdr.srcMac.toByteArray());
         assertArrayEquals(TEST_DST_MAC_ADDR, na.ethHdr.dstMac.toByteArray());
         assertEquals(ETH_P_IPV6, na.ethHdr.etherType);
@@ -181,20 +218,46 @@
         assertEquals(0, na.icmpv6Hdr.code);
         assertEquals(0, na.naHdr.flags);
         assertEquals(TEST_TARGET_ADDR, na.naHdr.target);
-        assertEquals(2, na.tlla.type);
-        assertEquals(1, na.tlla.length);
-        assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.tlla.linkLayerAddress.toByteArray());
+        if (hasTllaOption) {
+            assertEquals(ICMPV6_ND_OPTION_TLLA, na.tlla.type);
+            assertEquals(1, na.tlla.length);
+            assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.tlla.linkLayerAddress.toByteArray());
+        }
+    }
 
+    @Test
+    public void testGratuitousNa_parse() throws Exception {
+        final NeighborAdvertisement na = NeighborAdvertisement.parse(TEST_GRATUITOUS_NA,
+                TEST_GRATUITOUS_NA.length);
+
+        assertNeighborAdvertisement(na, true /* hasTllaOption */);
         assertArrayEquals(TEST_GRATUITOUS_NA, na.toByteBuffer().array());
     }
 
     @Test
-    public void testGratuitousNa_invalidByteBufferParameters() throws Exception {
+    public void testGratuitousNa_parseWithoutTllaOption() throws Exception {
+        final NeighborAdvertisement na =
+                NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_WITHOUT_TLLA,
+                        TEST_GRATUITOUS_NA_WITHOUT_TLLA.length);
+
+        assertNeighborAdvertisement(na, false /* hasTllaOption */);
+        assertArrayEquals(TEST_GRATUITOUS_NA_WITHOUT_TLLA, na.toByteBuffer().array());
+    }
+
+    @Test
+    public void testGratuitousNa_zeroPacketLength() throws Exception {
         assertThrows(NeighborAdvertisement.ParseException.class,
                 () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA, 0));
     }
 
     @Test
+    public void testGratuitousNa_invalidByteBufferLength() throws Exception {
+        assertThrows(NeighborAdvertisement.ParseException.class,
+                () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_TRUNCATED,
+                                                  TEST_GRATUITOUS_NA.length));
+    }
+
+    @Test
     public void testGratuitousNa_lessPacketLength() throws Exception {
         assertThrows(NeighborAdvertisement.ParseException.class,
                 () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_LESS_LENGTH,
diff --git a/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java b/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java
index c3ff239..18a3ef3 100644
--- a/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java
+++ b/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java
@@ -19,6 +19,7 @@
 import static android.system.OsConstants.ETH_P_IPV6;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
 
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
 import static com.android.testutils.MiscAsserts.assertThrows;
 
@@ -193,7 +194,7 @@
         (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44,
         // slla option
         (byte) 0x01, (byte) 0x01,
-        // link-layer address
+        // truncatd link-layer address: 4bytes
         (byte) 0x06, (byte) 0x5a, (byte) 0xac, (byte) 0x02,
     };
 
@@ -218,6 +219,8 @@
         assertEquals(0, ns.icmpv6Hdr.code);
         assertEquals(TEST_TARGET_ADDR, ns.nsHdr.target);
         if (hasSllaOption) {
+            assertEquals(ICMPV6_ND_OPTION_SLLA, ns.slla.type);
+            assertEquals(1, ns.slla.length);
             assertEquals(MacAddress.fromBytes(TEST_SOURCE_MAC_ADDR), ns.slla.linkLayerAddress);
         }
     }
diff --git a/tests/unit/src/com/android/server/NetworkStackServiceTest.kt b/tests/unit/src/com/android/server/NetworkStackServiceTest.kt
index b32a419..cf65cd7 100644
--- a/tests/unit/src/com/android/server/NetworkStackServiceTest.kt
+++ b/tests/unit/src/com/android/server/NetworkStackServiceTest.kt
@@ -43,7 +43,6 @@
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.ExceptionUtils
 import com.android.testutils.assertThrows
 import org.junit.Rule
 import org.junit.Test
@@ -207,10 +206,10 @@
         verify(mockDhcpCb, times(2)).onDhcpServerCreated(eq(IDhcpServer.STATUS_SUCCESS), any())
 
         // allowTestUid does not need to record the caller's version
-        assertThrows(SecurityException::class.java, ExceptionUtils.ThrowingRunnable {
+        assertThrows(SecurityException::class.java) {
             // Should throw because the test does not run as root
             connector.allowTestUid(Process.myUid(), null)
-        })
+        }
 
         // Verify all methods were covered by the test (5 methods + getVersion + getHash)
         assertEquals(7, INetworkStackConnector::class.declaredMemberFunctions.count {
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index fa7b89f..9d392eb 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
+import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
 import static android.net.DnsResolver.TYPE_A;
 import static android.net.DnsResolver.TYPE_AAAA;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
@@ -25,9 +26,14 @@
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_SKIPPED;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
@@ -91,6 +97,7 @@
 import static java.util.stream.Collectors.toList;
 
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -202,6 +209,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
+@SuppressLint("NewApi")  // Uses hidden APIs, which the linter would identify as missing APIs.
 public class NetworkMonitorTest {
     private static final String LOCATION_HEADER = "location";
     private static final String CONTENT_TYPE_HEADER = "Content-Type";
@@ -316,6 +324,14 @@
     private static final NetworkCapabilities CELL_NO_INTERNET_CAPABILITIES =
             new NetworkCapabilities().addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
 
+    private static final NetworkCapabilities WIFI_OEM_PAID_CAPABILITIES =
+            new NetworkCapabilities()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_NOT_METERED)
+                .addCapability(NET_CAPABILITY_OEM_PAID)
+                .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+
     /**
      * Fakes DNS responses.
      *
@@ -573,7 +589,7 @@
     }
 
     private void resetCallbacks() {
-        resetCallbacks(6);
+        resetCallbacks(11);
     }
 
     private void resetCallbacks(int interfaceVersion) {
@@ -1780,19 +1796,99 @@
         runFailedNetworkTest();
     }
 
-    @Test
-    public void testNoInternetCapabilityValidated() throws Exception {
-        runNetworkTest(TEST_LINK_PROPERTIES, CELL_NO_INTERNET_CAPABILITIES,
-                NETWORK_VALIDATION_RESULT_VALID, 0 /* probesSucceeded */, null /* redirectUrl */);
+    private void doValidationSkippedTest(NetworkCapabilities nc, int validationResult)
+            throws Exception {
+        runNetworkTest(TEST_LINK_PROPERTIES, nc, validationResult,
+                0 /* probesSucceeded */, null /* redirectUrl */);
         verify(mCleartextDnsNetwork, never()).openConnection(any());
     }
 
     @Test
-    public void testLaunchCaptivePortalApp() throws Exception {
+    public void testNoInternetCapabilityValidated() throws Exception {
+        doValidationSkippedTest(CELL_NO_INTERNET_CAPABILITIES,
+                NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_SKIPPED);
+    }
+
+    @Test
+    public void testNoInternetCapabilityValidated_OlderPlatform() throws Exception {
+        // Before callbacks version 11, NETWORK_VALIDATION_RESULT_SKIPPED is not sent
+        resetCallbacks(10);
+        doValidationSkippedTest(CELL_NO_INTERNET_CAPABILITIES, NETWORK_VALIDATION_RESULT_VALID);
+    }
+
+    @Test
+    public void testNoTrustedCapabilityValidated() throws Exception {
+        // Cannot use the NetworkCapabilities builder on Q
+        final NetworkCapabilities nc = new NetworkCapabilities()
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .removeCapability(NET_CAPABILITY_TRUSTED)
+                .addTransportType(TRANSPORT_CELLULAR);
+        if (ShimUtils.isAtLeastS()) {
+            nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+        }
+        doValidationSkippedTest(nc,
+                NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_SKIPPED);
+    }
+
+    @Test
+    public void testRestrictedCapabilityValidated() throws Exception {
+        // Cannot use the NetworkCapabilities builder on Q
+        final NetworkCapabilities nc = new NetworkCapabilities()
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                .addTransportType(TRANSPORT_CELLULAR);
+        if (ShimUtils.isAtLeastS()) {
+            nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+        }
+        doValidationSkippedTest(nc,
+                NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_SKIPPED);
+    }
+
+    private NetworkCapabilities getVcnUnderlyingCarrierWifiCaps() {
+        // Must be called from within the test because NOT_VCN_MANAGED is an invalid capability
+        // value up to Android R. Thus, this must be guarded by an SDK check in tests that use this.
+        return new NetworkCapabilities.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+    }
+
+    @Test
+    public void testVcnUnderlyingNetwork() throws Exception {
+        assumeTrue(ShimUtils.isAtLeastS());
+        setStatus(mHttpsConnection, 204);
+        setStatus(mHttpConnection, 204);
+
+        final NetworkMonitor nm = runNetworkTest(
+                TEST_LINK_PROPERTIES, getVcnUnderlyingCarrierWifiCaps(),
+                NETWORK_VALIDATION_RESULT_VALID,
+                NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS,
+                null /* redirectUrl */);
+        assertEquals(NETWORK_VALIDATION_RESULT_VALID,
+                nm.getEvaluationState().getEvaluationResult());
+    }
+
+    @Test
+    public void testVcnUnderlyingNetworkBadNetwork() throws Exception {
+        assumeTrue(ShimUtils.isAtLeastS());
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 404);
+
+        final NetworkMonitor nm = runNetworkTest(
+                TEST_LINK_PROPERTIES, getVcnUnderlyingCarrierWifiCaps(),
+                VALIDATION_RESULT_INVALID, 0 /* probesSucceeded */, null /* redirectUrl */);
+        assertEquals(VALIDATION_RESULT_INVALID,
+                nm.getEvaluationState().getEvaluationResult());
+    }
+
+    public void setupAndLaunchCaptivePortalApp(final NetworkMonitor nm) throws Exception {
         setSslException(mHttpsConnection);
         setPortal302(mHttpConnection);
         when(mHttpConnection.getHeaderField(eq("location"))).thenReturn(TEST_LOGIN_URL);
-        final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES);
         notifyNetworkConnected(nm, CELL_METERED_CAPABILITIES);
 
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
@@ -1819,11 +1915,18 @@
         final String redirectUrl = bundle.getString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
         assertEquals(TEST_HTTP_URL, redirectUrl);
 
+        resetCallbacks();
+    }
+
+    @Test
+    public void testCaptivePortalLogin() throws Exception {
+        final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES);
+        setupAndLaunchCaptivePortalApp(nm);
+
         // Have the app report that the captive portal is dismissed, and check that we revalidate.
         setStatus(mHttpsConnection, 204);
         setStatus(mHttpConnection, 204);
 
-        resetCallbacks();
         nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
                 .notifyNetworkTestedWithExtras(matchNetworkTestResultParcelable(
@@ -1833,6 +1936,31 @@
     }
 
     @Test
+    public void testCaptivePortalUseAsIs() throws Exception {
+        final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES);
+        setupAndLaunchCaptivePortalApp(nm);
+
+        // The user decides this network is wanted as is, either by encountering an SSL error or
+        // encountering an unknown scheme and then deciding to continue through the browser, or by
+        // selecting this option through the options menu.
+        nm.notifyCaptivePortalAppFinished(APP_RETURN_WANTED_AS_IS);
+        // The captive portal is still closed, but the network validates since the user said so.
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
+                .notifyNetworkTestedWithExtras(matchNetworkTestResultParcelable(
+                        NETWORK_VALIDATION_RESULT_VALID, 0 /* probesSucceeded */));
+        resetCallbacks();
+
+        // Revalidate.
+        nm.forceReevaluation(0 /* responsibleUid */);
+
+        // The network should still be valid.
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
+                .notifyNetworkTestedWithExtras(matchNetworkTestResultParcelable(
+                        NETWORK_VALIDATION_RESULT_VALID, 0 /* probesSucceeded */,
+                        TEST_LOGIN_URL));
+    }
+
+    @Test
     public void testPrivateDnsSuccess() throws Exception {
         setStatus(mHttpsConnection, 204);
         setStatus(mHttpConnection, 204);
@@ -2633,6 +2761,64 @@
                         ConnectivityManager.EXTRA_NETWORK)).netId));
     }
 
+    @Test
+    public void testOemPaidNetworkValidated() throws Exception {
+        setValidProbes();
+
+        final NetworkMonitor nm = runNetworkTest(TEST_LINK_PROPERTIES,
+                WIFI_OEM_PAID_CAPABILITIES,
+                NETWORK_VALIDATION_RESULT_VALID,
+                NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS,
+                null /* redirectUrl */);
+        assertEquals(NETWORK_VALIDATION_RESULT_VALID,
+                nm.getEvaluationState().getEvaluationResult());
+    }
+
+    @Test
+    public void testOemPaidNetwork_AllProbesFailed() throws Exception {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 404);
+
+        runNetworkTest(TEST_LINK_PROPERTIES,
+                WIFI_OEM_PAID_CAPABILITIES,
+                VALIDATION_RESULT_INVALID, 0 /* probesSucceeded */, null /* redirectUrl */);
+    }
+
+    @Test
+    public void testOemPaidNetworkNoInternetCapabilityValidated() throws Exception {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 404);
+
+        final NetworkCapabilities networkCapabilities =
+                new NetworkCapabilities(WIFI_OEM_PAID_CAPABILITIES);
+        networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
+
+        final int validationResult =
+                NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_SKIPPED;
+        runNetworkTest(TEST_LINK_PROPERTIES, networkCapabilities,
+                validationResult, 0 /* probesSucceeded */, null /* redirectUrl */);
+
+        verify(mCleartextDnsNetwork, never()).openConnection(any());
+        verify(mHttpsConnection, never()).getResponseCode();
+        verify(mHttpConnection, never()).getResponseCode();
+        verify(mFallbackConnection, never()).getResponseCode();
+    }
+
+    @Test
+    public void testOemPaidNetwork_CaptivePortalNotLaunched() throws Exception {
+        setSslException(mHttpsConnection);
+        setStatus(mFallbackConnection, 404);
+        setPortal302(mHttpConnection);
+
+        runNetworkTest(TEST_LINK_PROPERTIES, WIFI_OEM_PAID_CAPABILITIES,
+                VALIDATION_RESULT_PORTAL, 0 /* probesSucceeded */,
+                TEST_LOGIN_URL);
+
+        verify(mCallbacks, never()).showProvisioningNotification(any(), any());
+    }
+
     private void setupResourceForMultipleProbes() {
         // Configure the resource to send multiple probe.
         when(mResources.getStringArray(R.array.config_captive_portal_https_urls))