Merge "Add a test for static IPv4 address tethering configuration." am: 9a920cb92e
Change-Id: I592468bf53ff925ec4ee8a04fee20404594237fe
This commit is contained in:
@@ -18,6 +18,7 @@ package android.net;
|
|||||||
|
|
||||||
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
||||||
import static android.Manifest.permission.NETWORK_SETTINGS;
|
import static android.Manifest.permission.NETWORK_SETTINGS;
|
||||||
|
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -57,6 +58,7 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InterfaceAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -66,6 +68,7 @@ import java.util.Random;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@@ -110,7 +113,7 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUp() throws Exception {
|
private void cleanUp() throws Exception {
|
||||||
mTm.stopTethering(TetheringManager.TETHERING_ETHERNET);
|
mTm.stopTethering(TETHERING_ETHERNET);
|
||||||
if (mTetheringEventCallback != null) {
|
if (mTetheringEventCallback != null) {
|
||||||
mTetheringEventCallback.awaitInterfaceUntethered();
|
mTetheringEventCallback.awaitInterfaceUntethered();
|
||||||
mTetheringEventCallback.unregister();
|
mTetheringEventCallback.unregister();
|
||||||
@@ -176,6 +179,49 @@ public class EthernetTetheringTest {
|
|||||||
checkVirtualEthernet(mTestIface, getMTU(mTestIface));
|
checkVirtualEthernet(mTestIface, getMTU(mTestIface));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStaticIpv4() throws Exception {
|
||||||
|
assumeFalse(mEm.isAvailable());
|
||||||
|
|
||||||
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
|
mTestIface = createTestInterface();
|
||||||
|
|
||||||
|
final String iface = mTetheredInterfaceRequester.getInterface();
|
||||||
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
|
mTestIface.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));
|
||||||
|
|
||||||
|
mTetheringEventCallback.awaitInterfaceTethered();
|
||||||
|
assertInterfaceHasIpAddress(iface, clientAddr);
|
||||||
|
|
||||||
|
byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
|
||||||
|
byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
|
||||||
|
|
||||||
|
FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
|
||||||
|
mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
|
||||||
|
DhcpResults dhcpResults = runDhcp(fd, client1);
|
||||||
|
assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
|
||||||
|
|
||||||
|
try {
|
||||||
|
runDhcp(fd, client2);
|
||||||
|
fail("Only one client should get an IP address");
|
||||||
|
} catch (TimeoutException expected) { }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPhysicalEthernet() throws Exception {
|
public void testPhysicalEthernet() throws Exception {
|
||||||
assumeTrue(mEm.isAvailable());
|
assumeTrue(mEm.isAvailable());
|
||||||
@@ -271,7 +317,8 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
|
private MyTetheringEventCallback enableEthernetTethering(String iface,
|
||||||
|
TetheringRequest request) throws Exception {
|
||||||
MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface);
|
MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface);
|
||||||
mTm.registerTetheringEventCallback(mHandler::post, callback);
|
mTm.registerTetheringEventCallback(mHandler::post, callback);
|
||||||
|
|
||||||
@@ -282,34 +329,37 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Log.d(TAG, "Starting Ethernet tethering");
|
Log.d(TAG, "Starting Ethernet tethering");
|
||||||
mTm.startTethering(
|
mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
|
||||||
new TetheringRequest.Builder(TetheringManager.TETHERING_ETHERNET).build(),
|
|
||||||
mHandler::post /* executor */, startTetheringCallback);
|
|
||||||
callback.awaitInterfaceTethered();
|
callback.awaitInterfaceTethered();
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
|
||||||
|
return enableEthernetTethering(iface,
|
||||||
|
new TetheringRequest.Builder(TETHERING_ETHERNET).build());
|
||||||
|
}
|
||||||
|
|
||||||
private int getMTU(TestNetworkInterface iface) throws SocketException {
|
private int getMTU(TestNetworkInterface iface) throws SocketException {
|
||||||
NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
|
NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
|
||||||
assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
|
assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
|
||||||
return nif.getMTU();
|
return nif.getMTU();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
|
||||||
|
final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
|
||||||
|
mHandler.post(() -> reader.start());
|
||||||
|
HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
|
private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
|
||||||
FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
|
FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
|
||||||
mTapPacketReader = new TapPacketReader(mHandler, fd, mtu);
|
mTapPacketReader = makePacketReader(fd, mtu);
|
||||||
mHandler.post(() -> mTapPacketReader.start());
|
|
||||||
HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
|
|
||||||
|
|
||||||
mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName());
|
mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName());
|
||||||
checkTetheredClientCallbacks(fd);
|
checkTetheredClientCallbacks(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
|
private DhcpResults runDhcp(FileDescriptor fd, byte[] clientMacAddr) throws Exception {
|
||||||
// Create a fake client.
|
|
||||||
byte[] clientMacAddr = new byte[6];
|
|
||||||
new Random().nextBytes(clientMacAddr);
|
|
||||||
|
|
||||||
// We have to retransmit DHCP requests because IpServer declares itself to be ready before
|
// We have to retransmit DHCP requests because IpServer declares itself to be ready before
|
||||||
// its DhcpServer is actually started. TODO: fix this race and remove this loop.
|
// its DhcpServer is actually started. TODO: fix this race and remove this loop.
|
||||||
DhcpPacket offerPacket = null;
|
DhcpPacket offerPacket = null;
|
||||||
@@ -319,13 +369,25 @@ public class EthernetTetheringTest {
|
|||||||
offerPacket = getNextDhcpPacket();
|
offerPacket = getNextDhcpPacket();
|
||||||
if (offerPacket instanceof DhcpOfferPacket) break;
|
if (offerPacket instanceof DhcpOfferPacket) break;
|
||||||
}
|
}
|
||||||
assertTrue("No DHCPOFFER received on interface within timeout",
|
if (!(offerPacket instanceof DhcpOfferPacket)) {
|
||||||
offerPacket instanceof DhcpOfferPacket);
|
throw new TimeoutException("No DHCPOFFER received on interface within timeout");
|
||||||
|
}
|
||||||
|
|
||||||
sendDhcpRequest(fd, offerPacket, clientMacAddr);
|
sendDhcpRequest(fd, offerPacket, clientMacAddr);
|
||||||
DhcpPacket ackPacket = getNextDhcpPacket();
|
DhcpPacket ackPacket = getNextDhcpPacket();
|
||||||
assertTrue("No DHCPACK received on interface within timeout",
|
if (!(ackPacket instanceof DhcpAckPacket)) {
|
||||||
ackPacket instanceof DhcpAckPacket);
|
throw new TimeoutException("No DHCPACK received on interface within timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ackPacket.toDhcpResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
|
||||||
|
// Create a fake client.
|
||||||
|
byte[] clientMacAddr = new byte[6];
|
||||||
|
new Random().nextBytes(clientMacAddr);
|
||||||
|
|
||||||
|
DhcpResults dhcpResults = runDhcp(fd, clientMacAddr);
|
||||||
|
|
||||||
final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
|
final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
|
||||||
assertEquals(1, clients.size());
|
assertEquals(1, clients.size());
|
||||||
@@ -333,7 +395,7 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
// Check the MAC address.
|
// Check the MAC address.
|
||||||
assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
|
assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
|
||||||
assertEquals(TetheringManager.TETHERING_ETHERNET, client.getTetheringType());
|
assertEquals(TETHERING_ETHERNET, client.getTetheringType());
|
||||||
|
|
||||||
// Check the hostname.
|
// Check the hostname.
|
||||||
assertEquals(1, client.getAddresses().size());
|
assertEquals(1, client.getAddresses().size());
|
||||||
@@ -341,7 +403,6 @@ public class EthernetTetheringTest {
|
|||||||
assertEquals(DHCP_HOSTNAME, info.getHostname());
|
assertEquals(DHCP_HOSTNAME, info.getHostname());
|
||||||
|
|
||||||
// Check the address is the one that was handed out in the DHCP ACK.
|
// Check the address is the one that was handed out in the DHCP ACK.
|
||||||
DhcpResults dhcpResults = offerPacket.toDhcpResults();
|
|
||||||
assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
|
assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
|
||||||
|
|
||||||
// Check that the lifetime is correct +/- 10s.
|
// Check that the lifetime is correct +/- 10s.
|
||||||
@@ -441,6 +502,34 @@ public class EthernetTetheringTest {
|
|||||||
assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
|
assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TetheringRequest requestWithStaticIpv4(String local, String client) {
|
||||||
|
LinkAddress localAddr = local == null ? null : new LinkAddress(local);
|
||||||
|
LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
|
||||||
|
return new TetheringRequest.Builder(TETHERING_ETHERNET)
|
||||||
|
.setStaticIpv4Addresses(localAddr, clientAddr).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertInvalidStaticIpv4Request(String iface, String local, String client)
|
||||||
|
throws Exception {
|
||||||
|
try {
|
||||||
|
enableEthernetTethering(iface, requestWithStaticIpv4(local, client));
|
||||||
|
fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
|
||||||
|
} catch (IllegalArgumentException | NullPointerException expected) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
|
||||||
|
LinkAddress expectedAddr = new LinkAddress(expected);
|
||||||
|
NetworkInterface nif = NetworkInterface.getByName(iface);
|
||||||
|
for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
|
||||||
|
final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
|
||||||
|
if (expectedAddr.equals(addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail("Expected " + iface + " to have IP address " + expected + ", found "
|
||||||
|
+ nif.getInterfaceAddresses());
|
||||||
|
}
|
||||||
|
|
||||||
private TestNetworkInterface createTestInterface() throws Exception {
|
private TestNetworkInterface createTestInterface() throws Exception {
|
||||||
TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
|
TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
|
||||||
TestNetworkInterface iface = tnm.createTapInterface();
|
TestNetworkInterface iface = tnm.createTapInterface();
|
||||||
|
|||||||
Reference in New Issue
Block a user