summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiao Ma <xiaom@google.com>2019-06-03 10:30:04 +0900
committerXiao Ma <xiaom@google.com>2019-07-06 05:31:17 +0000
commitc00a7935e581eaac66595d815c49393d6ccb2310 (patch)
treee9d1b5f50de728986ecf7ab409709bf6673f0fb7
parent692abb71d97ef89285eacf301f1cf27fb4cfe38d (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.java2
-rw-r--r--src/android/net/dhcp/DhcpDeclinePacket.java2
-rw-r--r--src/android/net/dhcp/DhcpInformPacket.java2
-rw-r--r--src/android/net/dhcp/DhcpNakPacket.java2
-rw-r--r--src/android/net/dhcp/DhcpOfferPacket.java2
-rw-r--r--src/android/net/dhcp/DhcpReleasePacket.java2
-rw-r--r--src/android/net/dhcp/DhcpRequestPacket.java4
-rw-r--r--tests/integration/src/android/net/ip/IpClientIntegrationTest.java388
-rw-r--r--tests/unit/src/android/net/dhcp/DhcpPacketTest.java4
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