summaryrefslogtreecommitdiff
path: root/src/android
diff options
context:
space:
mode:
authorXiao Ma <xiaom@google.com>2019-06-11 18:51:24 +0900
committerXiao Ma <xiaom@google.com>2019-07-02 18:57:04 +0900
commitf963e366ec80924fd17e4631f2243fb6b1a3670d (patch)
tree014a2690fa5883cdeb9db393ce1a75c2e8b13b2a /src/android
parent74c651f8f3fde9ebb4bd43b433759aaa40bf8f40 (diff)
Add DHCP Rapid Commit option(RFC4039) support in client side.
Bug: 122710829 Bug: 136216415 Test: atest FrameworksNetTests NetworkStackTests Test: manual test Change-Id: I384282b7efd0df0c4a6de7bdc1957048303ad88b
Diffstat (limited to 'src/android')
-rw-r--r--src/android/net/dhcp/DhcpClient.java91
-rw-r--r--src/android/net/dhcp/DhcpDiscoverPacket.java3
-rw-r--r--src/android/net/dhcp/DhcpPacket.java25
-rw-r--r--src/android/net/ip/IpClient.java10
-rw-r--r--src/android/net/util/NetworkStackUtils.java26
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;