diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index c2c9fc4e72..da69a8db36 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -67,16 +67,13 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; -import android.app.UiAutomation; import android.content.Context; -import android.content.pm.PackageManager; import android.net.EthernetManager.TetheredInterfaceCallback; import android.net.EthernetManager.TetheredInterfaceRequest; import android.net.TetheringManager.StartTetheringCallback; import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringRequest; import android.net.TetheringTester.TetheredDevice; -import android.net.cts.util.CtsNetUtils; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; @@ -88,7 +85,6 @@ import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; @@ -143,17 +139,12 @@ import java.util.concurrent.TimeoutException; @RunWith(AndroidJUnit4.class) @MediumTest -public class EthernetTetheringTest { +public class EthernetTetheringTest extends EthernetTetheringTestBase { @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); private static final String TAG = EthernetTetheringTest.class.getSimpleName(); - private static final int TIMEOUT_MS = 5000; - // Used to check if any tethering interface is available. Choose 200ms to be request timeout - // because the average interface requested time on cuttlefish@acloud is around 10ms. - // See TetheredInterfaceRequester.getInterface, isInterfaceForTetheringAvailable. - private static final int AVAILABLE_TETHER_IFACE_REQUEST_TIMEOUT_MS = 200; - private static final int TETHER_REACHABILITY_ATTEMPTS = 20; + private static final int DUMP_POLLING_MAX_RETRY = 100; private static final int DUMP_POLLING_INTERVAL_MS = 50; // Kernel treats a confirmed UDP connection which active after two seconds as stream mode. @@ -168,35 +159,14 @@ public class EthernetTetheringTest { // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes. private static final int TX_UDP_PACKET_SIZE = 44; private static final int TX_UDP_PACKET_COUNT = 123; - private static final long WAIT_RA_TIMEOUT_MS = 2000; - - private static final MacAddress TEST_MAC = MacAddress.fromString("1:2:3:4:5:6"); - private static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/24"); - private static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64"); - private static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8"); - private static final InetAddress TEST_IP6_DNS = parseNumericAddress("2001:db8:1::888"); - private static final IpPrefix TEST_NAT64PREFIX = new IpPrefix("64:ff9b::/96"); - private static final Inet6Address REMOTE_NAT64_ADDR = - (Inet6Address) parseNumericAddress("64:ff9b::808:808"); - private static final Inet6Address REMOTE_IP6_ADDR = - (Inet6Address) parseNumericAddress("2002:db8:1::515:ca"); - private static final ByteBuffer TEST_REACHABILITY_PAYLOAD = - ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa }); - private static final ByteBuffer EMPTY_PAYLOAD = ByteBuffer.wrap(new byte[0]); private static final short DNS_PORT = 53; - private static final short WINDOW = (short) 0x2000; - private static final short URGENT_POINTER = 0; private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap"; private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats"; private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4"; private static final String LINE_DELIMITER = "\\n"; - // version=6, traffic class=0x0, flowlabel=0x0; - private static final int VERSION_TRAFFICCLASS_FLOWLABEL = 0x60000000; - private static final short HOP_LIMIT = 0x40; - private static final short ICMPECHO_CODE = 0x0; private static final short ICMPECHO_ID = 0x0; private static final short ICMPECHO_SEQ = 0x0; @@ -261,27 +231,9 @@ public class EthernetTetheringTest { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04 /* Address: 1.2.3.4 */ }; - private final Context mContext = InstrumentationRegistry.getContext(); - private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class); - private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class); - private final PackageManager mPackageManager = mContext.getPackageManager(); - private final CtsNetUtils mCtsNetUtils = new CtsNetUtils(mContext); - - private TestNetworkInterface mDownstreamIface; - private HandlerThread mHandlerThread; - private Handler mHandler; - private TapPacketReader mDownstreamReader; - private TapPacketReader mUpstreamReader; - private TetheredInterfaceRequester mTetheredInterfaceRequester; private MyTetheringEventCallback mTetheringEventCallback; - private UiAutomation mUiAutomation = - InstrumentationRegistry.getInstrumentation().getUiAutomation(); - private boolean mRunTests; - - private TestNetworkTracker mUpstreamTracker; - @Before public void setUp() throws Exception { mHandlerThread = new HandlerThread(getClass().getSimpleName()); @@ -295,6 +247,30 @@ public class EthernetTetheringTest { mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm); } + private void maybeStopTapPacketReader(final TapPacketReader tapPacketReader) + throws Exception { + if (tapPacketReader != null) { + TapPacketReader reader = tapPacketReader; + mHandler.post(() -> reader.stop()); + } + } + + private void maybeCloseTestInterface(final TestNetworkInterface testInterface) + throws Exception { + if (testInterface != null) { + testInterface.getFileDescriptor().close(); + Log.d(TAG, "Deleted test interface " + testInterface.getInterfaceName()); + } + } + + private void maybeUnregisterTetheringEventCallback(final MyTetheringEventCallback callback) + throws Exception { + if (callback != null) { + callback.awaitInterfaceUntethered(); + callback.unregister(); + } + } + private void cleanUp() throws Exception { setPreferTestNetworks(false); @@ -310,24 +286,19 @@ public class EthernetTetheringTest { mUpstreamReader = null; } - if (mDownstreamReader != null) { - TapPacketReader reader = mDownstreamReader; - mHandler.post(() -> reader.stop()); - mDownstreamReader = null; - } - + maybeStopTapPacketReader(mDownstreamReader); + mDownstreamReader = null; // To avoid flaky which caused by the next test started but the previous interface is not // untracked from EthernetTracker yet. Just delete the test interface without explicitly // calling TetheringManager#stopTethering could let EthernetTracker untrack the test // interface from server mode before tethering stopped. Thus, awaitInterfaceUntethered // could not only make sure tethering is stopped but also guarantee the test interface is // untracked from EthernetTracker. - maybeDeleteTestInterface(); - if (mTetheringEventCallback != null) { - mTetheringEventCallback.awaitInterfaceUntethered(); - mTetheringEventCallback.unregister(); - mTetheringEventCallback = null; - } + maybeCloseTestInterface(mDownstreamIface); + mDownstreamIface = null; + maybeUnregisterTetheringEventCallback(mTetheringEventCallback); + mTetheringEventCallback = null; + runAsShell(NETWORK_SETTINGS, () -> mTetheredInterfaceRequester.release()); setIncludeTestInterfaces(false); } @@ -383,26 +354,50 @@ public class EthernetTetheringTest { }); } + private String getTetheredInterface() throws Exception { + return mTetheredInterfaceRequester.getInterface(); + } + + private CompletableFuture requestTetheredInterface() throws Exception { + return mTetheredInterfaceRequester.requestInterface(); + } + @Test public void testVirtualEthernetAlreadyExists() throws Exception { // This test requires manipulating packets. Skip if there is a physical Ethernet connected. assumeFalse(isInterfaceForTetheringAvailable()); - mDownstreamIface = createTestInterface(); - // This must be done now because as soon as setIncludeTestInterfaces(true) is called, the - // interface will be placed in client mode, which will delete the link-local address. - // At that point NetworkInterface.getByName() will cease to work on the interface, because - // starting in R NetworkInterface can no longer see interfaces without IP addresses. - int mtu = getMTU(mDownstreamIface); + TestNetworkInterface downstreamIface = null; + MyTetheringEventCallback tetheringEventCallback = null; + TapPacketReader downstreamReader = null; - Log.d(TAG, "Including test interfaces"); - setIncludeTestInterfaces(true); + try { + downstreamIface = createTestInterface(); + // This must be done now because as soon as setIncludeTestInterfaces(true) is called, + // the interface will be placed in client mode, which will delete the link-local + // address. At that point NetworkInterface.getByName() will cease to work on the + // interface, because starting in R NetworkInterface can no longer see interfaces + // without IP addresses. + int mtu = getMTU(downstreamIface); - final String iface = mTetheredInterfaceRequester.getInterface(); - assertEquals("TetheredInterfaceCallback for unexpected interface", - mDownstreamIface.getInterfaceName(), iface); + Log.d(TAG, "Including test interfaces"); + setIncludeTestInterfaces(true); - checkVirtualEthernet(mDownstreamIface, mtu); + final String iface = getTetheredInterface(); + assertEquals("TetheredInterfaceCallback for unexpected interface", + downstreamIface.getInterfaceName(), iface); + + // Check virtual ethernet. + FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor(); + downstreamReader = makePacketReader(fd, mtu); + tetheringEventCallback = enableEthernetTethering(downstreamIface.getInterfaceName(), + null /* any upstream */); + checkTetheredClientCallbacks(downstreamReader, tetheringEventCallback); + } finally { + maybeStopTapPacketReader(downstreamReader); + maybeCloseTestInterface(downstreamIface); + maybeUnregisterTetheringEventCallback(tetheringEventCallback); + } } @Test @@ -410,17 +405,32 @@ public class EthernetTetheringTest { // This test requires manipulating packets. Skip if there is a physical Ethernet connected. assumeFalse(isInterfaceForTetheringAvailable()); - CompletableFuture futureIface = mTetheredInterfaceRequester.requestInterface(); + CompletableFuture futureIface = requestTetheredInterface(); setIncludeTestInterfaces(true); - mDownstreamIface = createTestInterface(); + TestNetworkInterface downstreamIface = null; + MyTetheringEventCallback tetheringEventCallback = null; + TapPacketReader downstreamReader = null; - final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - assertEquals("TetheredInterfaceCallback for unexpected interface", - mDownstreamIface.getInterfaceName(), iface); + try { + downstreamIface = createTestInterface(); - checkVirtualEthernet(mDownstreamIface, getMTU(mDownstreamIface)); + final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + assertEquals("TetheredInterfaceCallback for unexpected interface", + downstreamIface.getInterfaceName(), iface); + + // Check virtual ethernet. + FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor(); + downstreamReader = makePacketReader(fd, getMTU(downstreamIface)); + tetheringEventCallback = enableEthernetTethering(downstreamIface.getInterfaceName(), + null /* any upstream */); + checkTetheredClientCallbacks(downstreamReader, tetheringEventCallback); + } finally { + maybeStopTapPacketReader(downstreamReader); + maybeCloseTestInterface(downstreamIface); + maybeUnregisterTetheringEventCallback(tetheringEventCallback); + } } @Test @@ -429,42 +439,51 @@ public class EthernetTetheringTest { setIncludeTestInterfaces(true); - mDownstreamIface = createTestInterface(); - - final String iface = mTetheredInterfaceRequester.getInterface(); - assertEquals("TetheredInterfaceCallback for unexpected interface", - mDownstreamIface.getInterfaceName(), iface); - - assertInvalidStaticIpv4Request(iface, null, null); - assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64"); - assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28"); - assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28"); - assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null); - assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28"); - assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28"); - - final String localAddr = "192.0.2.3/28"; - final String clientAddr = "192.0.2.2/28"; - mTetheringEventCallback = enableEthernetTethering(iface, - requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */); - - mTetheringEventCallback.awaitInterfaceTethered(); - assertInterfaceHasIpAddress(iface, localAddr); - - byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray(); - byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray(); - - FileDescriptor fd = mDownstreamIface.getFileDescriptor().getFileDescriptor(); - mDownstreamReader = makePacketReader(fd, getMTU(mDownstreamIface)); - TetheringTester tester = new TetheringTester(mDownstreamReader); - DhcpResults dhcpResults = tester.runDhcp(client1); - assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress); + TestNetworkInterface downstreamIface = null; + MyTetheringEventCallback tetheringEventCallback = null; + TapPacketReader downstreamReader = null; try { - tester.runDhcp(client2); - fail("Only one client should get an IP address"); - } catch (TimeoutException expected) { } + downstreamIface = createTestInterface(); + final String iface = getTetheredInterface(); + assertEquals("TetheredInterfaceCallback for unexpected interface", + downstreamIface.getInterfaceName(), iface); + + assertInvalidStaticIpv4Request(iface, null, null); + assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64"); + assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28"); + assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28"); + assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null); + assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28"); + assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28"); + + final String localAddr = "192.0.2.3/28"; + final String clientAddr = "192.0.2.2/28"; + tetheringEventCallback = enableEthernetTethering(iface, + requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */); + + tetheringEventCallback.awaitInterfaceTethered(); + assertInterfaceHasIpAddress(iface, localAddr); + + byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray(); + byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray(); + + FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor(); + downstreamReader = makePacketReader(fd, getMTU(downstreamIface)); + TetheringTester tester = new TetheringTester(downstreamReader); + DhcpResults dhcpResults = tester.runDhcp(client1); + assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress); + + try { + tester.runDhcp(client2); + fail("Only one client should get an IP address"); + } catch (TimeoutException expected) { } + } finally { + maybeStopTapPacketReader(downstreamReader); + maybeCloseTestInterface(downstreamIface); + maybeUnregisterTetheringEventCallback(tetheringEventCallback); + } } private static void waitForRouterAdvertisement(TapPacketReader reader, String iface, @@ -510,26 +529,36 @@ public class EthernetTetheringTest { setIncludeTestInterfaces(true); - mDownstreamIface = createTestInterface(); + TestNetworkInterface downstreamIface = null; + MyTetheringEventCallback tetheringEventCallback = null; + TapPacketReader downstreamReader = null; - final String iface = mTetheredInterfaceRequester.getInterface(); - assertEquals("TetheredInterfaceCallback for unexpected interface", - mDownstreamIface.getInterfaceName(), iface); + try { + downstreamIface = createTestInterface(); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET) - .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build(); - mTetheringEventCallback = enableEthernetTethering(iface, request, - null /* any upstream */); - mTetheringEventCallback.awaitInterfaceLocalOnly(); + final String iface = getTetheredInterface(); + assertEquals("TetheredInterfaceCallback for unexpected interface", + downstreamIface.getInterfaceName(), iface); - // makePacketReader only works after tethering is started, because until then the interface - // does not have an IP address, and unprivileged apps cannot see interfaces without IP - // addresses. This shouldn't be flaky because the TAP interface will buffer all packets even - // before the reader is started. - mDownstreamReader = makePacketReader(mDownstreamIface); + final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET) + .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build(); + tetheringEventCallback = enableEthernetTethering(iface, request, + null /* any upstream */); + tetheringEventCallback.awaitInterfaceLocalOnly(); - waitForRouterAdvertisement(mDownstreamReader, iface, WAIT_RA_TIMEOUT_MS); - expectLocalOnlyAddresses(iface); + // makePacketReader only works after tethering is started, because until then the + // interface does not have an IP address, and unprivileged apps cannot see interfaces + // without IP addresses. This shouldn't be flaky because the TAP interface will buffer + // all packets even before the reader is started. + downstreamReader = makePacketReader(downstreamIface); + + waitForRouterAdvertisement(downstreamReader, iface, WAIT_RA_TIMEOUT_MS); + expectLocalOnlyAddresses(iface); + } finally { + maybeStopTapPacketReader(downstreamReader); + maybeCloseTestInterface(downstreamIface); + maybeUnregisterTetheringEventCallback(tetheringEventCallback); + } } private boolean isAdbOverNetwork() { @@ -546,12 +575,16 @@ public class EthernetTetheringTest { // from client mode to server mode. See b/160389275. assumeFalse(isAdbOverNetwork()); - // Get an interface to use. - final String iface = mTetheredInterfaceRequester.getInterface(); - - // Enable Ethernet tethering and check that it starts. - mTetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */); + MyTetheringEventCallback tetheringEventCallback = null; + try { + // Get an interface to use. + final String iface = getTetheredInterface(); + // Enable Ethernet tethering and check that it starts. + tetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */); + } finally { + maybeUnregisterTetheringEventCallback(tetheringEventCallback); + } // There is nothing more we can do on a physical interface without connecting an actual // client, which is not possible in this test. } @@ -810,15 +843,8 @@ public class EthernetTetheringTest { return reader; } - private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception { - FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor(); - mDownstreamReader = makePacketReader(fd, mtu); - mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName(), - null /* any upstream */); - checkTetheredClientCallbacks(mDownstreamReader); - } - - private void checkTetheredClientCallbacks(TapPacketReader packetReader) throws Exception { + private void checkTetheredClientCallbacks(final TapPacketReader packetReader, + final MyTetheringEventCallback tetheringEventCallback) throws Exception { // Create a fake client. byte[] clientMacAddr = new byte[6]; new Random().nextBytes(clientMacAddr); @@ -826,7 +852,7 @@ public class EthernetTetheringTest { TetheringTester tester = new TetheringTester(packetReader); DhcpResults dhcpResults = tester.runDhcp(clientMacAddr); - final Collection clients = mTetheringEventCallback.awaitClientConnected(); + final Collection clients = tetheringEventCallback.awaitClientConnected(); assertEquals(1, clients.size()); final TetheredClient client = clients.iterator().next(); @@ -945,14 +971,6 @@ public class EthernetTetheringTest { return iface; } - private void maybeDeleteTestInterface() throws Exception { - if (mDownstreamIface != null) { - mDownstreamIface.getFileDescriptor().close(); - Log.d(TAG, "Deleted test interface " + mDownstreamIface.getInterfaceName()); - mDownstreamIface = null; - } - } - private TestNetworkTracker createTestUpstream(final List addresses, final List dnses) throws Exception { setPreferTestNetworks(true); @@ -1002,22 +1020,6 @@ public class EthernetTetheringTest { // remote ip public ip private ip // 8.8.8.8:443 :9876 :9876 // - private static final Inet4Address REMOTE_IP4_ADDR = - (Inet4Address) parseNumericAddress("8.8.8.8"); - // Used by public port and private port. Assume port 9876 has not been used yet before the - // testing that public port and private port are the same in the testing. Note that NAT port - // forwarding could be different between private port and public port. - // TODO: move to the start of test class. - private static final short LOCAL_PORT = 9876; - private static final short REMOTE_PORT = 433; - private static final byte TYPE_OF_SERVICE = 0; - private static final short ID = 27149; - private static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0 - private static final byte TIME_TO_LIVE = (byte) 0x40; - private static final ByteBuffer RX_PAYLOAD = - ByteBuffer.wrap(new byte[] { (byte) 0x12, (byte) 0x34 }); - 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; diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java new file mode 100644 index 0000000000..d58a60c428 --- /dev/null +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.InetAddresses.parseNumericAddress; + +import android.app.UiAutomation; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.cts.util.CtsNetUtils; +import android.os.Handler; +import android.os.HandlerThread; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.testutils.TapPacketReader; +import com.android.testutils.TestNetworkTracker; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; + +/** + * TODO: Common variables or methods shared between CtsEthernetTetheringTest and + * MtsEthernetTetheringTest. + */ +public abstract class EthernetTetheringTestBase { + private static final String TAG = EthernetTetheringTestBase.class.getSimpleName(); + + protected static final int TIMEOUT_MS = 5000; + // Used to check if any tethering interface is available. Choose 200ms to be request timeout + // because the average interface requested time on cuttlefish@acloud is around 10ms. + // See TetheredInterfaceRequester.getInterface, isInterfaceForTetheringAvailable. + protected static final int AVAILABLE_TETHER_IFACE_REQUEST_TIMEOUT_MS = 200; + protected static final int TETHER_REACHABILITY_ATTEMPTS = 20; + protected static final long WAIT_RA_TIMEOUT_MS = 2000; + + // Address and NAT prefix definition. + protected static final MacAddress TEST_MAC = MacAddress.fromString("1:2:3:4:5:6"); + protected static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/24"); + protected static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64"); + protected static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8"); + protected static final InetAddress TEST_IP6_DNS = parseNumericAddress("2001:db8:1::888"); + + protected static final Inet4Address REMOTE_IP4_ADDR = + (Inet4Address) parseNumericAddress("8.8.8.8"); + protected static final Inet6Address REMOTE_IP6_ADDR = + (Inet6Address) parseNumericAddress("2002:db8:1::515:ca"); + protected static final Inet6Address REMOTE_NAT64_ADDR = + (Inet6Address) parseNumericAddress("64:ff9b::808:808"); + protected static final IpPrefix TEST_NAT64PREFIX = new IpPrefix("64:ff9b::/96"); + + // IPv4 header definition. + protected static final short ID = 27149; + protected static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0 + protected static final byte TIME_TO_LIVE = (byte) 0x40; + protected static final byte TYPE_OF_SERVICE = 0; + + // IPv6 header definition. + protected static final short HOP_LIMIT = 0x40; + // version=6, traffic class=0x0, flowlabel=0x0; + protected static final int VERSION_TRAFFICCLASS_FLOWLABEL = 0x60000000; + + // UDP and TCP header definition. + // LOCAL_PORT is used by public port and private port. Assume port 9876 has not been used yet + // before the testing that public port and private port are the same in the testing. Note that + // NAT port forwarding could be different between private port and public port. + protected static final short LOCAL_PORT = 9876; + protected static final short REMOTE_PORT = 433; + protected static final short WINDOW = (short) 0x2000; + protected static final short URGENT_POINTER = 0; + + // Payload definition. + protected static final ByteBuffer EMPTY_PAYLOAD = ByteBuffer.wrap(new byte[0]); + protected static final ByteBuffer TEST_REACHABILITY_PAYLOAD = + ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa }); + protected static final ByteBuffer RX_PAYLOAD = + ByteBuffer.wrap(new byte[] { (byte) 0x12, (byte) 0x34 }); + protected static final ByteBuffer TX_PAYLOAD = + ByteBuffer.wrap(new byte[] { (byte) 0x56, (byte) 0x78 }); + + protected final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + protected final EthernetManager mEm = mContext.getSystemService(EthernetManager.class); + protected final TetheringManager mTm = mContext.getSystemService(TetheringManager.class); + protected final PackageManager mPackageManager = mContext.getPackageManager(); + protected final CtsNetUtils mCtsNetUtils = new CtsNetUtils(mContext); + protected final UiAutomation mUiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + + // Late initialization in setUp() + protected boolean mRunTests; + protected HandlerThread mHandlerThread; + protected Handler mHandler; + + // Late initialization in initTetheringTester(). + protected TapPacketReader mUpstreamReader; + protected TestNetworkTracker mUpstreamTracker; + protected TestNetworkInterface mDownstreamIface; + protected TapPacketReader mDownstreamReader; +}