Merge changes I58f904d5,Ie0bf7804

am: 6717a6f930

Change-Id: Icce72f30997a66e8251a34a313957fb3f9f3e0e3
This commit is contained in:
Remi NGUYEN VAN
2018-08-30 02:57:03 -07:00
committed by android-build-merger
8 changed files with 186 additions and 61 deletions

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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() {

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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();
}
}