Merge changes I58f904d5,Ie0bf7804 am: 6717a6f930 am: 32efb6d2b3
am: d409459c5d
Change-Id: Ifce50d127c1b36805600df6c8c8626da59b6e813
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 1a4119c..5accb45 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -218,6 +218,7 @@
.setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
.setDnsServers(addr)
.setServerAddr(new LinkAddress(addr, prefixLen))
+ .setMetered(true)
.build();
// TODO: also advertise link MTU
} catch (DhcpServingParams.InvalidParameterException e) {
diff --git a/services/net/java/android/net/dhcp/DhcpAckPacket.java b/services/net/java/android/net/dhcp/DhcpAckPacket.java
index df44b11..b2eb4e2 100644
--- a/services/net/java/android/net/dhcp/DhcpAckPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpAckPacket.java
@@ -30,8 +30,8 @@
private final Inet4Address mSrcIp;
DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
- Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
- super(transId, secs, clientIp, yourIp, serverAddress, INADDR_ANY, clientMac, broadcast);
+ Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
+ super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast);
mBroadcast = broadcast;
mSrcIp = serverAddress;
}
@@ -70,19 +70,8 @@
void finishPacket(ByteBuffer buffer) {
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_ACK);
addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
- addTlv(buffer, DHCP_LEASE_TIME, mLeaseTime);
- // the client should renew at 1/2 the lease-expiry interval
- if (mLeaseTime != null) {
- addTlv(buffer, DHCP_RENEWAL_TIME,
- Integer.valueOf(mLeaseTime.intValue() / 2));
- }
-
- addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask);
- addTlv(buffer, DHCP_ROUTER, mGateways);
- addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName);
- addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
- addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);
+ addCommonServerTlvs(buffer);
addTlvEnd(buffer);
}
diff --git a/services/net/java/android/net/dhcp/DhcpNakPacket.java b/services/net/java/android/net/dhcp/DhcpNakPacket.java
index ef9af52..1da0b73 100644
--- a/services/net/java/android/net/dhcp/DhcpNakPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpNakPacket.java
@@ -26,9 +26,10 @@
/**
* Generates a NAK packet with the specified parameters.
*/
- DhcpNakPacket(int transId, short secs, Inet4Address nextIp, Inet4Address relayIp,
- byte[] clientMac, boolean broadcast) {
- super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp, clientMac, broadcast);
+ DhcpNakPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac,
+ boolean broadcast) {
+ super(transId, secs, INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */,
+ INADDR_ANY /* nextIp */, relayIp, clientMac, broadcast);
}
public String toString() {
diff --git a/services/net/java/android/net/dhcp/DhcpOfferPacket.java b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
index 99154ef..0eba77e 100644
--- a/services/net/java/android/net/dhcp/DhcpOfferPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
@@ -32,8 +32,8 @@
* Generates a OFFER packet with the specified parameters.
*/
DhcpOfferPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
- Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
- super(transId, secs, clientIp, yourIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
+ Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
+ super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast);
mSrcIp = serverAddress;
}
@@ -72,19 +72,8 @@
void finishPacket(ByteBuffer buffer) {
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_OFFER);
addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
- addTlv(buffer, DHCP_LEASE_TIME, mLeaseTime);
- // the client should renew at 1/2 the lease-expiry interval
- if (mLeaseTime != null) {
- addTlv(buffer, DHCP_RENEWAL_TIME,
- Integer.valueOf(mLeaseTime.intValue() / 2));
- }
-
- addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask);
- addTlv(buffer, DHCP_ROUTER, mGateways);
- addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName);
- addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
- addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);
+ addCommonServerTlvs(buffer);
addTlvEnd(buffer);
}
}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 175e27e..595a129 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -184,6 +184,11 @@
protected String mVendorInfo;
/**
+ * Value of the vendor specific option used to indicate that the network is metered
+ */
+ public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
+
+ /**
* DHCP Optional Type: DHCP Requested IP Address
*/
protected static final byte DHCP_REQUESTED_IP = 50;
@@ -677,6 +682,23 @@
if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
}
+ protected void addCommonServerTlvs(ByteBuffer buf) {
+ addTlv(buf, DHCP_LEASE_TIME, mLeaseTime);
+ if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) {
+ // The client should renew at 1/2 the lease-expiry interval
+ addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2));
+ // Default rebinding time is set as below by RFC2131
+ addTlv(buf, DHCP_REBINDING_TIME,
+ (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L));
+ }
+ addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask);
+ addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
+ addTlv(buf, DHCP_ROUTER, mGateways);
+ addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
+ addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
+ addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
+ }
+
/**
* Converts a MAC from an array of octets to an ASCII string.
*/
@@ -1085,7 +1107,7 @@
break;
case DHCP_MESSAGE_TYPE_OFFER:
newPacket = new DhcpOfferPacket(
- transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
+ transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
break;
case DHCP_MESSAGE_TYPE_REQUEST:
newPacket = new DhcpRequestPacket(
@@ -1098,11 +1120,11 @@
break;
case DHCP_MESSAGE_TYPE_ACK:
newPacket = new DhcpAckPacket(
- transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
+ transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
break;
case DHCP_MESSAGE_TYPE_NAK:
newPacket = new DhcpNakPacket(
- transactionId, secs, nextIp, relayIp, clientMac, broadcast);
+ transactionId, secs, relayIp, clientMac, broadcast);
break;
case DHCP_MESSAGE_TYPE_RELEASE:
if (serverIdentifier == null) {
@@ -1234,12 +1256,13 @@
* parameters.
*/
public static ByteBuffer buildOfferPacket(int encap, int transactionId,
- boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
- byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
- List<Inet4Address> gateways, List<Inet4Address> dnsServers,
- Inet4Address dhcpServerIdentifier, String domainName) {
+ 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) {
DhcpPacket pkt = new DhcpOfferPacket(
- transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
+ transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
+ INADDR_ANY /* clientIp */, yourIp, mac);
pkt.mGateways = gateways;
pkt.mDnsServers = dnsServers;
pkt.mLeaseTime = timeout;
@@ -1247,6 +1270,9 @@
pkt.mServerIdentifier = dhcpServerIdentifier;
pkt.mSubnetMask = netMask;
pkt.mBroadcastAddress = bcAddr;
+ if (metered) {
+ pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
+ }
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
}
@@ -1254,12 +1280,13 @@
* Builds a DHCP-ACK packet from the required specified parameters.
*/
public static ByteBuffer buildAckPacket(int encap, int transactionId,
- boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
+ 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) {
+ Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
DhcpPacket pkt = new DhcpAckPacket(
- transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
+ transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
+ INADDR_ANY /* clientIp */, yourIp, mac);
pkt.mGateways = gateways;
pkt.mDnsServers = dnsServers;
pkt.mLeaseTime = timeout;
@@ -1267,6 +1294,9 @@
pkt.mSubnetMask = netMask;
pkt.mServerIdentifier = dhcpServerIdentifier;
pkt.mBroadcastAddress = bcAddr;
+ if (metered) {
+ pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
+ }
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
}
@@ -1274,10 +1304,11 @@
* Builds a DHCP-NAK packet from the required specified parameters.
*/
public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
- byte[] mac, boolean broadcast, String message) {
+ Inet4Address relayIp, byte[] mac, boolean broadcast, String message) {
DhcpPacket pkt = new DhcpNakPacket(
- transactionId, (short) 0, serverIpAddr, serverIpAddr, mac, broadcast);
+ transactionId, (short) 0, relayIp, mac, broadcast);
pkt.mMessage = message;
+ pkt.mServerIdentifier = serverIpAddr;
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
}
diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java
index 095a5eb72..da8c8bb 100644
--- a/services/net/java/android/net/dhcp/DhcpServer.java
+++ b/services/net/java/android/net/dhcp/DhcpServer.java
@@ -351,12 +351,10 @@
mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
- lease.getNetAddr(), request.mClientMac, timeout,
- prefixMask,
- broadcastAddr,
- new ArrayList<>(mServingParams.defaultRouters),
+ request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
+ broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
new ArrayList<>(mServingParams.dnsServers),
- mServingParams.getServerInet4Addr(), null /* domainName */);
+ mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
}
@@ -368,12 +366,12 @@
final boolean broadcastFlag = getBroadcastFlag(request, lease);
final int timeout = getLeaseTimeout(lease);
final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
- broadcastFlag, mServingParams.getServerInet4Addr(), lease.getNetAddr(),
- request.mClientMac, timeout, mServingParams.getPrefixMaskAsAddress(),
- mServingParams.getBroadcastAddress(),
+ broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
+ lease.getNetAddr(), request.mClientMac, timeout,
+ mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
new ArrayList<>(mServingParams.defaultRouters),
new ArrayList<>(mServingParams.dnsServers),
- mServingParams.getServerInet4Addr(), null /* domainName */);
+ mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
}
@@ -383,7 +381,7 @@
// Always set broadcast flag for NAK: client may not have a correct IP
final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
- request.mClientMac, true /* broadcast */, message);
+ request.mRelayIp, request.mClientMac, true /* broadcast */, message);
final Inet4Address dst = isEmpty(request.mRelayIp)
? (Inet4Address) Inet4Address.ALL
diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/services/net/java/android/net/dhcp/DhcpServingParams.java
index 6d58bc6..df15ba1 100644
--- a/services/net/java/android/net/dhcp/DhcpServingParams.java
+++ b/services/net/java/android/net/dhcp/DhcpServingParams.java
@@ -76,6 +76,11 @@
public final int linkMtu;
/**
+ * Indicates whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+ */
+ public final boolean metered;
+
+ /**
* Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
* missing or invalid.
*/
@@ -88,13 +93,14 @@
private DhcpServingParams(@NonNull LinkAddress serverAddr,
@NonNull Set<Inet4Address> defaultRouters,
@NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
- long dhcpLeaseTimeSecs, int linkMtu) {
+ long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
this.serverAddr = serverAddr;
this.defaultRouters = defaultRouters;
this.dnsServers = dnsServers;
this.excludedAddrs = excludedAddrs;
this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
this.linkMtu = linkMtu;
+ this.metered = metered;
}
@NonNull
@@ -134,6 +140,7 @@
private Set<Inet4Address> excludedAddrs;
private long dhcpLeaseTimeSecs;
private int linkMtu = MTU_UNSET;
+ private boolean metered;
/**
* Set the server address and served prefix for the DHCP server.
@@ -248,6 +255,16 @@
}
/**
+ * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+ *
+ * <p>If not set, the default value is false.
+ */
+ public Builder setMetered(boolean metered) {
+ this.metered = metered;
+ return this;
+ }
+
+ /**
* Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
*
* <p>This method has no side-effects. If it does not throw, a valid
@@ -301,7 +318,7 @@
Collections.unmodifiableSet(new HashSet<>(defaultRouters)),
Collections.unmodifiableSet(new HashSet<>(dnsServers)),
Collections.unmodifiableSet(excl),
- dhcpLeaseTimeSecs, linkMtu);
+ dhcpLeaseTimeSecs, linkMtu, metered);
}
}
diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
index 050183c..312b3d1 100644
--- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
@@ -16,6 +16,8 @@
package android.net.dhcp;
+import static android.net.NetworkUtils.getBroadcastAddress;
+import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
import static android.net.dhcp.DhcpPacket.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -29,14 +31,15 @@
import android.net.metrics.DhcpErrorEvent;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
-import android.system.OsConstants;
import com.android.internal.util.HexDump;
+import java.io.ByteArrayOutputStream;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Random;
import org.junit.Before;
@@ -47,13 +50,17 @@
@SmallTest
public class DhcpPacketTest {
- private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
- private static Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
+ private static final Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
+ private static final Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
+ private static final int PREFIX_LENGTH = 22;
+ private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
+ private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
+ SERVER_ADDR, PREFIX_LENGTH);
// 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 Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
+ private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
- private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+ private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException {
return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
@@ -952,4 +959,96 @@
"\nActual:\n " + Arrays.toString(actual);
assertTrue(msg, Arrays.equals(expected, actual));
}
+
+ public void checkBuildOfferPacket(int leaseTimeSecs) throws Exception {
+ final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2);
+ final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000);
+ final int transactionId = 0xdeadbeef;
+
+ final ByteBuffer packet = DhcpPacket.buildOfferPacket(
+ DhcpPacket.ENCAP_BOOTP, transactionId, false /* broadcast */,
+ SERVER_ADDR, INADDR_ANY /* relayIp */, CLIENT_ADDR /* yourIp */,
+ 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 */);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ // BOOTP headers
+ bos.write(new byte[] {
+ (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x00,
+ (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ // ciaddr
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ // yiaddr
+ bos.write(CLIENT_ADDR.getAddress());
+ // siaddr
+ bos.write(SERVER_ADDR.getAddress());
+ // giaddr
+ bos.write(INADDR_ANY.getAddress());
+ // chaddr
+ bos.write(CLIENT_MAC);
+
+ // Padding
+ bos.write(new byte[202]);
+
+ // Options
+ bos.write(new byte[]{
+ // Magic cookie 0x63825363.
+ (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
+ // Message type OFFER.
+ (byte) 0x35, (byte) 0x01, (byte) 0x02,
+ });
+ // Server ID
+ bos.write(new byte[] { (byte) 0x36, (byte) 0x04 });
+ bos.write(SERVER_ADDR.getAddress());
+ // Lease time
+ bos.write(new byte[] { (byte) 0x33, (byte) 0x04 });
+ bos.write(intToByteArray(leaseTimeSecs));
+ if (leaseTimeSecs != INFINITE_LEASE) {
+ // Renewal time
+ bos.write(new byte[]{(byte) 0x3a, (byte) 0x04});
+ bos.write(intToByteArray(renewalTime));
+ // Rebinding time
+ bos.write(new byte[]{(byte) 0x3b, (byte) 0x04});
+ bos.write(intToByteArray(rebindingTime));
+ }
+ // Subnet mask
+ bos.write(new byte[] { (byte) 0x01, (byte) 0x04 });
+ bos.write(NETMASK.getAddress());
+ // Broadcast address
+ bos.write(new byte[] { (byte) 0x1c, (byte) 0x04 });
+ bos.write(BROADCAST_ADDR.getAddress());
+ // Router
+ bos.write(new byte[] { (byte) 0x03, (byte) 0x04 });
+ bos.write(SERVER_ADDR.getAddress());
+ // Nameserver
+ bos.write(new byte[] { (byte) 0x06, (byte) 0x04 });
+ bos.write(SERVER_ADDR.getAddress());
+ // End options.
+ bos.write(0xff);
+
+ final byte[] expected = bos.toByteArray();
+ assertTrue((expected.length & 1) == 0);
+
+ final byte[] actual = new byte[packet.limit()];
+ packet.get(actual);
+ final String msg = "Expected:\n " + HexDump.dumpHexString(expected) +
+ "\nActual:\n " + HexDump.dumpHexString(actual);
+ assertTrue(msg, Arrays.equals(expected, actual));
+ }
+
+ @Test
+ public void testOfferPacket() throws Exception {
+ checkBuildOfferPacket(3600);
+ checkBuildOfferPacket(Integer.MAX_VALUE);
+ checkBuildOfferPacket(0x80000000);
+ checkBuildOfferPacket(INFINITE_LEASE);
+ }
+
+ private static byte[] intToByteArray(int val) {
+ return ByteBuffer.allocate(4).putInt(val).array();
+ }
}