Merge "Revert "Add unit tests for IKEv2 VPN setup and MOBIKE""
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 237a645..c3a7a6d 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -26,8 +26,8 @@
 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
 import static android.net.TetheringManager.TETHERING_ETHERNET;
-import static android.net.TetheringTester.RemoteResponder;
-import static android.net.TetheringTester.isIcmpv6Type;
+import static android.net.TetheringTester.isExpectedIcmpv6Packet;
+import static android.net.TetheringTester.isExpectedUdpPacket;
 import static android.system.OsConstants.IPPROTO_IP;
 import static android.system.OsConstants.IPPROTO_IPV6;
 import static android.system.OsConstants.IPPROTO_UDP;
@@ -83,10 +83,7 @@
 import com.android.net.module.util.bpf.Tether4Value;
 import com.android.net.module.util.bpf.TetherStatsKey;
 import com.android.net.module.util.bpf.TetherStatsValue;
-import com.android.net.module.util.structs.EthernetHeader;
-import com.android.net.module.util.structs.Ipv4Header;
 import com.android.net.module.util.structs.Ipv6Header;
-import com.android.net.module.util.structs.UdpHeader;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -333,7 +330,7 @@
         final long deadline = SystemClock.uptimeMillis() + timeoutMs;
         do {
             byte[] pkt = reader.popPacket(timeoutMs);
-            if (isIcmpv6Type(pkt, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return;
+            if (isExpectedIcmpv6Packet(pkt, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return;
 
             timeoutMs = deadline - SystemClock.uptimeMillis();
         } while (timeoutMs > 0);
@@ -793,61 +790,28 @@
 
     @Test
     public void testIcmpv6Echo() throws Exception {
-        assumeFalse(mEm.isAvailable());
-
-        // MyTetheringEventCallback currently only support await first available upstream. Tethering
-        // may select internet network as upstream if test network is not available and not be
-        // preferred yet. Create test upstream network before enable tethering.
-        mUpstreamTracker = createTestUpstream(toList(TEST_IP4_ADDR, TEST_IP6_ADDR),
-                toList(TEST_IP4_DNS, TEST_IP6_DNS));
-
-        mDownstreamIface = createTestInterface();
-        mEm.setIncludeTestInterfaces(true);
-
-        final String iface = mTetheredInterfaceRequester.getInterface();
-        assertEquals("TetheredInterfaceCallback for unexpected interface",
-                mDownstreamIface.getInterfaceName(), iface);
-
-        mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
-                mUpstreamTracker.getNetwork());
-        assertEquals("onUpstreamChanged for unexpected network", mUpstreamTracker.getNetwork(),
-                mTetheringEventCallback.awaitUpstreamChanged());
-
-        mDownstreamReader = makePacketReader(mDownstreamIface);
-        mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
-
-        runPing6Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader));
+        runPing6Test(initTetheringTester(toList(TEST_IP4_ADDR, TEST_IP6_ADDR),
+                toList(TEST_IP4_DNS, TEST_IP6_DNS)));
     }
 
-    private void runPing6Test(TetheringTester tester, RemoteResponder remote) throws Exception {
-        // Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
-        // TetheringTester test ipv6 tethering connectivity before testing ipv6.
-        // TODO: move to a common place to avoid that every IPv6 test needs to call this function.
-        tester.waitForIpv6TetherConnectivityVerified();
-
+    private void runPing6Test(TetheringTester tester) throws Exception {
         TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString("1:2:3:4:5:6"),
                 true /* hasIpv6 */);
         Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
         ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr,
                 tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr);
-        tester.sendPacket(request);
-
-        final byte[] echoRequest = remote.getNextMatchedPacket((p) -> {
+        tester.verifyUpload(request, p -> {
             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
 
-            return isIcmpv6Type(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
+            return isExpectedIcmpv6Packet(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
         });
-        assertNotNull("No icmpv6 echo request in upstream", echoRequest);
 
         ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
-        remote.sendPacket(reply);
-
-        final byte[] echoReply = tester.getNextMatchedPacket((p) -> {
+        tester.verifyDownload(reply, p -> {
             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
 
-            return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
+            return isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
         });
-        assertNotNull("No icmpv6 echo reply in downstream", echoReply);
     }
 
     // Test network topology:
@@ -879,28 +843,6 @@
     private static final ByteBuffer PAYLOAD3 =
             ByteBuffer.wrap(new byte[] { (byte) 0x9a, (byte) 0xbc });
 
-    private boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEther,
-            boolean isIpv4, @NonNull final ByteBuffer payload) {
-        final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
-
-        if (hasEther) {
-            if (Struct.parse(EthernetHeader.class, buf) == null) return false;
-        }
-
-        if (isIpv4) {
-            if (Struct.parse(Ipv4Header.class, buf) == null) return false;
-        } else {
-            if (Struct.parse(Ipv6Header.class, buf) == null) return false;
-        }
-
-        if (Struct.parse(UdpHeader.class, buf) == null) return false;
-
-        if (buf.remaining() != payload.limit()) return false;
-
-        return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
-                payload.array());
-    }
-
     @NonNull
     private ByteBuffer buildUdpPacket(
             @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
@@ -964,7 +906,7 @@
     // TODO: remove this verification once upstream connected notification race is fixed.
     // See #runUdp4Test.
     private boolean isIpv4TetherConnectivityVerified(TetheringTester tester,
-            RemoteResponder remote, TetheredDevice tethered) throws Exception {
+            TetheredDevice tethered) throws Exception {
         final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
                 tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
                 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
@@ -972,8 +914,7 @@
 
         // Send a UDP packet from client and check the packet can be found on upstream interface.
         for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
-            tester.sendPacket(probePacket);
-            byte[] expectedPacket = remote.getNextMatchedPacket(p -> {
+            byte[] expectedPacket = tester.testUpload(probePacket, p -> {
                 Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
                 return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */,
                         TEST_REACHABILITY_PAYLOAD);
@@ -983,8 +924,7 @@
         return false;
     }
 
-    private void runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf)
-            throws Exception {
+    private void runUdp4Test(TetheringTester tester, boolean usingBpf) throws Exception {
         final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
                 "1:2:3:4:5:6"), false /* hasIpv6 */);
 
@@ -994,14 +934,14 @@
         // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
         // from upstream. That can guarantee that the routing is ready. Long term plan is that
         // refactors upstream connected notification from async to sync.
-        assertTrue(isIpv4TetherConnectivityVerified(tester, remote, tethered));
+        assertTrue(isIpv4TetherConnectivityVerified(tester, tethered));
 
         // Send a UDP packet in original direction.
         final ByteBuffer originalPacket = buildUdpPacket(tethered.macAddr,
                 tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
                 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
                 PAYLOAD /* payload */);
-        tester.verifyUpload(remote, originalPacket, p -> {
+        tester.verifyUpload(originalPacket, p -> {
             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
             return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
         });
@@ -1011,7 +951,7 @@
         final ByteBuffer replyPacket = buildUdpPacket(REMOTE_IP4_ADDR /* srcIp */,
                 publicIp4Addr /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
                 PAYLOAD2 /* payload */);
-        remote.verifyDownload(tester, replyPacket, p -> {
+        tester.verifyDownload(replyPacket, p -> {
             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
             return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
         });
@@ -1030,7 +970,7 @@
                     tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
                     REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */,
                     REMOTE_PORT /* dstPort */, PAYLOAD3 /* payload */);
-            tester.verifyUpload(remote, originalPacket2, p -> {
+            tester.verifyUpload(originalPacket2, p -> {
                 Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
                 return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD3);
             });
@@ -1066,7 +1006,7 @@
 
             // Send packets on original direction.
             for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
-                tester.verifyUpload(remote, originalPacket, p -> {
+                tester.verifyUpload(originalPacket, p -> {
                     Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
                     return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
                 });
@@ -1074,7 +1014,7 @@
 
             // Send packets on reply direction.
             for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
-                remote.verifyDownload(tester, replyPacket, p -> {
+                tester.verifyDownload(replyPacket, p -> {
                     Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
                     return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
                 });
@@ -1101,8 +1041,8 @@
         }
     }
 
-    void initializeTethering(List<LinkAddress> upstreamAddresses, List<InetAddress> upstreamDnses)
-            throws Exception {
+    private TetheringTester initTetheringTester(List<LinkAddress> upstreamAddresses,
+            List<InetAddress> upstreamDnses) throws Exception {
         assumeFalse(mEm.isAvailable());
 
         // MyTetheringEventCallback currently only support await first available upstream. Tethering
@@ -1113,9 +1053,9 @@
         mDownstreamIface = createTestInterface();
         mEm.setIncludeTestInterfaces(true);
 
-        final String iface = mTetheredInterfaceRequester.getInterface();
+        // Make sure EtherentTracker use "mDownstreamIface" as server mode interface.
         assertEquals("TetheredInterfaceCallback for unexpected interface",
-                mDownstreamIface.getInterfaceName(), iface);
+                mDownstreamIface.getInterfaceName(), mTetheredInterfaceRequester.getInterface());
 
         mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
                 mUpstreamTracker.getNetwork());
@@ -1124,13 +1064,22 @@
 
         mDownstreamReader = makePacketReader(mDownstreamIface);
         mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
+
+        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        // Currently tethering don't have API to tell when ipv6 tethering is available. Thus, make
+        // sure tethering already have ipv6 connectivity before testing.
+        if (cm.getLinkProperties(mUpstreamTracker.getNetwork()).hasGlobalIpv6Address()) {
+            waitForRouterAdvertisement(mDownstreamReader, mDownstreamIface.getInterfaceName(),
+                    WAIT_RA_TIMEOUT_MS);
+        }
+
+        return new TetheringTester(mDownstreamReader, mUpstreamReader);
     }
 
     @Test
     @IgnoreAfter(Build.VERSION_CODES.R)
     public void testTetherUdpV4UpToR() throws Exception {
-        initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS));
-        runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
+        runUdp4Test(initTetheringTester(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS)),
                 false /* usingBpf */);
     }
 
@@ -1165,15 +1114,13 @@
     @Test
     @IgnoreUpTo(Build.VERSION_CODES.R)
     public void testTetherUdpV4AfterR() throws Exception {
-        initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS));
         final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
         boolean usingBpf = isUdpOffloadSupportedByKernel(kernelVersion);
         if (!usingBpf) {
             Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
                     + kernelVersion);
         }
-        runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
-                usingBpf);
+        runUdp4Test(initTetheringTester(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS)), usingBpf);
     }
 
     @Nullable
@@ -1233,8 +1180,8 @@
     }
 
     @Nullable
-    private Inet6Address getClatIpv6Address(TetheringTester tester,
-            RemoteResponder remote, TetheredDevice tethered) throws Exception {
+    private Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered)
+            throws Exception {
         final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
                 tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
                 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
@@ -1245,8 +1192,7 @@
         // packet.
         byte[] expectedPacket = null;
         for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
-            tester.sendPacket(probePacket);
-            expectedPacket = remote.getNextMatchedPacket(p -> {
+            expectedPacket = tester.verifyUpload(probePacket, p -> {
                 Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
                 return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */,
                         TEST_REACHABILITY_PAYLOAD);
@@ -1275,18 +1221,12 @@
     // sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
     // packet.
     //
-    private void runClatUdpTest(TetheringTester tester, RemoteResponder remote)
-            throws Exception {
-        // Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
-        // TetheringTester test ipv6 tethering connectivity before testing ipv6.
-        // TODO: move to a common place to avoid that every IPv6 test needs to call this function.
-        tester.waitForIpv6TetherConnectivityVerified();
-
+    private void runClatUdpTest(TetheringTester tester) throws Exception {
         final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
                 "1:2:3:4:5:6"), true /* hasIpv6 */);
 
         // Get CLAT IPv6 address.
-        final Inet6Address clatAddr6 = getClatIpv6Address(tester, remote, tethered);
+        final Inet6Address clatAddr6 = getClatIpv6Address(tester, tethered);
         assertNotNull(clatAddr6);
 
         // Send an IPv4 UDP packet in original direction.
@@ -1295,7 +1235,7 @@
                 tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
                 REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
                 PAYLOAD /* payload */);
-        tester.verifyUpload(remote, originalPacket, p -> {
+        tester.verifyUpload(originalPacket, p -> {
             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
             return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */, PAYLOAD);
         });
@@ -1305,7 +1245,7 @@
         final ByteBuffer replyPacket = buildUdpPacket(REMOTE_NAT64_ADDR /* srcIp */,
                 clatAddr6 /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
                 PAYLOAD2 /* payload */);
-        remote.verifyDownload(tester, replyPacket, p -> {
+        tester.verifyDownload(replyPacket, p -> {
             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
             return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
         });
@@ -1317,9 +1257,7 @@
     @IgnoreUpTo(Build.VERSION_CODES.R)
     public void testTetherClatUdp() throws Exception {
         // CLAT only starts on IPv6 only network.
-        initializeTethering(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS));
-        runClatUdpTest(new TetheringTester(mDownstreamReader),
-                new RemoteResponder(mUpstreamReader));
+        runClatUdpTest(initTetheringTester(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS)));
     }
 
     private <T> List<T> toList(T... array) {
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/src/android/net/TetheringTester.java
index 458680a..4d90d39 100644
--- a/Tethering/tests/integration/src/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/src/android/net/TetheringTester.java
@@ -18,11 +18,13 @@
 
 import static android.net.InetAddresses.parseNumericAddress;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_UDP;
 
 import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
 import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
 import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
@@ -42,17 +44,20 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.net.module.util.Ipv6Utils;
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.structs.EthernetHeader;
 import com.android.net.module.util.structs.Icmpv6Header;
+import com.android.net.module.util.structs.Ipv4Header;
 import com.android.net.module.util.structs.Ipv6Header;
 import com.android.net.module.util.structs.LlaOption;
 import com.android.net.module.util.structs.NsHeader;
 import com.android.net.module.util.structs.PrefixInformationOption;
 import com.android.net.module.util.structs.RaHeader;
+import com.android.net.module.util.structs.UdpHeader;
 import com.android.networkstack.arp.ArpPacket;
 import com.android.testutils.TapPacketReader;
 
@@ -61,6 +66,7 @@
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 import java.util.concurrent.TimeoutException;
@@ -88,11 +94,17 @@
 
     private final ArrayMap<MacAddress, TetheredDevice> mTetheredDevices;
     private final TapPacketReader mDownstreamReader;
+    private final TapPacketReader mUpstreamReader;
 
     public TetheringTester(TapPacketReader downstream) {
+        this(downstream, null);
+    }
+
+    public TetheringTester(TapPacketReader downstream, TapPacketReader upstream) {
         if (downstream == null) fail("Downstream reader could not be NULL");
 
         mDownstreamReader = downstream;
+        mUpstreamReader = upstream;
         mTetheredDevices = new ArrayMap<>();
     }
 
@@ -170,7 +182,7 @@
     }
 
     private DhcpPacket getNextDhcpPacket() throws Exception {
-        final byte[] packet = getNextMatchedPacket((p) -> {
+        final byte[] packet = getDownloadPacket((p) -> {
             // Test whether this is DHCP packet.
             try {
                 DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
@@ -213,7 +225,7 @@
                     tethered.ipv4Addr.getAddress() /* sender IP */,
                     (short) ARP_REPLY);
             try {
-                sendPacket(arpReply);
+                sendUploadPacket(arpReply);
             } catch (Exception e) {
                 fail("Failed to reply ARP for " + tethered.ipv4Addr);
             }
@@ -227,9 +239,9 @@
                 tetherMac.toByteArray() /* srcMac */, routerIp.getAddress() /* target IP */,
                 new byte[ETHER_ADDR_LEN] /* target HW address */,
                 tetherIp.getAddress() /* sender IP */, (short) ARP_REQUEST);
-        sendPacket(arpProbe);
+        sendUploadPacket(arpProbe);
 
-        final byte[] packet = getNextMatchedPacket((p) -> {
+        final byte[] packet = getDownloadPacket((p) -> {
             final ArpPacket arpPacket = parseArpPacket(p);
             if (arpPacket == null || arpPacket.opCode != ARP_REPLY) return false;
             return arpPacket.targetIp.equals(tetherIp);
@@ -245,25 +257,11 @@
         return null;
     }
 
-    public void waitForIpv6TetherConnectivityVerified() throws Exception {
-        Log.d(TAG, "Waiting RA multicast");
-
-        // Wait for RA multicast message from router to confirm that the IPv6 tethering
-        // connectivity is ready. We don't extract the router mac address from RA because
-        // we get the router mac address from IPv4 ARP packet. See #getRouterMacAddressFromArp.
-        for (int i = 0; i < READ_RA_ATTEMPTS; i++) {
-            final byte[] raPacket = getNextMatchedPacket((p) -> {
-                return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
-            });
-            if (raPacket != null) return;
-        }
-
-        fail("Could not get RA multicast packet after " + READ_RA_ATTEMPTS + " attempts");
-    }
-
     private List<PrefixInformationOption> getRaPrefixOptions(byte[] packet) {
         ByteBuffer buf = ByteBuffer.wrap(packet);
-        if (!isIcmpv6Type(buf, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return null;
+        if (!isExpectedIcmpv6Packet(buf, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) {
+            fail("Parsing RA packet fail");
+        }
 
         Struct.parse(RaHeader.class, buf);
         final ArrayList<PrefixInformationOption> pioList = new ArrayList<>();
@@ -290,13 +288,10 @@
     private Inet6Address runSlaac(MacAddress srcMac, MacAddress dstMac) throws Exception {
         sendRsPacket(srcMac, dstMac);
 
-        final byte[] raPacket = getNextMatchedPacket((p) -> {
-            return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
-        });
+        final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> {
+            return isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
+        }));
 
-        if (raPacket == null) {
-            fail("Could not get ra for prefix options");
-        }
         final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
 
         for (PrefixInformationOption pio : options) {
@@ -312,7 +307,7 @@
             }
         }
 
-        fail("Could not get ipv6 address");
+        fail("No available ipv6 prefix");
         return null;
     }
 
@@ -322,7 +317,7 @@
         ByteBuffer rs = Ipv6Utils.buildRsPacket(srcMac, dstMac, (Inet6Address) LINK_LOCAL,
                 IPV6_ADDR_ALL_NODES_MULTICAST, slla);
 
-        sendPacket(rs);
+        sendUploadPacket(rs);
     }
 
     private void maybeReplyNa(byte[] packet) {
@@ -347,7 +342,7 @@
             ByteBuffer ns = Ipv6Utils.buildNaPacket(tethered.macAddr, tethered.routerMacAddr,
                     nsHdr.target, ipv6Hdr.srcIp, flags, nsHdr.target, tlla);
             try {
-                sendPacket(ns);
+                sendUploadPacket(ns);
             } catch (Exception e) {
                 fail("Failed to reply NA for " + tethered.ipv6Addr);
             }
@@ -356,23 +351,18 @@
         }
     }
 
-    public static boolean isIcmpv6Type(byte[] packet, boolean hasEth, int type) {
+    public static boolean isExpectedIcmpv6Packet(byte[] packet, boolean hasEth, int type) {
         final ByteBuffer buf = ByteBuffer.wrap(packet);
-        return isIcmpv6Type(buf, hasEth, type);
+        return isExpectedIcmpv6Packet(buf, hasEth, type);
     }
 
-    private static boolean isIcmpv6Type(ByteBuffer buf, boolean hasEth, int type) {
+    private static boolean isExpectedIcmpv6Packet(ByteBuffer buf, boolean hasEth, int type) {
         try {
-            if (hasEth) {
-                final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf);
-                if (ethHdr.etherType != ETHER_TYPE_IPV6) return false;
-            }
+            if (hasEth && !hasExpectedEtherHeader(buf, false /* isIpv4 */)) return false;
 
-            final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf);
-            if (ipv6Hdr.nextHeader != (byte) IPPROTO_ICMPV6) return false;
+            if (!hasExpectedIpHeader(buf, false /* isIpv4 */, IPPROTO_ICMPV6)) return false;
 
-            final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, buf);
-            return icmpv6Hdr.type == (short) type;
+            return Struct.parse(Icmpv6Header.class, buf).type == (short) type;
         } catch (Exception e) {
             // Parsing packet fail means it is not icmpv6 packet.
         }
@@ -380,11 +370,53 @@
         return false;
     }
 
-    public void sendPacket(ByteBuffer packet) throws Exception {
+    private static boolean hasExpectedEtherHeader(@NonNull final ByteBuffer buf, boolean isIpv4)
+            throws Exception {
+        final int expected = isIpv4 ? ETHER_TYPE_IPV4 : ETHER_TYPE_IPV6;
+
+        return Struct.parse(EthernetHeader.class, buf).etherType == expected;
+    }
+
+    private static boolean hasExpectedIpHeader(@NonNull final ByteBuffer buf, boolean isIpv4,
+            int ipProto) throws Exception {
+        if (isIpv4) {
+            return Struct.parse(Ipv4Header.class, buf).protocol == (byte) ipProto;
+        } else {
+            return Struct.parse(Ipv6Header.class, buf).nextHeader == (byte) ipProto;
+        }
+    }
+
+    public static boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEth,
+            boolean isIpv4, @NonNull final ByteBuffer payload) {
+        final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
+        try {
+            if (hasEth && !hasExpectedEtherHeader(buf, isIpv4)) return false;
+
+            if (!hasExpectedIpHeader(buf, isIpv4, IPPROTO_UDP)) return false;
+
+            if (Struct.parse(UdpHeader.class, buf) == null) return false;
+        } catch (Exception e) {
+            // Parsing packet fail means it is not udp packet.
+            return false;
+        }
+
+        if (buf.remaining() != payload.limit()) return false;
+
+        return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
+                payload.array());
+    }
+
+    private void sendUploadPacket(ByteBuffer packet) throws Exception {
         mDownstreamReader.sendResponse(packet);
     }
 
-    public byte[] getNextMatchedPacket(Predicate<byte[]> filter) {
+    private void sendDownloadPacket(ByteBuffer packet) throws Exception {
+        assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader);
+
+        mUpstreamReader.sendResponse(packet);
+    }
+
+    private byte[] getDownloadPacket(Predicate<byte[]> filter) {
         byte[] packet;
         while ((packet = mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS)) != null) {
             if (filter.test(packet)) return packet;
@@ -396,30 +428,34 @@
         return null;
     }
 
-    public void verifyUpload(final RemoteResponder dst, final ByteBuffer packet,
-            final Predicate<byte[]> filter) throws Exception {
-        sendPacket(packet);
-        assertNotNull("Upload fail", dst.getNextMatchedPacket(filter));
+    private byte[] getUploadPacket(Predicate<byte[]> filter) {
+        assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader);
+
+        return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
     }
 
-    public static class RemoteResponder {
-        final TapPacketReader mUpstreamReader;
-        public RemoteResponder(TapPacketReader reader) {
-            mUpstreamReader = reader;
-        }
+    private @NonNull byte[] verifyPacketNotNull(String message, @Nullable byte[] packet) {
+        assertNotNull(message, packet);
 
-        public void sendPacket(ByteBuffer packet) throws Exception {
-            mUpstreamReader.sendResponse(packet);
-        }
+        return packet;
+    }
 
-        public byte[] getNextMatchedPacket(Predicate<byte[]> filter) throws Exception {
-            return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
-        }
+    public byte[] testUpload(final ByteBuffer packet, final Predicate<byte[]> filter)
+            throws Exception {
+        sendUploadPacket(packet);
 
-        public void verifyDownload(final TetheringTester dst, final ByteBuffer packet,
-                final Predicate<byte[]> filter) throws Exception {
-            sendPacket(packet);
-            assertNotNull("Download fail", dst.getNextMatchedPacket(filter));
-        }
+        return getUploadPacket(filter);
+    }
+
+    public byte[] verifyUpload(final ByteBuffer packet, final Predicate<byte[]> filter)
+            throws Exception {
+        return verifyPacketNotNull("Upload fail", testUpload(packet, filter));
+    }
+
+    public byte[] verifyDownload(final ByteBuffer packet, final Predicate<byte[]> filter)
+            throws Exception {
+        sendDownloadPacket(packet);
+
+        return verifyPacketNotNull("Download fail", getDownloadPacket(filter));
     }
 }
diff --git a/framework/Android.bp b/framework/Android.bp
index d7de439..24d8cca 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -64,7 +64,6 @@
         ":framework-connectivity-sources",
         ":net-utils-framework-common-srcs",
         ":framework-connectivity-api-shared-srcs",
-        ":framework-connectivity-javastream-protos",
     ],
     aidl: {
         generate_get_transaction_name: true,
@@ -90,6 +89,7 @@
         "modules-utils-backgroundthread",
         "modules-utils-build",
         "modules-utils-preconditions",
+        "framework-connectivity-javastream-protos",
     ],
     libs: [
         "app-compat-annotations",
@@ -197,28 +197,16 @@
     visibility: ["//frameworks/base"],
 }
 
-gensrcs {
+java_library {
     name: "framework-connectivity-javastream-protos",
-    depfile: true,
-
-    tools: [
-        "aprotoc",
-        "protoc-gen-javastream",
-        "soong_zip",
+    proto: {
+        type: "stream",
+    },
+    srcs: [":framework-connectivity-protos"],
+    installable: false,
+    sdk_version: "module_current",
+    min_sdk_version: "30",
+    apex_available: [
+        "com.android.tethering",
     ],
-
-    cmd: "mkdir -p $(genDir)/$(in) " +
-        "&& $(location aprotoc) " +
-        "  --plugin=$(location protoc-gen-javastream) " +
-        "  --dependency_out=$(depfile) " +
-        "  --javastream_out=$(genDir)/$(in) " +
-        "  -Iexternal/protobuf/src " +
-        "  -I . " +
-        "  $(in) " +
-        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
-    srcs: [
-        ":framework-connectivity-protos",
-    ],
-    output_extension: "srcjar",
 }
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index ddac19d..4ce6add 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -51,6 +51,9 @@
     field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
     field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
     field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5
+    field public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7; // 0x7
+    field public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8; // 0x8
+    field public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9; // 0x9
     field public static final int FIREWALL_CHAIN_POWERSAVE = 3; // 0x3
     field public static final int FIREWALL_CHAIN_RESTRICTED = 4; // 0x4
     field public static final int FIREWALL_CHAIN_STANDBY = 2; // 0x2
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 5769b92..1b0578f 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -997,6 +997,7 @@
      * Denylist of apps that will not have network access due to OEM-specific restrictions.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7;
 
     /**
@@ -1004,6 +1005,7 @@
      * Denylist of apps that will not have network access due to OEM-specific restrictions.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8;
 
     /**
@@ -1011,6 +1013,7 @@
      * Denylist of apps that will not have network access due to OEM-specific restrictions.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9;
 
     /** @hide */
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 2eabc26..0134dea 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -262,37 +262,6 @@
         EXPECT_TRUE(mTc.mPrivilegedUser.empty());
     }
 
-    void addPrivilegedUid(uid_t uid) {
-        std::vector privilegedUid = {uid};
-        mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, privilegedUid);
-    }
-
-    void removePrivilegedUid(uid_t uid) {
-        std::vector privilegedUid = {uid};
-        mTc.setPermissionForUids(INetd::PERMISSION_NONE, privilegedUid);
-    }
-
-    void expectFakeStatsUnchanged(uint64_t cookie, uint32_t tag, uint32_t uid,
-                                  StatsKey tagStatsMapKey) {
-        Result<UidTagValue> cookieMapResult = mFakeCookieTagMap.readValue(cookie);
-        EXPECT_RESULT_OK(cookieMapResult);
-        EXPECT_EQ(uid, cookieMapResult.value().uid);
-        EXPECT_EQ(tag, cookieMapResult.value().tag);
-        Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
-        EXPECT_RESULT_OK(statsMapResult);
-        EXPECT_EQ((uint64_t)RXPACKETS, statsMapResult.value().rxPackets);
-        EXPECT_EQ((uint64_t)RXBYTES, statsMapResult.value().rxBytes);
-        tagStatsMapKey.tag = 0;
-        statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
-        EXPECT_RESULT_OK(statsMapResult);
-        EXPECT_EQ((uint64_t)RXPACKETS, statsMapResult.value().rxPackets);
-        EXPECT_EQ((uint64_t)RXBYTES, statsMapResult.value().rxBytes);
-        auto appStatsResult = mFakeAppUidStatsMap.readValue(uid);
-        EXPECT_RESULT_OK(appStatsResult);
-        EXPECT_EQ((uint64_t)RXPACKETS, appStatsResult.value().rxPackets);
-        EXPECT_EQ((uint64_t)RXBYTES, appStatsResult.value().rxBytes);
-    }
-
     Status updateUidOwnerMaps(const std::vector<uint32_t>& appUids,
                               UidOwnerMatchType matchType, TrafficController::IptOp op) {
         Status ret(0);
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index ea89be6..498cf63 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -596,7 +596,6 @@
         try {
             mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
         } catch (RemoteException | ServiceSpecificException e) {
-            maybeCleanUp(tunFd, readSock6, writeSock6);
             Log.e(TAG, "Disable IPv6 on " + tunIface + " failed: " + e);
         }
 
diff --git a/tests/common/java/android/net/LinkPropertiesTest.java b/tests/common/java/android/net/LinkPropertiesTest.java
index 581ee22..9ed2bb3 100644
--- a/tests/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/common/java/android/net/LinkPropertiesTest.java
@@ -20,7 +20,6 @@
 import static android.net.RouteInfo.RTN_UNICAST;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 
-import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
 import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
 import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
 
@@ -53,6 +52,7 @@
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
 import java.net.Inet4Address;
@@ -68,11 +68,13 @@
 @SmallTest
 @ConnectivityModuleTest
 public class LinkPropertiesTest {
+    // Use a RuleChain to explicitly specify the order of rules. DevSdkIgnoreRule must run before
+    // PlatformCompatChange rule, because otherwise tests with that should be skipped when targeting
+    // target SDK 33 will still attempt to override compat changes (which on user builds will crash)
+    // before being skipped.
     @Rule
-    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
-    @Rule
-    public final PlatformCompatChangeRule compatChangeRule = new PlatformCompatChangeRule();
+    public final RuleChain chain = RuleChain.outerRule(
+            new DevSdkIgnoreRule()).around(new PlatformCompatChangeRule());
 
     private static final InetAddress ADDRV4 = address("75.208.6.1");
     private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
@@ -1262,7 +1264,8 @@
         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
     @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
     public void testHasExcludeRoute() {
         LinkProperties lp = new LinkProperties();
@@ -1274,7 +1277,8 @@
         assertTrue(lp.hasExcludeRoute());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
     @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
     public void testRouteAddWithSameKey() throws Exception {
         LinkProperties lp = new LinkProperties();
@@ -1291,7 +1295,8 @@
         assertEquals(2, lp.getRoutes().size());
     }
 
-    @Test @IgnoreUpTo(SC_V2)
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
     @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
     public void testExcludedRoutesEnabled() {
         final LinkProperties lp = new LinkProperties();
@@ -1307,8 +1312,8 @@
         assertEquals(3, lp.getRoutes().size());
     }
 
-    @Test @IgnoreUpTo(SC_V2)
-    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden on T or above")
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
     @DisableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
     public void testExcludedRoutesDisabled() {
         final LinkProperties lp = new LinkProperties();
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 6dfadc7..bd1b74a 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -26,13 +26,8 @@
 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
 import static android.net.cts.util.CtsTetheringUtils.isAnyIfaceMatch;
 
-import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL;
-import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -73,19 +68,14 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.TestCarrierConfigReceiver;
-
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -94,9 +84,6 @@
 @RunWith(AndroidJUnit4.class)
 public class TetheringManagerTest {
 
-    @Rule
-    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
     private Context mContext;
 
     private ConnectivityManager mCm;
@@ -405,7 +392,7 @@
         // Override carrier config to ignore entitlement check.
         final PersistableBundle bundle = new PersistableBundle();
         bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false);
-        overrideCarrierConfig(bundle, CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+        overrideCarrierConfig(bundle);
 
         // Verify that requestLatestTetheringEntitlementResult() can get entitlement
         // result TETHER_ERROR_NO_ERROR due to provisioning bypassed.
@@ -413,112 +400,14 @@
                 TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR);
 
         // Reset carrier config.
-        overrideCarrierConfig(null, "");
+        overrideCarrierConfig(null);
     }
 
-    @Test
-    @IgnoreUpTo(SC_V2)
-    public void testEnableTethering_carrierUnsupported_noTetheringActive() throws Exception {
-        assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
-
-        final TestTetheringEventCallback tetherEventCallback =
-                mCtsTetheringUtils.registerTetheringEventCallback();
-        boolean previousWifiEnabledState = false;
-        try {
-            tetherEventCallback.assumeWifiTetheringSupported(mContext);
-            // Avoid device connected to Wifi network.
-            previousWifiEnabledState = ensureCurrentNetworkIsCellular();
-            final PersistableBundle bundle = new PersistableBundle();
-            bundle.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, false);
-            // Override carrier config to make carrier not support.
-            overrideCarrierConfig(bundle, KEY_CARRIER_SUPPORTS_TETHERING_BOOL);
-
-            mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
-
-            mCtsTetheringUtils.expectSoftApDisabled();
-            tetherEventCallback.expectNoTetheringActive();
-        } finally {
-            overrideCarrierConfig(null, "");
-            mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
-            if (previousWifiEnabledState) {
-                mCtsNetUtils.connectToWifi();
-            }
-        }
-    }
-
-    @Test
-    @IgnoreUpTo(SC_V2)
-    public void testEnableTethering_carrierUnsupportByConfigChange_noTetheringActive()
-            throws Exception {
-        assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
-
-        final TestTetheringEventCallback tetherEventCallback =
-                mCtsTetheringUtils.registerTetheringEventCallback();
-        boolean previousWifiEnabledState = false;
-        try {
-            tetherEventCallback.assumeWifiTetheringSupported(mContext);
-            // Avoid device connected to Wifi network.
-            previousWifiEnabledState = ensureCurrentNetworkIsCellular();
-            mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
-
-            final PersistableBundle bundle = new PersistableBundle();
-            bundle.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, false);
-            // Override carrier config to make carrier not support.
-            overrideCarrierConfig(bundle, KEY_CARRIER_SUPPORTS_TETHERING_BOOL);
-
-            mCtsTetheringUtils.expectSoftApDisabled();
-            tetherEventCallback.expectNoTetheringActive();
-        } finally {
-            overrideCarrierConfig(null, "");
-            mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
-            if (previousWifiEnabledState) {
-                mCtsNetUtils.connectToWifi();
-            }
-        }
-    }
-
-    @Test
-    @IgnoreUpTo(SC_V2)
-    public void testRequestLatestEntitlementResult_carrierUnsupported() throws Exception {
-        assumeTrue(mTM.isTetheringSupported());
-        assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
-
-        final PersistableBundle bundle = new PersistableBundle();
-        bundle.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, false);
-        try {
-            // Override carrier config to make carrier not support.
-            overrideCarrierConfig(bundle, KEY_CARRIER_SUPPORTS_TETHERING_BOOL);
-
-            // Verify that requestLatestTetheringEntitlementResult() can get entitlement
-            // result TETHER_ERROR_PROVISIONING_FAILED due to carrier unsupported
-            assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
-                    TETHERING_WIFI,
-                    false,
-                    c -> c.run(),
-                    listener),
-                    TETHER_ERROR_PROVISIONING_FAILED);
-        } finally {
-            // Reset carrier config.
-            overrideCarrierConfig(null, "");
-        }
-    }
-
-    private void overrideCarrierConfig(PersistableBundle bundle, String configName)
-            throws Exception {
-        final int timeoutMs = 5_000;
-        final int currentSubId = SubscriptionManager.getDefaultSubscriptionId();
-        TestCarrierConfigReceiver configListener =
-                new TestCarrierConfigReceiver(mContext, currentSubId, timeoutMs, bundle,
-                        (configs) -> {
-                            if (bundle == null) {
-                                // This is to restore carrier config and means no need to do match.
-                                return true;
-                            }
-                            boolean requestConfigValue = bundle.getBoolean(configName);
-                            boolean receiveConfigValue = configs.getBoolean(configName);
-                            return Objects.equals(receiveConfigValue, requestConfigValue);
-                        });
-        configListener.overrideCarrierConfigForTest();
+    private void overrideCarrierConfig(PersistableBundle bundle) {
+        final CarrierConfigManager configManager = (CarrierConfigManager) mContext
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        final int subId = SubscriptionManager.getDefaultSubscriptionId();
+        configManager.overrideConfig(subId, bundle);
     }
 
     @Test
@@ -532,8 +421,30 @@
         try {
             tetherEventCallback.assumeWifiTetheringSupported(mContext);
             tetherEventCallback.expectNoTetheringActive();
-            // Avoid device connected to Wifi network.
-            previousWifiEnabledState = ensureCurrentNetworkIsCellular();
+
+            previousWifiEnabledState = mWm.isWifiEnabled();
+            if (previousWifiEnabledState) {
+                mCtsNetUtils.ensureWifiDisconnected(null);
+            }
+
+            final TestNetworkCallback networkCallback = new TestNetworkCallback();
+            Network activeNetwork = null;
+            try {
+                mCm.registerDefaultNetworkCallback(networkCallback);
+                activeNetwork = networkCallback.waitForAvailable();
+            } finally {
+                mCm.unregisterNetworkCallback(networkCallback);
+            }
+
+            assertNotNull("No active network. Please ensure the device has working mobile data.",
+                    activeNetwork);
+            final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork);
+
+            // If active nework is ETHERNET, tethering may not use cell network as upstream.
+            assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET));
+
+            assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR));
+
             mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
 
             final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
@@ -553,36 +464,4 @@
             }
         }
     }
-
-    /**
-     * Make sure current network is cellular data.
-     * @return true Previous Wifi state is enabled, false is disabled.
-     */
-    private boolean ensureCurrentNetworkIsCellular() throws Exception {
-        final boolean previousWifiEnabledState = mWm.isWifiEnabled();
-        if (previousWifiEnabledState) {
-            mCtsNetUtils.ensureWifiDisconnected(null);
-        }
-
-        final TestNetworkCallback networkCallback = new TestNetworkCallback();
-        Network activeNetwork = null;
-        try {
-            mCm.registerDefaultNetworkCallback(networkCallback);
-            activeNetwork = networkCallback.waitForAvailable();
-        } finally {
-            mCm.unregisterNetworkCallback(networkCallback);
-        }
-
-        assertNotNull("No active network. Please ensure the device has working mobile data.",
-                activeNetwork);
-
-        final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork);
-
-        // If active nework is ETHERNET, tethering may not use cell network as upstream.
-        assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET));
-
-        assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR));
-
-        return previousWifiEnabledState;
-    }
 }