Merge changes from topic "dscp-tap"

* changes:
  DscpPolicyTest: fix linter errors
  DscpPolicyTest: use tap instead of tun
  TestNetworkService: fix test network interface bringup
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
index a6efbc6..a1d0310 100644
--- a/service/jni/com_android_server_TestNetworkService.cpp
+++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -76,22 +76,41 @@
         setTunTapCarrierEnabledImpl(env, iface, tun.get(), hasCarrier);
     }
 
-    // Activate interface using an unconnected datagram socket.
-    base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
-    ifr.ifr_flags = IFF_UP;
     // Mark TAP interfaces as supporting multicast
-    if (!isTun) ifr.ifr_flags |= IFF_MULTICAST;
+    if (!isTun) {
+        base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
+        ifr.ifr_flags = IFF_MULTICAST;
 
-    if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
-        throwException(env, errno, "activating", ifr.ifr_name);
-        return -1;
+        if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
+            throwException(env, errno, "set IFF_MULTICAST", ifr.ifr_name);
+            return -1;
+        }
     }
 
     return tun.release();
 }
 
+static void bringUpInterfaceImpl(JNIEnv* env, const char* iface) {
+    // Activate interface using an unconnected datagram socket.
+    base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
+
+    ifreq ifr{};
+    strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
+    if (ioctl(inet6CtrlSock.get(), SIOCGIFFLAGS, &ifr)) {
+        throwException(env, errno, "read flags", iface);
+        return;
+    }
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
+        throwException(env, errno, "set IFF_UP", iface);
+        return;
+    }
+}
+
 //------------------------------------------------------------------------------
 
+
+
 static void setTunTapCarrierEnabled(JNIEnv* env, jclass /* clazz */, jstring
                                     jIface, jint tunFd, jboolean enabled) {
     ScopedUtfChars iface(env, jIface);
@@ -113,11 +132,21 @@
     return createTunTapImpl(env, isTun, hasCarrier, iface.c_str());
 }
 
+static void bringUpInterface(JNIEnv* env, jclass /* clazz */, jstring jIface) {
+    ScopedUtfChars iface(env, jIface);
+    if (!iface.c_str()) {
+        jniThrowNullPointerException(env, "iface");
+        return;
+    }
+    bringUpInterfaceImpl(env, iface.c_str());
+}
+
 //------------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
     {"nativeSetTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", (void*)setTunTapCarrierEnabled},
     {"nativeCreateTunTap", "(ZZLjava/lang/String;)I", (void*)createTunTap},
+    {"nativeBringUpInterface", "(Ljava/lang/String;)V", (void*)bringUpInterface},
 };
 
 int register_com_android_server_TestNetworkService(JNIEnv* env) {
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index dc922f4..15d9f13 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -47,7 +47,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.NetworkStackConstants;
 
 import java.io.IOException;
@@ -83,6 +82,8 @@
     private static native void nativeSetTunTapCarrierEnabled(@NonNull String iface, int tunFd,
             boolean enabled);
 
+    private static native void nativeBringUpInterface(String iface);
+
     @VisibleForTesting
     protected TestNetworkService(@NonNull Context context) {
         mHandlerThread = new HandlerThread("TestNetworkServiceThread");
@@ -153,7 +154,7 @@
             }
 
             if (bringUp) {
-                NetdUtils.setInterfaceUp(mNetd, interfaceName);
+                nativeBringUpInterface(interfaceName);
             }
 
             return new TestNetworkInterface(tunIntf, interfaceName);
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 621b743..b68d3bf 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -27,6 +27,8 @@
 import android.net.IpPrefix
 import android.net.LinkAddress
 import android.net.LinkProperties
+import android.net.Network
+import android.net.MacAddress
 import android.net.NetworkAgent
 import android.net.NetworkAgent.DSCP_POLICY_STATUS_DELETED
 import android.net.NetworkAgent.DSCP_POLICY_STATUS_SUCCESS
@@ -45,10 +47,13 @@
 import android.net.TestNetworkManager
 import android.net.RouteInfo
 import android.os.HandlerThread
+import android.os.SystemClock
 import android.platform.test.annotations.AppModeFull
+import android.system.ErrnoException
 import android.system.Os
 import android.system.OsConstants.AF_INET
 import android.system.OsConstants.AF_INET6
+import android.system.OsConstants.ENETUNREACH
 import android.system.OsConstants.IPPROTO_UDP
 import android.system.OsConstants.SOCK_DGRAM
 import android.system.OsConstants.SOCK_NONBLOCK
@@ -56,9 +61,15 @@
 import android.util.Range
 import androidx.test.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
+import com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4
+import com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6
+import com.android.net.module.util.Struct
+import com.android.net.module.util.structs.EthernetHeader
+import com.android.testutils.ArpResponder
 import com.android.testutils.CompatUtil
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.assertParcelingIsLossless
+import com.android.testutils.RouterAdvertisementResponder
 import com.android.testutils.runAsShell
 import com.android.testutils.SC_V2
 import com.android.testutils.TapPacketReader
@@ -74,7 +85,7 @@
 import org.junit.runner.RunWith
 import java.net.Inet4Address
 import java.net.Inet6Address
-import java.net.InetAddress
+import java.net.InetSocketAddress
 import java.nio.ByteBuffer
 import java.nio.ByteOrder
 import java.util.regex.Pattern
@@ -103,10 +114,12 @@
 
     private val LOCAL_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1")
     private val TEST_TARGET_IPV4_ADDR =
-            InetAddresses.parseNumericAddress("8.8.8.8") as Inet4Address
-    private val LOCAL_IPV6_ADDRESS = InetAddresses.parseNumericAddress("2001:db8::1")
+            InetAddresses.parseNumericAddress("203.0.113.1") as Inet4Address
     private val TEST_TARGET_IPV6_ADDR =
-            InetAddresses.parseNumericAddress("2001:4860:4860::8888") as Inet6Address
+        InetAddresses.parseNumericAddress("2001:4860:4860::8888") as Inet6Address
+    private val TEST_ROUTER_IPV6_ADDR =
+        InetAddresses.parseNumericAddress("fe80::1234") as Inet6Address
+    private val TEST_TARGET_MAC_ADDR = MacAddress.fromString("12:34:56:78:9a:bc")
 
     private val realContext = InstrumentationRegistry.getContext()
     private val cm = realContext.getSystemService(ConnectivityManager::class.java)
@@ -116,9 +129,12 @@
 
     private val handlerThread = HandlerThread(DscpPolicyTest::class.java.simpleName)
 
+    private lateinit var srcAddressV6: Inet6Address
     private lateinit var iface: TestNetworkInterface
     private lateinit var tunNetworkCallback: TestNetworkCallback
     private lateinit var reader: TapPacketReader
+    private lateinit var arpResponder: ArpResponder
+    private lateinit var raResponder: RouterAdvertisementResponder
 
     private fun getKernelVersion(): IntArray {
         // Example:
@@ -129,6 +145,7 @@
         return intArrayOf(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)))
     }
 
+    // TODO: replace with DeviceInfoUtils#isKernelVersionAtLeast
     private fun kernelIsAtLeast(major: Int, minor: Int): Boolean {
         val version = getKernelVersion()
         return (version.get(0) > major || (version.get(0) == major && version.get(1) >= minor))
@@ -142,9 +159,10 @@
         runAsShell(MANAGE_TEST_NETWORKS) {
             val tnm = realContext.getSystemService(TestNetworkManager::class.java)
 
-            iface = tnm.createTunInterface(arrayOf(
-                    LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN),
-                    LinkAddress(LOCAL_IPV6_ADDRESS, IP6_PREFIX_LEN)))
+            // Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
+            // address.
+            iface = tnm.createTapInterface(true /* disableIpv6ProvisioningDelay */,
+                    arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
             assertNotNull(iface)
         }
 
@@ -154,21 +172,30 @@
                 iface.fileDescriptor.fileDescriptor,
                 MAX_PACKET_LENGTH)
         reader.startAsyncForTest()
+
+        arpResponder = ArpResponder(reader, mapOf(TEST_TARGET_IPV4_ADDR to TEST_TARGET_MAC_ADDR))
+        arpResponder.start()
+        raResponder = RouterAdvertisementResponder(reader)
+        raResponder.addRouterEntry(TEST_TARGET_MAC_ADDR, TEST_ROUTER_IPV6_ADDR)
+        raResponder.start()
     }
 
     @After
     fun tearDown() {
         if (!kernelIsAtLeast(5, 15)) {
-            return;
+            return
         }
+        raResponder.stop()
+        arpResponder.stop()
+
         agentsToCleanUp.forEach { it.unregister() }
         callbacksToCleanUp.forEach { cm.unregisterNetworkCallback(it) }
 
         // reader.stop() cleans up tun fd
         reader.handler.post { reader.stop() }
-        if (iface.fileDescriptor.fileDescriptor != null)
-            Os.close(iface.fileDescriptor.fileDescriptor)
+        // quitSafely processes all events in the queue, except delayed messages.
         handlerThread.quitSafely()
+        handlerThread.join()
     }
 
     private fun requestNetwork(request: NetworkRequest, callback: TestableNetworkCallback) {
@@ -189,6 +216,39 @@
                 .build()
     }
 
+    private fun waitForGlobalIpv6Address(network: Network): Inet6Address {
+        // Wait for global IPv6 address to be available
+        val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
+        network.bindSocket(sock)
+
+        var inet6Addr: Inet6Address? = null
+        val timeout = SystemClock.elapsedRealtime() + PACKET_TIMEOUT_MS
+        while (timeout > SystemClock.elapsedRealtime()) {
+            try {
+                // Pick any arbitrary port
+                Os.connect(sock, TEST_TARGET_IPV6_ADDR, 12345)
+                val sockAddr = Os.getsockname(sock) as InetSocketAddress
+
+                // TODO: make RouterAdvertisementResponder.SLAAC_PREFIX public and use it here,
+                // or make it configurable and configure it here.
+                if (IpPrefix("2001:db8::/64").contains(sockAddr.address)) {
+                    inet6Addr = sockAddr.address as Inet6Address
+                    break
+                }
+            } catch (e: ErrnoException) {
+                // ignore ENETUNREACH -- there may not be an address available yet.
+                if (e.errno != ENETUNREACH) {
+                    Os.close(sock)
+                    throw e
+                }
+            }
+            SystemClock.sleep(10 /* ms */)
+        }
+        Os.close(sock)
+        assertNotNull(inet6Addr)
+        return inet6Addr!!
+    }
+
     private fun createConnectedNetworkAgent(
         context: Context = realContext,
         specifier: String? = iface.getInterfaceName()
@@ -211,9 +271,8 @@
         }
         val lp = LinkProperties().apply {
             addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
-            addLinkAddress(LinkAddress(LOCAL_IPV6_ADDRESS, IP6_PREFIX_LEN))
             addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
-            addRoute(RouteInfo(InetAddress.getByName("fe80::1234")))
+            addRoute(RouteInfo(IpPrefix("::/0"), TEST_ROUTER_IPV6_ADDR))
             setInterfaceName(specifier)
         }
         val config = NetworkAgentConfig.Builder().build()
@@ -226,7 +285,9 @@
         agent.expectCallback<OnNetworkCreated>()
         agent.expectSignalStrengths(intArrayOf())
         agent.expectValidationBypassedStatus()
+
         val network = agent.network ?: fail("Expected a non-null network")
+        srcAddressV6 = waitForGlobalIpv6Address(network)
         return agent to callback
     }
 
@@ -237,7 +298,7 @@
     fun sendPacket(
         agent: TestableNetworkAgent,
         sendV6: Boolean,
-        dstPort: Int = 0,
+        dstPort: Int = 0
     ) {
         val testString = "test string"
         val testPacket = ByteBuffer.wrap(testString.toByteArray(Charsets.UTF_8))
@@ -249,11 +310,11 @@
 
         val originalPacket = testPacket.readAsArray()
         Os.sendto(socket, originalPacket, 0 /* bytesOffset */, originalPacket.size, 0 /* flags */,
-                if(sendV6) TEST_TARGET_IPV6_ADDR else TEST_TARGET_IPV4_ADDR, dstPort)
+                if (sendV6) TEST_TARGET_IPV6_ADDR else TEST_TARGET_IPV4_ADDR, dstPort)
         Os.close(socket)
     }
 
-    fun parseV4PacketDscp(buffer : ByteBuffer) : Int {
+    fun parseV4PacketDscp(buffer: ByteBuffer): Int {
         val ip_ver = buffer.get()
         val tos = buffer.get()
         val length = buffer.getShort()
@@ -265,7 +326,7 @@
         return tos.toInt().shr(2)
     }
 
-    fun parseV6PacketDscp(buffer : ByteBuffer) : Int {
+    fun parseV6PacketDscp(buffer: ByteBuffer): Int {
         val ip_ver = buffer.get()
         val tc = buffer.get()
         val fl = buffer.getShort()
@@ -279,9 +340,9 @@
     }
 
     fun parsePacketIp(
-        buffer : ByteBuffer,
-        sendV6 : Boolean,
-    ) : Boolean {
+        buffer: ByteBuffer,
+        sendV6: Boolean
+    ): Boolean {
         val ipAddr = if (sendV6) ByteArray(16) else ByteArray(4)
         buffer.get(ipAddr)
         val srcIp = if (sendV6) Inet6Address.getByAddress(ipAddr)
@@ -292,20 +353,20 @@
 
         Log.e(TAG, "IP Src:" + srcIp + " dst: " + dstIp)
 
-        if ((sendV6 && srcIp == LOCAL_IPV6_ADDRESS && dstIp == TEST_TARGET_IPV6_ADDR) ||
+        if ((sendV6 && srcIp == srcAddressV6 && dstIp == TEST_TARGET_IPV6_ADDR) ||
                 (!sendV6 && srcIp == LOCAL_IPV4_ADDRESS && dstIp == TEST_TARGET_IPV4_ADDR)) {
-            Log.e(TAG, "IP return true");
+            Log.e(TAG, "IP return true")
             return true
         }
-        Log.e(TAG, "IP return false");
+        Log.e(TAG, "IP return false")
         return false
     }
 
     fun parsePacketPort(
-        buffer : ByteBuffer,
-        srcPort : Int,
-        dstPort : Int
-    ) : Boolean {
+        buffer: ByteBuffer,
+        srcPort: Int,
+        dstPort: Int
+    ): Boolean {
         if (srcPort == 0 && dstPort == 0) return true
 
         val packetSrcPort = buffer.getShort().toInt()
@@ -315,26 +376,33 @@
 
         if ((srcPort == 0 || (srcPort != 0 && srcPort == packetSrcPort)) &&
                 (dstPort == 0 || (dstPort != 0 && dstPort == packetDstPort))) {
-            Log.e(TAG, "Port return true");
+            Log.e(TAG, "Port return true")
             return true
         }
-        Log.e(TAG, "Port return false");
+        Log.e(TAG, "Port return false")
         return false
     }
 
     fun validatePacket(
-        agent : TestableNetworkAgent,
-        sendV6 : Boolean = false,
-        dscpValue : Int = 0,
-        dstPort : Int = 0,
+        agent: TestableNetworkAgent,
+        sendV6: Boolean = false,
+        dscpValue: Int = 0,
+        dstPort: Int = 0
     ) {
-        var packetFound = false;
+        var packetFound = false
         sendPacket(agent, sendV6, dstPort)
         // TODO: grab source port from socket in sendPacket
 
         Log.e(TAG, "find DSCP value:" + dscpValue)
-        generateSequence { reader.poll(PACKET_TIMEOUT_MS) }.forEach { packet ->
+        val packets = generateSequence { reader.poll(PACKET_TIMEOUT_MS) }
+        for (packet in packets) {
             val buffer = ByteBuffer.wrap(packet, 0, packet.size).order(ByteOrder.BIG_ENDIAN)
+            // TODO: consider using Struct.parse for all packet parsing.
+            val etherHdr = Struct.parse(EthernetHeader::class.java, buffer)
+            val expectedType = if (sendV6) ETHER_TYPE_IPV6 else ETHER_TYPE_IPV4
+            if (etherHdr.etherType != expectedType) {
+                continue
+            }
             val dscp = if (sendV6) parseV6PacketDscp(buffer) else parseV4PacketDscp(buffer)
             Log.e(TAG, "DSCP value:" + dscp)
 
@@ -420,7 +488,7 @@
         val policy2 = DscpPolicy.Builder(1, 4)
                 .setDestinationPortRange(Range(5555, 5555))
                 .setDestinationAddress(TEST_TARGET_IPV6_ADDR)
-                .setSourceAddress(LOCAL_IPV6_ADDRESS)
+                .setSourceAddress(srcAddressV6)
                 .setProtocol(IPPROTO_UDP).build()
         agent.sendAddDscpPolicy(policy2)
         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {