Merge "Increase the amount of RA packets to 200 to overflow netlink recv buf size."
diff --git a/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java b/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java
index 19ff9d3..b80cc32 100644
--- a/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java
+++ b/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java
@@ -46,4 +46,8 @@
     public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
     public static final int NET_CAPABILITY_ENTERPRISE = 29;
     public static final int TRANSPORT_TEST = 7;
+
+    // Constants defined in android.content.pm.PackageManager
+    public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES =
+            "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES";
 }
diff --git a/apishim/34/com/android/networkstack/apishim/ConstantsShim.java b/apishim/34/com/android/networkstack/apishim/ConstantsShim.java
index 9df84d5..c946544 100644
--- a/apishim/34/com/android/networkstack/apishim/ConstantsShim.java
+++ b/apishim/34/com/android/networkstack/apishim/ConstantsShim.java
@@ -16,6 +16,7 @@
 
 package com.android.networkstack.apishim;
 
+import android.content.pm.PackageManager;
 import android.os.Build;
 
 import androidx.annotation.RequiresApi;
@@ -35,4 +36,8 @@
      */
     @VisibleForTesting
     public static final int VERSION = 34;
+
+    // Constants defined in android.content.pm.PackageManager
+    public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES =
+            PackageManager.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES;
 }
diff --git a/src/com/android/networkstack/netlink/TcpSocketTracker.java b/src/com/android/networkstack/netlink/TcpSocketTracker.java
index a3a58e6..60ebf78 100644
--- a/src/com/android/networkstack/netlink/TcpSocketTracker.java
+++ b/src/com/android/networkstack/netlink/TcpSocketTracker.java
@@ -240,7 +240,7 @@
 
     // Return true if there are more pending messages to read
     private boolean parseMessage(ByteBuffer bytes, int family, TcpStat stat, long time) {
-        if (!enoughBytesRemainForValidNlMsg(bytes)) {
+        if (!NetlinkUtils.enoughBytesRemainForValidNlMsg(bytes)) {
             // This is unlikely to happen in real cases. Check this first for testing.
             Log.e(TAG, "Size is less than header size. Ignored.");
             return false;
@@ -283,7 +283,7 @@
                             calculateLatestPacketsStat(info, mSocketInfos.get(cookie)));
                     mSocketInfos.put(cookie, info);
                 }
-            } while (enoughBytesRemainForValidNlMsg(bytes));
+            } while (NetlinkUtils.enoughBytesRemainForValidNlMsg(bytes));
         } catch (IllegalArgumentException | BufferUnderflowException e) {
             Log.wtf(TAG, "Unexpected socket info parsing, family " + family
                     + " buffer:" + bytes + " "
@@ -435,12 +435,6 @@
         return mLatestReceivedCount;
     }
 
-    /** Check if the length and position of the given ByteBuffer is valid for a nlmsghdr message. */
-    @VisibleForTesting
-    static boolean enoughBytesRemainForValidNlMsg(@NonNull final ByteBuffer bytes) {
-        return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE;
-    }
-
     private static boolean isValidInetDiagMsgSize(final int nlMsgLen) {
         return nlMsgLen >= SOCKDIAG_MSG_HEADER_SIZE;
     }
diff --git a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
index b1bbf84..e36af57 100644
--- a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
+++ b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
@@ -37,7 +37,6 @@
 import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable;
 import static android.net.ip.IpClientLinkObserver.CLAT_PREFIX;
 import static android.net.ip.IpClientLinkObserver.CONFIG_SOCKET_RECV_BUFSIZE;
-import static android.net.ip.IpReachabilityMonitor.MIN_NUD_SOLICIT_NUM;
 import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM;
 import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt;
 import static android.net.ipmemorystore.Status.SUCCESS;
@@ -577,6 +576,10 @@
 
     protected abstract void assertIpMemoryNeverStoreNetworkAttributes(String l2Key, long timeout);
 
+    protected abstract int readNudSolicitNumInSteadyStateFromResource();
+
+    protected abstract int readNudSolicitNumPostRoamingFromResource();
+
     protected final boolean testSkipped() {
         if (!useNetworkStackSignature() && !TestNetworkStackServiceClient.isSupported()) {
             fail("Device running root tests doesn't support TestNetworkStackServiceClient.");
@@ -3806,7 +3809,8 @@
         prepareIpReachabilityMonitorTest();
 
         final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations();
-        assertEquals(MIN_NUD_SOLICIT_NUM, nsList.size());
+        final int expectedNudSolicitNum = readNudSolicitNumPostRoamingFromResource();
+        assertEquals(expectedNudSolicitNum, nsList.size());
         for (NeighborSolicitation ns : nsList) {
             assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
                     ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
@@ -3849,13 +3853,14 @@
         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)) {
+        final int expectedNudSolicitNum = readNudSolicitNumPostRoamingFromResource();
+        int expectedSize = expectedNudSolicitNum + NUD_MCAST_RESOLICIT_NUM;
+        assertEquals(expectedSize, nsList.size());
+        for (NeighborSolicitation ns : nsList.subList(0, expectedNudSolicitNum)) {
             assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */,
                     ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */);
         }
-        for (NeighborSolicitation ns : nsList.subList(MIN_NUD_SOLICIT_NUM, nsList.size())) {
+        for (NeighborSolicitation ns : nsList.subList(expectedNudSolicitNum, nsList.size())) {
             assertMulticastNeighborSolicitation(ns, ROUTER_LINK_LOCAL /* targetIp */);
         }
     }
@@ -4060,12 +4065,8 @@
         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());
+        assertTrue(addresses.get(0).getAddress().isLinkLocalAddress()); // only IPv6 link-local
+        assertTrue(hasRouteTo(lp, IPV6_LINK_LOCAL_PREFIX)); // fe80::/64 -> :: iface mtu 0
 
         // Check that if an RA is received, no IP addresses, routes, or DNS servers are configured.
         // Instead of waiting some period of time for the RA to be received and checking the
diff --git a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
index 481bfdc..bff1088 100644
--- a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
+++ b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
@@ -35,8 +35,8 @@
         private val TAG = "TestNetworkStackServiceClient"
         private val testNetworkStackServiceAction = "android.net.INetworkStackConnector.Test"
         private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
+        private val component = getNetworkStackComponent(testNetworkStackServiceAction)
         private val networkStackVersion by lazy {
-            val component = getNetworkStackComponent(testNetworkStackServiceAction)
             val info = context.packageManager.getPackageInfo(component.packageName, 0 /* flags */)
             info.longVersionCode
         }
@@ -88,4 +88,8 @@
     fun disconnect() {
         InstrumentationRegistry.getInstrumentation().context.unbindService(serviceConnection)
     }
+
+    fun getNetworkStackPackageName(): String {
+        return component.packageName
+    }
 }
diff --git a/tests/integration/root/android/net/ip/IpClientRootTest.kt b/tests/integration/root/android/net/ip/IpClientRootTest.kt
index 7359e05..f1fa1c7 100644
--- a/tests/integration/root/android/net/ip/IpClientRootTest.kt
+++ b/tests/integration/root/android/net/ip/IpClientRootTest.kt
@@ -22,8 +22,8 @@
 import android.net.IIpMemoryStore
 import android.net.IIpMemoryStoreCallbacks
 import android.net.NetworkStackIpMemoryStore
-import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener
 import android.net.ipmemorystore.NetworkAttributes
+import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener
 import android.net.ipmemorystore.Status
 import android.net.networkstack.TestNetworkStackServiceClient
 import android.os.Process
@@ -265,4 +265,19 @@
     override fun storeNetworkAttributes(l2Key: String, na: NetworkAttributes) {
         mStore.storeNetworkAttributes(l2Key, na, null /* listener */)
     }
+
+    private fun readNudSolicitNumFromResource(name: String): Int {
+        val packageName = nsClient.getNetworkStackPackageName()
+        val resource = mContext.createPackageContext(packageName, 0).getResources()
+        val id = resource.getIdentifier(name, "integer", packageName)
+        return resource.getInteger(id)
+    }
+
+    override fun readNudSolicitNumInSteadyStateFromResource(): Int {
+        return readNudSolicitNumFromResource("config_nud_steadystate_solicit_num")
+    }
+
+    override fun readNudSolicitNumPostRoamingFromResource(): Int {
+        return readNudSolicitNumFromResource("config_nud_postroaming_solicit_num")
+    }
 }
diff --git a/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt b/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt
index c9e33b5..26938b6 100644
--- a/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt
+++ b/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt
@@ -21,9 +21,9 @@
 import android.net.ipmemorystore.Status
 import android.net.ipmemorystore.Status.SUCCESS
 import android.util.ArrayMap
+import org.mockito.ArgumentCaptor
 import org.mockito.Mockito.any
 import org.mockito.Mockito.doAnswer
-import org.mockito.ArgumentCaptor
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.never
 import org.mockito.Mockito.timeout
@@ -33,6 +33,9 @@
  * Tests for IpClient, run with signature permissions.
  */
 class IpClientSignatureTest : IpClientIntegrationTestCommon() {
+    private val DEFAULT_NUD_SOLICIT_NUM_POST_ROAM = 5
+    private val DEFAULT_NUD_SOLICIT_NUM_STEADY_STATE = 10
+
     private val mEnabledFeatures = ArrayMap<String, Boolean>()
 
     override fun makeIIpClient(ifaceName: String, cb: IIpClientCallbacks): IIpClient {
@@ -68,4 +71,12 @@
             true
         }.`when`(mIpMemoryStore).retrieveNetworkAttributes(eq(l2Key), any())
     }
+
+    override fun readNudSolicitNumInSteadyStateFromResource(): Int {
+        return DEFAULT_NUD_SOLICIT_NUM_STEADY_STATE
+    }
+
+    override fun readNudSolicitNumPostRoamingFromResource(): Int {
+        return DEFAULT_NUD_SOLICIT_NUM_POST_ROAM
+    }
 }
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
index 85d3842..968acee 100644
--- a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
+++ b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
@@ -54,6 +54,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.netlink.NetlinkUtils;
 import com.android.net.module.util.netlink.StructNlMsgHdr;
 import com.android.networkstack.apishim.ConstantsShim;
 import com.android.testutils.DevSdkIgnoreRule;
@@ -189,13 +190,13 @@
         final ByteBuffer buffer = ByteBuffer.allocate(TEST_BUFFER_SIZE);
 
         buffer.position(TEST_BUFFER_SIZE - StructNlMsgHdr.STRUCT_SIZE);
-        assertTrue(TcpSocketTracker.enoughBytesRemainForValidNlMsg(buffer));
+        assertTrue(NetlinkUtils.enoughBytesRemainForValidNlMsg(buffer));
         // Remaining buffer size is less than a valid StructNlMsgHdr size.
         buffer.position(TEST_BUFFER_SIZE - StructNlMsgHdr.STRUCT_SIZE + 1);
-        assertFalse(TcpSocketTracker.enoughBytesRemainForValidNlMsg(buffer));
+        assertFalse(NetlinkUtils.enoughBytesRemainForValidNlMsg(buffer));
 
         buffer.position(TEST_BUFFER_SIZE);
-        assertFalse(TcpSocketTracker.enoughBytesRemainForValidNlMsg(buffer));
+        assertFalse(NetlinkUtils.enoughBytesRemainForValidNlMsg(buffer));
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // TCP info parsing is not supported on Q