diff options
-rw-r--r-- | src/android/net/dhcp/DhcpAckPacket.java | 8 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpClient.java | 3 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpDiscoverPacket.java | 3 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpLeaseRepository.java | 19 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpPacket.java | 13 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpServer.java | 62 | ||||
-rw-r--r-- | src/android/net/util/NetworkStackUtils.java | 9 | ||||
-rw-r--r-- | src/com/android/server/NetworkStackService.java | 1 | ||||
-rw-r--r-- | tests/integration/src/android/net/ip/IpClientIntegrationTest.java | 35 | ||||
-rw-r--r-- | tests/unit/src/android/net/dhcp/DhcpServerTest.java | 27 |
10 files changed, 120 insertions, 60 deletions
diff --git a/src/android/net/dhcp/DhcpAckPacket.java b/src/android/net/dhcp/DhcpAckPacket.java index 052af35..9e981ef 100644 --- a/src/android/net/dhcp/DhcpAckPacket.java +++ b/src/android/net/dhcp/DhcpAckPacket.java @@ -30,10 +30,12 @@ public class DhcpAckPacket extends DhcpPacket { private final Inet4Address mSrcIp; DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress, - Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) { + Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac, + boolean rapidCommit) { super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast); mBroadcast = broadcast; mSrcIp = serverAddress; + mRapidCommit = rapidCommit; } public String toString() { @@ -70,8 +72,10 @@ public class DhcpAckPacket extends DhcpPacket { void finishPacket(ByteBuffer buffer) { addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_ACK); addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier); - addCommonServerTlvs(buffer); + if (mRapidCommit) { + addTlv(buffer, DHCP_RAPID_COMMIT); + } addTlvEnd(buffer); } diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java index e7d53ee..dc0175e 100644 --- a/src/android/net/dhcp/DhcpClient.java +++ b/src/android/net/dhcp/DhcpClient.java @@ -1171,7 +1171,8 @@ public class DhcpClient extends StateMachine { final DhcpResults results = packet.toDhcpResults(); if (results != null) { confirmDhcpLease(packet, results); - transitionTo(mConfiguringInterfaceState); + transitionTo(isDhcpIpConflictDetectEnabled() + ? mIpAddressConflictDetectingState : mConfiguringInterfaceState); } } } diff --git a/src/android/net/dhcp/DhcpDiscoverPacket.java b/src/android/net/dhcp/DhcpDiscoverPacket.java index a749796..15c20cf 100644 --- a/src/android/net/dhcp/DhcpDiscoverPacket.java +++ b/src/android/net/dhcp/DhcpDiscoverPacket.java @@ -32,9 +32,10 @@ public class DhcpDiscoverPacket extends DhcpPacket { * Generates a DISCOVER packet with the specified parameters. */ DhcpDiscoverPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac, - boolean broadcast, Inet4Address srcIp) { + boolean broadcast, Inet4Address srcIp, boolean rapidCommit) { super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast); mSrcIp = srcIp; + mRapidCommit = rapidCommit; } public String toString() { diff --git a/src/android/net/dhcp/DhcpLeaseRepository.java b/src/android/net/dhcp/DhcpLeaseRepository.java index d22193b..4e74dc8 100644 --- a/src/android/net/dhcp/DhcpLeaseRepository.java +++ b/src/android/net/dhcp/DhcpLeaseRepository.java @@ -190,6 +190,25 @@ class DhcpLeaseRepository { return newLease; } + /** + * Get a rapid committed DHCP Lease, to reply to a DHCPDISCOVER w/ Rapid Commit option. + * + * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC} + * @param relayAddr Internet address of the relay (giaddr), can be {@link Inet4Address#ANY} + * @param hostname Client-provided hostname, or {@link DhcpLease#HOSTNAME_NONE} + * @throws OutOfAddressesException The server does not have any available address + * @throws InvalidSubnetException The lease was requested from an unsupported subnet + */ + @NonNull + public DhcpLease getCommittedLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + @NonNull Inet4Address relayAddr, @Nullable String hostname) + throws OutOfAddressesException, InvalidSubnetException { + final DhcpLease newLease = getOffer(clientId, hwAddr, relayAddr, null /* reqAddr */, + hostname); + commitLease(newLease); + return newLease; + } + private void checkValidRelayAddr(@Nullable Inet4Address relayAddr) throws InvalidSubnetException { // As per #4.3.1, addresses are assigned based on the relay address if present. This diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java index 5ab769b..c5700b3 100644 --- a/src/android/net/dhcp/DhcpPacket.java +++ b/src/android/net/dhcp/DhcpPacket.java @@ -1179,7 +1179,7 @@ public abstract class DhcpPacket { "No DHCP message type option"); case DHCP_MESSAGE_TYPE_DISCOVER: newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac, - broadcast, ipSrc); + broadcast, ipSrc, rapidCommit); break; case DHCP_MESSAGE_TYPE_OFFER: newPacket = new DhcpOfferPacket( @@ -1196,7 +1196,8 @@ public abstract class DhcpPacket { break; case DHCP_MESSAGE_TYPE_ACK: newPacket = new DhcpAckPacket( - transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac); + transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac, + rapidCommit); break; case DHCP_MESSAGE_TYPE_NAK: newPacket = new DhcpNakPacket( @@ -1238,7 +1239,6 @@ public abstract class DhcpPacket { newPacket.mT2 = T2; newPacket.mVendorId = vendorId; newPacket.mVendorInfo = vendorInfo; - newPacket.mRapidCommit = rapidCommit; if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) { newPacket.mServerHostName = serverHostName; } else { @@ -1330,9 +1330,8 @@ public abstract class DhcpPacket { short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit) { DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */, - clientMac, broadcast, INADDR_ANY /* srcIp */); + clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit); pkt.mRequestedParams = expectedParams; - pkt.mRapidCommit = rapidCommit; return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); } @@ -1372,10 +1371,10 @@ public abstract class DhcpPacket { Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, - short mtu) { + short mtu, boolean rapidCommit) { DhcpPacket pkt = new DhcpAckPacket( transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp, - mac); + mac, rapidCommit); pkt.mGateways = gateways; pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; diff --git a/src/android/net/dhcp/DhcpServer.java b/src/android/net/dhcp/DhcpServer.java index 37dd972..4fc213a 100644 --- a/src/android/net/dhcp/DhcpServer.java +++ b/src/android/net/dhcp/DhcpServer.java @@ -22,6 +22,8 @@ import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; +import static android.net.util.NetworkStackUtils.DHCP_RAPID_COMMIT_VERSION; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -38,6 +40,7 @@ import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingP import static java.lang.Integer.toUnsignedLong; +import android.content.Context; import android.net.INetworkStackStatusCallback; import android.net.MacAddress; import android.net.TrafficStats; @@ -92,6 +95,8 @@ public class DhcpServer extends IDhcpServer.Stub { private static final int CMD_UPDATE_PARAMS = 3; @NonNull + private final Context mContext; + @NonNull private final HandlerThread mHandlerThread; @NonNull private final String mIfName; @@ -107,6 +112,8 @@ public class DhcpServer extends IDhcpServer.Stub { @Nullable private volatile ServerHandler mHandler; + private final boolean mDhcpRapidCommitEnabled; + // Accessed only on the handler thread @Nullable private DhcpPacketListener mPacketListener; @@ -176,6 +183,14 @@ public class DhcpServer extends IDhcpServer.Stub { * @throws SecurityException The caller is not allowed to call public methods on DhcpServer. */ void checkCaller() throws SecurityException; + + /** + * Check whether or not one specific experimental feature for connectivity namespace is + * enabled. + * @param context The global context information about an app environment. + * @param name Specific experimental flag name. + */ + boolean isFeatureEnabled(@NonNull Context context, @NonNull String name); } private class DependenciesImpl implements Dependencies { @@ -214,6 +229,11 @@ public class DhcpServer extends IDhcpServer.Stub { public void checkCaller() { enforceNetworkStackCallingPermission(); } + + @Override + public boolean isFeatureEnabled(@NonNull Context context, @NonNull String name) { + return NetworkStackUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name); + } } private static class MalformedPacketException extends Exception { @@ -222,19 +242,20 @@ public class DhcpServer extends IDhcpServer.Stub { } } - public DhcpServer(@NonNull String ifName, + public DhcpServer(@NonNull Context context, @NonNull String ifName, @NonNull DhcpServingParams params, @NonNull SharedLog log) { - this(new HandlerThread(DhcpServer.class.getSimpleName() + "." + ifName), + this(context, new HandlerThread(DhcpServer.class.getSimpleName() + "." + ifName), ifName, params, log, null); } @VisibleForTesting - DhcpServer(@NonNull HandlerThread handlerThread, @NonNull String ifName, - @NonNull DhcpServingParams params, @NonNull SharedLog log, + DhcpServer(@NonNull Context context, @NonNull HandlerThread handlerThread, + @NonNull String ifName, @NonNull DhcpServingParams params, @NonNull SharedLog log, @Nullable Dependencies deps) { if (deps == null) { deps = new DependenciesImpl(); } + mContext = context; mHandlerThread = handlerThread; mIfName = ifName; mServingParams = params; @@ -242,6 +263,7 @@ public class DhcpServer extends IDhcpServer.Stub { mDeps = deps; mClock = deps.makeClock(); mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock); + mDhcpRapidCommitEnabled = deps.isFeatureEnabled(context, DHCP_RAPID_COMMIT_VERSION); } /** @@ -388,17 +410,20 @@ public class DhcpServer extends IDhcpServer.Stub { final DhcpLease lease; final MacAddress clientMac = getMacAddr(packet); try { - lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac, - packet.mRelayIp, packet.mRequestedIp, packet.mHostName); + if (mDhcpRapidCommitEnabled && packet.mRapidCommit) { + lease = mLeaseRepo.getCommittedLease(packet.getExplicitClientIdOrNull(), clientMac, + packet.mRelayIp, packet.mHostName); + transmitAck(packet, lease, clientMac); + } else { + lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac, + packet.mRelayIp, packet.mRequestedIp, packet.mHostName); + transmitOffer(packet, lease, clientMac); + } } catch (DhcpLeaseRepository.OutOfAddressesException e) { transmitNak(packet, "Out of addresses to offer"); - return; } catch (DhcpLeaseRepository.InvalidSubnetException e) { logIgnoredPacketInvalidSubnet(e); - return; } - - transmitOffer(packet, lease, clientMac); } private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException { @@ -492,23 +517,24 @@ public class DhcpServer extends IDhcpServer.Stub { return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag); } - private boolean transmitAck(@NonNull DhcpPacket request, @NonNull DhcpLease lease, + private boolean transmitAck(@NonNull DhcpPacket packet, @NonNull DhcpLease lease, @NonNull MacAddress clientMac) { // TODO: replace DhcpPacket's build methods with real builders and use common code with // transmitOffer above - final boolean broadcastFlag = getBroadcastFlag(request, lease); + final boolean broadcastFlag = getBroadcastFlag(packet, lease); final int timeout = getLeaseTimeout(lease); - final String hostname = getHostnameIfRequested(request, lease); - final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId, - broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp, - lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout, + final String hostname = getHostnameIfRequested(packet, lease); + final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, packet.mTransId, + broadcastFlag, mServingParams.getServerInet4Addr(), packet.mRelayIp, + lease.getNetAddr(), packet.mClientIp, packet.mClientMac, timeout, mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(), new ArrayList<>(mServingParams.defaultRouters), new ArrayList<>(mServingParams.dnsServers), mServingParams.getServerInet4Addr(), null /* domainName */, hostname, - mServingParams.metered, (short) mServingParams.linkMtu); + mServingParams.metered, (short) mServingParams.linkMtu, + packet.mRapidCommit && mDhcpRapidCommitEnabled); - return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag); + return transmitOfferOrAckPacket(ackPacket, packet, lease, clientMac, broadcastFlag); } private boolean transmitNak(DhcpPacket request, String message) { diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java index 993f3cb..45ed367 100644 --- a/src/android/net/util/NetworkStackUtils.java +++ b/src/android/net/util/NetworkStackUtils.java @@ -112,13 +112,18 @@ public class NetworkStackUtils { public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; /** - * Experiment flag to enable DHCP INIT-REBOOT state, default value is false. + * @deprecated Considering boolean experiment flag is likely to cause misconfiguration + * particularly when NetworkStack module rolls back to previous version. It's + * much safer to determine whether or not to enable one specific experimental + * feature by comparing flag version with module version. */ + @Deprecated public static final String DHCP_INIT_REBOOT_ENABLED = "dhcp_init_reboot_enabled"; /** - * Experiment flag to enable DHCP Rapid Commit option, default value is false. + * @deprecated See above explanation. */ + @Deprecated public static final String DHCP_RAPID_COMMIT_ENABLED = "dhcp_rapid_commit_enabled"; /** diff --git a/src/com/android/server/NetworkStackService.java b/src/com/android/server/NetworkStackService.java index 74a5da0..0114e45 100644 --- a/src/com/android/server/NetworkStackService.java +++ b/src/com/android/server/NetworkStackService.java @@ -198,6 +198,7 @@ public class NetworkStackService extends Service { final DhcpServer server; try { server = new DhcpServer( + mContext, ifName, DhcpServingParams.fromParcelableObject(params), mLog.forSubComponent(ifName + ".DHCP")); diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java index c5f99c5..afd5929 100644 --- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java +++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java @@ -118,7 +118,6 @@ 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; @@ -459,7 +458,7 @@ public class IpClientIntegrationTest { } private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet, - final Integer leaseTimeSec, final short mtu) { + final Integer leaseTimeSec, final short mtu, final boolean rapidCommit) { return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(), false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */, CLIENT_ADDR /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(), @@ -467,7 +466,7 @@ public class IpClientIntegrationTest { Collections.singletonList(SERVER_ADDR) /* gateways */, Collections.singletonList(SERVER_ADDR) /* dnsServers */, SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME, - false /* metered */, mtu); + false /* metered */, mtu, rapidCommit); } private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet) { @@ -560,13 +559,15 @@ public class IpClientIntegrationTest { while ((packet = getNextDhcpPacket()) != null) { if (packet instanceof DhcpDiscoverPacket) { if (isDhcpRapidCommitEnabled) { - sendResponse(buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu)); + sendResponse(buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, + true /* rapidCommit */)); } else { sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec, (short) mtu)); } } else if (packet instanceof DhcpRequestPacket) { final ByteBuffer byteBuffer = isSuccessLease - ? buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu) + ? buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, + false /* rapidCommit */) : buildDhcpNakPacket(packet); sendResponse(byteBuffer); } else { @@ -679,11 +680,9 @@ public class IpClientIntegrationTest { packet = getNextDhcpPacket(); assertTrue(packet instanceof DhcpRequestPacket); } - // TODO: currently the DHCPACK packet doesn't include the Rapid Commit option. - // This does not matter because the client will accept the ACK even if the Rapid Commit - // option is not present. Fix the test code, and then change the client to ensure - // it will only accept the ACK if the Rapid Commit option is present. - sendResponse(buildDhcpAckPacket(packet, TEST_LEASE_DURATION_S, mtu)); + + sendResponse(buildDhcpAckPacket(packet, TEST_LEASE_DURATION_S, mtu, + isDhcpRapidCommitEnabled)); if (!shouldAbortPreconnection) { mIpc.sendMessage(IpClient.CMD_COMPLETE_PRECONNECTION, 1 /* success */); } @@ -823,10 +822,8 @@ public class IpClientIntegrationTest { 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 */, @@ -1170,18 +1167,12 @@ public class IpClientIntegrationTest { false /* shouldAbortPreconnection */); } - // So far DHCPACK doesn't include Rapid Commit option(aosp/1092270 is adding the option), when - // receiving the DHCPACK packet in DhcpPreconnectionState or DhcpInitState, dropping the DHCPACK - // packet directly, which would cause test cases with enabled "isDhcpRapidCommitEnabled" flag - // fail. - @Ignore @Test public void testDhcpClientPreconnectionEnabled() throws Exception { doIpClientProvisioningWithPreconnectionTest(true /* isDhcpRapidCommitEnabled */, false /* shouldAbortPreconnection */); } - @Ignore @Test public void testDhcpClientPreconnectionEnabled_WithRapidCommit() throws Exception { doIpClientProvisioningWithPreconnectionTest(true /* isDhcpRapidCommitEnabled */, @@ -1215,11 +1206,6 @@ public class IpClientIntegrationTest { false /* shouldResponseArpReply */); } - // So far Rapid Commit option has not been built within DHCPACK packet (implemention at - // aosp/1092270), hence, client can't deal with DHCPACK in INIT state correctly and drop - // the received DHCPACK, which causes the following verify checks fails. After checking in - // aosp/1092270, remove all below @Ignore annotations. - @Ignore @Test public void testDhcpDecline_WithRapidCommitWithoutIpConflict() throws Exception { doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */, @@ -1227,7 +1213,6 @@ public class IpClientIntegrationTest { false /* shouldResponseArpReply */); } - @Ignore @Test public void testDhcpDecline_WithRapidCommitConflictByArpReply() throws Exception { doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */, @@ -1235,7 +1220,6 @@ public class IpClientIntegrationTest { true /* shouldResponseArpReply */); } - @Ignore @Test public void testDhcpDecline_WithRapidCommitConflictByArpProbe() throws Exception { doIpAddressConflictDetectionTest(true /* causeIpAddressConflict */, @@ -1243,7 +1227,6 @@ public class IpClientIntegrationTest { false /* shouldResponseArpReply */); } - @Ignore @Test public void testDhcpDecline_EnableFlagWithRapidCommitWithoutIpConflict() throws Exception { doIpAddressConflictDetectionTest(false /* causeIpAddressConflict */, diff --git a/tests/unit/src/android/net/dhcp/DhcpServerTest.java b/tests/unit/src/android/net/dhcp/DhcpServerTest.java index f0e2f1b..5074f82 100644 --- a/tests/unit/src/android/net/dhcp/DhcpServerTest.java +++ b/tests/unit/src/android/net/dhcp/DhcpServerTest.java @@ -23,6 +23,7 @@ import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.DhcpPacket.INADDR_ANY; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.util.NetworkStackUtils.DHCP_RAPID_COMMIT_VERSION; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -42,6 +43,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.net.INetworkStackStatusCallback; import android.net.LinkAddress; import android.net.MacAddress; @@ -104,6 +106,8 @@ public class DhcpServerTest { TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME); @NonNull @Mock + private Context mContext; + @NonNull @Mock private Dependencies mDeps; @NonNull @Mock private DhcpLeaseRepository mRepository; @@ -147,6 +151,7 @@ public class DhcpServerTest { when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository); when(mDeps.makeClock()).thenReturn(mClock); when(mDeps.makePacketListener()).thenReturn(mPacketListener); + when(mDeps.isFeatureEnabled(eq(mContext), eq(DHCP_RAPID_COMMIT_VERSION))).thenReturn(true); doNothing().when(mDeps) .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture()); when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME); @@ -163,7 +168,7 @@ public class DhcpServerTest { mLooper = TestableLooper.get(this); mHandlerThread = spy(new HandlerThread("TestDhcpServer")); when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); - mServer = new DhcpServer(mHandlerThread, TEST_IFACE, servingParams, + mServer = new DhcpServer(mContext, mHandlerThread, TEST_IFACE, servingParams, new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps); mServer.start(mAssertSuccessCallback); @@ -192,7 +197,7 @@ public class DhcpServerTest { final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, - false /* broadcast */, INADDR_ANY /* srcIp */); + false /* broadcast */, INADDR_ANY /* srcIp */, false /* rapidCommit */); mServer.processPacket(discover, DHCP_CLIENT); assertResponseSentTo(TEST_CLIENT_ADDR); @@ -201,6 +206,22 @@ public class DhcpServerTest { } @Test + public void testDiscover_RapidCommit() throws Exception { + when(mDeps.isFeatureEnabled(eq(mContext), eq(DHCP_RAPID_COMMIT_VERSION))).thenReturn(true); + when(mRepository.getCommittedLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC), + eq(INADDR_ANY) /* relayAddr */, isNull() /* hostname */)).thenReturn(TEST_LEASE); + + final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, + (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, + false /* broadcast */, INADDR_ANY /* srcIp */, true /* rapidCommit */); + mServer.processPacket(discover, DHCP_CLIENT); + + assertResponseSentTo(TEST_CLIENT_ADDR); + final DhcpAckPacket packet = assertAck(getPacket()); + assertMatchesTestLease(packet); + } + + @Test public void testDiscover_OutOfAddresses() throws Exception { when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */)) @@ -208,7 +229,7 @@ public class DhcpServerTest { final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, - false /* broadcast */, INADDR_ANY /* srcIp */); + false /* broadcast */, INADDR_ANY /* srcIp */, false /* rapidCommit */); mServer.processPacket(discover, DHCP_CLIENT); assertResponseSentTo(INADDR_BROADCAST); |