Merge "NsdService should set the Inet6Address scope ids"
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index cbe6691..c00f1ae 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -72,6 +72,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
@@ -1155,22 +1156,7 @@
                                 Log.e(TAG, "Invalid attribute", e);
                             }
                         }
-                        final List<InetAddress> addresses = new ArrayList<>();
-                        for (String ipv4Address : serviceInfo.getIpv4Addresses()) {
-                            try {
-                                addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
-                            } catch (IllegalArgumentException e) {
-                                Log.wtf(TAG, "Invalid ipv4 address", e);
-                            }
-                        }
-                        for (String ipv6Address : serviceInfo.getIpv6Addresses()) {
-                            try {
-                                addresses.add(InetAddresses.parseNumericAddress(ipv6Address));
-                            } catch (IllegalArgumentException e) {
-                                Log.wtf(TAG, "Invalid ipv6 address", e);
-                            }
-                        }
-
+                        final List<InetAddress> addresses = getInetAddresses(serviceInfo);
                         if (addresses.size() != 0) {
                             info.setHostAddresses(addresses);
                             clientInfo.onResolveServiceSucceeded(clientId, info);
@@ -1202,21 +1188,7 @@
                             }
                         }
 
-                        final List<InetAddress> addresses = new ArrayList<>();
-                        for (String ipv4Address : serviceInfo.getIpv4Addresses()) {
-                            try {
-                                addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
-                            } catch (IllegalArgumentException e) {
-                                Log.wtf(TAG, "Invalid ipv4 address", e);
-                            }
-                        }
-                        for (String ipv6Address : serviceInfo.getIpv6Addresses()) {
-                            try {
-                                addresses.add(InetAddresses.parseNumericAddress(ipv6Address));
-                            } catch (IllegalArgumentException e) {
-                                Log.wtf(TAG, "Invalid ipv6 address", e);
-                            }
-                        }
+                        final List<InetAddress> addresses = getInetAddresses(serviceInfo);
                         info.setHostAddresses(addresses);
                         clientInfo.onServiceUpdated(clientId, info);
                         break;
@@ -1232,6 +1204,36 @@
        }
     }
 
+    @NonNull
+    private static List<InetAddress> getInetAddresses(@NonNull MdnsServiceInfo serviceInfo) {
+        final List<String> v4Addrs = serviceInfo.getIpv4Addresses();
+        final List<String> v6Addrs = serviceInfo.getIpv6Addresses();
+        final List<InetAddress> addresses = new ArrayList<>(v4Addrs.size() + v6Addrs.size());
+        for (String ipv4Address : v4Addrs) {
+            try {
+                addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
+            } catch (IllegalArgumentException e) {
+                Log.wtf(TAG, "Invalid ipv4 address", e);
+            }
+        }
+        for (String ipv6Address : v6Addrs) {
+            try {
+                final InetAddress addr = InetAddresses.parseNumericAddress(ipv6Address);
+                if (addr.isLinkLocalAddress()) {
+                    final Inet6Address v6Addr = Inet6Address.getByAddress(
+                            null /* host */, addr.getAddress(),
+                            serviceInfo.getInterfaceIndex());
+                    addresses.add(v6Addr);
+                } else {
+                    addresses.add(addr);
+                }
+            } catch (IllegalArgumentException | UnknownHostException e) {
+                Log.wtf(TAG, "Invalid ipv6 address", e);
+            }
+        }
+        return addresses;
+    }
+
     private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) {
         switch (netId) {
             case NETID_UNSET:
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 4c63cb0..469fdba 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -96,6 +96,8 @@
 import com.android.testutils.waitForIdle
 import java.io.File
 import java.io.IOException
+import java.net.Inet6Address
+import java.net.InetAddress
 import java.net.NetworkInterface
 import java.net.ServerSocket
 import java.nio.charset.StandardCharsets
@@ -132,6 +134,7 @@
 
 @AppModeFull(reason = "Socket cannot bind in instant app mode")
 @RunWith(AndroidJUnit4::class)
+@ConnectivityModuleTest
 class NsdManagerTest {
     // Rule used to filter CtsNetTestCasesMaxTargetSdkXX
     @get:Rule
@@ -697,6 +700,20 @@
         }
     }
 
+    private fun checkAddressScopeId(iface: TestNetworkInterface, address: List<InetAddress>) {
+        val targetSdkVersion = context.packageManager
+            .getTargetSdkVersion(context.applicationInfo.packageName)
+        if (targetSdkVersion <= Build.VERSION_CODES.TIRAMISU) {
+            return
+        }
+        val ifaceIdx = NetworkInterface.getByName(iface.interfaceName).index
+        address.forEach {
+            if (it is Inet6Address && it.isLinkLocalAddress) {
+                assertEquals(ifaceIdx, it.scopeId)
+            }
+        }
+    }
+
     @Test
     fun testNsdManager_ResolveOnNetwork() {
         // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
@@ -732,6 +749,7 @@
                 assertEquals(registeredInfo.serviceName, it.serviceName)
                 assertEquals(si.port, it.port)
                 assertEquals(testNetwork1.network, nsdShim.getNetwork(it))
+                checkAddressScopeId(testNetwork1.iface, it.hostAddresses)
             }
             // TODO: check that MDNS packets are sent only on testNetwork1.
         } cleanupStep {
@@ -971,6 +989,7 @@
             for (hostAddress in hostAddresses) {
                 assertTrue(addresses.contains(hostAddress))
             }
+            checkAddressScopeId(testNetwork1.iface, serviceInfoCb.serviceInfo.hostAddresses)
         } cleanupStep {
             nsdManager.unregisterService(registrationRecord)
             registrationRecord.expectCallback<ServiceUnregistered>()