Merge changes I9bccc558,Ifd855571 am: fbef749cda
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2319858 Change-Id: I7ae6719f2f0b04576d1184ada42620611263841a Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -67,16 +67,13 @@ import static org.junit.Assert.fail;
|
|||||||
import static org.junit.Assume.assumeFalse;
|
import static org.junit.Assume.assumeFalse;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
import android.app.UiAutomation;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.net.EthernetManager.TetheredInterfaceCallback;
|
import android.net.EthernetManager.TetheredInterfaceCallback;
|
||||||
import android.net.EthernetManager.TetheredInterfaceRequest;
|
import android.net.EthernetManager.TetheredInterfaceRequest;
|
||||||
import android.net.TetheringManager.StartTetheringCallback;
|
import android.net.TetheringManager.StartTetheringCallback;
|
||||||
import android.net.TetheringManager.TetheringEventCallback;
|
import android.net.TetheringManager.TetheringEventCallback;
|
||||||
import android.net.TetheringManager.TetheringRequest;
|
import android.net.TetheringManager.TetheringRequest;
|
||||||
import android.net.TetheringTester.TetheredDevice;
|
import android.net.TetheringTester.TetheredDevice;
|
||||||
import android.net.cts.util.CtsNetUtils;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
@@ -88,7 +85,6 @@ import android.util.Pair;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.test.InstrumentationRegistry;
|
|
||||||
import androidx.test.filters.MediumTest;
|
import androidx.test.filters.MediumTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -143,17 +139,12 @@ import java.util.concurrent.TimeoutException;
|
|||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@MediumTest
|
@MediumTest
|
||||||
public class EthernetTetheringTest {
|
public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
||||||
@Rule
|
@Rule
|
||||||
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
|
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
private static final String TAG = EthernetTetheringTest.class.getSimpleName();
|
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_MAX_RETRY = 100;
|
||||||
private static final int DUMP_POLLING_INTERVAL_MS = 50;
|
private static final int DUMP_POLLING_INTERVAL_MS = 50;
|
||||||
// Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
|
// 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.
|
// 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_SIZE = 44;
|
||||||
private static final int TX_UDP_PACKET_COUNT = 123;
|
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 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_TETHERING_RAWMAP_ARG = "bpfRawMap";
|
||||||
private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
|
private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
|
||||||
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
|
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
|
||||||
private static final String LINE_DELIMITER = "\\n";
|
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_CODE = 0x0;
|
||||||
private static final short ICMPECHO_ID = 0x0;
|
private static final short ICMPECHO_ID = 0x0;
|
||||||
private static final short ICMPECHO_SEQ = 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 */
|
(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 TetheredInterfaceRequester mTetheredInterfaceRequester;
|
||||||
private MyTetheringEventCallback mTetheringEventCallback;
|
private MyTetheringEventCallback mTetheringEventCallback;
|
||||||
|
|
||||||
private UiAutomation mUiAutomation =
|
|
||||||
InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
|
||||||
private boolean mRunTests;
|
|
||||||
|
|
||||||
private TestNetworkTracker mUpstreamTracker;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mHandlerThread = new HandlerThread(getClass().getSimpleName());
|
mHandlerThread = new HandlerThread(getClass().getSimpleName());
|
||||||
@@ -295,6 +247,30 @@ public class EthernetTetheringTest {
|
|||||||
mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
|
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 {
|
private void cleanUp() throws Exception {
|
||||||
setPreferTestNetworks(false);
|
setPreferTestNetworks(false);
|
||||||
|
|
||||||
@@ -310,24 +286,19 @@ public class EthernetTetheringTest {
|
|||||||
mUpstreamReader = null;
|
mUpstreamReader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDownstreamReader != null) {
|
maybeStopTapPacketReader(mDownstreamReader);
|
||||||
TapPacketReader reader = mDownstreamReader;
|
|
||||||
mHandler.post(() -> reader.stop());
|
|
||||||
mDownstreamReader = null;
|
mDownstreamReader = null;
|
||||||
}
|
|
||||||
|
|
||||||
// To avoid flaky which caused by the next test started but the previous interface is not
|
// 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
|
// untracked from EthernetTracker yet. Just delete the test interface without explicitly
|
||||||
// calling TetheringManager#stopTethering could let EthernetTracker untrack the test
|
// calling TetheringManager#stopTethering could let EthernetTracker untrack the test
|
||||||
// interface from server mode before tethering stopped. Thus, awaitInterfaceUntethered
|
// interface from server mode before tethering stopped. Thus, awaitInterfaceUntethered
|
||||||
// could not only make sure tethering is stopped but also guarantee the test interface is
|
// could not only make sure tethering is stopped but also guarantee the test interface is
|
||||||
// untracked from EthernetTracker.
|
// untracked from EthernetTracker.
|
||||||
maybeDeleteTestInterface();
|
maybeCloseTestInterface(mDownstreamIface);
|
||||||
if (mTetheringEventCallback != null) {
|
mDownstreamIface = null;
|
||||||
mTetheringEventCallback.awaitInterfaceUntethered();
|
maybeUnregisterTetheringEventCallback(mTetheringEventCallback);
|
||||||
mTetheringEventCallback.unregister();
|
|
||||||
mTetheringEventCallback = null;
|
mTetheringEventCallback = null;
|
||||||
}
|
|
||||||
runAsShell(NETWORK_SETTINGS, () -> mTetheredInterfaceRequester.release());
|
runAsShell(NETWORK_SETTINGS, () -> mTetheredInterfaceRequester.release());
|
||||||
setIncludeTestInterfaces(false);
|
setIncludeTestInterfaces(false);
|
||||||
}
|
}
|
||||||
@@ -383,26 +354,50 @@ public class EthernetTetheringTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getTetheredInterface() throws Exception {
|
||||||
|
return mTetheredInterfaceRequester.getInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<String> requestTetheredInterface() throws Exception {
|
||||||
|
return mTetheredInterfaceRequester.requestInterface();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVirtualEthernetAlreadyExists() throws Exception {
|
public void testVirtualEthernetAlreadyExists() throws Exception {
|
||||||
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
|
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
|
||||||
assumeFalse(isInterfaceForTetheringAvailable());
|
assumeFalse(isInterfaceForTetheringAvailable());
|
||||||
|
|
||||||
mDownstreamIface = createTestInterface();
|
TestNetworkInterface downstreamIface = null;
|
||||||
// This must be done now because as soon as setIncludeTestInterfaces(true) is called, the
|
MyTetheringEventCallback tetheringEventCallback = null;
|
||||||
// interface will be placed in client mode, which will delete the link-local address.
|
TapPacketReader downstreamReader = null;
|
||||||
// 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.
|
try {
|
||||||
int mtu = getMTU(mDownstreamIface);
|
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);
|
||||||
|
|
||||||
Log.d(TAG, "Including test interfaces");
|
Log.d(TAG, "Including test interfaces");
|
||||||
setIncludeTestInterfaces(true);
|
setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
final String iface = getTetheredInterface();
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mDownstreamIface.getInterfaceName(), iface);
|
downstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
checkVirtualEthernet(mDownstreamIface, mtu);
|
// 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
|
@Test
|
||||||
@@ -410,17 +405,32 @@ public class EthernetTetheringTest {
|
|||||||
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
|
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
|
||||||
assumeFalse(isInterfaceForTetheringAvailable());
|
assumeFalse(isInterfaceForTetheringAvailable());
|
||||||
|
|
||||||
CompletableFuture<String> futureIface = mTetheredInterfaceRequester.requestInterface();
|
CompletableFuture<String> futureIface = requestTetheredInterface();
|
||||||
|
|
||||||
setIncludeTestInterfaces(true);
|
setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
mDownstreamIface = createTestInterface();
|
TestNetworkInterface downstreamIface = null;
|
||||||
|
MyTetheringEventCallback tetheringEventCallback = null;
|
||||||
|
TapPacketReader downstreamReader = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
downstreamIface = createTestInterface();
|
||||||
|
|
||||||
final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mDownstreamIface.getInterfaceName(), iface);
|
downstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
checkVirtualEthernet(mDownstreamIface, getMTU(mDownstreamIface));
|
// 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
|
@Test
|
||||||
@@ -429,11 +439,16 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
setIncludeTestInterfaces(true);
|
setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
mDownstreamIface = createTestInterface();
|
TestNetworkInterface downstreamIface = null;
|
||||||
|
MyTetheringEventCallback tetheringEventCallback = null;
|
||||||
|
TapPacketReader downstreamReader = null;
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
try {
|
||||||
|
downstreamIface = createTestInterface();
|
||||||
|
|
||||||
|
final String iface = getTetheredInterface();
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mDownstreamIface.getInterfaceName(), iface);
|
downstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
assertInvalidStaticIpv4Request(iface, null, null);
|
assertInvalidStaticIpv4Request(iface, null, null);
|
||||||
assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
|
assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
|
||||||
@@ -445,18 +460,18 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
final String localAddr = "192.0.2.3/28";
|
final String localAddr = "192.0.2.3/28";
|
||||||
final String clientAddr = "192.0.2.2/28";
|
final String clientAddr = "192.0.2.2/28";
|
||||||
mTetheringEventCallback = enableEthernetTethering(iface,
|
tetheringEventCallback = enableEthernetTethering(iface,
|
||||||
requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */);
|
requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */);
|
||||||
|
|
||||||
mTetheringEventCallback.awaitInterfaceTethered();
|
tetheringEventCallback.awaitInterfaceTethered();
|
||||||
assertInterfaceHasIpAddress(iface, localAddr);
|
assertInterfaceHasIpAddress(iface, localAddr);
|
||||||
|
|
||||||
byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
|
byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
|
||||||
byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
|
byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
|
||||||
|
|
||||||
FileDescriptor fd = mDownstreamIface.getFileDescriptor().getFileDescriptor();
|
FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
|
||||||
mDownstreamReader = makePacketReader(fd, getMTU(mDownstreamIface));
|
downstreamReader = makePacketReader(fd, getMTU(downstreamIface));
|
||||||
TetheringTester tester = new TetheringTester(mDownstreamReader);
|
TetheringTester tester = new TetheringTester(downstreamReader);
|
||||||
DhcpResults dhcpResults = tester.runDhcp(client1);
|
DhcpResults dhcpResults = tester.runDhcp(client1);
|
||||||
assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
|
assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
|
||||||
|
|
||||||
@@ -464,7 +479,11 @@ public class EthernetTetheringTest {
|
|||||||
tester.runDhcp(client2);
|
tester.runDhcp(client2);
|
||||||
fail("Only one client should get an IP address");
|
fail("Only one client should get an IP address");
|
||||||
} catch (TimeoutException expected) { }
|
} catch (TimeoutException expected) { }
|
||||||
|
} finally {
|
||||||
|
maybeStopTapPacketReader(downstreamReader);
|
||||||
|
maybeCloseTestInterface(downstreamIface);
|
||||||
|
maybeUnregisterTetheringEventCallback(tetheringEventCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void waitForRouterAdvertisement(TapPacketReader reader, String iface,
|
private static void waitForRouterAdvertisement(TapPacketReader reader, String iface,
|
||||||
@@ -510,26 +529,36 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
setIncludeTestInterfaces(true);
|
setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
mDownstreamIface = createTestInterface();
|
TestNetworkInterface downstreamIface = null;
|
||||||
|
MyTetheringEventCallback tetheringEventCallback = null;
|
||||||
|
TapPacketReader downstreamReader = null;
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
try {
|
||||||
|
downstreamIface = createTestInterface();
|
||||||
|
|
||||||
|
final String iface = getTetheredInterface();
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mDownstreamIface.getInterfaceName(), iface);
|
downstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
|
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
|
||||||
.setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
|
.setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
|
||||||
mTetheringEventCallback = enableEthernetTethering(iface, request,
|
tetheringEventCallback = enableEthernetTethering(iface, request,
|
||||||
null /* any upstream */);
|
null /* any upstream */);
|
||||||
mTetheringEventCallback.awaitInterfaceLocalOnly();
|
tetheringEventCallback.awaitInterfaceLocalOnly();
|
||||||
|
|
||||||
// makePacketReader only works after tethering is started, because until then the interface
|
// makePacketReader only works after tethering is started, because until then the
|
||||||
// does not have an IP address, and unprivileged apps cannot see interfaces without IP
|
// interface does not have an IP address, and unprivileged apps cannot see interfaces
|
||||||
// addresses. This shouldn't be flaky because the TAP interface will buffer all packets even
|
// without IP addresses. This shouldn't be flaky because the TAP interface will buffer
|
||||||
// before the reader is started.
|
// all packets even before the reader is started.
|
||||||
mDownstreamReader = makePacketReader(mDownstreamIface);
|
downstreamReader = makePacketReader(downstreamIface);
|
||||||
|
|
||||||
waitForRouterAdvertisement(mDownstreamReader, iface, WAIT_RA_TIMEOUT_MS);
|
waitForRouterAdvertisement(downstreamReader, iface, WAIT_RA_TIMEOUT_MS);
|
||||||
expectLocalOnlyAddresses(iface);
|
expectLocalOnlyAddresses(iface);
|
||||||
|
} finally {
|
||||||
|
maybeStopTapPacketReader(downstreamReader);
|
||||||
|
maybeCloseTestInterface(downstreamIface);
|
||||||
|
maybeUnregisterTetheringEventCallback(tetheringEventCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAdbOverNetwork() {
|
private boolean isAdbOverNetwork() {
|
||||||
@@ -546,12 +575,16 @@ public class EthernetTetheringTest {
|
|||||||
// from client mode to server mode. See b/160389275.
|
// from client mode to server mode. See b/160389275.
|
||||||
assumeFalse(isAdbOverNetwork());
|
assumeFalse(isAdbOverNetwork());
|
||||||
|
|
||||||
|
MyTetheringEventCallback tetheringEventCallback = null;
|
||||||
|
try {
|
||||||
// Get an interface to use.
|
// Get an interface to use.
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
final String iface = getTetheredInterface();
|
||||||
|
|
||||||
// Enable Ethernet tethering and check that it starts.
|
// Enable Ethernet tethering and check that it starts.
|
||||||
mTetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */);
|
tetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */);
|
||||||
|
} finally {
|
||||||
|
maybeUnregisterTetheringEventCallback(tetheringEventCallback);
|
||||||
|
}
|
||||||
// There is nothing more we can do on a physical interface without connecting an actual
|
// There is nothing more we can do on a physical interface without connecting an actual
|
||||||
// client, which is not possible in this test.
|
// client, which is not possible in this test.
|
||||||
}
|
}
|
||||||
@@ -810,15 +843,8 @@ public class EthernetTetheringTest {
|
|||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
|
private void checkTetheredClientCallbacks(final TapPacketReader packetReader,
|
||||||
FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
|
final MyTetheringEventCallback tetheringEventCallback) throws Exception {
|
||||||
mDownstreamReader = makePacketReader(fd, mtu);
|
|
||||||
mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName(),
|
|
||||||
null /* any upstream */);
|
|
||||||
checkTetheredClientCallbacks(mDownstreamReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkTetheredClientCallbacks(TapPacketReader packetReader) throws Exception {
|
|
||||||
// Create a fake client.
|
// Create a fake client.
|
||||||
byte[] clientMacAddr = new byte[6];
|
byte[] clientMacAddr = new byte[6];
|
||||||
new Random().nextBytes(clientMacAddr);
|
new Random().nextBytes(clientMacAddr);
|
||||||
@@ -826,7 +852,7 @@ public class EthernetTetheringTest {
|
|||||||
TetheringTester tester = new TetheringTester(packetReader);
|
TetheringTester tester = new TetheringTester(packetReader);
|
||||||
DhcpResults dhcpResults = tester.runDhcp(clientMacAddr);
|
DhcpResults dhcpResults = tester.runDhcp(clientMacAddr);
|
||||||
|
|
||||||
final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
|
final Collection<TetheredClient> clients = tetheringEventCallback.awaitClientConnected();
|
||||||
assertEquals(1, clients.size());
|
assertEquals(1, clients.size());
|
||||||
final TetheredClient client = clients.iterator().next();
|
final TetheredClient client = clients.iterator().next();
|
||||||
|
|
||||||
@@ -945,14 +971,6 @@ public class EthernetTetheringTest {
|
|||||||
return iface;
|
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<LinkAddress> addresses,
|
private TestNetworkTracker createTestUpstream(final List<LinkAddress> addresses,
|
||||||
final List<InetAddress> dnses) throws Exception {
|
final List<InetAddress> dnses) throws Exception {
|
||||||
setPreferTestNetworks(true);
|
setPreferTestNetworks(true);
|
||||||
@@ -1002,22 +1020,6 @@ public class EthernetTetheringTest {
|
|||||||
// remote ip public ip private ip
|
// remote ip public ip private ip
|
||||||
// 8.8.8.8:443 <Upstream ip>:9876 <TetheredDevice ip>:9876
|
// 8.8.8.8:443 <Upstream ip>:9876 <TetheredDevice ip>: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) {
|
private short getEthType(@NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp) {
|
||||||
return isAddressIpv4(srcIp, dstIp) ? (short) ETHER_TYPE_IPV4 : (short) ETHER_TYPE_IPV6;
|
return isAddressIpv4(srcIp, dstIp) ? (short) ETHER_TYPE_IPV4 : (short) ETHER_TYPE_IPV6;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user