Merge "Send hostname and MTU options in DHCP ACK/OFFER"
am: 3b12359e4c
Change-Id: I47972e25fd69471aacd52b58ffed67be1e685557
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package android.net.dhcp;
|
||||
|
||||
import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
|
||||
import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.DhcpResults;
|
||||
import android.net.LinkAddress;
|
||||
@@ -380,6 +383,26 @@ public abstract class DhcpPacket {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a parameter is included in the parameter request list option of this packet.
|
||||
*
|
||||
* <p>If there is no parameter request list option in the packet, false is returned.
|
||||
*
|
||||
* @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
|
||||
*/
|
||||
public boolean hasRequestedParam(byte paramId) {
|
||||
if (mRequestedParams == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (byte reqParam : mRequestedParams) {
|
||||
if (reqParam == paramId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new L3 packet (including IP header) containing the
|
||||
* DHCP udp packet. This method relies upon the delegated method
|
||||
@@ -696,7 +719,11 @@ public abstract class DhcpPacket {
|
||||
addTlv(buf, DHCP_ROUTER, mGateways);
|
||||
addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
|
||||
addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
|
||||
addTlv(buf, DHCP_HOST_NAME, mHostName);
|
||||
addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
|
||||
if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
|
||||
addTlv(buf, DHCP_MTU, mMtu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1259,7 +1286,8 @@ public abstract class DhcpPacket {
|
||||
boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
|
||||
Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
|
||||
Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
|
||||
Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
|
||||
Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
|
||||
short mtu) {
|
||||
DhcpPacket pkt = new DhcpOfferPacket(
|
||||
transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
|
||||
INADDR_ANY /* clientIp */, yourIp, mac);
|
||||
@@ -1267,9 +1295,11 @@ public abstract class DhcpPacket {
|
||||
pkt.mDnsServers = dnsServers;
|
||||
pkt.mLeaseTime = timeout;
|
||||
pkt.mDomainName = domainName;
|
||||
pkt.mHostName = hostname;
|
||||
pkt.mServerIdentifier = dhcpServerIdentifier;
|
||||
pkt.mSubnetMask = netMask;
|
||||
pkt.mBroadcastAddress = bcAddr;
|
||||
pkt.mMtu = mtu;
|
||||
if (metered) {
|
||||
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
|
||||
}
|
||||
@@ -1283,7 +1313,8 @@ public abstract class DhcpPacket {
|
||||
boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
|
||||
Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
|
||||
Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
|
||||
Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
|
||||
Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
|
||||
short mtu) {
|
||||
DhcpPacket pkt = new DhcpAckPacket(
|
||||
transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
|
||||
mac);
|
||||
@@ -1291,9 +1322,11 @@ public abstract class DhcpPacket {
|
||||
pkt.mDnsServers = dnsServers;
|
||||
pkt.mLeaseTime = timeout;
|
||||
pkt.mDomainName = domainName;
|
||||
pkt.mHostName = hostname;
|
||||
pkt.mSubnetMask = netMask;
|
||||
pkt.mServerIdentifier = dhcpServerIdentifier;
|
||||
pkt.mBroadcastAddress = bcAddr;
|
||||
pkt.mMtu = mtu;
|
||||
if (metered) {
|
||||
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.net.NetworkUtils.getBroadcastAddress;
|
||||
import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
|
||||
import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
|
||||
import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
|
||||
import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
|
||||
import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
|
||||
import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
|
||||
import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
|
||||
@@ -46,6 +47,7 @@ import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.HexDump;
|
||||
@@ -350,6 +352,19 @@ public class DhcpServer {
|
||||
return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hostname from a lease if non-empty and requested in the incoming request.
|
||||
* @param request The incoming request.
|
||||
* @return The hostname, or null if not requested or empty.
|
||||
*/
|
||||
@Nullable
|
||||
private static String getHostnameIfRequested(@NonNull DhcpPacket request,
|
||||
@NonNull DhcpLease lease) {
|
||||
return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname())
|
||||
? lease.getHostname()
|
||||
: null;
|
||||
}
|
||||
|
||||
private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
|
||||
@NonNull MacAddress clientMac) {
|
||||
final boolean broadcastFlag = getBroadcastFlag(request, lease);
|
||||
@@ -358,12 +373,14 @@ public class DhcpServer {
|
||||
getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength());
|
||||
final Inet4Address broadcastAddr = getBroadcastAddress(
|
||||
mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
|
||||
final String hostname = getHostnameIfRequested(request, lease);
|
||||
final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
|
||||
ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
|
||||
request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
|
||||
broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
|
||||
new ArrayList<>(mServingParams.dnsServers),
|
||||
mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
|
||||
mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
|
||||
mServingParams.metered, (short) mServingParams.linkMtu);
|
||||
|
||||
return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
|
||||
}
|
||||
@@ -374,13 +391,15 @@ public class DhcpServer {
|
||||
// transmitOffer above
|
||||
final boolean broadcastFlag = getBroadcastFlag(request, 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,
|
||||
mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
|
||||
new ArrayList<>(mServingParams.defaultRouters),
|
||||
new ArrayList<>(mServingParams.dnsServers),
|
||||
mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
|
||||
mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
|
||||
mServingParams.metered, (short) mServingParams.linkMtu);
|
||||
|
||||
return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.DhcpResults;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.NetworkUtils;
|
||||
@@ -37,6 +38,7 @@ import com.android.internal.util.HexDump;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -56,6 +58,8 @@ public class DhcpPacketTest {
|
||||
private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
|
||||
private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
|
||||
SERVER_ADDR, PREFIX_LENGTH);
|
||||
private static final String HOSTNAME = "testhostname";
|
||||
private static final short MTU = 1500;
|
||||
// Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code
|
||||
// doesn't use == instead of equals when comparing addresses.
|
||||
private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
|
||||
@@ -960,7 +964,8 @@ public class DhcpPacketTest {
|
||||
assertTrue(msg, Arrays.equals(expected, actual));
|
||||
}
|
||||
|
||||
public void checkBuildOfferPacket(int leaseTimeSecs) throws Exception {
|
||||
public void checkBuildOfferPacket(int leaseTimeSecs, @Nullable String hostname)
|
||||
throws Exception {
|
||||
final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2);
|
||||
final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000);
|
||||
final int transactionId = 0xdeadbeef;
|
||||
@@ -971,7 +976,8 @@ public class DhcpPacketTest {
|
||||
CLIENT_MAC, leaseTimeSecs, NETMASK /* netMask */,
|
||||
BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */,
|
||||
Collections.singletonList(SERVER_ADDR) /* dnsServers */,
|
||||
SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, false /* metered */);
|
||||
SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname,
|
||||
false /* metered */, MTU);
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
// BOOTP headers
|
||||
@@ -1027,12 +1033,22 @@ public class DhcpPacketTest {
|
||||
// Nameserver
|
||||
bos.write(new byte[] { (byte) 0x06, (byte) 0x04 });
|
||||
bos.write(SERVER_ADDR.getAddress());
|
||||
// Hostname
|
||||
if (hostname != null) {
|
||||
bos.write(new byte[]{(byte) 0x0c, (byte) hostname.length()});
|
||||
bos.write(hostname.getBytes(Charset.forName("US-ASCII")));
|
||||
}
|
||||
// MTU
|
||||
bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 });
|
||||
bos.write(shortToByteArray(MTU));
|
||||
// End options.
|
||||
bos.write(0xff);
|
||||
|
||||
final byte[] expected = bos.toByteArray();
|
||||
assertTrue((expected.length & 1) == 0);
|
||||
if ((bos.size() & 1) != 0) {
|
||||
bos.write(0x00);
|
||||
}
|
||||
|
||||
final byte[] expected = bos.toByteArray();
|
||||
final byte[] actual = new byte[packet.limit()];
|
||||
packet.get(actual);
|
||||
final String msg = "Expected:\n " + HexDump.dumpHexString(expected) +
|
||||
@@ -1042,13 +1058,18 @@ public class DhcpPacketTest {
|
||||
|
||||
@Test
|
||||
public void testOfferPacket() throws Exception {
|
||||
checkBuildOfferPacket(3600);
|
||||
checkBuildOfferPacket(Integer.MAX_VALUE);
|
||||
checkBuildOfferPacket(0x80000000);
|
||||
checkBuildOfferPacket(INFINITE_LEASE);
|
||||
checkBuildOfferPacket(3600, HOSTNAME);
|
||||
checkBuildOfferPacket(Integer.MAX_VALUE, HOSTNAME);
|
||||
checkBuildOfferPacket(0x80000000, HOSTNAME);
|
||||
checkBuildOfferPacket(INFINITE_LEASE, HOSTNAME);
|
||||
checkBuildOfferPacket(3600, null);
|
||||
}
|
||||
|
||||
private static byte[] intToByteArray(int val) {
|
||||
return ByteBuffer.allocate(4).putInt(val).array();
|
||||
}
|
||||
|
||||
private static byte[] shortToByteArray(short val) {
|
||||
return ByteBuffer.allocate(2).putShort(val).array();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.net.dhcp;
|
||||
|
||||
import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
|
||||
import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
|
||||
import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
|
||||
import static android.net.dhcp.DhcpPacket.INADDR_ANY;
|
||||
import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
|
||||
@@ -87,6 +88,7 @@ public class DhcpServerTest {
|
||||
Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
|
||||
private static final long TEST_LEASE_TIME_SECS = 3600L;
|
||||
private static final int TEST_MTU = 1500;
|
||||
private static final String TEST_HOSTNAME = "testhostname";
|
||||
|
||||
private static final int TEST_TRANSACTION_ID = 123;
|
||||
private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 };
|
||||
@@ -96,7 +98,10 @@ public class DhcpServerTest {
|
||||
private static final long TEST_CLOCK_TIME = 1234L;
|
||||
private static final int TEST_LEASE_EXPTIME_SECS = 3600;
|
||||
private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC,
|
||||
TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS*1000L + TEST_CLOCK_TIME, null /* hostname */);
|
||||
TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME,
|
||||
null /* hostname */);
|
||||
private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC,
|
||||
TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME);
|
||||
|
||||
@NonNull @Mock
|
||||
private Dependencies mDeps;
|
||||
@@ -217,15 +222,17 @@ public class DhcpServerTest {
|
||||
public void testRequest_Selecting_Ack() throws Exception {
|
||||
when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
|
||||
eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
|
||||
eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */))
|
||||
.thenReturn(TEST_LEASE);
|
||||
eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME)))
|
||||
.thenReturn(TEST_LEASE_WITH_HOSTNAME);
|
||||
|
||||
final DhcpRequestPacket request = makeRequestSelectingPacket();
|
||||
request.mHostName = TEST_HOSTNAME;
|
||||
request.mRequestedParams = new byte[] { DHCP_HOST_NAME };
|
||||
mServer.processPacket(request, DHCP_CLIENT);
|
||||
|
||||
assertResponseSentTo(TEST_CLIENT_ADDR);
|
||||
final DhcpAckPacket packet = assertAck(getPacket());
|
||||
assertMatchesTestLease(packet);
|
||||
assertMatchesTestLease(packet, TEST_HOSTNAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -270,14 +277,18 @@ public class DhcpServerTest {
|
||||
* - other request states (init-reboot/renewing/rebinding)
|
||||
*/
|
||||
|
||||
private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
|
||||
private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) {
|
||||
assertMatchesClient(packet);
|
||||
assertFalse(packet.hasExplicitClientId());
|
||||
assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier);
|
||||
assertEquals(TEST_CLIENT_ADDR, packet.mYourIp);
|
||||
assertNotNull(packet.mLeaseTime);
|
||||
assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime);
|
||||
assertNull(packet.mHostName);
|
||||
assertEquals(hostname, packet.mHostName);
|
||||
}
|
||||
|
||||
private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
|
||||
assertMatchesTestLease(packet, null);
|
||||
}
|
||||
|
||||
private void assertMatchesClient(@NonNull DhcpPacket packet) {
|
||||
|
||||
Reference in New Issue
Block a user