diff options
Diffstat (limited to 'src/android/net')
-rw-r--r-- | src/android/net/dhcp/DhcpClient.java | 91 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpDiscoverPacket.java | 3 | ||||
-rw-r--r-- | src/android/net/dhcp/DhcpPacket.java | 25 | ||||
-rw-r--r-- | src/android/net/ip/IpClient.java | 10 | ||||
-rw-r--r-- | src/android/net/util/NetworkStackUtils.java | 26 |
5 files changed, 128 insertions, 27 deletions
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java index 0ed81a3..a140f4d 100644 --- a/src/android/net/dhcp/DhcpClient.java +++ b/src/android/net/dhcp/DhcpClient.java @@ -179,7 +179,8 @@ public class DhcpClient extends StateMachine { private static final int EVENT_CONFIGURATION_INVALID = PRIVATE_BASE + 9; // constant to represent this DHCP lease has been expired. - private static final long EXPIRED_LEASE = 1L; + @VisibleForTesting + public static final long EXPIRED_LEASE = 1L; // For message logging. private static final Class[] sMessageClasses = { DhcpClient.class }; @@ -239,7 +240,7 @@ public class DhcpClient extends StateMachine { private String mL2Key; private Inet4Address mLastAssignedIpv4Address; private long mLastAssignedIpv4AddressExpiry; - private boolean mDhcpLeaseCacheEnabled; + private Dependencies mDependencies; @NonNull private final NetworkStackIpMemoryStore mIpMemoryStore; @@ -271,15 +272,43 @@ public class DhcpClient extends StateMachine { return new WakeupMessage(mContext, getHandler(), cmdName, cmd); } + /** + * Encapsulates DhcpClient depencencies that's used for unit testing and + * integration testing. + */ + public static class Dependencies { + private final NetworkStackIpMemoryStore mNetworkStackIpMemoryStore; + + public Dependencies(NetworkStackIpMemoryStore store) { + mNetworkStackIpMemoryStore = store; + } + + /** + * Get a IpMemoryStore instance. + */ + public NetworkStackIpMemoryStore getIpMemoryStore() { + return mNetworkStackIpMemoryStore; + } + + /** + * Get the value of DHCP related experiment flags. + */ + public boolean getBooleanDeviceConfig(final String nameSpace, final String flagName) { + return NetworkStackUtils.getDeviceConfigPropertyBoolean(nameSpace, flagName, + false /* default value */); + } + } + // TODO: Take an InterfaceParams instance instead of an interface name String. private DhcpClient(Context context, StateMachine controller, String iface, - NetworkStackIpMemoryStore ipMemoryStore) { + Dependencies deps) { super(TAG, controller.getHandler()); + mDependencies = deps; mContext = context; mController = controller; mIfaceName = iface; - mIpMemoryStore = ipMemoryStore; + mIpMemoryStore = deps.getIpMemoryStore(); // CHECKSTYLE:OFF IndentationCheck addState(mStoppedState); @@ -320,8 +349,8 @@ public class DhcpClient extends StateMachine { public static DhcpClient makeDhcpClient( Context context, StateMachine controller, InterfaceParams ifParams, - NetworkStackIpMemoryStore ipMemoryStore) { - DhcpClient client = new DhcpClient(context, controller, ifParams.name, ipMemoryStore); + Dependencies deps) { + DhcpClient client = new DhcpClient(context, controller, ifParams.name, deps); client.mIface = ifParams; client.start(); return client; @@ -332,19 +361,21 @@ public class DhcpClient extends StateMachine { * */ public boolean isDhcpLeaseCacheEnabled() { - // TODO: call DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, - // DeviceConfig.PROPERTY); - // to fetch the dynamic experiment flag value. Return false by default. - return mDhcpLeaseCacheEnabled; + return mDependencies.getBooleanDeviceConfig(NetworkStackUtils.NAMESPACE_CONNECTIVITY, + NetworkStackUtils.DHCP_INIT_REBOOT_ENABLED); } /** - * set DHCP lease cached enabled experiment flag. - * + * check whether or not to support DHCP Rapid Commit option. */ - @VisibleForTesting - public void setDhcpLeaseCacheEnabled(final boolean enabled) { - mDhcpLeaseCacheEnabled = enabled; + public boolean isDhcpRapidCommitEnabled() { + return mDependencies.getBooleanDeviceConfig(NetworkStackUtils.NAMESPACE_CONNECTIVITY, + NetworkStackUtils.DHCP_RAPID_COMMIT_ENABLED); + } + + private void confirmDhcpLease(DhcpPacket packet, DhcpResults results) { + setDhcpLeaseExpiry(packet); + acceptDhcpResults(results, "Confirmed"); } private boolean initInterface() { @@ -495,7 +526,7 @@ public class DhcpClient extends StateMachine { private boolean sendDiscoverPacket() { ByteBuffer packet = DhcpPacket.buildDiscoverPacket( DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr, - DO_UNICAST, REQUESTED_PARAMS); + DO_UNICAST, REQUESTED_PARAMS, isDhcpRapidCommitEnabled()); return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST); } @@ -959,11 +990,26 @@ public class DhcpClient extends StateMachine { protected void receivePacket(DhcpPacket packet) { if (!isValidPacket(packet)) return; - if (!(packet instanceof DhcpOfferPacket)) return; - mOffer = packet.toDhcpResults(); - if (mOffer != null) { - Log.d(TAG, "Got pending lease: " + mOffer); - transitionTo(mDhcpRequestingState); + + // 1. received the DHCPOFFER packet, process it by following RFC2131. + // 2. received the DHCPACK packet from DHCP Servers who support Rapid + // Commit option, process it by following RFC4039. + if (packet instanceof DhcpOfferPacket) { + mOffer = packet.toDhcpResults(); + if (mOffer != null) { + Log.d(TAG, "Got pending lease: " + mOffer); + transitionTo(mDhcpRequestingState); + } + } else if (packet instanceof DhcpAckPacket) { + // If received DHCPACK packet w/o Rapid Commit option in this state, + // just drop it and wait for the next DHCPOFFER packet or DHCPACK w/ + // Rapid Commit option. + if (!isDhcpRapidCommitEnabled() || !packet.mRapidCommit) return; + final DhcpResults results = packet.toDhcpResults(); + if (results != null) { + confirmDhcpLease(packet, results); + transitionTo(mConfiguringInterfaceState); + } } } } @@ -990,8 +1036,7 @@ public class DhcpClient extends StateMachine { if ((packet instanceof DhcpAckPacket)) { DhcpResults results = packet.toDhcpResults(); if (results != null) { - setDhcpLeaseExpiry(packet); - acceptDhcpResults(results, "Confirmed"); + confirmDhcpLease(packet, results); transitionTo(mConfiguringInterfaceState); } } else if (packet instanceof DhcpNakPacket) { diff --git a/src/android/net/dhcp/DhcpDiscoverPacket.java b/src/android/net/dhcp/DhcpDiscoverPacket.java index 9707d13..a749796 100644 --- a/src/android/net/dhcp/DhcpDiscoverPacket.java +++ b/src/android/net/dhcp/DhcpDiscoverPacket.java @@ -62,6 +62,9 @@ public class DhcpDiscoverPacket extends DhcpPacket { addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId()); addCommonClientTlvs(buffer); addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams); + if (mRapidCommit) { + addTlv(buffer, DHCP_RAPID_COMMIT); + } addTlvEnd(buffer); } } diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java index d5c3efb..79e1c4f 100644 --- a/src/android/net/dhcp/DhcpPacket.java +++ b/src/android/net/dhcp/DhcpPacket.java @@ -281,6 +281,13 @@ public abstract class DhcpPacket { protected byte[] mClientId; /** + * DHCP zero-length Optional Type: Rapid Commit. Per RFC4039, both DHCPDISCOVER and DHCPACK + * packet may include this option. + */ + protected static final byte DHCP_RAPID_COMMIT = 80; + protected boolean mRapidCommit; + + /** * DHCP zero-length option code: pad */ protected static final byte DHCP_OPTION_PAD = 0x00; @@ -605,6 +612,14 @@ public abstract class DhcpPacket { } /** + * Adds an optional parameter containing zero-length value. + */ + protected static void addTlv(ByteBuffer buf, byte type) { + buf.put(type); + buf.put((byte) 0); + } + + /** * Adds an optional parameter containing an array of bytes. * * <p>This method is a no-op if the payload argument is null. @@ -858,6 +873,7 @@ public abstract class DhcpPacket { String message = null; String vendorId = null; String vendorInfo = null; + boolean rapidCommit = false; byte[] expectedParams = null; String hostName = null; String domainName = null; @@ -1126,6 +1142,10 @@ public abstract class DhcpPacket { optionOverload = packet.get(); optionOverload &= OPTION_OVERLOAD_BOTH; break; + case DHCP_RAPID_COMMIT: + expectedLen = 0; + rapidCommit = true; + break; default: // ignore any other parameters for (int i = 0; i < optionLen; i++) { @@ -1216,6 +1236,7 @@ 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 { @@ -1304,10 +1325,12 @@ public abstract class DhcpPacket { * parameters. */ public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, - short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) { + short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, + boolean rapidCommit) { DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */, clientMac, broadcast, INADDR_ANY /* srcIp */); pkt.mRequestedParams = expectedParams; + pkt.mRapidCommit = rapidCommit; return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); } diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index ea19c7b..799184e 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java @@ -401,6 +401,14 @@ public class IpClient extends StateMachine { NetworkStackServiceManager nssManager) { return new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService()); } + + /** + * Get a DhcpClient Dependencies instance. + */ + public DhcpClient.Dependencies getDhcpClientDependencies( + NetworkStackIpMemoryStore ipMemoryStore) { + return new DhcpClient.Dependencies(ipMemoryStore); + } } public IpClient(Context context, String ifName, IIpClientCallbacks callback, @@ -1190,7 +1198,7 @@ public class IpClient extends StateMachine { } else { // Start DHCPv4. mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams, - mIpMemoryStore); + mDependencies.getDhcpClientDependencies(mIpMemoryStore)); mDhcpClient.registerForPreDhcpNotification(); mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP, mL2Key); } diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java index 541f9d8..4afc34b 100644 --- a/src/android/net/util/NetworkStackUtils.java +++ b/src/android/net/util/NetworkStackUtils.java @@ -107,6 +107,16 @@ public class NetworkStackUtils { */ public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; + /** + * Experiment flag to enable DHCP INIT-REBOOT state, default value is false. + */ + public static final String DHCP_INIT_REBOOT_ENABLED = "dhcp_init_reboot_enabled"; + + /** + * Experiment flag to enable DHCP Rapid Commit option, default value is false. + */ + public static final String DHCP_RAPID_COMMIT_ENABLED = "dhcp_rapid_commit_enabled"; + static { System.loadLibrary("networkstackutilsjni"); } @@ -181,8 +191,7 @@ public class NetworkStackUtils { * Look up the value of a property for a particular namespace from {@link DeviceConfig}. * @param namespace The namespace containing the property to look up. * @param name The name of the property to look up. - * @param defaultValue The value to return if the property does not exist or has no non-null - * value. + * @param defaultValue The value to return if the property does not exist or its value is null. * @return the corresponding value, or defaultValue if none exists. */ public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, @@ -196,6 +205,19 @@ public class NetworkStackUtils { } /** + * Look up the value of a property for a particular namespace from {@link DeviceConfig}. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or its value is null. + * @return the corresponding value, or defaultValue if none exists. + */ + public static boolean getDeviceConfigPropertyBoolean(@NonNull String namespace, + @NonNull String name, boolean defaultValue) { + String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */); + return (value != null) ? Boolean.parseBoolean(value) : defaultValue; + } + + /** * Attaches a socket filter that accepts DHCP packets to the given socket. */ public static native void attachDhcpFilter(FileDescriptor fd) throws SocketException; |