Merge changes I58f904d5,Ie0bf7804
am: 6717a6f930
Change-Id: Icce72f30997a66e8251a34a313957fb3f9f3e0e3
This commit is contained in:
@@ -218,6 +218,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
.setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
|
.setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
|
||||||
.setDnsServers(addr)
|
.setDnsServers(addr)
|
||||||
.setServerAddr(new LinkAddress(addr, prefixLen))
|
.setServerAddr(new LinkAddress(addr, prefixLen))
|
||||||
|
.setMetered(true)
|
||||||
.build();
|
.build();
|
||||||
// TODO: also advertise link MTU
|
// TODO: also advertise link MTU
|
||||||
} catch (DhcpServingParams.InvalidParameterException e) {
|
} catch (DhcpServingParams.InvalidParameterException e) {
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ class DhcpAckPacket extends DhcpPacket {
|
|||||||
private final Inet4Address mSrcIp;
|
private final Inet4Address mSrcIp;
|
||||||
|
|
||||||
DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
|
DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
|
||||||
Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
|
Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
|
||||||
super(transId, secs, clientIp, yourIp, serverAddress, INADDR_ANY, clientMac, broadcast);
|
super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast);
|
||||||
mBroadcast = broadcast;
|
mBroadcast = broadcast;
|
||||||
mSrcIp = serverAddress;
|
mSrcIp = serverAddress;
|
||||||
}
|
}
|
||||||
@@ -70,19 +70,8 @@ class DhcpAckPacket extends DhcpPacket {
|
|||||||
void finishPacket(ByteBuffer buffer) {
|
void finishPacket(ByteBuffer buffer) {
|
||||||
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_ACK);
|
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_ACK);
|
||||||
addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
|
addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
|
||||||
addTlv(buffer, DHCP_LEASE_TIME, mLeaseTime);
|
|
||||||
|
|
||||||
// the client should renew at 1/2 the lease-expiry interval
|
addCommonServerTlvs(buffer);
|
||||||
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);
|
|
||||||
addTlvEnd(buffer);
|
addTlvEnd(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ class DhcpNakPacket extends DhcpPacket {
|
|||||||
/**
|
/**
|
||||||
* Generates a NAK packet with the specified parameters.
|
* Generates a NAK packet with the specified parameters.
|
||||||
*/
|
*/
|
||||||
DhcpNakPacket(int transId, short secs, Inet4Address nextIp, Inet4Address relayIp,
|
DhcpNakPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac,
|
||||||
byte[] clientMac, boolean broadcast) {
|
boolean broadcast) {
|
||||||
super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp, clientMac, broadcast);
|
super(transId, secs, INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */,
|
||||||
|
INADDR_ANY /* nextIp */, relayIp, clientMac, broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ class DhcpOfferPacket extends DhcpPacket {
|
|||||||
* Generates a OFFER packet with the specified parameters.
|
* Generates a OFFER packet with the specified parameters.
|
||||||
*/
|
*/
|
||||||
DhcpOfferPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
|
DhcpOfferPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
|
||||||
Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
|
Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
|
||||||
super(transId, secs, clientIp, yourIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
|
super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast);
|
||||||
mSrcIp = serverAddress;
|
mSrcIp = serverAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,19 +72,8 @@ class DhcpOfferPacket extends DhcpPacket {
|
|||||||
void finishPacket(ByteBuffer buffer) {
|
void finishPacket(ByteBuffer buffer) {
|
||||||
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_OFFER);
|
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_OFFER);
|
||||||
addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
|
addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
|
||||||
addTlv(buffer, DHCP_LEASE_TIME, mLeaseTime);
|
|
||||||
|
|
||||||
// the client should renew at 1/2 the lease-expiry interval
|
addCommonServerTlvs(buffer);
|
||||||
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);
|
|
||||||
addTlvEnd(buffer);
|
addTlvEnd(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,11 @@ public abstract class DhcpPacket {
|
|||||||
protected static final byte DHCP_VENDOR_INFO = 43;
|
protected static final byte DHCP_VENDOR_INFO = 43;
|
||||||
protected String mVendorInfo;
|
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
|
* 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);
|
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.
|
* Converts a MAC from an array of octets to an ASCII string.
|
||||||
*/
|
*/
|
||||||
@@ -1085,7 +1107,7 @@ public abstract class DhcpPacket {
|
|||||||
break;
|
break;
|
||||||
case DHCP_MESSAGE_TYPE_OFFER:
|
case DHCP_MESSAGE_TYPE_OFFER:
|
||||||
newPacket = new DhcpOfferPacket(
|
newPacket = new DhcpOfferPacket(
|
||||||
transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
|
transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
|
||||||
break;
|
break;
|
||||||
case DHCP_MESSAGE_TYPE_REQUEST:
|
case DHCP_MESSAGE_TYPE_REQUEST:
|
||||||
newPacket = new DhcpRequestPacket(
|
newPacket = new DhcpRequestPacket(
|
||||||
@@ -1098,11 +1120,11 @@ public abstract class DhcpPacket {
|
|||||||
break;
|
break;
|
||||||
case DHCP_MESSAGE_TYPE_ACK:
|
case DHCP_MESSAGE_TYPE_ACK:
|
||||||
newPacket = new DhcpAckPacket(
|
newPacket = new DhcpAckPacket(
|
||||||
transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
|
transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
|
||||||
break;
|
break;
|
||||||
case DHCP_MESSAGE_TYPE_NAK:
|
case DHCP_MESSAGE_TYPE_NAK:
|
||||||
newPacket = new DhcpNakPacket(
|
newPacket = new DhcpNakPacket(
|
||||||
transactionId, secs, nextIp, relayIp, clientMac, broadcast);
|
transactionId, secs, relayIp, clientMac, broadcast);
|
||||||
break;
|
break;
|
||||||
case DHCP_MESSAGE_TYPE_RELEASE:
|
case DHCP_MESSAGE_TYPE_RELEASE:
|
||||||
if (serverIdentifier == null) {
|
if (serverIdentifier == null) {
|
||||||
@@ -1234,12 +1256,13 @@ public abstract class DhcpPacket {
|
|||||||
* parameters.
|
* parameters.
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer buildOfferPacket(int encap, int transactionId,
|
public static ByteBuffer buildOfferPacket(int encap, int transactionId,
|
||||||
boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
|
boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
|
||||||
byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
|
Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
|
||||||
List<Inet4Address> gateways, List<Inet4Address> dnsServers,
|
Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
|
||||||
Inet4Address dhcpServerIdentifier, String domainName) {
|
Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
|
||||||
DhcpPacket pkt = new DhcpOfferPacket(
|
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.mGateways = gateways;
|
||||||
pkt.mDnsServers = dnsServers;
|
pkt.mDnsServers = dnsServers;
|
||||||
pkt.mLeaseTime = timeout;
|
pkt.mLeaseTime = timeout;
|
||||||
@@ -1247,6 +1270,9 @@ public abstract class DhcpPacket {
|
|||||||
pkt.mServerIdentifier = dhcpServerIdentifier;
|
pkt.mServerIdentifier = dhcpServerIdentifier;
|
||||||
pkt.mSubnetMask = netMask;
|
pkt.mSubnetMask = netMask;
|
||||||
pkt.mBroadcastAddress = bcAddr;
|
pkt.mBroadcastAddress = bcAddr;
|
||||||
|
if (metered) {
|
||||||
|
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
|
||||||
|
}
|
||||||
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
|
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.
|
* Builds a DHCP-ACK packet from the required specified parameters.
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer buildAckPacket(int encap, int transactionId,
|
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,
|
byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
|
||||||
List<Inet4Address> gateways, List<Inet4Address> dnsServers,
|
List<Inet4Address> gateways, List<Inet4Address> dnsServers,
|
||||||
Inet4Address dhcpServerIdentifier, String domainName) {
|
Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
|
||||||
DhcpPacket pkt = new DhcpAckPacket(
|
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.mGateways = gateways;
|
||||||
pkt.mDnsServers = dnsServers;
|
pkt.mDnsServers = dnsServers;
|
||||||
pkt.mLeaseTime = timeout;
|
pkt.mLeaseTime = timeout;
|
||||||
@@ -1267,6 +1294,9 @@ public abstract class DhcpPacket {
|
|||||||
pkt.mSubnetMask = netMask;
|
pkt.mSubnetMask = netMask;
|
||||||
pkt.mServerIdentifier = dhcpServerIdentifier;
|
pkt.mServerIdentifier = dhcpServerIdentifier;
|
||||||
pkt.mBroadcastAddress = bcAddr;
|
pkt.mBroadcastAddress = bcAddr;
|
||||||
|
if (metered) {
|
||||||
|
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
|
||||||
|
}
|
||||||
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
|
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.
|
* Builds a DHCP-NAK packet from the required specified parameters.
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
|
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(
|
DhcpPacket pkt = new DhcpNakPacket(
|
||||||
transactionId, (short) 0, serverIpAddr, serverIpAddr, mac, broadcast);
|
transactionId, (short) 0, relayIp, mac, broadcast);
|
||||||
pkt.mMessage = message;
|
pkt.mMessage = message;
|
||||||
|
pkt.mServerIdentifier = serverIpAddr;
|
||||||
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
|
return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -351,12 +351,10 @@ public class DhcpServer {
|
|||||||
mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
|
mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
|
||||||
final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
|
final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
|
||||||
ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
|
ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
|
||||||
lease.getNetAddr(), request.mClientMac, timeout,
|
request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
|
||||||
prefixMask,
|
broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
|
||||||
broadcastAddr,
|
|
||||||
new ArrayList<>(mServingParams.defaultRouters),
|
|
||||||
new ArrayList<>(mServingParams.dnsServers),
|
new ArrayList<>(mServingParams.dnsServers),
|
||||||
mServingParams.getServerInet4Addr(), null /* domainName */);
|
mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
|
||||||
|
|
||||||
return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
|
return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
|
||||||
}
|
}
|
||||||
@@ -368,12 +366,12 @@ public class DhcpServer {
|
|||||||
final boolean broadcastFlag = getBroadcastFlag(request, lease);
|
final boolean broadcastFlag = getBroadcastFlag(request, lease);
|
||||||
final int timeout = getLeaseTimeout(lease);
|
final int timeout = getLeaseTimeout(lease);
|
||||||
final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
|
final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
|
||||||
broadcastFlag, mServingParams.getServerInet4Addr(), lease.getNetAddr(),
|
broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
|
||||||
request.mClientMac, timeout, mServingParams.getPrefixMaskAsAddress(),
|
lease.getNetAddr(), request.mClientMac, timeout,
|
||||||
mServingParams.getBroadcastAddress(),
|
mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
|
||||||
new ArrayList<>(mServingParams.defaultRouters),
|
new ArrayList<>(mServingParams.defaultRouters),
|
||||||
new ArrayList<>(mServingParams.dnsServers),
|
new ArrayList<>(mServingParams.dnsServers),
|
||||||
mServingParams.getServerInet4Addr(), null /* domainName */);
|
mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
|
||||||
|
|
||||||
return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
|
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
|
// Always set broadcast flag for NAK: client may not have a correct IP
|
||||||
final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
|
final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
|
||||||
ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
|
ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
|
||||||
request.mClientMac, true /* broadcast */, message);
|
request.mRelayIp, request.mClientMac, true /* broadcast */, message);
|
||||||
|
|
||||||
final Inet4Address dst = isEmpty(request.mRelayIp)
|
final Inet4Address dst = isEmpty(request.mRelayIp)
|
||||||
? (Inet4Address) Inet4Address.ALL
|
? (Inet4Address) Inet4Address.ALL
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ public class DhcpServingParams {
|
|||||||
public final long dhcpLeaseTimeSecs;
|
public final long dhcpLeaseTimeSecs;
|
||||||
public final int linkMtu;
|
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
|
* Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
|
||||||
* missing or invalid.
|
* missing or invalid.
|
||||||
@@ -88,13 +93,14 @@ public class DhcpServingParams {
|
|||||||
private DhcpServingParams(@NonNull LinkAddress serverAddr,
|
private DhcpServingParams(@NonNull LinkAddress serverAddr,
|
||||||
@NonNull Set<Inet4Address> defaultRouters,
|
@NonNull Set<Inet4Address> defaultRouters,
|
||||||
@NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
|
@NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
|
||||||
long dhcpLeaseTimeSecs, int linkMtu) {
|
long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
|
||||||
this.serverAddr = serverAddr;
|
this.serverAddr = serverAddr;
|
||||||
this.defaultRouters = defaultRouters;
|
this.defaultRouters = defaultRouters;
|
||||||
this.dnsServers = dnsServers;
|
this.dnsServers = dnsServers;
|
||||||
this.excludedAddrs = excludedAddrs;
|
this.excludedAddrs = excludedAddrs;
|
||||||
this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
|
this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
|
||||||
this.linkMtu = linkMtu;
|
this.linkMtu = linkMtu;
|
||||||
|
this.metered = metered;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -134,6 +140,7 @@ public class DhcpServingParams {
|
|||||||
private Set<Inet4Address> excludedAddrs;
|
private Set<Inet4Address> excludedAddrs;
|
||||||
private long dhcpLeaseTimeSecs;
|
private long dhcpLeaseTimeSecs;
|
||||||
private int linkMtu = MTU_UNSET;
|
private int linkMtu = MTU_UNSET;
|
||||||
|
private boolean metered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the server address and served prefix for the DHCP server.
|
* Set the server address and served prefix for the DHCP server.
|
||||||
@@ -247,6 +254,16 @@ public class DhcpServingParams {
|
|||||||
return this;
|
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.
|
* 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<>(defaultRouters)),
|
||||||
Collections.unmodifiableSet(new HashSet<>(dnsServers)),
|
Collections.unmodifiableSet(new HashSet<>(dnsServers)),
|
||||||
Collections.unmodifiableSet(excl),
|
Collections.unmodifiableSet(excl),
|
||||||
dhcpLeaseTimeSecs, linkMtu);
|
dhcpLeaseTimeSecs, linkMtu, metered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package android.net.dhcp;
|
package android.net.dhcp;
|
||||||
|
|
||||||
|
import static android.net.NetworkUtils.getBroadcastAddress;
|
||||||
|
import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
|
||||||
import static android.net.dhcp.DhcpPacket.*;
|
import static android.net.dhcp.DhcpPacket.*;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -29,14 +31,15 @@ import android.net.NetworkUtils;
|
|||||||
import android.net.metrics.DhcpErrorEvent;
|
import android.net.metrics.DhcpErrorEvent;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.system.OsConstants;
|
|
||||||
|
|
||||||
import com.android.internal.util.HexDump;
|
import com.android.internal.util.HexDump;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -47,13 +50,17 @@ import org.junit.runner.RunWith;
|
|||||||
@SmallTest
|
@SmallTest
|
||||||
public class DhcpPacketTest {
|
public class DhcpPacketTest {
|
||||||
|
|
||||||
private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
|
private static final Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
|
||||||
private static Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
|
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
|
// 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.
|
// 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 {
|
private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException {
|
||||||
return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
|
return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
|
||||||
@@ -952,4 +959,96 @@ public class DhcpPacketTest {
|
|||||||
"\nActual:\n " + Arrays.toString(actual);
|
"\nActual:\n " + Arrays.toString(actual);
|
||||||
assertTrue(msg, Arrays.equals(expected, 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