Merge "Add a method to convert IPv6 ULA/anycast to Solicited Node Multicast Address."
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java
index 7d0e527..954c0a3 100755
--- a/src/com/android/networkstack/util/NetworkStackUtils.java
+++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -20,8 +20,10 @@
 import android.net.MacAddress;
 import android.net.util.SocketUtils;
 import android.system.ErrnoException;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.net.module.util.DeviceConfigUtils;
 
@@ -29,7 +31,9 @@
 import java.io.IOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.net.SocketException;
+import java.net.UnknownHostException;
 
 /**
  * Collection of utilities for the network stack.
@@ -284,6 +288,29 @@
     }
 
     /**
+     * Convert IPv6 unicast or anycast address to solicited node multicast address
+     * per RFC4291 section 2.7.1.
+     */
+    @Nullable
+    public static Inet6Address ipv6AddressToSolicitedNodeMulticast(
+            @NonNull final Inet6Address addr) {
+        final byte[] address = new byte[16];
+        address[0] = (byte) 0xFF;
+        address[1] = (byte) 0x02;
+        address[11] = (byte) 0x01;
+        address[12] = (byte) 0xFF;
+        address[13] = addr.getAddress()[13];
+        address[14] = addr.getAddress()[14];
+        address[15] = addr.getAddress()[15];
+        try {
+            return (Inet6Address) InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Invalid host IP address " + addr.getHostAddress(), e);
+            return null;
+        }
+    }
+
+    /**
      * Attaches a socket filter that accepts DHCP packets to the given socket.
      */
     public static native void attachDhcpFilter(FileDescriptor fd) throws ErrnoException;