Merge "Check the ByteArray actual size before writing it to ByteBuffer."
diff --git a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java
index d895cfa..92ef8a7 100644
--- a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java
+++ b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java
@@ -40,7 +40,7 @@
  * +-                             -+
  * |            Address            |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |1 0 0 0 0 1 1 0 1 1 0 1 1 1 0 1|
+ * |            EtherType          |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 public class EthernetHeader extends Struct {
diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java
index 3ad8157..a14e064 100644
--- a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java
+++ b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java
@@ -53,7 +53,7 @@
     @Field(order = 0, type = Type.S32)
     public int vtf;
     @Field(order = 1, type = Type.U16)
-    public int length;
+    public int payloadLength;
     @Field(order = 2, type = Type.S8)
     public byte nextHeader;
     @Field(order = 3, type = Type.U8)
@@ -63,10 +63,10 @@
     @Field(order = 5, type = Type.Ipv6Address)
     public Inet6Address dstIp;
 
-    public Ipv6Header(final int vtf, final int length, final byte nextHeader, final short hopLimit,
-            final Inet6Address srcIp, final Inet6Address dstIp) {
+    public Ipv6Header(final int vtf, final int payloadLength, final byte nextHeader,
+            final short hopLimit, final Inet6Address srcIp, final Inet6Address dstIp) {
         this.vtf = vtf;
-        this.length = length;
+        this.payloadLength = payloadLength;
         this.nextHeader = nextHeader;
         this.hopLimit = hopLimit;
         this.srcIp = srcIp;
diff --git a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java
index 2cdeefb..fbaccab 100644
--- a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java
+++ b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java
@@ -36,14 +36,16 @@
  */
 public class LlaOption extends Struct {
     @Field(order = 0, type = Type.S8)
-    // 1 for Source Link-layer Address; 2 for Target Link-layer Address.
     public final byte type;
     @Field(order = 1, type = Type.S8)
     public final byte length; // Length in 8-byte units
     @Field(order = 2, type = Type.EUI48)
+    // Link layer address length and format varies on different link layers, which is not
+    // guaranteed to be a 6-byte MAC address. However, Struct only supports 6-byte MAC
+    // addresses type(EUI-48) for now.
     public final MacAddress linkLayerAddress;
 
-    public LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) {
+    LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) {
         this.type = type;
         this.length = length;
         this.linkLayerAddress = linkLayerAddress;
@@ -54,6 +56,6 @@
      */
     public static ByteBuffer build(final byte type, final MacAddress linkLayerAddress) {
         final LlaOption option = new LlaOption(type, (byte) 1 /* option len */, linkLayerAddress);
-        return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder()));
+        return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN));
     }
 }
diff --git a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java
index a35b576..34bc21c 100644
--- a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java
+++ b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java
@@ -46,7 +46,7 @@
     @Field(order = 3, type = Type.U32)
     public final long mtu;
 
-    public MtuOption(final byte type, final byte length, final short reserved,
+    MtuOption(final byte type, final byte length, final short reserved,
             final long mtu) {
         this.type = type;
         this.length = length;
@@ -60,6 +60,6 @@
     public static ByteBuffer build(final long mtu) {
         final MtuOption option = new MtuOption((byte) ICMPV6_ND_OPTION_MTU,
                 (byte) 1 /* option len */, (short) 0 /* reserved */, mtu);
-        return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder()));
+        return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN));
     }
 }
diff --git a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java
index 8101b06..571d67b 100644
--- a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java
+++ b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java
@@ -23,7 +23,7 @@
 import java.net.Inet6Address;
 
 /**
- * ICMPv6 Neighbor Advertisement header, follow [Icmpv6Header], as per
+ * ICMPv6 Neighbor Advertisement header, follow {@link Icmpv6Header}, as per
  * https://tools.ietf.org/html/rfc4861. This does not contain any option.
  *
  * 0                   1                   2                   3
diff --git a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java
index 7dc0192..1bdee29 100644
--- a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java
+++ b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java
@@ -70,7 +70,7 @@
     @Field(order = 7, type = Type.ByteArray, arraysize = 16)
     public final byte[] prefix;
 
-    public PrefixInformationOption(final byte type, final byte length, final byte prefixLen,
+    PrefixInformationOption(final byte type, final byte length, final byte prefixLen,
             final byte flags, final long validLifetime, final long preferredLifetime,
             final int reserved, @NonNull final byte[] prefix) {
         this.type = type;
@@ -92,6 +92,6 @@
                 (byte) ICMPV6_ND_OPTION_PIO, (byte) 4 /* option len */,
                 (byte) prefix.getPrefixLength(), flags, validLifetime, preferredLifetime,
                 (int) 0, prefix.getRawAddress());
-        return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder()));
+        return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN));
     }
 }
diff --git a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java
index de55e66..b7c2b0c 100644
--- a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java
+++ b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java
@@ -53,8 +53,7 @@
     @Field(order = 3, type = Type.U32)
     public final long lifetime;
 
-    public RdnssOption(final byte type, final byte length, final short reserved,
-            final long lifetime) {
+    RdnssOption(final byte type, final byte length, final short reserved, final long lifetime) {
         this.type = type;
         this.length = length;
         this.reserved = reserved;
@@ -79,6 +78,8 @@
 
     /**
      * Build a RDNSS option from the required specified String parameters.
+     *
+     * @throws IllegalArgumentException if {@code servers} does not contain only numeric addresses.
      */
     public static ByteBuffer build(final long lifetime, final String... servers) {
         final Inet6Address[] serverArray = new Inet6Address[servers.length];
diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
index e5bb58d..115f19d 100644
--- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
@@ -76,15 +76,26 @@
         return true;
 
     }
+
     /**
      * @return True if any element satisfies the predicate, false otherwise.
      *   Note that means this always returns false for empty collections.
      */
     public static <T> boolean any(@NonNull Collection<T> elem, @NonNull Predicate<T> predicate) {
+        return indexOf(elem, predicate) >= 0;
+    }
+
+    /**
+     * @return The index of the first element that matches the predicate, or -1 if none.
+     */
+    @Nullable
+    public static <T> int indexOf(@NonNull Collection<T> elem, @NonNull Predicate<T> predicate) {
+        int idx = 0;
         for (final T e : elem) {
-            if (predicate.test(e)) return true;
+            if (predicate.test(e)) return idx;
+            idx++;
         }
-        return false;
+        return -1;
     }
 
     /**
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
index 5a0200f..3de78c6 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
@@ -78,4 +78,31 @@
         }
         return transports[0];
     }
+
+    /**
+     * Unpacks long value into an array of bits.
+     */
+    public static int[] unpackBits(long val) {
+        int size = Long.bitCount(val);
+        int[] result = new int[size];
+        int index = 0;
+        int bitPos = 0;
+        while (val != 0) {
+            if ((val & 1) == 1) result[index++] = bitPos;
+            val = val >>> 1;
+            bitPos++;
+        }
+        return result;
+    }
+
+    /**
+     * Packs array of bits into a long value.
+     */
+    public static long packBits(int[] bits) {
+        long packed = 0;
+        for (int b : bits) {
+            packed |= (1L << b);
+        }
+        return packed;
+    }
 }
diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt
index 09126d7..91fb1cd 100644
--- a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt
+++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt
@@ -32,10 +32,18 @@
     assertEquals(0, len, "Expected empty array, but length was $len")
 }
 
+fun <T> assertEmpty(ts: List<T>) = ts.size.let { len ->
+    assertEquals(0, len, "Expected empty list, but length was $len")
+}
+
 fun <T> assertLength(expected: Int, got: Array<T>) = got.size.let { len ->
     assertEquals(expected, len, "Expected array of length $expected, but was $len for $got")
 }
 
+fun <T> assertLength(expected: Int, got: List<T>) = got.size.let { len ->
+    assertEquals(expected, len, "Expected list of length $expected, but was $len for $got")
+}
+
 // Bridge method to help write this in Java. If you're writing Kotlin, consider using
 // kotlin.test.assertFailsWith instead, as that method is reified and inlined.
 fun <T : Exception> assertThrows(expected: Class<T>, block: ThrowingRunnable): T {
@@ -103,3 +111,12 @@
         !Modifier.isStatic(it.modifiers) && !Modifier.isTransient(it.modifiers)
     }.size)
 }
+
+fun assertSameElements(expected: List<String?>, actual: List<String?>) {
+    val expectedSet: HashSet<String?> = HashSet<String?>(expected)
+    assertEquals(expectedSet.size.toLong(), expected.size.toLong(),
+            "expected list contains duplicates")
+    val actualSet: HashSet<String?> = HashSet<String?>(actual)
+    assertEquals(actualSet.size.toLong(), actual.size.toLong(), "actual list contains duplicates")
+    assertEquals(expectedSet, actualSet)
+}
diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java
index e47c864..45493bd 100644
--- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java
+++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java
@@ -16,6 +16,8 @@
 
 package android.net.util;
 
+import static com.android.testutils.MiscAsserts.assertSameElements;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -40,7 +42,6 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.function.Function;
 
@@ -247,14 +248,6 @@
         assertEquals(linkAddr2, results.added.get(0));
     }
 
-    private void assertSameElements(List<String> expected, List<String> actual) {
-        HashSet<String> expectedSet = new HashSet(expected);
-        assertEquals("expected list contains duplicates", expectedSet.size(), expected.size());
-        HashSet<String> actualSet = new HashSet(actual);
-        assertEquals("actual list contains duplicates", actualSet.size(), actual.size());
-        assertEquals(expectedSet, actualSet);
-    }
-
     private void assertCompareOrUpdateResult(CompareOrUpdateResult result,
             List<String> expectedAdded, List<String> expectedRemoved,
             List<String> expectedUpdated) {
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
index 0007742..0886426 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.runner.AndroidJUnit4
 import org.junit.Test
 import org.junit.runner.RunWith
+import kotlin.test.assertEquals
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
 
@@ -40,6 +41,15 @@
     }
 
     @Test
+    fun testIndexOf() {
+        assertEquals(4, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "E" })
+        assertEquals(0, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "A" })
+        assertEquals(1, CollectionUtils.indexOf(listOf("AA", "BBB", "CCCC")) { it.length >= 3 })
+        assertEquals(1, CollectionUtils.indexOf(listOf("AA", null, "CCCC")) { it == null })
+        assertEquals(1, CollectionUtils.indexOf(listOf(null, "CCCC")) { it != null })
+    }
+
+    @Test
     fun testAll() {
         assertFalse(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "E" })
         assertTrue(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "F" })
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
index e94d132..df2f459 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
@@ -26,11 +26,14 @@
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
 import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport
+import com.android.net.module.util.NetworkCapabilitiesUtils.packBits
+import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits
 import org.junit.Test
 import org.junit.runner.RunWith
 import java.lang.IllegalArgumentException
 import kotlin.test.assertEquals
 import kotlin.test.assertFailsWith
+import kotlin.test.assertTrue
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
@@ -58,4 +61,21 @@
             getDisplayTransport(intArrayOf())
         }
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testBitPackingTestCase() {
+        runBitPackingTestCase(0, intArrayOf())
+        runBitPackingTestCase(1, intArrayOf(0))
+        runBitPackingTestCase(3, intArrayOf(0, 1))
+        runBitPackingTestCase(4, intArrayOf(2))
+        runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5))
+        runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63))
+        runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63))
+        runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63))
+    }
+
+    fun runBitPackingTestCase(packedBits: Long, bits: IntArray) {
+        assertEquals(packedBits, packBits(bits))
+        assertTrue(bits contentEquals unpackBits(packedBits))
+    }
+}