diff options
author | Xiao Ma <xiaom@google.com> | 2019-06-03 10:30:04 +0900 |
---|---|---|
committer | Xiao Ma <xiaom@google.com> | 2019-07-06 05:31:17 +0000 |
commit | c00a7935e581eaac66595d815c49393d6ccb2310 (patch) | |
tree | e9d1b5f50de728986ecf7ab409709bf6673f0fb7 | |
parent | 692abb71d97ef89285eacf301f1cf27fb4cfe38d (diff) |
Add integration test to verify different DHCP handshake process.
Bug: 122710829
Test: atest NetworkStackIntegrationTests
Test: atest NetworkStackTests
Change-Id: If605a5688827b376866b68289b76c452e8366d0c
-rw-r--r-- | src/android/net/dhcp/DhcpAckPacket.java | 2 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpDeclinePacket.java | 2 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpInformPacket.java | 2 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpNakPacket.java | 2 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpOfferPacket.java | 2 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpReleasePacket.java | 2 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpRequestPacket.java | 4 | ||||
-rw-r--r-- | tests/integration/src/android/net/ip/IpClientIntegrationTest.java | 388 | ||||
-rw-r--r-- | tests/unit/src/android/net/dhcp/DhcpPacketTest.java | 4 |
9 files changed, 345 insertions, 63 deletions
diff --git a/src/android/net/dhcp/DhcpAckPacket.java b/src/android/net/dhcp/DhcpAckPacket.java index b2eb4e2..052af35 100644 --- a/src/android/net/dhcp/DhcpAckPacket.java +++ b/src/android/net/dhcp/DhcpAckPacket.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; /** * This class implements the DHCP-ACK packet. */ -class DhcpAckPacket extends DhcpPacket { +public class DhcpAckPacket extends DhcpPacket { /** * The address of the server which sent this packet. diff --git a/src/android/net/dhcp/DhcpDeclinePacket.java b/src/android/net/dhcp/DhcpDeclinePacket.java index 7ecdea7..2f4f0f6 100644 --- a/src/android/net/dhcp/DhcpDeclinePacket.java +++ b/src/android/net/dhcp/DhcpDeclinePacket.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; /** * This class implements the DHCP-DECLINE packet. */ -class DhcpDeclinePacket extends DhcpPacket { +public class DhcpDeclinePacket extends DhcpPacket { /** * Generates a DECLINE packet with the specified parameters. */ diff --git a/src/android/net/dhcp/DhcpInformPacket.java b/src/android/net/dhcp/DhcpInformPacket.java index 7a83466..135b8f6 100644 --- a/src/android/net/dhcp/DhcpInformPacket.java +++ b/src/android/net/dhcp/DhcpInformPacket.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; /** * This class implements the (unused) DHCP-INFORM packet. */ -class DhcpInformPacket extends DhcpPacket { +public class DhcpInformPacket extends DhcpPacket { /** * Generates an INFORM packet with the specified parameters. */ diff --git a/src/android/net/dhcp/DhcpNakPacket.java b/src/android/net/dhcp/DhcpNakPacket.java index 1da0b73..98bd188 100644 --- a/src/android/net/dhcp/DhcpNakPacket.java +++ b/src/android/net/dhcp/DhcpNakPacket.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; /** * This class implements the DHCP-NAK packet. */ -class DhcpNakPacket extends DhcpPacket { +public class DhcpNakPacket extends DhcpPacket { /** * Generates a NAK packet with the specified parameters. */ diff --git a/src/android/net/dhcp/DhcpOfferPacket.java b/src/android/net/dhcp/DhcpOfferPacket.java index 0eba77e..aae08a7 100644 --- a/src/android/net/dhcp/DhcpOfferPacket.java +++ b/src/android/net/dhcp/DhcpOfferPacket.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; /** * This class implements the DHCP-OFFER packet. */ -class DhcpOfferPacket extends DhcpPacket { +public class DhcpOfferPacket extends DhcpPacket { /** * The IP address of the server which sent this packet. */ diff --git a/src/android/net/dhcp/DhcpReleasePacket.java b/src/android/net/dhcp/DhcpReleasePacket.java index 3958303..cef5567 100644 --- a/src/android/net/dhcp/DhcpReleasePacket.java +++ b/src/android/net/dhcp/DhcpReleasePacket.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; /** * Implements DHCP-RELEASE */ -class DhcpReleasePacket extends DhcpPacket { +public class DhcpReleasePacket extends DhcpPacket { final Inet4Address mClientAddr; diff --git a/src/android/net/dhcp/DhcpRequestPacket.java b/src/android/net/dhcp/DhcpRequestPacket.java index 231d045..0672871 100644 --- a/src/android/net/dhcp/DhcpRequestPacket.java +++ b/src/android/net/dhcp/DhcpRequestPacket.java @@ -16,15 +16,13 @@ package android.net.dhcp; -import android.util.Log; - import java.net.Inet4Address; import java.nio.ByteBuffer; /** * This class implements the DHCP-REQUEST packet. */ -class DhcpRequestPacket extends DhcpPacket { +public class DhcpRequestPacket extends DhcpPacket { /** * Generates a REQUEST packet with the specified parameters. */ diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java index ae6afdb..16e92ef 100644 --- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java +++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java @@ -16,23 +16,27 @@ package android.net.ip; +import static android.net.dhcp.DhcpClient.EXPIRED_LEASE; import static android.net.dhcp.DhcpPacket.DHCP_BOOTREQUEST; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; import static android.net.dhcp.DhcpPacket.DHCP_MAGIC_COOKIE; -import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE; -import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_DISCOVER; import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_L2; -import static android.net.dhcp.DhcpPacket.ETHER_BROADCAST; - -import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL; +import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; +import static android.net.ipmemorystore.Status.SUCCESS; +import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; +import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -43,20 +47,27 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; -import android.net.IIpMemoryStore; import android.net.INetd; +import android.net.InetAddresses; +import android.net.NetworkStackIpMemoryStore; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; +import android.net.dhcp.DhcpClient; import android.net.dhcp.DhcpDiscoverPacket; import android.net.dhcp.DhcpPacket; import android.net.dhcp.DhcpPacket.ParseException; +import android.net.dhcp.DhcpRequestPacket; +import android.net.ipmemorystore.NetworkAttributes; +import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.Status; import android.net.shared.ProvisioningConfiguration; -import android.net.util.InterfaceParams; +import android.net.util.NetworkStackUtils; import android.net.util.PacketReader; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; @@ -64,18 +75,25 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.NetworkObserverRegistry; -import com.android.server.NetworkStackService; +import com.android.server.NetworkStackService.NetworkStackServiceManager; +import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.Inet4Address; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.Collections; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -85,35 +103,36 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class IpClientIntegrationTest { + private static final int DATA_BUFFER_LEN = 4096; + private static final int PACKET_TIMEOUT_MS = 5_000; + private static final int TEST_TIMEOUT_MS = 400; + private static final String TEST_L2KEY = "some l2key"; + private static final String TEST_GROUPHINT = "some grouphint"; + private static final int TEST_LEASE_DURATION_S = 3_600; // 1 hour + @Mock private Context mContext; @Mock private ConnectivityManager mCm; @Mock private INetd mNetd; @Mock private Resources mResources; @Mock private IIpClientCallbacks mCb; @Mock private AlarmManager mAlarm; - @Mock private IpClient.Dependencies mDependencies; @Mock private ContentResolver mContentResolver; - @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager; - @Mock private IIpMemoryStore mIpMemoryStore; - @Mock private InterfaceParams mInterfaceParams; + @Mock private NetworkStackServiceManager mNetworkStackServiceManager; + @Mock private NetworkStackIpMemoryStore mIpMemoryStore; + @Mock private IpMemoryStoreService mIpMemoryStoreService; private String mIfaceName; private HandlerThread mPacketReaderThread; private TapPacketReader mPacketReader; private IpClient mIpc; - - private static final int DATA_BUFFER_LEN = 4096; - private static final long PACKET_TIMEOUT_MS = 5_000; + private Dependencies mDependencies; // Ethernet header private static final int ETH_HEADER_LEN = 14; - private static final int ETH_DEST_ADDR_OFFSET = 0; - private static final int ETH_MAC_ADDR_LEN = 6; // IP header private static final int IPV4_HEADER_LEN = 20; - private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; - private static final int IPV4_ADDR_LEN = 4; + private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12; // UDP header private static final int UDP_HEADER_LEN = 8; @@ -127,10 +146,19 @@ public class IpClientIntegrationTest { private static final int DHCP_TRANSACTION_ID_OFFSET = DHCP_HEADER_OFFSET + 4; private static final int DHCP_OPTION_MAGIC_COOKIE_OFFSET = DHCP_HEADER_OFFSET + 236; private static final int DHCP_OPTION_MESSAGE_TYPE_OFFSET = DHCP_OPTION_MAGIC_COOKIE_OFFSET + 4; - private static final int DHCP_OPTION_MESSAGE_TYPE_LEN_OFFSET = - DHCP_OPTION_MESSAGE_TYPE_OFFSET + 1; - private static final int DHCP_OPTION_MESSAGE_TYPE_VALUE_OFFSET = - DHCP_OPTION_MESSAGE_TYPE_OFFSET + 2; + + private static final Inet4Address SERVER_ADDR = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.100"); + private static final Inet4Address CLIENT_ADDR = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.2"); + private static final Inet4Address INADDR_ANY = + (Inet4Address) InetAddresses.parseNumericAddress("0.0.0.0"); + private static final int PREFIX_LENGTH = 24; + private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH); + private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress( + SERVER_ADDR, PREFIX_LENGTH); + private static final String HOSTNAME = "testhostname"; + private static final short MTU = 1500; private static class TapPacketReader extends PacketReader { private final ParcelFileDescriptor mTapFd; @@ -172,17 +200,61 @@ public class IpClientIntegrationTest { } } + private class Dependencies extends IpClient.Dependencies { + private boolean mIsDhcpLeaseCacheEnabled; + private boolean mIsDhcpRapidCommitEnabled; + + public void setDhcpLeaseCacheEnabled(final boolean enable) { + mIsDhcpLeaseCacheEnabled = enable; + } + + public void setDhcpRapidCommitEnabled(final boolean enable) { + mIsDhcpRapidCommitEnabled = enable; + } + + @Override + public INetd getNetd(Context context) { + return mNetd; + } + + @Override + public NetworkStackIpMemoryStore getIpMemoryStore(Context context, + NetworkStackServiceManager nssManager) { + return mIpMemoryStore; + } + + @Override + public DhcpClient.Dependencies getDhcpClientDependencies( + NetworkStackIpMemoryStore ipMemoryStore) { + return new DhcpClient.Dependencies(ipMemoryStore) { + @Override + public boolean getBooleanDeviceConfig(final String nameSpace, + final String flagName) { + switch (flagName) { + case NetworkStackUtils.DHCP_RAPID_COMMIT_ENABLED: + return mIsDhcpRapidCommitEnabled; + case NetworkStackUtils.DHCP_INIT_REBOOT_ENABLED: + return mIsDhcpLeaseCacheEnabled; + default: + fail("Invalid experiment flag: " + flagName); + return false; + } + } + }; + } + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mDependencies = new Dependencies(); when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm); when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm); when(mContext.getResources()).thenReturn(mResources); - when(mDependencies.getNetd(any())).thenReturn(mNetd); when(mContext.getContentResolver()).thenReturn(mContentResolver); - when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams); - when(mNetworkStackServiceManager.getIpMemoryStoreService()).thenReturn(mIpMemoryStore); + when(mNetworkStackServiceManager.getIpMemoryStoreService()) + .thenReturn(mIpMemoryStoreService); setUpTapInterface(); setUpIpClient(); @@ -196,6 +268,7 @@ public class IpClientIntegrationTest { if (mPacketReaderThread != null) { mPacketReaderThread.quitSafely(); } + mIpc.shutdown(); } private void setUpTapInterface() { @@ -233,7 +306,8 @@ public class IpClientIntegrationTest { final NetworkObserverRegistry reg = new NetworkObserverRegistry(); reg.register(netd); - mIpc = new IpClient(mContext, mIfaceName, mCb, reg, mNetworkStackServiceManager); + mIpc = new IpClient(mContext, mIfaceName, mCb, reg, mNetworkStackServiceManager, + mDependencies); } private boolean packetContainsExpectedField(final byte[] packet, final int offset, @@ -270,43 +344,253 @@ public class IpClientIntegrationTest { return true; } - private void verifyDhcpDiscoverPacketReceived(final byte[] packet) - throws ParseException { - assertTrue(packetContainsExpectedField(packet, ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST)); - assertTrue(packetContainsExpectedField(packet, IPV4_DEST_ADDR_OFFSET, - IPV4_ADDR_ALL.getAddress())); - - // check if received dhcp packet includes DHCP Message Type option and expected - // type/length/value. - assertTrue(packet[DHCP_OPTION_MESSAGE_TYPE_OFFSET] == DHCP_MESSAGE_TYPE); - assertTrue(packet[DHCP_OPTION_MESSAGE_TYPE_OFFSET + 1] == 1); - assertTrue(packet[DHCP_OPTION_MESSAGE_TYPE_OFFSET + 2] == DHCP_MESSAGE_TYPE_DISCOVER); - final DhcpPacket dhcpPacket = DhcpPacket.decodeFullPacket( - packet, packet.length, ENCAP_L2); - assertTrue(dhcpPacket instanceof DhcpDiscoverPacket); + private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet, + final Integer leaseTimeSec) { + return DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), + false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */, + CLIENT_ADDR /* yourIp */, packet.getClientMac(), leaseTimeSec, + NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, + Collections.singletonList(SERVER_ADDR) /* gateways */, + Collections.singletonList(SERVER_ADDR) /* dnsServers */, + SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME, + false /* metered */, MTU); } - @Test - public void testDhcpInit() throws Exception { + private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet, + final Integer leaseTimeSec) { + return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), + false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */, + CLIENT_ADDR /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(), + leaseTimeSec, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, + Collections.singletonList(SERVER_ADDR) /* gateways */, + Collections.singletonList(SERVER_ADDR) /* dnsServers */, + SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME, + false /* metered */, MTU); + } + + private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet) { + return DhcpPacket.buildNakPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), + SERVER_ADDR /* serverIp */, INADDR_ANY /* relayIp */, packet.getClientMac(), + false /* broadcast */, "duplicated request IP address"); + } + + private void sendResponse(final ByteBuffer packet) throws IOException { + try (FileOutputStream out = new FileOutputStream(mPacketReader.createFd())) { + out.write(packet.array()); + } + } + + private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled, + final boolean isDhcpRapidCommitEnabled) throws RemoteException { ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() + .withoutIPv6() .build(); + mDependencies.setDhcpLeaseCacheEnabled(isDhcpLeaseCacheEnabled); + mDependencies.setDhcpRapidCommitEnabled(isDhcpRapidCommitEnabled); + mIpc.setL2KeyAndGroupHint(TEST_L2KEY, TEST_GROUPHINT); mIpc.startProvisioning(config); verify(mCb, times(1)).setNeighborDiscoveryOffload(true); + verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false); + verify(mCb, never()).onProvisioningFailure(any()); + } + private void assertIpMemoryStoreNetworkAttributes(final Integer leaseTimeSec, + final long startTime) { + final ArgumentCaptor<NetworkAttributes> networkAttributes = + ArgumentCaptor.forClass(NetworkAttributes.class); + + verify(mIpMemoryStore, timeout(TEST_TIMEOUT_MS)) + .storeNetworkAttributes(eq(TEST_L2KEY), networkAttributes.capture(), any()); + final NetworkAttributes naValueCaptured = networkAttributes.getValue(); + assertEquals(CLIENT_ADDR, naValueCaptured.assignedV4Address); + if (leaseTimeSec == null || leaseTimeSec.intValue() == DhcpPacket.INFINITE_LEASE) { + assertEquals(Long.MAX_VALUE, naValueCaptured.assignedV4AddressExpiry.longValue()); + } else { + // check the lease expiry's scope + final long upperBound = startTime + 7_200_000; // start timestamp + 2h + final long lowerBound = startTime + 3_600_000; // start timestamp + 1h + final long expiry = naValueCaptured.assignedV4AddressExpiry; + assertTrue(upperBound > expiry); + assertTrue(lowerBound < expiry); + } + assertEquals(Collections.singletonList(SERVER_ADDR), naValueCaptured.dnsAddresses); + assertEquals(new Integer((int) MTU), naValueCaptured.mtu); + } + + private void assertIpMemoryNeverStoreNetworkAttributes() { + verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any()); + } + + // Helper method to complete DHCP 2-way or 4-way handshake + private void performDhcpHandshake(final boolean isSuccessLease, + final Integer leaseTimeSec, final boolean isDhcpLeaseCacheEnabled, + final boolean isDhcpRapidCommitEnabled) throws Exception { + startIpClientProvisioning(isDhcpLeaseCacheEnabled, isDhcpRapidCommitEnabled); + + DhcpPacket packet; + while ((packet = getNextDhcpPacket()) != null) { + if (packet instanceof DhcpDiscoverPacket) { + if (isDhcpRapidCommitEnabled) { + sendResponse(buildDhcpAckPacket(packet, leaseTimeSec)); + } else { + sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec)); + } + } else if (packet instanceof DhcpRequestPacket) { + final ByteBuffer byteBuffer = isSuccessLease + ? buildDhcpAckPacket(packet, leaseTimeSec) + : buildDhcpNakPacket(packet); + sendResponse(byteBuffer); + } else { + fail("invalid DHCP packet"); + } + // wait for reply to DHCPOFFER packet if disabling rapid commit option + if (isDhcpRapidCommitEnabled || !(packet instanceof DhcpDiscoverPacket)) return; + } + fail("No DHCPREQUEST received on interface"); + } + + private DhcpPacket getNextDhcpPacket() throws ParseException { byte[] packet; while ((packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS)) != null) { - try { - if (!isDhcpPacket(packet)) continue; - verifyDhcpDiscoverPacketReceived(packet); - mIpc.shutdown(); - return; - } catch (DhcpPacket.ParseException e) { - fail("parse exception: " + e); - } + if (!isDhcpPacket(packet)) continue; + return DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L2); } + fail("No expected DHCP packet received on interface within timeout"); + return null; + } + + private DhcpPacket getReplyFromDhcpLease(final NetworkAttributes na, boolean timeout) + throws Exception { + doAnswer(invocation -> { + if (timeout) return null; + ((OnNetworkAttributesRetrievedListener) invocation.getArgument(1)) + .onNetworkAttributesRetrieved(new Status(SUCCESS), TEST_L2KEY, na); + return null; + }).when(mIpMemoryStore).retrieveNetworkAttributes(eq(TEST_L2KEY), any()); + startIpClientProvisioning(true /* isDhcpLeaseCacheEnabled */, + false /* isDhcpRapidCommitEnabled */); + return getNextDhcpPacket(); + } + + @Test + public void testDhcpInit() throws Exception { + startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */, + false /* isDhcpRapidCommitEnabled */); + final DhcpPacket packet = getNextDhcpPacket(); + assertTrue(DhcpDiscoverPacket.class.isInstance(packet)); + } + + @Test + public void testHandleSuccessDhcpLease() throws Exception { + final long currentTime = System.currentTimeMillis(); + performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, + true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */); + assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime); + } + + @Test + public void testHandleFailureDhcpLease() throws Exception { + performDhcpHandshake(false /* isSuccessLease */, TEST_LEASE_DURATION_S, + true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */); + assertIpMemoryNeverStoreNetworkAttributes(); + } + + @Test + public void testHandleInfiniteLease() throws Exception { + final long currentTime = System.currentTimeMillis(); + performDhcpHandshake(true /* isSuccessLease */, INFINITE_LEASE, + true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */); + assertIpMemoryStoreNetworkAttributes(INFINITE_LEASE, currentTime); + } + + @Test + public void testHandleNoLease() throws Exception { + final long currentTime = System.currentTimeMillis(); + performDhcpHandshake(true /* isSuccessLease */, null /* no lease time */, + true /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */); + assertIpMemoryStoreNetworkAttributes(null, currentTime); + } + + @Test + public void testHandleDisableInitRebootState() throws Exception { + performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, + false /* isDhcpLeaseCacheEnabled */, false /* isDhcpRapidCommitEnabled */); + assertIpMemoryNeverStoreNetworkAttributes(); + } + + @Ignore + @Test + public void testHandleRapidCommitOption() throws Exception { + // TODO: remove @Ignore after supporting rapid commit option in DHCP server + final long currentTime = System.currentTimeMillis(); + performDhcpHandshake(true /* isSuccessLease */, TEST_LEASE_DURATION_S, + true /* isDhcpLeaseCacheEnabled */, true /* isDhcpRapidCommitEnabled */); + assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime); + } + + @Test + public void testDhcpClientStartWithCachedInfiniteLease() throws Exception { + final DhcpPacket packet = getReplyFromDhcpLease( + new NetworkAttributes.Builder() + .setAssignedV4Address(CLIENT_ADDR) + .setAssignedV4AddressExpiry(Long.MAX_VALUE) // lease is always valid + .setMtu(new Integer(MTU)) + .setGroupHint(TEST_GROUPHINT) + .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) + .build(), false /* timeout */); + assertTrue(DhcpRequestPacket.class.isInstance(packet)); + } + + @Test + public void testDhcpClientStartWithCachedExpiredLease() throws Exception { + final DhcpPacket packet = getReplyFromDhcpLease( + new NetworkAttributes.Builder() + .setAssignedV4Address(CLIENT_ADDR) + .setAssignedV4AddressExpiry(EXPIRED_LEASE) + .setMtu(new Integer(MTU)) + .setGroupHint(TEST_GROUPHINT) + .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) + .build(), false /* timeout */); + assertTrue(DhcpDiscoverPacket.class.isInstance(packet)); + } - fail("No DHCPDISCOVER received on interface"); + @Test + public void testDhcpClientStartWithNullRetrieveNetworkAttributes() throws Exception { + final DhcpPacket packet = getReplyFromDhcpLease(null /* na */, false /* timeout */); + assertTrue(DhcpDiscoverPacket.class.isInstance(packet)); + } + + @Test + public void testDhcpClientStartWithTimeoutRetrieveNetworkAttributes() throws Exception { + final DhcpPacket packet = getReplyFromDhcpLease( + new NetworkAttributes.Builder() + .setAssignedV4Address(CLIENT_ADDR) + .setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000) + .setMtu(new Integer(MTU)) + .setGroupHint(TEST_GROUPHINT) + .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) + .build(), true /* timeout */); + assertTrue(DhcpDiscoverPacket.class.isInstance(packet)); + } + + @Test + public void testDhcpClientStartWithCachedLeaseWithoutIPAddress() throws Exception { + final DhcpPacket packet = getReplyFromDhcpLease( + new NetworkAttributes.Builder() + .setMtu(new Integer(MTU)) + .setGroupHint(TEST_GROUPHINT) + .setDnsAddresses(Collections.singletonList(SERVER_ADDR)) + .build(), false /* timeout */); + assertTrue(DhcpDiscoverPacket.class.isInstance(packet)); + } + + @Test + public void testDhcpClientRapidCommitEnabled() throws Exception { + startIpClientProvisioning(true /* isDhcpLeaseCacheEnabled */, + true /* isDhcpRapidCommitEnabled */); + final DhcpPacket packet = getNextDhcpPacket(); + assertTrue(DhcpDiscoverPacket.class.isInstance(packet)); } } diff --git a/tests/unit/src/android/net/dhcp/DhcpPacketTest.java b/tests/unit/src/android/net/dhcp/DhcpPacketTest.java index 4429add..fcaf655 100644 --- a/tests/unit/src/android/net/dhcp/DhcpPacketTest.java +++ b/tests/unit/src/android/net/dhcp/DhcpPacketTest.java @@ -45,8 +45,8 @@ import static org.junit.Assert.fail; import android.annotation.Nullable; import android.net.DhcpResults; +import android.net.InetAddresses; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.metrics.DhcpErrorEvent; import androidx.test.filters.SmallTest; @@ -86,7 +86,7 @@ public class DhcpPacketTest { private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException { - return (Inet4Address) NetworkUtils.numericToInetAddress(addrString); + return (Inet4Address) InetAddresses.parseNumericAddress(addrString); } @Before |