Merge "Honour the DHCP MTU option." into nyc-dev

This commit is contained in:
Lorenzo Colitti
2016-04-01 00:55:06 +00:00
committed by Android (Google) Code Review
4 changed files with 97 additions and 23 deletions

View File

@@ -40,6 +40,9 @@ public class DhcpResults extends StaticIpConfiguration {
public int leaseDuration; public int leaseDuration;
/** Link MTU option. 0 means unset. */
public int mtu;
public DhcpResults() { public DhcpResults() {
super(); super();
} }
@@ -57,19 +60,7 @@ public class DhcpResults extends StaticIpConfiguration {
serverAddress = source.serverAddress; serverAddress = source.serverAddress;
vendorInfo = source.vendorInfo; vendorInfo = source.vendorInfo;
leaseDuration = source.leaseDuration; leaseDuration = source.leaseDuration;
} mtu = source.mtu;
}
/**
* Updates the DHCP fields that need to be retained from
* original DHCP request if the current renewal shows them
* being empty.
*/
public void updateFromDhcpRequest(DhcpResults orig) {
if (orig == null) return;
if (gateway == null) gateway = orig.gateway;
if (dnsServers.size() == 0) {
dnsServers.addAll(orig.dnsServers);
} }
} }
@@ -89,6 +80,7 @@ public class DhcpResults extends StaticIpConfiguration {
super.clear(); super.clear();
vendorInfo = null; vendorInfo = null;
leaseDuration = 0; leaseDuration = 0;
mtu = 0;
} }
@Override @Override
@@ -98,6 +90,7 @@ public class DhcpResults extends StaticIpConfiguration {
str.append(" DHCP server ").append(serverAddress); str.append(" DHCP server ").append(serverAddress);
str.append(" Vendor info ").append(vendorInfo); str.append(" Vendor info ").append(vendorInfo);
str.append(" lease ").append(leaseDuration).append(" seconds"); str.append(" lease ").append(leaseDuration).append(" seconds");
if (mtu != 0) str.append(" MTU ").append(mtu);
return str.toString(); return str.toString();
} }
@@ -113,7 +106,8 @@ public class DhcpResults extends StaticIpConfiguration {
return super.equals((StaticIpConfiguration) obj) && return super.equals((StaticIpConfiguration) obj) &&
Objects.equals(serverAddress, target.serverAddress) && Objects.equals(serverAddress, target.serverAddress) &&
Objects.equals(vendorInfo, target.vendorInfo) && Objects.equals(vendorInfo, target.vendorInfo) &&
leaseDuration == target.leaseDuration; leaseDuration == target.leaseDuration &&
mtu == target.mtu;
} }
/** Implement the Parcelable interface */ /** Implement the Parcelable interface */
@@ -134,6 +128,7 @@ public class DhcpResults extends StaticIpConfiguration {
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
dest.writeInt(leaseDuration); dest.writeInt(leaseDuration);
dest.writeInt(mtu);
NetworkUtils.parcelInetAddress(dest, serverAddress, flags); NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
dest.writeString(vendorInfo); dest.writeString(vendorInfo);
} }
@@ -141,6 +136,7 @@ public class DhcpResults extends StaticIpConfiguration {
private static void readFromParcel(DhcpResults dhcpResults, Parcel in) { private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
StaticIpConfiguration.readFromParcel(dhcpResults, in); StaticIpConfiguration.readFromParcel(dhcpResults, in);
dhcpResults.leaseDuration = in.readInt(); dhcpResults.leaseDuration = in.readInt();
dhcpResults.mtu = in.readInt();
dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in); dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
dhcpResults.vendorInfo = in.readString(); dhcpResults.vendorInfo = in.readString();
} }

View File

@@ -57,6 +57,17 @@ abstract class DhcpPacket {
public static final int HWADDR_LEN = 16; public static final int HWADDR_LEN = 16;
public static final int MAX_OPTION_LEN = 255; public static final int MAX_OPTION_LEN = 255;
/**
* The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
* IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
* and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
* because in general it is risky to assume that the hardware is able to send/receive packets
* larger than 1500 bytes even if the network supports it.
*/
private static final int MIN_MTU = 1280;
private static final int MAX_MTU = 1500;
/** /**
* IP layer definitions. * IP layer definitions.
*/ */
@@ -917,7 +928,7 @@ abstract class DhcpPacket {
break; break;
case DHCP_MTU: case DHCP_MTU:
expectedLen = 2; expectedLen = 2;
mtu = Short.valueOf(packet.getShort()); mtu = packet.getShort();
break; break;
case DHCP_DOMAIN_NAME: case DHCP_DOMAIN_NAME:
expectedLen = optionLen; expectedLen = optionLen;
@@ -1106,6 +1117,8 @@ abstract class DhcpPacket {
results.serverAddress = mServerIdentifier; results.serverAddress = mServerIdentifier;
results.vendorInfo = mVendorInfo; results.vendorInfo = mVendorInfo;
results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE; results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
return results; return results;
} }

View File

@@ -605,6 +605,10 @@ public class IpManager extends StateMachine {
} }
} }
newLp.setDomains(mDhcpResults.domains); newLp.setDomains(mDhcpResults.domains);
if (mDhcpResults.mtu != 0) {
newLp.setMtu(mDhcpResults.mtu);
}
} }
// [4] Add in TCP buffer sizes and HTTP Proxy config, if available. // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.

View File

@@ -261,7 +261,7 @@ public class DhcpPacketTest extends TestCase {
private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString, private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
String domains, String serverAddress, String vendorInfo, int leaseDuration, String domains, String serverAddress, String vendorInfo, int leaseDuration,
boolean hasMeteredHint, DhcpResults dhcpResults) throws Exception { boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress); assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
assertEquals(v4Address(gateway), dhcpResults.gateway); assertEquals(v4Address(gateway), dhcpResults.gateway);
@@ -277,6 +277,7 @@ public class DhcpPacketTest extends TestCase {
assertEquals(vendorInfo, dhcpResults.vendorInfo); assertEquals(vendorInfo, dhcpResults.vendorInfo);
assertEquals(leaseDuration, dhcpResults.leaseDuration); assertEquals(leaseDuration, dhcpResults.leaseDuration);
assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint()); assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
assertEquals(mtu, dhcpResults.mtu);
} }
@SmallTest @SmallTest
@@ -310,7 +311,7 @@ public class DhcpPacketTest extends TestCase {
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null. assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4", assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
null, "192.168.144.3", null, 7200, false, dhcpResults); null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
} }
@SmallTest @SmallTest
@@ -342,10 +343,70 @@ public class DhcpPacketTest extends TestCase {
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null. assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1", assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
null, "192.168.43.1", "ANDROID_METERED", 3600, true, dhcpResults); null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
assertTrue(dhcpResults.hasMeteredHint()); assertTrue(dhcpResults.hasMeteredHint());
} }
private byte[] mtuBytes(int mtu) {
// 0x1a02: option 26, length 2. 0xff: no more options.
if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
throw new IllegalArgumentException(
String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
}
String hexString = String.format("1a02%04xff", mtu);
return HexEncoding.decode(hexString.toCharArray(), false);
}
private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
if (mtuBytes != null) {
packet.position(packet.capacity() - mtuBytes.length);
packet.put(mtuBytes);
packet.clear();
}
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
}
@SmallTest
public void testMtu() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
// IP header.
"451001480000000080118849c0a89003c0a89ff7" +
// UDP header.
"004300440134dcfa" +
// BOOTP header.
"02010600c997a63b0000000000000000c0a89ff70000000000000000" +
// MAC address.
"30766ff2a90c00000000000000000000" +
// Server name.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
// File.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options
"638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
"3a0400000e103b040000189cff00000000"
).toCharArray(), false));
checkMtu(packet, 0, null);
checkMtu(packet, 0, mtuBytes(1501));
checkMtu(packet, 1500, mtuBytes(1500));
checkMtu(packet, 1499, mtuBytes(1499));
checkMtu(packet, 1280, mtuBytes(1280));
checkMtu(packet, 0, mtuBytes(1279));
checkMtu(packet, 0, mtuBytes(576));
checkMtu(packet, 0, mtuBytes(68));
checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
checkMtu(packet, 0, mtuBytes(-1));
}
@SmallTest @SmallTest
public void testBadHwaddrLength() throws Exception { public void testBadHwaddrLength() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode(( final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
@@ -453,7 +514,7 @@ public class DhcpPacketTest extends TestCase {
assertTrue(offerPacket instanceof DhcpOfferPacket); assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1", assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
null, "1.1.1.1", null, 43200, false, dhcpResults); null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
} }
@SmallTest @SmallTest
@@ -484,7 +545,7 @@ public class DhcpPacketTest extends TestCase {
assertTrue(offerPacket instanceof DhcpOfferPacket); assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2", assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
"domain123.co.uk", "192.0.2.254", null, 49094, false, dhcpResults); "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
} }
@SmallTest @SmallTest
@@ -518,7 +579,7 @@ public class DhcpPacketTest extends TestCase {
assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac())); assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53", assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
"lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults); "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
} }
@SmallTest @SmallTest
@@ -554,7 +615,7 @@ public class DhcpPacketTest extends TestCase {
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.15.122.242/16", "10.15.200.23", assertDhcpResults("10.15.122.242/16", "10.15.200.23",
"209.129.128.3,209.129.148.3,209.129.128.6", "209.129.128.3,209.129.148.3,209.129.128.6",
"wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults); "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
} }
@SmallTest @SmallTest
@@ -621,7 +682,7 @@ public class DhcpPacketTest extends TestCase {
assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac())); assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults(); DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4", assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
null, "192.171.189.2", null, 28800, false, dhcpResults); null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
} }
@SmallTest @SmallTest