Merge changes I58f904d5,Ie0bf7804
* changes: Fix DHCP options sent by DHCP server Fix BOOTP fields for server-generated DHCP packets
This commit is contained in:
@@ -218,6 +218,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
.setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
|
||||
.setDnsServers(addr)
|
||||
.setServerAddr(new LinkAddress(addr, prefixLen))
|
||||
.setMetered(true)
|
||||
.build();
|
||||
// TODO: also advertise link MTU
|
||||
} catch (DhcpServingParams.InvalidParameterException e) {
|
||||
|
||||
@@ -30,8 +30,8 @@ class DhcpAckPacket extends DhcpPacket {
|
||||
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 @@ class DhcpAckPacket extends DhcpPacket {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,10 @@ class DhcpNakPacket extends DhcpPacket {
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
@@ -32,8 +32,8 @@ class DhcpOfferPacket extends DhcpPacket {
|
||||
* 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 @@ class DhcpOfferPacket extends DhcpPacket {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,11 @@ public abstract class DhcpPacket {
|
||||
protected static final byte DHCP_VENDOR_INFO = 43;
|
||||
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
|
||||
*/
|
||||
@@ -677,6 +682,23 @@ public abstract class DhcpPacket {
|
||||
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 @@ public abstract class DhcpPacket {
|
||||
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 @@ public abstract class DhcpPacket {
|
||||
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 @@ public abstract class DhcpPacket {
|
||||
* 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 @@ public abstract class DhcpPacket {
|
||||
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 @@ public abstract class DhcpPacket {
|
||||
* 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 @@ public abstract class DhcpPacket {
|
||||
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 @@ public abstract class DhcpPacket {
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -351,12 +351,10 @@ public class DhcpServer {
|
||||
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 @@ public class DhcpServer {
|
||||
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 @@ public class DhcpServer {
|
||||
// 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
|
||||
|
||||
@@ -75,6 +75,11 @@ public class DhcpServingParams {
|
||||
public final long dhcpLeaseTimeSecs;
|
||||
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 @@ public class DhcpServingParams {
|
||||
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 @@ public class DhcpServingParams {
|
||||
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.
|
||||
@@ -247,6 +254,16 @@ public class DhcpServingParams {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -301,7 +318,7 @@ public class DhcpServingParams {
|
||||
Collections.unmodifiableSet(new HashSet<>(defaultRouters)),
|
||||
Collections.unmodifiableSet(new HashSet<>(dnsServers)),
|
||||
Collections.unmodifiableSet(excl),
|
||||
dhcpLeaseTimeSecs, linkMtu);
|
||||
dhcpLeaseTimeSecs, linkMtu, metered);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.NetworkUtils;
|
||||
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 @@ import org.junit.runner.RunWith;
|
||||
@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 @@ public class DhcpPacketTest {
|
||||
"\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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user