Apply IPv6 utils struct stuff to build RA packet in the Daemon.

Traffic log of testSolicitRouterAdvertisement:
fe80::4473:4aff:fecb:7799 > ff02::1: ICMP6, router advertisement, length 88
fe80::1122:3344:5566:7788 > ff02::1: ICMP6, router solicitation, length 16
fe80::4473:4aff:fecb:7799 > fe80::1122:3344:5566:7788: ICMP6, router advertisement, length 88

Bug: 154669942
Test: atest TetheringPrivilegedTests --iterations
Change-Id: I7defb80ef9dd1832c9e04d154e1d06aed9e733dc
diff --git a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index afccd0a..543a5c7 100644
--- a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -16,7 +16,6 @@
 
 package android.net.ip;
 
-import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
 import static android.net.util.TetheringUtils.getAllNodesForScopeId;
 import static android.system.OsConstants.AF_INET6;
@@ -25,8 +24,18 @@
 import static android.system.OsConstants.SOL_SOCKET;
 import static android.system.OsConstants.SO_SNDTIMEO;
 
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_RA_HEADER_LEN;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS;
+import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK;
+import static com.android.net.module.util.NetworkStackConstants.TAG_SYSTEM_NEIGHBOR;
+
 import android.net.IpPrefix;
 import android.net.LinkAddress;
+import android.net.MacAddress;
 import android.net.TrafficStats;
 import android.net.util.InterfaceParams;
 import android.net.util.SocketUtils;
@@ -37,7 +46,12 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.net.module.util.NetworkStackConstants;
+import com.android.net.module.util.structs.Icmpv6Header;
+import com.android.net.module.util.structs.LlaOption;
+import com.android.net.module.util.structs.MtuOption;
+import com.android.net.module.util.structs.PrefixInformationOption;
+import com.android.net.module.util.structs.RaHeader;
+import com.android.net.module.util.structs.RdnssOption;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -69,9 +83,6 @@
  */
 public class RouterAdvertisementDaemon {
     private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName();
-    private static final byte ICMPV6_ND_ROUTER_SOLICIT = asByte(133);
-    private static final byte ICMPV6_ND_ROUTER_ADVERT  = asByte(134);
-    private static final int MIN_RA_HEADER_SIZE = 16;
 
     // Summary of various timers and lifetimes.
     private static final int MIN_RTR_ADV_INTERVAL_SEC = 300;
@@ -366,54 +377,27 @@
     }
 
     private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
-        /**
-            Router Advertisement Message Format
-
-             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|H|Prf|P|R|R|       Router Lifetime         |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |                         Reachable Time                        |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |                          Retrans Timer                        |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |   Options ...
-            +-+-+-+-+-+-+-+-+-+-+-+-
-        */
-        ra.put(ICMPV6_ND_ROUTER_ADVERT)
-                .put(asByte(0))
-                .putShort(asShort(0))
-                .put(hopLimit)
-                // RFC 4191 "high" preference, iff. advertising a default route.
-                .put(hasDefaultRoute ? asByte(0x08) : asByte(0))
-                .putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
-                .putInt(0)
-                .putInt(0);
+        // RFC 4191 "high" preference, iff. advertising a default route.
+        final byte flags = hasDefaultRoute ? asByte(0x08) : asByte(0);
+        final short lifetime = hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0);
+        final Icmpv6Header icmpv6Header =
+                new Icmpv6Header(asByte(ICMPV6_ROUTER_ADVERTISEMENT) /* type */,
+                        asByte(0) /* code */, asShort(0) /* checksum */);
+        final RaHeader raHeader = new RaHeader(hopLimit, flags, lifetime, 0 /* reachableTime */,
+                0 /* retransTimer */);
+        icmpv6Header.writeToByteBuffer(ra);
+        raHeader.writeToByteBuffer(ra);
     }
 
     private static void putSlla(ByteBuffer ra, byte[] slla) {
-        /**
-            Source/Target Link-layer Address
-
-             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 ...
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-        */
         if (slla == null || slla.length != 6) {
             // Only IEEE 802.3 6-byte addresses are supported.
             return;
         }
 
-        final byte nd_option_slla = 1;
-        final byte slla_num_8octets = 1;
-        ra.put(nd_option_slla)
-            .put(slla_num_8octets)
-            .put(slla);
+        final ByteBuffer sllaOption = LlaOption.build(asByte(ICMPV6_ND_OPTION_SLLA),
+                MacAddress.fromBytes(slla));
+        ra.put(sllaOption);
     }
 
     private static void putExpandedFlagsOption(ByteBuffer ra) {
@@ -439,70 +423,24 @@
     }
 
     private static void putMtu(ByteBuffer ra, int mtu) {
-        /**
-            MTU
-
-             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                              |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-        */
-        final byte nd_option_mtu = 5;
-        final byte mtu_num_8octs = 1;
-        ra.put(nd_option_mtu)
-            .put(mtu_num_8octs)
-            .putShort(asShort(0))
-            .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
+        final ByteBuffer mtuOption = MtuOption.build((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
+        ra.put(mtuOption);
     }
 
     private static void putPio(ByteBuffer ra, IpPrefix ipp,
                                int validTime, int preferredTime) {
-        /**
-            Prefix Information
-
-             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                             +
-            |                                                               |
-            +                                                               +
-            |                                                               |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-        */
         final int prefixLength = ipp.getPrefixLength();
         if (prefixLength != 64) {
             return;
         }
-        final byte nd_option_pio = 3;
-        final byte pio_num_8octets = 4;
 
         if (validTime < 0) validTime = 0;
         if (preferredTime < 0) preferredTime = 0;
         if (preferredTime > validTime) preferredTime = validTime;
 
-        final byte[] addr = ipp.getAddress().getAddress();
-        ra.put(nd_option_pio)
-            .put(pio_num_8octets)
-            .put(asByte(prefixLength))
-            .put(asByte(0xc0)) /* L & A set */
-            .putInt(validTime)
-            .putInt(preferredTime)
-            .putInt(0)
-            .put(addr);
+        final ByteBuffer pioOption = PrefixInformationOption.build(ipp,
+                asByte(PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), validTime, preferredTime);
+        ra.put(pioOption);
     }
 
     private static void putRio(ByteBuffer ra, IpPrefix ipp) {
@@ -543,22 +481,6 @@
     }
 
     private static void putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime) {
-        /**
-            Recursive DNS Server (RDNSS) 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      |     Length    |           Reserved            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |                           Lifetime                            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |                                                               |
-            :            Addresses of IPv6 Recursive DNS Servers            :
-            |                                                               |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         */
-
         final HashSet<Inet6Address> filteredDnses = new HashSet<>();
         for (Inet6Address dns : dnses) {
             if ((new LinkAddress(dns, RFC7421_PREFIX_LENGTH)).isGlobalPreferred()) {
@@ -567,29 +489,22 @@
         }
         if (filteredDnses.isEmpty()) return;
 
-        final byte nd_option_rdnss = 25;
-        final byte rdnss_num_8octets = asByte(dnses.size() * 2 + 1);
-        ra.put(nd_option_rdnss)
-            .put(rdnss_num_8octets)
-            .putShort(asShort(0))
-            .putInt(lifetime);
-
-        for (Inet6Address dns : filteredDnses) {
-            // NOTE: If the full of list DNS servers doesn't fit in the packet,
-            // this code will cause a buffer overflow and the RA won't include
-            // this instance of the option at all.
-            //
-            // TODO: Consider looking at ra.remaining() to determine how many
-            // DNS servers will fit, and adding only those.
-            ra.put(dns.getAddress());
-        }
+        final Inet6Address[] dnsesArray =
+                filteredDnses.toArray(new Inet6Address[filteredDnses.size()]);
+        final ByteBuffer rdnssOption = RdnssOption.build(lifetime, dnsesArray);
+        // NOTE: If the full of list DNS servers doesn't fit in the packet,
+        // this code will cause a buffer overflow and the RA won't include
+        // this instance of the option at all.
+        //
+        // TODO: Consider looking at ra.remaining() to determine how many
+        // DNS servers will fit, and adding only those.
+        ra.put(rdnssOption);
     }
 
     private boolean createSocket() {
         final int send_timout_ms = 300;
 
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                NetworkStackConstants.TAG_SYSTEM_NEIGHBOR);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_NEIGHBOR);
         try {
             mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
             // Setting SNDTIMEO is purely for defensive purposes.
@@ -639,7 +554,7 @@
 
         try {
             synchronized (mLock) {
-                if (mRaLength < MIN_RA_HEADER_SIZE) {
+                if (mRaLength < ICMPV6_RA_HEADER_LEN) {
                     // No actual RA to send.
                     return;
                 }
@@ -668,7 +583,7 @@
                     final int rval = Os.recvfrom(
                             mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor);
                     // Do the least possible amount of validation.
-                    if (rval < 1 || mSolicitation[0] != ICMPV6_ND_ROUTER_SOLICIT) {
+                    if (rval < 1 || mSolicitation[0] != asByte(ICMPV6_ROUTER_SOLICITATION)) {
                         continue;
                     }
                 } catch (ErrnoException | SocketException e) {
@@ -721,7 +636,7 @@
         private int getNextMulticastTransmitDelaySec() {
             boolean deprecationInProgress = false;
             synchronized (mLock) {
-                if (mRaLength < MIN_RA_HEADER_SIZE) {
+                if (mRaLength < ICMPV6_RA_HEADER_LEN) {
                     // No actual RA to send; just sleep for 1 day.
                     return DAY_IN_SECONDS;
                 }