summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRemi NGUYEN VAN <reminv@google.com>2019-10-28 17:04:55 +0900
committerXiao Ma <xiaom@google.com>2020-02-19 21:54:01 +0900
commit2a7389299668893d0532838af5f9210f0884604a (patch)
treeba7578961ae0e0bc5684b9b1825e9cbcc4dce5bd
parent21907e1cdc3dc9f86c4446d7e111a6637aefcec4 (diff)
Add captive portal info to DhcpClient output
Requesting the captive portal option is flagged off by default. The URL it provides will be used to support the captive portal API; see RFC7710bis. Bug: 139269711 Test: atest NetworkStackTests NetworkStackNextTests Test: atest NetworkStackIntegrationTests NetworkStackNextIntegrationTests Change-Id: I783466e0e60f364e79cd76af3fe43a7862d35cf2
-rw-r--r--apishim/30/com/android/networkstack/apishim/CaptivePortalDataShimImpl.java2
-rw-r--r--src/android/net/dhcp/DhcpClient.java32
-rw-r--r--src/android/net/dhcp/DhcpPacket.java64
-rw-r--r--src/android/net/dhcp/DhcpServer.java7
-rw-r--r--src/android/net/ip/IpClient.java11
-rw-r--r--src/android/net/util/ConnectivityPacketSummary.java14
-rw-r--r--tests/integration/Android.bp30
-rw-r--r--tests/integration/src/android/net/ip/IpClientIntegrationTest.java100
-rw-r--r--tests/unit/src/android/net/dhcp/DhcpPacketTest.java153
-rw-r--r--tests/unit/src/android/net/dhcp/DhcpServerTest.java3
10 files changed, 347 insertions, 69 deletions
diff --git a/apishim/30/com/android/networkstack/apishim/CaptivePortalDataShimImpl.java b/apishim/30/com/android/networkstack/apishim/CaptivePortalDataShimImpl.java
index 135aa63..10df01b 100644
--- a/apishim/30/com/android/networkstack/apishim/CaptivePortalDataShimImpl.java
+++ b/apishim/30/com/android/networkstack/apishim/CaptivePortalDataShimImpl.java
@@ -23,7 +23,6 @@ import android.os.Build;
import android.os.RemoteException;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import org.json.JSONException;
import org.json.JSONObject;
@@ -70,7 +69,6 @@ public class CaptivePortalDataShimImpl
.build());
}
- @VisibleForTesting
public static boolean isSupported() {
return ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q);
}
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java
index fbcd0f6..41e54a4 100644
--- a/src/android/net/dhcp/DhcpClient.java
+++ b/src/android/net/dhcp/DhcpClient.java
@@ -17,6 +17,7 @@
package android.net.dhcp;
import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
+import static android.net.dhcp.DhcpPacket.DHCP_CAPTIVE_PORTAL;
import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
@@ -95,6 +96,7 @@ import com.android.internal.util.StateMachine;
import com.android.internal.util.TrafficStatsConstants;
import com.android.internal.util.WakeupMessage;
import com.android.networkstack.R;
+import com.android.networkstack.apishim.CaptivePortalDataShimImpl;
import com.android.networkstack.apishim.SocketUtilsShimImpl;
import com.android.networkstack.arp.ArpPacket;
@@ -260,8 +262,9 @@ public class DhcpClient extends StateMachine {
private static final SparseArray<String> sMessageNames =
MessageUtils.findMessageNames(sMessageClasses);
- // DHCP parameters that we request.
- /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
+ // DHCP parameters that we request by default.
+ @VisibleForTesting
+ /* package */ static final byte[] DEFAULT_REQUESTED_PARAMS = new byte[] {
DHCP_SUBNET_MASK,
DHCP_ROUTER,
DHCP_DNS_SERVER,
@@ -274,6 +277,21 @@ public class DhcpClient extends StateMachine {
DHCP_VENDOR_INFO,
};
+ @NonNull
+ private byte[] getRequestedParams() {
+ if (isCapportApiEnabled()) {
+ final byte[] params = Arrays.copyOf(DEFAULT_REQUESTED_PARAMS,
+ DEFAULT_REQUESTED_PARAMS.length + 1);
+ params[params.length - 1] = DHCP_CAPTIVE_PORTAL;
+ return params;
+ }
+ return DEFAULT_REQUESTED_PARAMS;
+ }
+
+ private static boolean isCapportApiEnabled() {
+ return CaptivePortalDataShimImpl.isSupported();
+ }
+
// DHCP flag that means "yes, we support unicast."
private static final boolean DO_UNICAST = false;
@@ -556,8 +574,10 @@ public class DhcpClient extends StateMachine {
@Override
protected void handlePacket(byte[] recvbuf, int length) {
try {
+ final byte[] optionsToSkip =
+ isCapportApiEnabled() ? new byte[0] : new byte[] { DHCP_CAPTIVE_PORTAL };
final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf, length,
- DhcpPacket.ENCAP_L2);
+ DhcpPacket.ENCAP_L2, optionsToSkip);
if (DBG) Log.d(TAG, "Received packet: " + packet);
sendMessage(CMD_RECEIVED_PACKET, packet);
} catch (DhcpPacket.ParseException e) {
@@ -649,7 +669,7 @@ public class DhcpClient extends StateMachine {
private boolean sendDiscoverPacket() {
final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
- DO_UNICAST, REQUESTED_PARAMS, isDhcpRapidCommitEnabled(), mHostname);
+ DO_UNICAST, getRequestedParams(), isDhcpRapidCommitEnabled(), mHostname);
return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
}
@@ -663,7 +683,7 @@ public class DhcpClient extends StateMachine {
final ByteBuffer packet = DhcpPacket.buildRequestPacket(
encap, mTransactionId, getSecs(), clientAddress,
DO_UNICAST, mHwAddr, requestedAddress,
- serverAddress, REQUESTED_PARAMS, mHostname);
+ serverAddress, getRequestedParams(), mHostname);
String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
" request=" + requestedAddress.getHostAddress() +
@@ -1267,7 +1287,7 @@ public class DhcpClient extends StateMachine {
final Layer2PacketParcelable l2Packet = new Layer2PacketParcelable();
final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
- DO_UNICAST, REQUESTED_PARAMS, true /* rapid commit */, mHostname);
+ DO_UNICAST, getRequestedParams(), true /* rapid commit */, mHostname);
l2Packet.dstMacAddress = MacAddress.fromBytes(DhcpPacket.ETHER_BROADCAST);
l2Packet.payload = Arrays.copyOf(packet.array(), packet.limit());
diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java
index 9eca0b5..19af74c 100644
--- a/src/android/net/dhcp/DhcpPacket.java
+++ b/src/android/net/dhcp/DhcpPacket.java
@@ -307,6 +307,10 @@ public abstract class DhcpPacket {
protected static final byte DHCP_RAPID_COMMIT = 80;
protected boolean mRapidCommit;
+ @VisibleForTesting
+ public static final byte DHCP_CAPTIVE_PORTAL = (byte) 114;
+ protected String mCaptivePortalUrl;
+
/**
* DHCP zero-length option code: pad
*/
@@ -785,6 +789,7 @@ public abstract class DhcpPacket {
if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
addTlv(buf, DHCP_MTU, mMtu);
}
+ addTlv(buf, DHCP_CAPTIVE_PORTAL, mCaptivePortalUrl);
}
/**
@@ -871,6 +876,23 @@ public abstract class DhcpPacket {
}
}
+ private static int skipOption(ByteBuffer packet, int optionLen)
+ throws BufferUnderflowException {
+ int expectedLen = 0;
+ for (int i = 0; i < optionLen; i++) {
+ expectedLen++;
+ packet.get();
+ }
+ return expectedLen;
+ }
+
+ private static boolean shouldSkipOption(byte optionType, byte[] optionsToSkip) {
+ for (byte option : optionsToSkip) {
+ if (option == optionType) return true;
+ }
+ return false;
+ }
+
/**
* Creates a concrete DhcpPacket from the supplied ByteBuffer. The
* buffer may have an L2 encapsulation (which is the full EthernetII
@@ -881,8 +903,8 @@ public abstract class DhcpPacket {
* in object fields.
*/
@VisibleForTesting
- static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
- {
+ static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip)
+ throws ParseException {
// bootp parameters
int transactionId;
short secs;
@@ -900,6 +922,7 @@ public abstract class DhcpPacket {
String vendorId = null;
String vendorInfo = null;
boolean rapidCommit = false;
+ String captivePortalUrl = null;
byte[] expectedParams = null;
String hostName = null;
String domainName = null;
@@ -1080,6 +1103,11 @@ public abstract class DhcpPacket {
int optionLen = packet.get() & 0xFF;
int expectedLen = 0;
+ if (shouldSkipOption(optionType, optionsToSkip)) {
+ skipOption(packet, optionLen);
+ continue;
+ }
+
switch(optionType) {
case DHCP_SUBNET_MASK:
netMask = readIpAddress(packet);
@@ -1172,12 +1200,12 @@ public abstract class DhcpPacket {
expectedLen = 0;
rapidCommit = true;
break;
+ case DHCP_CAPTIVE_PORTAL:
+ expectedLen = optionLen;
+ captivePortalUrl = readAsciiString(packet, optionLen, true);
+ break;
default:
- // ignore any other parameters
- for (int i = 0; i < optionLen; i++) {
- expectedLen++;
- byte throwaway = packet.get();
- }
+ expectedLen = skipOption(packet, optionLen);
}
if (expectedLen != optionLen) {
@@ -1263,6 +1291,7 @@ public abstract class DhcpPacket {
newPacket.mT2 = T2;
newPacket.mVendorId = vendorId;
newPacket.mVendorInfo = vendorInfo;
+ newPacket.mCaptivePortalUrl = captivePortalUrl;
if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) {
newPacket.mServerHostName = serverHostName;
} else {
@@ -1274,11 +1303,11 @@ public abstract class DhcpPacket {
/**
* Parse a packet from an array of bytes, stopping at the given length.
*/
- public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
- throws ParseException {
+ public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType,
+ byte[] optionsToSkip) throws ParseException {
ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
try {
- return decodeFullPacket(buffer, pktType);
+ return decodeFullPacket(buffer, pktType, optionsToSkip);
} catch (ParseException e) {
throw e;
} catch (Exception e) {
@@ -1287,6 +1316,14 @@ public abstract class DhcpPacket {
}
/**
+ * Parse a packet from an array of bytes, stopping at the given length.
+ */
+ public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
+ throws ParseException {
+ return decodeFullPacket(packet, length, pktType, new byte[0]);
+ }
+
+ /**
* Construct a DhcpResults object from a DHCP reply packet.
*/
public DhcpResults toDhcpResults() {
@@ -1328,6 +1365,7 @@ public abstract class DhcpPacket {
results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
results.serverHostName = mServerHostName;
+ results.captivePortalApiUrl = mCaptivePortalUrl;
return results;
}
@@ -1369,7 +1407,7 @@ public abstract class DhcpPacket {
Inet4Address yourIp, 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, String captivePortalUrl) {
DhcpPacket pkt = new DhcpOfferPacket(
transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
INADDR_ANY /* clientIp */, yourIp, mac);
@@ -1382,6 +1420,7 @@ public abstract class DhcpPacket {
pkt.mSubnetMask = netMask;
pkt.mBroadcastAddress = bcAddr;
pkt.mMtu = mtu;
+ pkt.mCaptivePortalUrl = captivePortalUrl;
if (metered) {
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
}
@@ -1396,7 +1435,7 @@ 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, boolean rapidCommit) {
+ short mtu, boolean rapidCommit, String captivePortalUrl) {
DhcpPacket pkt = new DhcpAckPacket(
transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
mac, rapidCommit);
@@ -1409,6 +1448,7 @@ public abstract class DhcpPacket {
pkt.mServerIdentifier = dhcpServerIdentifier;
pkt.mBroadcastAddress = bcAddr;
pkt.mMtu = mtu;
+ pkt.mCaptivePortalUrl = captivePortalUrl;
if (metered) {
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
}
diff --git a/src/android/net/dhcp/DhcpServer.java b/src/android/net/dhcp/DhcpServer.java
index 9e54a69..9c5b3c6 100644
--- a/src/android/net/dhcp/DhcpServer.java
+++ b/src/android/net/dhcp/DhcpServer.java
@@ -529,7 +529,9 @@ public class DhcpServer extends IDhcpServer.Stub {
broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
new ArrayList<>(mServingParams.dnsServers),
mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
- mServingParams.metered, (short) mServingParams.linkMtu);
+ mServingParams.metered, (short) mServingParams.linkMtu,
+ // TODO (b/144402437): advertise the URL if known
+ null /* captivePortalApiUrl */);
return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
}
@@ -549,7 +551,8 @@ public class DhcpServer extends IDhcpServer.Stub {
new ArrayList<>(mServingParams.dnsServers),
mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
mServingParams.metered, (short) mServingParams.linkMtu,
- packet.mRapidCommit && mDhcpRapidCommitEnabled);
+ // TODO (b/144402437): advertise the URL if known
+ packet.mRapidCommit && mDhcpRapidCommitEnabled, null /* captivePortalApiUrl */);
return transmitOfferOrAckPacket(ackPacket, packet, lease, clientMac, broadcastFlag);
}
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java
index 47f955a..173f136 100644
--- a/src/android/net/ip/IpClient.java
+++ b/src/android/net/ip/IpClient.java
@@ -36,6 +36,7 @@ import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.TcpKeepalivePacketDataParcelable;
+import android.net.Uri;
import android.net.apf.ApfCapabilities;
import android.net.apf.ApfFilter;
import android.net.dhcp.DhcpClient;
@@ -57,6 +58,7 @@ import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
import android.util.Pair;
+import android.util.Patterns;
import android.util.SparseArray;
import androidx.annotation.NonNull;
@@ -1192,6 +1194,15 @@ public class IpClient extends StateMachine {
if (mDhcpResults.mtu != 0) {
newLp.setMtu(mDhcpResults.mtu);
}
+
+ final String capportUrl = mDhcpResults.captivePortalApiUrl;
+ // Uri.parse does no syntax check; do a simple regex check to eliminate garbage.
+ // If the URL is still incorrect data fetching will fail later, which is fine.
+ if (capportUrl != null && Patterns.WEB_URL.matcher(capportUrl).matches()) {
+ NetworkInformationShimImpl.newInstance()
+ .setCaptivePortalApiUrl(newLp, Uri.parse(capportUrl));
+ }
+ // TODO: also look at the IPv6 RA (netlink) for captive portal URL
}
// [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
diff --git a/src/android/net/util/ConnectivityPacketSummary.java b/src/android/net/util/ConnectivityPacketSummary.java
index 08c3f60..4d04911 100644
--- a/src/android/net/util/ConnectivityPacketSummary.java
+++ b/src/android/net/util/ConnectivityPacketSummary.java
@@ -82,12 +82,26 @@ public class ConnectivityPacketSummary {
private final ByteBuffer mPacket;
private final String mSummary;
+ /**
+ * Create a string summary of a received packet.
+ * @param hwaddr MacAddress of the receiving device.
+ * @param buffer Buffer of the packet. Length is assumed to be the buffer length.
+ * @return A summary of the packet.
+ */
public static String summarize(MacAddress hwaddr, byte[] buffer) {
return summarize(hwaddr, buffer, buffer.length);
}
// Methods called herein perform some but by no means all error checking.
// They may throw runtime exceptions on malformed packets.
+
+ /**
+ * Create a string summary of a received packet.
+ * @param macAddr MacAddress of the receiving device.
+ * @param buffer Buffer of the packet.
+ * @param length Length of the packet.
+ * @return A summary of the packet.
+ */
public static String summarize(MacAddress macAddr, byte[] buffer, int length) {
if ((macAddr == null) || (buffer == null)) return null;
length = Math.min(length, buffer.length);
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp
index c4f057b..a9eabc8 100644
--- a/tests/integration/Android.bp
+++ b/tests/integration/Android.bp
@@ -27,9 +27,8 @@ java_defaults {
visibility: ["//visibility:private"],
}
-android_library {
- name: "NetworkStackIntegrationTestsLib",
- min_sdk_version: "29",
+java_defaults {
+ name: "NetworkStackIntegrationTestsDefaults",
srcs: ["src/**/*.java"],
static_libs: [
"androidx.annotation_annotation",
@@ -37,7 +36,6 @@ android_library {
"mockito-target-extended-minus-junit4",
"net-tests-utils",
"testables",
- "NetworkStackApiStableLib",
],
libs: [
"android.test.runner",
@@ -48,6 +46,15 @@ android_library {
visibility: ["//visibility:private"],
}
+android_library {
+ name: "NetworkStackIntegrationTestsLib",
+ defaults: ["NetworkStackIntegrationTestsDefaults"],
+ min_sdk_version: "29",
+ static_libs: [
+ "NetworkStackApiStableLib",
+ ],
+}
+
// Network stack integration tests.
android_test {
name: "NetworkStackIntegrationTests",
@@ -59,6 +66,21 @@ android_test {
min_sdk_version: "29",
}
+// Network stack next integration tests.
+android_test {
+ name: "NetworkStackNextIntegrationTests",
+ defaults: [
+ "NetworkStackIntegrationTestsDefaults",
+ "NetworkStackIntegrationTestsJniDefaults",
+ ],
+ static_libs: [
+ "NetworkStackApiCurrentLib",
+ ],
+ certificate: "networkstack",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+}
+
// Special version of the network stack tests that includes all tests necessary for code coverage
// purposes. This is currently the union of NetworkStackTests and NetworkStackIntegrationTests.
android_test {
diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java
index 4bbee9a..b3ca925 100644
--- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java
+++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java
@@ -56,6 +56,8 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
@@ -86,6 +88,7 @@ import android.net.MacAddress;
import android.net.NetworkStackIpMemoryStore;
import android.net.TestNetworkInterface;
import android.net.TestNetworkManager;
+import android.net.Uri;
import android.net.dhcp.DhcpClient;
import android.net.dhcp.DhcpDeclinePacket;
import android.net.dhcp.DhcpDiscoverPacket;
@@ -117,6 +120,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.StateMachine;
+import com.android.networkstack.apishim.CaptivePortalDataShimImpl;
import com.android.networkstack.apishim.ShimUtils;
import com.android.networkstack.arp.ArpPacket;
import com.android.server.NetworkObserverRegistry;
@@ -146,6 +150,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -219,6 +224,7 @@ public class IpClientIntegrationTest {
private static final byte[] SERVER_MAC = new byte[] { 0x00, 0x1A, 0x11, 0x22, 0x33, 0x44 };
private static final String TEST_HOST_NAME = "AOSP on Crosshatch";
private static final String TEST_HOST_NAME_TRANSLITERATION = "AOSP-on-Crosshatch";
+ private static final String TEST_CAPTIVE_PORTAL_URL = "https://example.com/capportapi";
private static class TapPacketReader extends PacketReader {
private final ParcelFileDescriptor mTapFd;
@@ -484,7 +490,7 @@ public class IpClientIntegrationTest {
}
private static ByteBuffer buildDhcpOfferPacket(final DhcpPacket packet,
- final Integer leaseTimeSec, final short mtu) {
+ final Integer leaseTimeSec, final short mtu, final String captivePortalUrl) {
return DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
CLIENT_ADDR /* yourIp */, packet.getClientMac(), leaseTimeSec,
@@ -492,11 +498,12 @@ 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, captivePortalUrl);
}
private static ByteBuffer buildDhcpAckPacket(final DhcpPacket packet,
- final Integer leaseTimeSec, final short mtu, final boolean rapidCommit) {
+ final Integer leaseTimeSec, final short mtu, final boolean rapidCommit,
+ final String captivePortalApiUrl) {
return DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, packet.getTransactionId(),
false /* broadcast */, SERVER_ADDR, INADDR_ANY /* relayIp */,
CLIENT_ADDR /* yourIp */, CLIENT_ADDR /* requestIp */, packet.getClientMac(),
@@ -504,7 +511,7 @@ public class IpClientIntegrationTest {
Collections.singletonList(SERVER_ADDR) /* gateways */,
Collections.singletonList(SERVER_ADDR) /* dnsServers */,
SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, HOSTNAME,
- false /* metered */, mtu, rapidCommit);
+ false /* metered */, mtu, rapidCommit, captivePortalApiUrl);
}
private static ByteBuffer buildDhcpNakPacket(final DhcpPacket packet) {
@@ -624,27 +631,35 @@ public class IpClientIntegrationTest {
final Integer leaseTimeSec, final boolean isDhcpLeaseCacheEnabled,
final boolean shouldReplyRapidCommitAck, final int mtu,
final boolean isDhcpIpConflictDetectEnabled,
- final boolean isHostnameConfigurationEnabled, final String hostname)
- throws Exception {
- final List<DhcpPacket> packetList = new ArrayList<DhcpPacket>();
+ final boolean isHostnameConfigurationEnabled, final String hostname,
+ final String captivePortalApiUrl) throws Exception {
startIpClientProvisioning(isDhcpLeaseCacheEnabled, shouldReplyRapidCommitAck,
false /* isPreconnectionEnabled */, isDhcpIpConflictDetectEnabled,
isHostnameConfigurationEnabled, hostname);
+ return handleDhcpPackets(isSuccessLease, leaseTimeSec, shouldReplyRapidCommitAck, mtu,
+ isDhcpIpConflictDetectEnabled, captivePortalApiUrl);
+ }
+ private List<DhcpPacket> handleDhcpPackets(final boolean isSuccessLease,
+ final Integer leaseTimeSec, final boolean shouldReplyRapidCommitAck, final int mtu,
+ final boolean isDhcpIpConflictDetectEnabled, final String captivePortalApiUrl)
+ throws Exception {
+ final List<DhcpPacket> packetList = new ArrayList<>();
DhcpPacket packet;
while ((packet = getNextDhcpPacket()) != null) {
packetList.add(packet);
if (packet instanceof DhcpDiscoverPacket) {
if (shouldReplyRapidCommitAck) {
sendResponse(buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu,
- true /* rapidCommit */));
+ true /* rapidCommit */, captivePortalApiUrl));
} else {
- sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec, (short) mtu));
+ sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec, (short) mtu,
+ captivePortalApiUrl));
}
} else if (packet instanceof DhcpRequestPacket) {
final ByteBuffer byteBuffer = isSuccessLease
? buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu,
- false /* rapidCommit */)
+ false /* rapidCommit */, captivePortalApiUrl)
: buildDhcpNakPacket(packet);
sendResponse(byteBuffer);
} else {
@@ -676,7 +691,8 @@ public class IpClientIntegrationTest {
final boolean isDhcpIpConflictDetectEnabled) throws Exception {
return performDhcpHandshake(isSuccessLease, leaseTimeSec, isDhcpLeaseCacheEnabled,
isDhcpRapidCommitEnabled, mtu, isDhcpIpConflictDetectEnabled,
- false /* isHostnameConfigurationEnabled */, null /* hostname */);
+ false /* isHostnameConfigurationEnabled */, null /* hostname */,
+ null /* captivePortalApiUrl */);
}
private DhcpPacket getNextDhcpPacket() throws ParseException {
@@ -812,12 +828,13 @@ public class IpClientIntegrationTest {
final short mtu = (short) TEST_DEFAULT_MTU;
if (!shouldReplyRapidCommitAck) {
- sendResponse(buildDhcpOfferPacket(packet, TEST_LEASE_DURATION_S, mtu));
+ sendResponse(buildDhcpOfferPacket(packet, TEST_LEASE_DURATION_S, mtu,
+ null /* captivePortalUrl */));
packet = getNextDhcpPacket();
assertTrue(packet instanceof DhcpRequestPacket);
}
sendResponse(buildDhcpAckPacket(packet, TEST_LEASE_DURATION_S, mtu,
- shouldReplyRapidCommitAck));
+ shouldReplyRapidCommitAck, null /* captivePortalUrl */));
if (!shouldAbortPreconnection) {
mIpc.notifyPreconnectionComplete(true /* success */);
@@ -1447,7 +1464,8 @@ public class IpClientIntegrationTest {
TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
false /* isDhcpIpConflictDetectEnabled */,
- true /* isHostnameConfigurationEnabled */, TEST_HOST_NAME /* hostname */);
+ true /* isHostnameConfigurationEnabled */, TEST_HOST_NAME /* hostname */,
+ null /* captivePortalApiUrl */);
assertEquals(2, sentPackets.size());
assertHostname(true, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets);
assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
@@ -1460,7 +1478,8 @@ public class IpClientIntegrationTest {
TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
false /* isDhcpIpConflictDetectEnabled */,
- false /* isHostnameConfigurationEnabled */, TEST_HOST_NAME);
+ false /* isHostnameConfigurationEnabled */, TEST_HOST_NAME,
+ null /* captivePortalApiUrl */);
assertEquals(2, sentPackets.size());
assertHostname(false, TEST_HOST_NAME, TEST_HOST_NAME_TRANSLITERATION, sentPackets);
assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
@@ -1473,10 +1492,59 @@ public class IpClientIntegrationTest {
TEST_LEASE_DURATION_S, true /* isDhcpLeaseCacheEnabled */,
false /* isDhcpRapidCommitEnabled */, TEST_DEFAULT_MTU,
false /* isDhcpIpConflictDetectEnabled */,
- true /* isHostnameConfigurationEnabled */, null /* hostname */);
+ true /* isHostnameConfigurationEnabled */, null /* hostname */,
+ null /* captivePortalApiUrl */);
assertEquals(2, sentPackets.size());
assertHostname(true, null /* hostname */, null /* hostnameAfterTransliteration */,
sentPackets);
assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
}
+
+ private void runDhcpClientCaptivePortalApiTest(boolean featureEnabled,
+ boolean serverSendsOption) throws Exception {
+ startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
+ false /* shouldReplyRapidCommitAck */, false /* isPreConnectionEnabled */,
+ false /* isDhcpIpConflictDetectEnabled */);
+ final DhcpPacket discover = getNextDhcpPacket();
+ assertTrue(discover instanceof DhcpDiscoverPacket);
+ assertEquals(featureEnabled, discover.hasRequestedParam(DhcpPacket.DHCP_CAPTIVE_PORTAL));
+
+ // Send Offer and handle Request -> Ack
+ final String serverSentUrl = serverSendsOption ? TEST_CAPTIVE_PORTAL_URL : null;
+ sendResponse(buildDhcpOfferPacket(discover, TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU,
+ serverSentUrl));
+ final int testMtu = 1345;
+ handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
+ false /* isDhcpRapidCommitEnabled */, testMtu,
+ false /* isDhcpIpConflictDetectEnabled */, serverSentUrl);
+
+ final Uri expectedUrl = featureEnabled && serverSendsOption
+ ? Uri.parse(TEST_CAPTIVE_PORTAL_URL) : null;
+ // Wait for LinkProperties containing DHCP-obtained info, such as MTU, and ensure that the
+ // URL is set as expected
+ verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(argThat(lp ->
+ lp.getMtu() == testMtu
+ && Objects.equals(expectedUrl, lp.getCaptivePortalApiUrl())));
+ }
+
+ @Test
+ public void testDhcpClientCaptivePortalApiEnabled() throws Exception {
+ // Only run the test on platforms / builds where the API is enabled
+ assumeTrue(CaptivePortalDataShimImpl.isSupported());
+ runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, true /* serverSendsOption */);
+ }
+
+ @Test
+ public void testDhcpClientCaptivePortalApiEnabled_NoUrl() throws Exception {
+ // Only run the test on platforms / builds where the API is enabled
+ assumeTrue(CaptivePortalDataShimImpl.isSupported());
+ runDhcpClientCaptivePortalApiTest(true /* featureEnabled */, false /* serverSendsOption */);
+ }
+
+ @Test
+ public void testDhcpClientCaptivePortalApiDisabled() throws Exception {
+ // Only run the test on platforms / builds where the API is disabled
+ assumeFalse(CaptivePortalDataShimImpl.isSupported());
+ runDhcpClientCaptivePortalApiTest(false /* featureEnabled */, true /* serverSendsOption */);
+ }
}
diff --git a/tests/unit/src/android/net/dhcp/DhcpPacketTest.java b/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
index 090631b..6ce1fdf 100644
--- a/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
@@ -78,10 +78,12 @@ public class DhcpPacketTest {
private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
SERVER_ADDR, PREFIX_LENGTH);
private static final String HOSTNAME = "testhostname";
+ private static final String CAPTIVE_PORTAL_API_URL = "https://example.com/capportapi";
private static final short MTU = 1500;
// Use our own empty address instead of IPV4_ADDR_ANY or INADDR_ANY to ensure that the code
// doesn't use == instead of equals when comparing addresses.
private static final Inet4Address ANY = v4Address("0.0.0.0");
+ private static final byte[] TEST_EMPTY_OPTIONS_SKIP_LIST = new byte[0];
private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
@@ -169,7 +171,8 @@ public class DhcpPacketTest {
.setDomainBytes(domainBytes)
.setVendorInfoBytes(vendorInfoBytes)
.build();
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertEquals(expectedDomain, offerPacket.mDomainName);
assertEquals(expectedVendorInfo, offerPacket.mVendorInfo);
}
@@ -215,14 +218,16 @@ public class DhcpPacketTest {
if (!expectValid) {
try {
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
fail("Invalid packet parsed successfully: " + offerPacket);
} catch (ParseException expected) {
}
return;
}
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertNotNull(offerPacket);
assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
DhcpResults dhcpResults = offerPacket.toDhcpResults(); // Just check this doesn't crash.
@@ -266,7 +271,8 @@ public class DhcpPacketTest {
ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
.setNetmaskBytes(netmaskBytes)
.build();
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
DhcpResults results = offerPacket.toDhcpResults();
if (expected != null) {
@@ -351,7 +357,8 @@ public class DhcpPacketTest {
"3a0400000e103b040000189cff00000000000000000000"));
// CHECKSTYLE:ON Generated code
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
@@ -384,7 +391,8 @@ public class DhcpPacketTest {
// CHECKSTYLE:ON Generated code
assertEquals(337, packet.limit());
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
@@ -393,6 +401,88 @@ public class DhcpPacketTest {
assertTrue(dhcpResults.hasMeteredHint());
}
+ private void runCapportOptionTest(boolean enabled) throws Exception {
+ // CHECKSTYLE:OFF Generated code
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header
+ "00430044013d9ac7" +
+ // BOOTP header
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name ("dhcp.android.com" plus invalid "AAAA" after null terminator).
+ "646863702e616e64726f69642e636f6d00000000000000000000000000000000" +
+ "0000000000004141414100000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options
+ "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544721d" +
+ "68747470733a2f2f706f7274616c6170692e6578616d706c652e636f6dff"));
+ // CHECKSTYLE:ON Generated code
+
+ final DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ enabled ? TEST_EMPTY_OPTIONS_SKIP_LIST
+ : new byte[] { DhcpPacket.DHCP_CAPTIVE_PORTAL });
+ assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
+ final DhcpResults dhcpResults = offerPacket.toDhcpResults();
+ final String testUrl = enabled ? "https://portalapi.example.com" : null;
+ assertEquals(testUrl, dhcpResults.captivePortalApiUrl);
+ }
+
+ @Test
+ public void testCapportOption() throws Exception {
+ runCapportOptionTest(true /* enabled */);
+ }
+
+ @Test
+ public void testCapportOption_Disabled() throws Exception {
+ runCapportOptionTest(false /* enabled */);
+ }
+
+ @Test
+ public void testCapportOption_Invalid() throws Exception {
+ // CHECKSTYLE:OFF Generated code
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header
+ "00430044013d9ac7" +
+ // BOOTP header
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name ("dhcp.android.com" plus invalid "AAAA" after null terminator).
+ "646863702e616e64726f69642e636f6d00000000000000000000000000000000" +
+ "0000000000004141414100000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options
+ "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544" +
+ // Option 114 (0x72, capport), length 10 (0x0a)
+ "720a" +
+ // バグ-com in UTF-8, plus the ff byte that marks the end of options.
+ "e38390e382b02d636f6dff"));
+ // CHECKSTYLE:ON Generated code
+
+ final DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
+ assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
+ final DhcpResults dhcpResults = offerPacket.toDhcpResults();
+ // Output URL will be garbled because some characters do not exist in the target charset,
+ // but the parser should not crash.
+ assertTrue(dhcpResults.captivePortalApiUrl.length() > 0);
+ }
+
@Test
public void testBadIpPacket() throws Exception {
final byte[] packet = HexDump.hexStringToByteArray(
@@ -400,7 +490,8 @@ public class DhcpPacketTest {
"450001518d0600004011144dc0a82b01c0a82bf7");
try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
} catch (DhcpPacket.ParseException expected) {
assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
return;
@@ -419,7 +510,7 @@ public class DhcpPacketTest {
"02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
} catch (DhcpPacket.ParseException expected) {
assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
return;
@@ -448,7 +539,7 @@ public class DhcpPacketTest {
"00000000000000000000000000000000000000000000000000000000000000");
try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
} catch (DhcpPacket.ParseException expected) {
assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
return;
@@ -479,7 +570,7 @@ public class DhcpPacketTest {
);
try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
} catch (DhcpPacket.ParseException expected) {
assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
return;
@@ -511,7 +602,7 @@ public class DhcpPacketTest {
"1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
} catch (DhcpPacket.ParseException expected) {
assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
return;
@@ -590,7 +681,8 @@ public class DhcpPacketTest {
packet.put(mtuBytes);
packet.clear();
}
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
@@ -665,7 +757,8 @@ public class DhcpPacketTest {
assertEquals(6, packet.get(hwAddrLenOffset));
// Expect the expected.
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertNotNull(offerPacket);
assertEquals(6, offerPacket.getClientMac().length);
assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
@@ -673,7 +766,7 @@ public class DhcpPacketTest {
// Reduce the hardware address length and verify that it shortens the client MAC.
packet.flip();
packet.put(hwAddrLenOffset, (byte) 5);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3, TEST_EMPTY_OPTIONS_SKIP_LIST);
assertNotNull(offerPacket);
assertEquals(5, offerPacket.getClientMac().length);
assertEquals(expectedClientMac.substring(0, 10),
@@ -681,7 +774,7 @@ public class DhcpPacketTest {
packet.flip();
packet.put(hwAddrLenOffset, (byte) 3);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3, TEST_EMPTY_OPTIONS_SKIP_LIST);
assertNotNull(offerPacket);
assertEquals(3, offerPacket.getClientMac().length);
assertEquals(expectedClientMac.substring(0, 6),
@@ -691,7 +784,7 @@ public class DhcpPacketTest {
// and crash, and b) hardcode it to 6.
packet.flip();
packet.put(hwAddrLenOffset, (byte) -1);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3, TEST_EMPTY_OPTIONS_SKIP_LIST);
assertNotNull(offerPacket);
assertEquals(6, offerPacket.getClientMac().length);
assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
@@ -700,7 +793,7 @@ public class DhcpPacketTest {
// hardcode it to 6.
packet.flip();
packet.put(hwAddrLenOffset, (byte) 17);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3, TEST_EMPTY_OPTIONS_SKIP_LIST);
assertNotNull(offerPacket);
assertEquals(6, offerPacket.getClientMac().length);
assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
@@ -740,7 +833,8 @@ public class DhcpPacketTest {
"0000000000000000000000000000000000000000000000ff000000"));
// CHECKSTYLE:ON Generated code
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
@@ -772,7 +866,8 @@ public class DhcpPacketTest {
"0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
// CHECKSTYLE:ON Generated code
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
@@ -806,7 +901,8 @@ public class DhcpPacketTest {
"0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
// CHECKSTYLE:ON Generated code
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
@@ -842,7 +938,8 @@ public class DhcpPacketTest {
"d18180060f0777766d2e6564751c040a0fffffff000000"));
// CHECKSTYLE:ON Generated code
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
@@ -880,7 +977,7 @@ public class DhcpPacketTest {
// CHECKSTYLE:ON Generated code
try {
- DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ DhcpPacket.decodeFullPacket(packet, ENCAP_L2, TEST_EMPTY_OPTIONS_SKIP_LIST);
fail("Packet with invalid dst port did not throw ParseException");
} catch (ParseException expected) {}
}
@@ -912,7 +1009,8 @@ public class DhcpPacketTest {
"0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
// CHECKSTYLE:ON Generated code
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2,
+ TEST_EMPTY_OPTIONS_SKIP_LIST);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
@@ -931,8 +1029,8 @@ public class DhcpPacketTest {
ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
- false /* do unicast */, DhcpClient.REQUESTED_PARAMS, false /* rapid commit */,
- testHostname);
+ false /* do unicast */, DhcpClient.DEFAULT_REQUESTED_PARAMS,
+ false /* rapid commit */, testHostname);
final byte[] headers = new byte[] {
// Ethernet header.
@@ -1021,7 +1119,7 @@ public class DhcpPacketTest {
BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */,
Collections.singletonList(SERVER_ADDR) /* dnsServers */,
SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname,
- false /* metered */, MTU);
+ false /* metered */, MTU, CAPTIVE_PORTAL_API_URL);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// BOOTP headers
@@ -1085,6 +1183,9 @@ public class DhcpPacketTest {
// MTU
bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 });
bos.write(shortToByteArray(MTU));
+ // capport URL. Option 114 = 0x72
+ bos.write(new byte[] { (byte) 0x72, (byte) CAPTIVE_PORTAL_API_URL.length() });
+ bos.write(CAPTIVE_PORTAL_API_URL.getBytes(Charset.forName("US-ASCII")));
// End options.
bos.write(0xff);
diff --git a/tests/unit/src/android/net/dhcp/DhcpServerTest.java b/tests/unit/src/android/net/dhcp/DhcpServerTest.java
index a1613c5..a278a88 100644
--- a/tests/unit/src/android/net/dhcp/DhcpServerTest.java
+++ b/tests/unit/src/android/net/dhcp/DhcpServerTest.java
@@ -383,7 +383,8 @@ public class DhcpServerTest {
private DhcpPacket getPacket() throws Exception {
verify(mDeps, times(1)).sendPacket(any(), any(), any());
- return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP);
+ return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP,
+ new byte[0] /* optionsToSkip */);
}
private static Inet4Address parseAddr(@Nullable String inet4Addr) {