Add some ipv6 packet utils

1. Allow build icmpv6 packet without ethernet header.
2. Add util for building icmpv6 echo reply.

Bug: 183166581
Test: atest EthernetTetheringTest

Change-Id: I79eb78c8ae4859749f5a5d8d0dc240025d8784e2
diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java
index fe7c89b..d538221 100644
--- a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java
+++ b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java
@@ -20,6 +20,7 @@
 
 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_ECHO_REPLY_TYPE;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
@@ -45,29 +46,23 @@
  */
 public class Ipv6Utils {
     /**
-     * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol).
+     * Build a generic ICMPv6 packet without Ethernet header.
      */
-    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);
+    public static ByteBuffer buildIcmpv6Packet(final Inet6Address srcIp, final Inet6Address dstIp,
+            short type, short code, final ByteBuffer... options) {
         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 ByteBuffer packet = ByteBuffer.allocate(ipv6HeaderLen + icmpv6HeaderLen + payloadLen);
         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) {
@@ -79,11 +74,31 @@
         packet.flip();
 
         // Populate the ICMPv6 checksum field.
-        packet.putShort(etherHeaderLen + ipv6HeaderLen + 2, icmpv6Checksum(packet,
-                etherHeaderLen /* ipOffset */,
-                (int) (etherHeaderLen + ipv6HeaderLen) /* transportOffset */,
+        packet.putShort(ipv6HeaderLen + 2, icmpv6Checksum(packet, 0 /* ipOffset */,
+                ipv6HeaderLen /* transportOffset */,
                 (short) (icmpv6HeaderLen + payloadLen) /* transportLen */));
         return packet;
+
+    }
+
+    /**
+     * 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 ByteBuffer payload = buildIcmpv6Packet(srcIp, dstIp, type, code, options);
+
+        final int etherHeaderLen = Struct.getSize(EthernetHeader.class);
+        final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + payload.limit());
+        final EthernetHeader ethHeader =
+                new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6);
+
+        ethHeader.writeToByteBuffer(packet);
+        packet.put(payload);
+        packet.flip();
+
+        return packet;
     }
 
     /**
@@ -159,4 +174,14 @@
         return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp,
                 (byte) ICMPV6_ECHO_REQUEST_TYPE /* type */, (byte) 0 /* code */, payload);
     }
+
+    /**
+     * Build an ICMPv6 Echo Reply packet without ethernet header.
+     */
+    public static ByteBuffer buildEchoReplyPacket(final Inet6Address srcIp,
+            final Inet6Address dstIp) {
+        final ByteBuffer payload = ByteBuffer.allocate(4); // ID and Sequence number may be zero.
+        return buildIcmpv6Packet(srcIp, dstIp, (byte) ICMPV6_ECHO_REPLY_TYPE /* type */,
+                (byte) 0 /* code */, payload);
+    }
 }