Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7258cf6b authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Automerger Merge Worker
Browse files

Merge "Add a test for static IPv4 address tethering configuration." am:...

Merge "Add a test for static IPv4 address tethering configuration." am: 9a920cb9 am: 61029221 am: 1aa0b321 am: 6c078ff6 am: 141421eb

Change-Id: I5375da5a15dfd050754beb1573c69c89983a2aa8
parents 6eb24ccb 141421eb
Loading
Loading
Loading
Loading
+109 −20
Original line number Original line Diff line number Diff line
@@ -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 void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
    private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
        FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
        final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
        mTapPacketReader = new TapPacketReader(mHandler, fd, mtu);
        mHandler.post(() -> reader.start());
        mHandler.post(() -> mTapPacketReader.start());
        HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
        HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
        return reader;
    }


    private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
        FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
        mTapPacketReader = makePacketReader(fd, mtu);
        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();