EthernetTetheringTest: add testTetherTcpV6

Bug: 237369591
Test: atest EthernetTetheringTest
Change-Id: I476a8d984eb8ccb6b2e64d6c36dbb455029a4c51
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index de788e7..50786e6 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -1036,26 +1036,21 @@
     private static final ByteBuffer TX_PAYLOAD =
             ByteBuffer.wrap(new byte[] { (byte) 0x56, (byte) 0x78 });
 
+    private short getEthType(@NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp) {
+        return isAddressIpv4(srcIp, dstIp) ? (short) ETHER_TYPE_IPV4 : (short) ETHER_TYPE_IPV6;
+    }
+
+    private int getIpProto(@NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp) {
+        return isAddressIpv4(srcIp, dstIp) ? IPPROTO_IP : IPPROTO_IPV6;
+    }
+
     @NonNull
     private ByteBuffer buildUdpPacket(
             @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
             @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp,
             short srcPort, short dstPort, @Nullable final ByteBuffer payload)
             throws Exception {
-        int ipProto;
-        short ethType;
-        if (srcIp instanceof Inet4Address && dstIp instanceof Inet4Address) {
-            ipProto = IPPROTO_IP;
-            ethType = (short) ETHER_TYPE_IPV4;
-        } else if (srcIp instanceof Inet6Address && dstIp instanceof Inet6Address) {
-            ipProto = IPPROTO_IPV6;
-            ethType = (short) ETHER_TYPE_IPV6;
-        } else {
-            fail("Unsupported conditions: srcIp " + srcIp + ", dstIp " + dstIp);
-            // Make compiler happy to the uninitialized ipProto and ethType.
-            return null;  // unreachable, the annotation @NonNull of function return value is true.
-        }
-
+        final int ipProto = getIpProto(srcIp, dstIp);
         final boolean hasEther = (srcMac != null && dstMac != null);
         final int payloadLen = (payload == null) ? 0 : payload.limit();
         final ByteBuffer buffer = PacketBuilder.allocate(hasEther, ipProto, IPPROTO_UDP,
@@ -1063,7 +1058,9 @@
         final PacketBuilder packetBuilder = new PacketBuilder(buffer);
 
         // [1] Ethernet header
-        if (hasEther) packetBuilder.writeL2Header(srcMac, dstMac, (short) ethType);
+        if (hasEther) {
+            packetBuilder.writeL2Header(srcMac, dstMac, getEthType(srcIp, dstIp));
+        }
 
         // [2] IP header
         if (ipProto == IPPROTO_IP) {
@@ -1784,23 +1781,25 @@
             @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp,
             short srcPort, short dstPort, final short seq, final short ack,
             final byte tcpFlags, @NonNull final ByteBuffer payload) throws Exception {
-        // TODO: support IPv6
-        if (!(srcIp instanceof Inet4Address && dstIp instanceof Inet4Address)) {
-            fail("Unsupported conditions: srcIp " + srcIp + ", dstIp " + dstIp);
-            return null;
-        }
-
+        final int ipProto = getIpProto(srcIp, dstIp);
         final boolean hasEther = (srcMac != null && dstMac != null);
-        final ByteBuffer buffer = PacketBuilder.allocate(hasEther, IPPROTO_IP, IPPROTO_TCP,
+        final ByteBuffer buffer = PacketBuilder.allocate(hasEther, ipProto, IPPROTO_TCP,
                 payload.limit());
         final PacketBuilder packetBuilder = new PacketBuilder(buffer);
 
         // [1] Ethernet header
-        if (hasEther) packetBuilder.writeL2Header(srcMac, dstMac, (short) ETHER_TYPE_IPV4);
+        if (hasEther) {
+            packetBuilder.writeL2Header(srcMac, dstMac, getEthType(srcIp, dstIp));
+        }
 
         // [2] IP header
-        packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
+        if (ipProto == IPPROTO_IP) {
+            packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
                     TIME_TO_LIVE, (byte) IPPROTO_TCP, (Inet4Address) srcIp, (Inet4Address) dstIp);
+        } else {
+            packetBuilder.writeIpv6Header(VERSION_TRAFFICCLASS_FLOWLABEL, (byte) IPPROTO_TCP,
+                    HOP_LIMIT, (Inet6Address) srcIp, (Inet6Address) dstIp);
+        }
 
         // [3] TCP header
         packetBuilder.writeTcpHeader(srcPort, dstPort, seq, ack, tcpFlags, WINDOW, URGENT_POINTER);
@@ -1818,14 +1817,14 @@
             @NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags,
             @NonNull final ByteBuffer payload, @NonNull final TetheringTester tester)
             throws Exception {
+        final boolean isIpv4 = isAddressIpv4(srcIp, dstIp);
         final ByteBuffer testPacket = buildTcpPacket(null /* srcMac */, null /* dstMac */,
                 srcIp, dstIp, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */, seq, ack,
                 tcpFlags, payload);
         tester.verifyDownload(testPacket, p -> {
             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
 
-            return isExpectedTcpPacket(p, true /* hasEther */, true /* isIpv4 */, seq,
-                    payload);
+            return isExpectedTcpPacket(p, true /* hasEther */, isIpv4, seq, payload);
         });
     }
 
@@ -1834,21 +1833,22 @@
             @NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags,
             @NonNull final ByteBuffer payload, @NonNull final TetheringTester tester)
             throws Exception {
+        final boolean isIpv4 = isAddressIpv4(srcIp, dstIp);
         final ByteBuffer testPacket = buildTcpPacket(srcMac, dstMac, srcIp, dstIp,
                 LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */, seq, ack, tcpFlags,
                 payload);
         tester.verifyUpload(testPacket, p -> {
             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
 
-            return isExpectedTcpPacket(p, false /* hasEther */, true /* isIpv4 */,
-                    seq, payload);
+            return isExpectedTcpPacket(p, false /* hasEther */, isIpv4, seq, payload);
         });
     }
 
-    void runTcpTest(@NonNull final MacAddress srcMac, @NonNull  final MacAddress dstMac,
-            @NonNull  final InetAddress remoteIp, @NonNull final InetAddress tetheringUpstreamIp,
-            @NonNull final InetAddress clientIp, @NonNull final TetheringTester tester)
-            throws Exception {
+    void runTcpTest(
+            @NonNull final MacAddress uploadSrcMac, @NonNull final MacAddress uploadDstMac,
+            @NonNull final InetAddress uploadSrcIp, @NonNull final InetAddress uploadDstIp,
+            @NonNull final InetAddress downloadSrcIp, @NonNull final InetAddress downloadDstIp,
+            @NonNull final TetheringTester tester) throws Exception {
         // Three way handshake and data transfer.
         //
         // Server (base seq = 2000)                                  Client (base seq = 1000)
@@ -1873,24 +1873,26 @@
         // This test can only verify the packets are transferred end to end but TCP state.
         // TODO: verify TCP state change via /proc/net/nf_conntrack or netlink conntrack event.
         // [1] [UPLOAD] [SYN]: SEQ = 1000
-        sendUploadPacketTcp(srcMac, dstMac, clientIp, remoteIp, (short) 1000 /* seq */,
-                (short) 0 /* ack */, TCPHDR_SYN, EMPTY_PAYLOAD, tester);
+        sendUploadPacketTcp(uploadSrcMac, uploadDstMac, uploadSrcIp, uploadDstIp,
+                (short) 1000 /* seq */, (short) 0 /* ack */, TCPHDR_SYN, EMPTY_PAYLOAD,
+                tester);
 
         // [2] [DONWLOAD] [SYN + ACK]: SEQ = 2000, ACK = 1001
-        sendDownloadPacketTcp(remoteIp, tetheringUpstreamIp, (short) 2000 /* seq */,
-                (short) 1001 /* ack */, (byte) ((TCPHDR_SYN | TCPHDR_ACK) & 0xff),
-                EMPTY_PAYLOAD, tester);
+        sendDownloadPacketTcp(downloadSrcIp, downloadDstIp, (short) 2000 /* seq */,
+                (short) 1001 /* ack */, (byte) ((TCPHDR_SYN | TCPHDR_ACK) & 0xff), EMPTY_PAYLOAD,
+                tester);
 
         // [3] [UPLOAD] [ACK]: SEQ = 1001, ACK = 2001
-        sendUploadPacketTcp(srcMac, dstMac, clientIp, remoteIp, (short) 1001 /* seq */,
-                (short) 2001 /* ack */, TCPHDR_ACK, EMPTY_PAYLOAD, tester);
+        sendUploadPacketTcp(uploadSrcMac, uploadDstMac, uploadSrcIp, uploadDstIp,
+                (short) 1001 /* seq */, (short) 2001 /* ack */, TCPHDR_ACK, EMPTY_PAYLOAD, tester);
 
         // [4] [UPLOAD] [ACK]: SEQ = 1001, ACK = 2001, 2 byte payload
-        sendUploadPacketTcp(srcMac, dstMac, clientIp, remoteIp, (short) 1001 /* seq */,
-                (short) 2001 /* ack */, TCPHDR_ACK, TX_PAYLOAD, tester);
+        sendUploadPacketTcp(uploadSrcMac, uploadDstMac, uploadSrcIp, uploadDstIp,
+                (short) 1001 /* seq */, (short) 2001 /* ack */, TCPHDR_ACK, TX_PAYLOAD,
+                tester);
 
         // [5] [DONWLOAD] [ACK]: SEQ = 2001, ACK = 1003, 2 byte payload
-        sendDownloadPacketTcp(remoteIp, tetheringUpstreamIp, (short) 2001 /* seq */,
+        sendDownloadPacketTcp(downloadSrcIp, downloadDstIp, (short) 2001 /* seq */,
                 (short) 1003 /* ack */, TCPHDR_ACK, RX_PAYLOAD, tester);
     }
 
@@ -1904,10 +1906,22 @@
         // See the same reason in runUdp4Test().
         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
 
-        runTcpTest(tethered.macAddr /* srcMac */, tethered.routerMacAddr /* dstMac */,
-                REMOTE_IP4_ADDR /* remoteIp */,
-                TEST_IP4_ADDR.getAddress() /* tetheringUpstreamIp */,
-                tethered.ipv4Addr /* clientIp */, tester);
+        runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
+                tethered.ipv4Addr /* uploadSrcIp */, REMOTE_IP4_ADDR /* uploadDstIp */,
+                REMOTE_IP4_ADDR /* downloadSrcIp */, TEST_IP4_ADDR.getAddress() /* downloadDstIp */,
+                tester);
+    }
+
+    @Test
+    public void testTetherTcpV6() throws Exception {
+        final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
+                toList(TEST_IP6_DNS));
+        final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
+
+        runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
+                tethered.ipv6Addr /* uploadSrcIp */, REMOTE_IP6_ADDR /* uploadDstIp */,
+                REMOTE_IP6_ADDR /* downloadSrcIp */, tethered.ipv6Addr /* downloadDstIp */,
+                tester);
     }
 
     private <T> List<T> toList(T... array) {