Revert "Revert "Add utilities to create IPv6 ICMP messages.""

This reverts commit 405c1bfca93fa25ae1616a93ee6e2a1f76d87d1e.

Bug: 168868607
Test: atest NetworkStackIntegrationTest

Reason for revert: Roll forward the previous change and try to merge it one by one instead of using the topic, which should avoid the build broken on the sc-dev branch due to the deferred auto-merge process.

Change-Id: I751fbd9d978ed60206bab009212f621fe902f321
diff --git a/common/Android.bp b/common/Android.bp
index a3bfbce..03296e7 100644
--- a/common/Android.bp
+++ b/common/Android.bp
@@ -60,6 +60,9 @@
         "//packages/modules/CaptivePortalLogin",
         "//frameworks/libs/net/common/tests:__subpackages__",
   ],
+  static_libs: [
+      "net-utils-framework-common",
+  ],
   libs: [
       "androidx.annotation_annotation",
   ],
@@ -146,6 +149,7 @@
         "//packages/modules/NetworkStack:__subpackages__",
         "//packages/modules/CaptivePortalLogin",
         "//frameworks/libs/net/common/tests:__subpackages__",
+        "//frameworks/libs/net/common/device",
         "//packages/modules/Wifi/framework/tests:__subpackages__",
     ]
 }
diff --git a/common/device/com/android/net/module/util/Ipv6Utils.java b/common/device/com/android/net/module/util/Ipv6Utils.java
new file mode 100644
index 0000000..73c2431
--- /dev/null
+++ b/common/device/com/android/net/module/util/Ipv6Utils.java
@@ -0,0 +1,136 @@
+/*
+ * 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.net.module.util;
+
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+
+import static com.android.net.module.util.IpUtils.icmpv6Checksum;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
+
+import android.net.MacAddress;
+
+import com.android.net.module.util.structs.EthernetHeader;
+import com.android.net.module.util.structs.Icmpv6Header;
+import com.android.net.module.util.structs.Ipv6Header;
+import com.android.net.module.util.structs.NaHeader;
+import com.android.net.module.util.structs.RaHeader;
+import com.android.net.module.util.structs.RsHeader;
+
+import java.net.Inet6Address;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Utilities for IPv6 packets.
+ */
+public class Ipv6Utils {
+    /**
+     * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol).
+     */
+    public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac,
+            final Inet6Address srcIp, final Inet6Address dstIp, short type, short code,
+            final ByteBuffer... options) {
+        final int etherHeaderLen = Struct.getSize(EthernetHeader.class);
+        final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class);
+        final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class);
+        int payloadLen = 0;
+        for (ByteBuffer option: options) {
+            payloadLen += option.limit();
+        }
+        final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen
+                + icmpv6HeaderLen + payloadLen);
+        final EthernetHeader ethHeader =
+                new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6);
+        final Ipv6Header ipv6Header =
+                new Ipv6Header((int) 0x60000000 /* version, traffic class, flowlabel */,
+                icmpv6HeaderLen + payloadLen /* payload length */,
+                (byte) IPPROTO_ICMPV6 /* next header */, (byte) 0xff /* hop limit */, srcIp, dstIp);
+        final Icmpv6Header icmpv6Header = new Icmpv6Header(type, code, (short) 0 /* checksum */);
+
+        ethHeader.writeToByteBuffer(packet);
+        ipv6Header.writeToByteBuffer(packet);
+        icmpv6Header.writeToByteBuffer(packet);
+        for (ByteBuffer option : options) {
+            packet.put(option);
+            // in case option might be reused by caller, restore the position and
+            // limit of bytebuffer.
+            option.clear();
+        }
+        packet.flip();
+
+        // Populate the ICMPv6 checksum field.
+        packet.putShort(etherHeaderLen + ipv6HeaderLen + 2, icmpv6Checksum(packet,
+                etherHeaderLen /* ipOffset */,
+                (int) (etherHeaderLen + ipv6HeaderLen) /* transportOffset */,
+                (short) (icmpv6HeaderLen + payloadLen) /* transportLen */));
+        return packet;
+    }
+
+    /**
+     * Build the ICMPv6 packet payload including payload header and specific options.
+     */
+    private static ByteBuffer[] buildIcmpv6Payload(final ByteBuffer payloadHeader,
+            final ByteBuffer... options) {
+        final ByteBuffer[] payload = new ByteBuffer[options.length + 1];
+        payload[0] = payloadHeader;
+        System.arraycopy(options, 0, payload, 1, options.length);
+        return payload;
+    }
+
+    /**
+     * Build an ICMPv6 Router Advertisement packet from the required specified parameters.
+     */
+    public static ByteBuffer buildRaPacket(final MacAddress srcMac, final MacAddress dstMac,
+            final Inet6Address srcIp, final Inet6Address dstIp, final byte flags,
+            final int lifetime, final long reachableTime, final long retransTimer,
+            final ByteBuffer... options) {
+        final RaHeader raHeader = new RaHeader((byte) 0 /* hopLimit, unspecified */,
+                flags, lifetime, reachableTime, retransTimer);
+        final ByteBuffer[] payload = buildIcmpv6Payload(
+                ByteBuffer.wrap(raHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options);
+        return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp,
+                (byte) ICMPV6_ROUTER_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload);
+    }
+
+    /**
+     * Build an ICMPv6 Neighbor Advertisement packet from the required specified parameters.
+     */
+    public static ByteBuffer buildNaPacket(final MacAddress srcMac, final MacAddress dstMac,
+            final Inet6Address srcIp, final Inet6Address dstIp, final int flags,
+            final Inet6Address target, final ByteBuffer... options) {
+        final NaHeader naHeader = new NaHeader(flags, target);
+        final ByteBuffer[] payload = buildIcmpv6Payload(
+                ByteBuffer.wrap(naHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options);
+        return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp,
+                (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload);
+    }
+
+    /**
+     * Build an ICMPv6 Router Solicitation packet from the required specified parameters.
+     */
+    public static ByteBuffer buildRsPacket(final MacAddress srcMac, final MacAddress dstMac,
+            final Inet6Address srcIp, final Inet6Address dstIp, final ByteBuffer... options) {
+        final RsHeader rsHeader = new RsHeader((int) 0 /* reserved */);
+        final ByteBuffer[] payload = buildIcmpv6Payload(
+                ByteBuffer.wrap(rsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options);
+        return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp,
+                (byte) ICMPV6_ROUTER_SOLICITATION /* type */, (byte) 0 /* code */, payload);
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/EthernetHeader.java b/common/device/com/android/net/module/util/structs/EthernetHeader.java
new file mode 100644
index 0000000..d895cfa
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/EthernetHeader.java
@@ -0,0 +1,60 @@
+/*
+ * 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.net.module.util.structs;
+
+import android.net.MacAddress;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * L2 ethernet header as per IEEE 802.3. Does not include a 802.1Q tag.
+ *
+ * 0                   1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          Destination          |
+ * +-                             -+
+ * |            Ethernet           |
+ * +-                             -+
+ * |            Address            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |             Source            |
+ * +-                             -+
+ * |            Ethernet           |
+ * +-                             -+
+ * |            Address            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1 0 0 0 0 1 1 0 1 1 0 1 1 1 0 1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class EthernetHeader extends Struct {
+    @Field(order = 0, type = Type.EUI48)
+    public final MacAddress dstMac;
+    @Field(order = 1, type = Type.EUI48)
+    public final MacAddress srcMac;
+    @Field(order = 2, type = Type.U16)
+    public final int etherType;
+
+    public EthernetHeader(final MacAddress dstMac, final MacAddress srcMac,
+            final int etherType) {
+        this.dstMac = dstMac;
+        this.srcMac = srcMac;
+        this.etherType = etherType;
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/Icmpv6Header.java b/common/device/com/android/net/module/util/structs/Icmpv6Header.java
new file mode 100644
index 0000000..c82ae02
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/Icmpv6Header.java
@@ -0,0 +1,45 @@
+/*
+ * 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.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * ICMPv6 header as per https://tools.ietf.org/html/rfc4443.
+ *
+ * 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      |     Code      |          Checksum             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class Icmpv6Header extends Struct {
+    @Field(order = 0, type = Type.U8)
+    public short type;
+    @Field(order = 1, type = Type.U8)
+    public short code;
+    @Field(order = 2, type = Type.S16)
+    public short checksum;
+
+    public Icmpv6Header(final short type, final short code, final short checksum) {
+        this.type = type;
+        this.code = code;
+        this.checksum = checksum;
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/Ipv6Header.java b/common/device/com/android/net/module/util/structs/Ipv6Header.java
new file mode 100644
index 0000000..3ad8157
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/Ipv6Header.java
@@ -0,0 +1,75 @@
+/*
+ * 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.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.net.Inet6Address;
+
+/**
+ * L3 IPv6 header as per https://tools.ietf.org/html/rfc8200.
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Version| Traffic Class |           Flow Label                  |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |         Payload Length        |  Next Header  |   Hop Limit   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +                         Source Address                        +
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +                      Destination Address                      +
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class Ipv6Header extends Struct {
+    @Field(order = 0, type = Type.S32)
+    public int vtf;
+    @Field(order = 1, type = Type.U16)
+    public int length;
+    @Field(order = 2, type = Type.S8)
+    public byte nextHeader;
+    @Field(order = 3, type = Type.U8)
+    public short hopLimit;
+    @Field(order = 4, type = Type.Ipv6Address)
+    public Inet6Address srcIp;
+    @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) {
+        this.vtf = vtf;
+        this.length = length;
+        this.nextHeader = nextHeader;
+        this.hopLimit = hopLimit;
+        this.srcIp = srcIp;
+        this.dstIp = dstIp;
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/LlaOption.java b/common/device/com/android/net/module/util/structs/LlaOption.java
new file mode 100644
index 0000000..2cdeefb
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/LlaOption.java
@@ -0,0 +1,59 @@
+/*
+ * 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.net.module.util.structs;
+
+import android.net.MacAddress;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * ICMPv6 source/target link-layer address option, as per https://tools.ietf.org/html/rfc4861.
+ *
+ * 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     |    Link-Layer Address ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+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)
+    public final MacAddress linkLayerAddress;
+
+    public LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) {
+        this.type = type;
+        this.length = length;
+        this.linkLayerAddress = linkLayerAddress;
+    }
+
+    /**
+     * Build a target link-layer address option from the required specified parameters.
+     */
+    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()));
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/MtuOption.java b/common/device/com/android/net/module/util/structs/MtuOption.java
new file mode 100644
index 0000000..a35b576
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/MtuOption.java
@@ -0,0 +1,65 @@
+/*
+ * 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.net.module.util.structs;
+
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * ICMPv6 MTU option, as per https://tools.ietf.org/html/rfc4861.
+ *
+ * 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     |           Reserved            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                              MTU                              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class MtuOption extends Struct {
+    @Field(order = 0, type = Type.S8)
+    public final byte type;
+    @Field(order = 1, type = Type.S8)
+    public final byte length; // Length in 8-byte units
+    @Field(order = 2, type = Type.S16)
+    public final short reserved;
+    @Field(order = 3, type = Type.U32)
+    public final long mtu;
+
+    public MtuOption(final byte type, final byte length, final short reserved,
+            final long mtu) {
+        this.type = type;
+        this.length = length;
+        this.reserved = reserved;
+        this.mtu = mtu;
+    }
+
+    /**
+     * Build a MTU option from the required specified parameters.
+     */
+    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()));
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/NaHeader.java b/common/device/com/android/net/module/util/structs/NaHeader.java
new file mode 100644
index 0000000..8101b06
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/NaHeader.java
@@ -0,0 +1,57 @@
+/*
+ * 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.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.net.Inet6Address;
+
+/**
+ * ICMPv6 Neighbor Advertisement header, follow [Icmpv6Header], as per
+ * https://tools.ietf.org/html/rfc4861. This does not contain any option.
+ *
+ * 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      |     Code      |          Checksum             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |R|S|O|                     Reserved                            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +                       Target Address                          +
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Options ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-
+ */
+public class NaHeader extends Struct {
+    @Field(order = 0, type = Type.S32)
+    public int flags; // Router flag, Solicited flag, Override flag and 29 Reserved bits.
+    @Field(order = 1, type = Type.Ipv6Address)
+    public Inet6Address target;
+
+    public NaHeader(final int flags, final Inet6Address target) {
+        this.flags = flags;
+        this.target = target;
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/PrefixInformationOption.java b/common/device/com/android/net/module/util/structs/PrefixInformationOption.java
new file mode 100644
index 0000000..7dc0192
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/PrefixInformationOption.java
@@ -0,0 +1,97 @@
+/*
+ * 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.net.module.util.structs;
+
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
+
+import android.annotation.NonNull;
+import android.net.IpPrefix;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * ICMPv6 prefix information option, as per https://tools.ietf.org/html/rfc4861.
+ *
+ * 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     | Prefix Length |L|A| Reserved1 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Valid Lifetime                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Preferred Lifetime                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           Reserved2                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +                            Prefix                             +
+ * |                                                               |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class PrefixInformationOption extends Struct {
+    @Field(order = 0, type = Type.S8)
+    public final byte type;
+    @Field(order = 1, type = Type.S8)
+    public final byte length; // Length in 8-byte units
+    @Field(order = 2, type = Type.S8)
+    public final byte prefixLen;
+    @Field(order = 3, type = Type.S8)
+    // On-link flag, Autonomous address configuration flag, 6-reserved bits
+    public final byte flags;
+    @Field(order = 4, type = Type.U32)
+    public final long validLifetime;
+    @Field(order = 5, type = Type.U32)
+    public final long preferredLifetime;
+    @Field(order = 6, type = Type.S32)
+    public final int reserved;
+    @Field(order = 7, type = Type.ByteArray, arraysize = 16)
+    public final byte[] prefix;
+
+    public 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;
+        this.length = length;
+        this.prefixLen = prefixLen;
+        this.flags = flags;
+        this.validLifetime = validLifetime;
+        this.preferredLifetime = preferredLifetime;
+        this.reserved = reserved;
+        this.prefix = prefix;
+    }
+
+    /**
+     * Build a Prefix Information option from the required specified parameters.
+     */
+    public static ByteBuffer build(final IpPrefix prefix, final byte flags,
+            final long validLifetime, final long preferredLifetime) {
+        final PrefixInformationOption option = new PrefixInformationOption(
+                (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()));
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/RaHeader.java b/common/device/com/android/net/module/util/structs/RaHeader.java
new file mode 100644
index 0000000..31a5cb7
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/RaHeader.java
@@ -0,0 +1,62 @@
+/*
+ * 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.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * ICMPv6 Router Advertisement header, follow [Icmpv6Header], as per
+ * https://tools.ietf.org/html/rfc4861. This does not contain any option.
+ *
+ * 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      |     Code      |          Checksum             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Cur Hop Limit |M|O|  Reserved |       Router Lifetime         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Reachable Time                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Retrans Timer                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Options ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-
+ */
+public class RaHeader extends Struct {
+    @Field(order = 0, type = Type.S8)
+    public final byte hopLimit;
+    // "Managed address configuration", "Other configuration" bits, and 6 reserved bits
+    @Field(order = 1, type = Type.S8)
+    public final byte flags;
+    @Field(order = 2, type = Type.U16)
+    public final int lifetime;
+    @Field(order = 3, type = Type.U32)
+    public final long reachableTime;
+    @Field(order = 4, type = Type.U32)
+    public final long retransTimer;
+
+    public RaHeader(final byte hopLimit, final byte flags, final int lifetime,
+            final long reachableTime, final long retransTimer) {
+        this.hopLimit = hopLimit;
+        this.flags = flags;
+        this.lifetime = lifetime;
+        this.reachableTime = reachableTime;
+        this.retransTimer = retransTimer;
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/RdnssOption.java b/common/device/com/android/net/module/util/structs/RdnssOption.java
new file mode 100644
index 0000000..de55e66
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/RdnssOption.java
@@ -0,0 +1,90 @@
+/*
+ * 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.net.module.util.structs;
+
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS;
+
+import android.net.InetAddresses;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.net.Inet6Address;
+import java.nio.ByteBuffer;
+
+/**
+ * IPv6 RA recursive DNS server option, as per https://tools.ietf.org/html/rfc8106.
+ * This should be followed by a series of DNSv6 server addresses.
+ *
+ * 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    |           Reserved            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           Lifetime                            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * :            Addresses of IPv6 Recursive DNS Servers            :
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class RdnssOption extends Struct {
+    @Field(order = 0, type = Type.S8)
+    public final byte type;
+    @Field(order = 1, type = Type.S8)
+    public final byte length; // Length in 8-byte units
+    @Field(order = 2, type = Type.S16)
+    public final short reserved;
+    @Field(order = 3, type = Type.U32)
+    public final long lifetime;
+
+    public RdnssOption(final byte type, final byte length, final short reserved,
+            final long lifetime) {
+        this.type = type;
+        this.length = length;
+        this.reserved = reserved;
+        this.lifetime = lifetime;
+    }
+
+    /**
+     * Build a RDNSS option from the required specified Inet6Address parameters.
+     */
+    public static ByteBuffer build(final long lifetime, final Inet6Address... servers) {
+        final byte length = (byte) (1 + 2 * servers.length);
+        final RdnssOption option = new RdnssOption((byte) ICMPV6_ND_OPTION_RDNSS,
+                length, (short) 0, lifetime);
+        final ByteBuffer buffer = ByteBuffer.allocate(length * 8);
+        option.writeToByteBuffer(buffer);
+        for (Inet6Address server : servers) {
+            buffer.put(server.getAddress());
+        }
+        buffer.flip();
+        return buffer;
+    }
+
+    /**
+     * Build a RDNSS option from the required specified String parameters.
+     */
+    public static ByteBuffer build(final long lifetime, final String... servers) {
+        final Inet6Address[] serverArray = new Inet6Address[servers.length];
+        for (int i = 0; i < servers.length; i++) {
+            serverArray[i] = (Inet6Address) InetAddresses.parseNumericAddress(servers[i]);
+        }
+        return build(lifetime, serverArray);
+    }
+}
diff --git a/common/device/com/android/net/module/util/structs/RsHeader.java b/common/device/com/android/net/module/util/structs/RsHeader.java
new file mode 100644
index 0000000..0b51ff2
--- /dev/null
+++ b/common/device/com/android/net/module/util/structs/RsHeader.java
@@ -0,0 +1,44 @@
+/*
+ * 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.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * ICMPv6 Router Solicitation header, follow [Icmpv6Header], as per
+ * https://tools.ietf.org/html/rfc4861. This does not contain any option.
+ *
+ * 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      |     Code      |          Checksum             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                            Reserved                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Options ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-
+ */
+public class RsHeader extends Struct {
+    @Field(order = 0, type = Type.S32)
+    public final int reserved;
+
+    public RsHeader(final int reserved) {
+        this.reserved = reserved;
+    }
+}