[Test] multicast forwarding from LLA/MLA address test

Added E2E test cases to verify that packets from Thread network with
link-local/mesh-local source address to multicast group with scope
larger than realm-local are not forwarded to infra link.

Bug: 325770316

Test: atest ThreadNetworkIntegrationTests:android.net.thread.BorderRoutingTest
Change-Id: I77cb8dbc43d0a2d6936a2a4db45e9dea541ea3c0
diff --git a/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java b/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
index 1f27f06..7554610 100644
--- a/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
+++ b/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
@@ -41,6 +41,7 @@
 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assume.assumeNotNull;
@@ -451,6 +452,55 @@
     }
 
     @Test
+    public void multicastRouting_outboundForwarding_llaToScope4IsNotForwarded() throws Exception {
+        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        /*
+         * <pre>
+         * Topology:
+         *                 infra network                       Thread
+         * infra device -------------------- Border Router -------------- Full Thread device
+         *                                   (Cuttlefish)
+         * </pre>
+         */
+
+        FullThreadDevice ftd = mFtds.get(0);
+        startFtdChild(ftd);
+        Inet6Address ftdLla = ftd.getLinkLocalAddress();
+        assertNotNull(ftdLla);
+
+        ftd.ping(GROUP_ADDR_SCOPE_4, ftdLla, 100 /* size */, 1 /* count */);
+
+        assertNull(
+                pollForPacketOnInfraNetwork(ICMPV6_ECHO_REQUEST_TYPE, ftdLla, GROUP_ADDR_SCOPE_4));
+    }
+
+    @Test
+    public void multicastRouting_outboundForwarding_mlaToScope4IsNotForwarded() throws Exception {
+        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        /*
+         * <pre>
+         * Topology:
+         *                 infra network                       Thread
+         * infra device -------------------- Border Router -------------- Full Thread device
+         *                                   (Cuttlefish)
+         * </pre>
+         */
+
+        FullThreadDevice ftd = mFtds.get(0);
+        startFtdChild(ftd);
+        List<Inet6Address> ftdMlas = ftd.getMeshLocalAddresses();
+        assertFalse(ftdMlas.isEmpty());
+
+        for (Inet6Address ftdMla : ftdMlas) {
+            ftd.ping(GROUP_ADDR_SCOPE_4, ftdMla, 100 /* size */, 1 /* count */);
+
+            assertNull(
+                    pollForPacketOnInfraNetwork(
+                            ICMPV6_ECHO_REQUEST_TYPE, ftdMla, GROUP_ADDR_SCOPE_4));
+        }
+    }
+
+    @Test
     public void multicastRouting_infraNetworkSwitch_ftdRepliesToSubscribedAddress()
             throws Exception {
         assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
diff --git a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
index bb0034a..6cb1675 100644
--- a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
+++ b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
@@ -107,6 +107,39 @@
     }
 
     /**
+     * Returns the link-local address of the device.
+     *
+     * <p>This methods goes through all unicast addresses on the device and returns the address that
+     * begins with fe80.
+     */
+    public Inet6Address getLinkLocalAddress() {
+        List<String> output = executeCommand("ipaddr linklocal");
+        if (!output.isEmpty() && output.get(0).startsWith("fe80:")) {
+            return (Inet6Address) InetAddresses.parseNumericAddress(output.get(0));
+        }
+        return null;
+    }
+
+    /**
+     * Returns the mesh-local addresses of the device.
+     *
+     * <p>This methods goes through all unicast addresses on the device and returns the address that
+     * begins with mesh-local prefix.
+     */
+    public List<Inet6Address> getMeshLocalAddresses() {
+        List<String> addresses = executeCommand("ipaddr");
+        List<Inet6Address> meshLocalAddresses = new ArrayList<>();
+        IpPrefix meshLocalPrefix = mActiveOperationalDataset.getMeshLocalPrefix();
+        for (String address : addresses) {
+            Inet6Address addr = (Inet6Address) InetAddresses.parseNumericAddress(address);
+            if (meshLocalPrefix.contains(addr)) {
+                meshLocalAddresses.add(addr);
+            }
+        }
+        return meshLocalAddresses;
+    }
+
+    /**
      * Joins the Thread network using the given {@link ActiveOperationalDataset}.
      *
      * @param dataset the Active Operational Dataset