From d973537ee1bd013b4233d3369d66821e124a2e65 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 2 Jun 2015 13:15:50 +0900 Subject: Fix DHCP lease time parsing. Currently we treat a lease time larger than 2**31-1 as a negative value, which causes DhcpClient to attempt to renew its IP address constantly. Fix this by properly handling large and infinite lifetimes, and while we're at it, impose a minimum lease time of 60 seconds. Bug: 21352084 Change-Id: If62c9efeffad6222e2fe0c110f77d0e4c70de96d --- services/net/java/android/net/dhcp/DhcpClient.java | 28 +++++++++++++--------- services/net/java/android/net/dhcp/DhcpPacket.java | 22 ++++++++++++++++- 2 files changed, 38 insertions(+), 12 deletions(-) (limited to 'services/net') diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index e1d1787..1ee34cc 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -390,11 +390,15 @@ public class DhcpClient extends BaseDhcpStateMachine { } private void scheduleRenew() { - long now = SystemClock.elapsedRealtime(); - long alarmTime = (now + mDhcpLeaseExpiry) / 2; mAlarmManager.cancel(mRenewIntent); - mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mRenewIntent); - Log.d(TAG, "Scheduling renewal in " + ((alarmTime - now) / 1000) + "s"); + if (mDhcpLeaseExpiry != 0) { + long now = SystemClock.elapsedRealtime(); + long alarmTime = (now + mDhcpLeaseExpiry) / 2; + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mRenewIntent); + Log.d(TAG, "Scheduling renewal in " + ((alarmTime - now) / 1000) + "s"); + } else { + Log.d(TAG, "Infinite lease, no renewal needed"); + } } private void notifyLease() { @@ -586,6 +590,12 @@ public class DhcpClient extends BaseDhcpStateMachine { return true; } + public void setDhcpLeaseExpiry(DhcpPacket packet) { + long leaseTimeMillis = packet.getLeaseTimeMillis(); + mDhcpLeaseExpiry = + (leaseTimeMillis > 0) ? SystemClock.elapsedRealtime() + leaseTimeMillis : 0; + } + /** * Retransmits packets using jittered exponential backoff with an optional timeout. Packet * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. @@ -723,10 +733,9 @@ public class DhcpClient extends BaseDhcpStateMachine { DhcpResults results = packet.toDhcpResults(); if (results != null) { mDhcpLease = results; - Log.d(TAG, "Confirmed lease: " + mDhcpLease); - mDhcpLeaseExpiry = SystemClock.elapsedRealtime() + - mDhcpLease.leaseDuration * 1000; mOffer = null; + Log.d(TAG, "Confirmed lease: " + mDhcpLease); + setDhcpLeaseExpiry(packet); transitionTo(mDhcpBoundState); } } else if (packet instanceof DhcpNakPacket) { @@ -797,10 +806,7 @@ public class DhcpClient extends BaseDhcpStateMachine { protected void receivePacket(DhcpPacket packet) { if (!isValidPacket(packet)) return; if ((packet instanceof DhcpAckPacket)) { - DhcpResults results = packet.toDhcpResults(); - mDhcpLease.leaseDuration = results.leaseDuration; - mDhcpLeaseExpiry = SystemClock.elapsedRealtime() + - mDhcpLease.leaseDuration * 1000; + setDhcpLeaseExpiry(packet); transitionTo(mDhcpBoundState); } else if (packet instanceof DhcpNakPacket) { transitionTo(mDhcpInitState); diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index b923b1b..2a25d30 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -28,6 +28,12 @@ import java.util.List; abstract class DhcpPacket { protected static final String TAG = "DhcpPacket"; + // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the + // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the + // DHCP client timeout. + public static final int MINIMUM_LEASE = 60; + public static final int INFINITE_LEASE = (int) 0xffffffff; + public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY; public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL; public static final byte[] ETHER_BROADCAST = new byte[] { @@ -1006,11 +1012,25 @@ abstract class DhcpPacket { results.domains = mDomainName; results.serverAddress = mServerIdentifier; results.vendorInfo = mVendorId; - results.leaseDuration = mLeaseTime; + results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE; return results; } /** + * Returns the parsed lease time, in milliseconds, or 0 for infinite. + */ + public long getLeaseTimeMillis() { + // dhcpcd treats the lack of a lease time option as an infinite lease. + if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) { + return 0; + } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) { + return MINIMUM_LEASE * 1000; + } else { + return (mLeaseTime & 0xffffffffL) * 1000; + } + } + + /** * Builds a DHCP-DISCOVER packet from the required specified * parameters. */ -- cgit v1.1