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;
+ }
+}