Loading services/net/java/android/net/dhcp/DhcpClient.java +122 −55 Original line number Diff line number Diff line Loading @@ -125,17 +125,18 @@ public class DhcpClient extends StateMachine { public static final int CMD_CONFIGURE_LINKADDRESS = PUBLIC_BASE + 8; public static final int EVENT_LINKADDRESS_CONFIGURED = PUBLIC_BASE + 9; /* Message.arg1 arguments to CMD_POST_DHCP notification */ /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */ public static final int DHCP_SUCCESS = 1; public static final int DHCP_FAILURE = 2; // Messages. // Internal messages. private static final int PRIVATE_BASE = Protocol.BASE_DHCP + 100; private static final int CMD_KICK = PRIVATE_BASE + 1; private static final int CMD_RECEIVED_PACKET = PRIVATE_BASE + 2; private static final int CMD_TIMEOUT = PRIVATE_BASE + 3; private static final int CMD_RENEW_DHCP = PRIVATE_BASE + 4; private static final int CMD_EXPIRE_DHCP = PRIVATE_BASE + 5; private static final int CMD_REBIND_DHCP = PRIVATE_BASE + 5; private static final int CMD_EXPIRE_DHCP = PRIVATE_BASE + 6; // For message logging. private static final Class[] sMessageClasses = { DhcpClient.class }; Loading Loading @@ -177,6 +178,7 @@ public class DhcpClient extends StateMachine { private final WakeupMessage mKickAlarm; private final WakeupMessage mTimeoutAlarm; private final WakeupMessage mRenewAlarm; private final WakeupMessage mRebindAlarm; private final WakeupMessage mExpiryAlarm; private final String mIfaceName; Loading Loading @@ -241,8 +243,9 @@ public class DhcpClient extends StateMachine { mKickAlarm = makeWakeupMessage("KICK", CMD_KICK); // Used to time out PacketRetransmittingStates. mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT); // Used to schedule DHCP renews. // Used to schedule DHCP reacquisition. mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP); mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP); mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP); } Loading Loading @@ -276,6 +279,10 @@ public class DhcpClient extends StateMachine { } private boolean initSockets() { return initPacketSocket() && initUdpSocket(); } private boolean initPacketSocket() { try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP); PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex()); Loading @@ -285,6 +292,10 @@ public class DhcpClient extends StateMachine { Log.e(TAG, "Error creating packet socket", e); return false; } return true; } private boolean initUdpSocket() { try { mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1); Loading Loading @@ -363,16 +374,25 @@ public class DhcpClient extends StateMachine { return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000); } private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) { private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) { try { if (to.equals(INADDR_BROADCAST)) { if (encap == DhcpPacket.ENCAP_L2) { if (DBG) Log.d(TAG, "Broadcasting " + description); Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr); } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) { if (DBG) Log.d(TAG, "Broadcasting " + description); // We only send L3-encapped broadcasts in DhcpRebindingState, // where we have an IP address and an unconnected UDP socket. // // N.B.: We only need this codepath because DhcpRequestPacket // hardcodes the source IP address to 0.0.0.0. We could reuse // the packet socket if this ever changes. Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER); } else { // It's safe to call getpeername here, because we only send unicast packets if we // have an IP address, and we connect the UDP socket before // ConfiguringInterfaceState#exit. if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock)); // have an IP address, and we connect the UDP socket in DhcpBoundState#enter. if (DBG) Log.d(TAG, String.format("Unicasting %s to %s", description, Os.getpeername(mUdpSock))); Os.write(mUdpSock, buf); } } catch(ErrnoException|IOException e) { Loading @@ -386,14 +406,15 @@ public class DhcpClient extends StateMachine { ByteBuffer packet = DhcpPacket.buildDiscoverPacket( DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr, DO_UNICAST, REQUESTED_PARAMS); return transmitPacket(packet, "DHCPDISCOVER", INADDR_BROADCAST); return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST); } private boolean sendRequestPacket( Inet4Address clientAddress, Inet4Address requestedAddress, Inet4Address serverAddress, Inet4Address to) { // TODO: should we use the transaction ID from the server? int encap = to.equals(INADDR_BROADCAST) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP; final int encap = INADDR_ANY.equals(clientAddress) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP; ByteBuffer packet = DhcpPacket.buildRequestPacket( encap, mTransactionId, getSecs(), clientAddress, Loading @@ -403,7 +424,7 @@ public class DhcpClient extends StateMachine { String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() + " request=" + requestedAddress.getHostAddress() + " serverid=" + serverStr; return transmitPacket(packet, description, to); return transmitPacket(packet, description, encap, to); } private void scheduleLeaseTimers() { Loading @@ -413,14 +434,21 @@ public class DhcpClient extends StateMachine { } final long now = SystemClock.elapsedRealtime(); long renewTime = (now + mDhcpLeaseExpiry) / 2; mRenewAlarm.schedule(renewTime); long secondsHence = (renewTime - now) / 1000; Log.d(TAG, "Scheduling renewal in " + secondsHence + "s"); mExpiryAlarm.schedule(mDhcpLeaseExpiry); secondsHence = (mDhcpLeaseExpiry - now) / 1000; Log.d(TAG, "Scheduling expiry in " + secondsHence + "s"); // TODO: consider getting the renew and rebind timers from T1 and T2. // See also: // https://tools.ietf.org/html/rfc2131#section-4.4.5 // https://tools.ietf.org/html/rfc1533#section-9.9 // https://tools.ietf.org/html/rfc1533#section-9.10 final long remainingDelay = mDhcpLeaseExpiry - now; final long renewDelay = remainingDelay / 2; final long rebindDelay = remainingDelay * 7 / 8; mRenewAlarm.schedule(now + renewDelay); mRebindAlarm.schedule(now + rebindDelay); mExpiryAlarm.schedule(now + remainingDelay); Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s"); Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s"); Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s"); } private void notifySuccess() { Loading Loading @@ -719,7 +747,6 @@ public class DhcpClient extends StateMachine { class DhcpRequestingState extends PacketRetransmittingState { public DhcpRequestingState() { super(); mTimeout = DHCP_TIMEOUT_MS / 2; } Loading Loading @@ -777,7 +804,11 @@ public class DhcpClient extends StateMachine { @Override public void exit() { // Clear any extant alarms. mRenewAlarm.cancel(); mRebindAlarm.cancel(); mExpiryAlarm.cancel(); clearDhcpState(); // Tell IpManager to clear the IPv4 address. There is no need to // wait for confirmation since any subsequent packets are sent from // INADDR_ANY anyway (DISCOVER, REQUEST). Loading @@ -797,21 +828,7 @@ public class DhcpClient extends StateMachine { super.processMessage(message); switch (message.what) { case EVENT_LINKADDRESS_CONFIGURED: if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) { // There's likely no point in going into DhcpInitState here, we'll probably // just repeat the transaction, get the same IP address as before, and fail. // // NOTE: It is observed that connectUdpSock() basically never fails, due to // SO_BINDTODEVICE. Examining the local socket address shows it will happily // return an IPv4 address from another interface, or even return "0.0.0.0". // // TODO: Consider deleting this check, following testing on several kernels. notifyFailure(); transitionTo(mStoppedState); } else { transitionTo(mDhcpBoundState); } return HANDLED; default: return NOT_HANDLED; Loading @@ -823,8 +840,19 @@ public class DhcpClient extends StateMachine { @Override public void enter() { super.enter(); // TODO: DhcpStateMachine only supported renewing at 50% of the lease time, // and did not support rebinding. Now that the legacy DHCP client is gone, fix this. if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) { // There's likely no point in going into DhcpInitState here, we'll probably // just repeat the transaction, get the same IP address as before, and fail. // // NOTE: It is observed that connectUdpSock() basically never fails, due to // SO_BINDTODEVICE. Examining the local socket address shows it will happily // return an IPv4 address from another interface, or even return "0.0.0.0". // // TODO: Consider deleting this check, following testing on several kernels. notifyFailure(); transitionTo(mStoppedState); } scheduleLeaseTimers(); } Loading @@ -843,18 +871,10 @@ public class DhcpClient extends StateMachine { return NOT_HANDLED; } } @Override public void exit() { mRenewAlarm.cancel(); } } class DhcpRenewingState extends PacketRetransmittingState { public DhcpRenewingState() { super(); mTimeout = DHCP_TIMEOUT_MS; } abstract class DhcpReacquiringState extends PacketRetransmittingState { protected String mLeaseMsg; @Override public void enter() { Loading @@ -862,16 +882,14 @@ public class DhcpClient extends StateMachine { startNewTransaction(); } abstract protected Inet4Address packetDestination(); protected boolean sendPacket() { // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but... // http://b/25343517 . Try to make things work anyway by using broadcast renews. Inet4Address to = (mDhcpLease.serverAddress != null) ? mDhcpLease.serverAddress : INADDR_BROADCAST; return sendRequestPacket( (Inet4Address) mDhcpLease.ipAddress.getAddress(), // ciaddr INADDR_ANY, // DHCP_REQUESTED_IP null, // DHCP_SERVER_IDENTIFIER to); // packet destination address packetDestination()); // packet destination address } protected void receivePacket(DhcpPacket packet) { Loading @@ -890,7 +908,7 @@ public class DhcpClient extends StateMachine { // in IpManager and by any overridden relevant handlers of // the registered IpManager.Callback. IP address changes // are not supported here. acceptDhcpResults(results, "Renewed"); acceptDhcpResults(results, mLeaseMsg); transitionTo(mDhcpBoundState); } } else if (packet instanceof DhcpNakPacket) { Loading @@ -901,8 +919,57 @@ public class DhcpClient extends StateMachine { } } // Not implemented--yet. DhcpStateMachine did not implement it either. class DhcpRebindingState extends LoggingState { class DhcpRenewingState extends DhcpReacquiringState { public DhcpRenewingState() { mLeaseMsg = "Renewed"; } @Override public boolean processMessage(Message message) { if (super.processMessage(message) == HANDLED) { return HANDLED; } switch (message.what) { case CMD_REBIND_DHCP: transitionTo(mDhcpRebindingState); return HANDLED; default: return NOT_HANDLED; } } @Override protected Inet4Address packetDestination() { // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but... // http://b/25343517 . Try to make things work anyway by using broadcast renews. return (mDhcpLease.serverAddress != null) ? mDhcpLease.serverAddress : INADDR_BROADCAST; } } class DhcpRebindingState extends DhcpReacquiringState { public DhcpRebindingState() { mLeaseMsg = "Rebound"; } @Override public void enter() { super.enter(); // We need to broadcast and possibly reconnect the socket to a // completely different server. closeQuietly(mUdpSock); if (!initUdpSocket()) { Log.e(TAG, "Failed to recreate UDP socket"); transitionTo(mDhcpInitState); } } @Override protected Inet4Address packetDestination() { return INADDR_BROADCAST; } } class DhcpInitRebootState extends LoggingState { Loading services/net/java/android/net/ip/IpManager.java +21 −15 Original line number Diff line number Diff line Loading @@ -1027,6 +1027,8 @@ public class IpManager extends StateMachine { } class StartedState extends State { private boolean mDhcpActionInFlight; @Override public void enter() { mStartTimeMillis = SystemClock.elapsedRealtime(); Loading Loading @@ -1066,7 +1068,7 @@ public class IpManager extends StateMachine { @Override public void exit() { mProvisioningTimeoutAlarm.cancel(); mDhcpActionTimeoutAlarm.cancel(); stopDhcpAction(); if (mIpReachabilityMonitor != null) { mIpReachabilityMonitor.stop(); Loading @@ -1086,16 +1088,22 @@ public class IpManager extends StateMachine { resetLinkProperties(); } private void startDhcpAction() { private void ensureDhcpAction() { if (!mDhcpActionInFlight) { mCallback.onPreDhcpAction(); mDhcpActionInFlight = true; final long alarmTime = SystemClock.elapsedRealtime() + mConfiguration.mRequestedPreDhcpActionMs; mDhcpActionTimeoutAlarm.schedule(alarmTime); } } private void stopDhcpAction() { mDhcpActionTimeoutAlarm.cancel(); if (mDhcpActionInFlight) { mCallback.onPostDhcpAction(); mDhcpActionInFlight = false; } } @Override Loading Loading @@ -1165,9 +1173,8 @@ public class IpManager extends StateMachine { break; case DhcpClient.CMD_PRE_DHCP_ACTION: if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); } if (mConfiguration.mRequestedPreDhcpActionMs > 0) { startDhcpAction(); ensureDhcpAction(); } else { sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); } Loading @@ -1193,18 +1200,18 @@ public class IpManager extends StateMachine { // This message is only received when: // // a) initial address acquisition succeeds, // b) renew succeeds, // c) renew fails, // b) renew succeeds or is NAK'd, // c) rebind succeeds or is NAK'd, or // c) the lease expires, // // but never when initial address acquisition fails. The latter // condition is now governed by the provisioning timeout. case DhcpClient.CMD_POST_DHCP_ACTION: { case DhcpClient.CMD_POST_DHCP_ACTION: stopDhcpAction(); final DhcpResults dhcpResults = (DhcpResults) msg.obj; switch (msg.arg1) { case DhcpClient.DHCP_SUCCESS: handleIPv4Success(dhcpResults); handleIPv4Success((DhcpResults) msg.obj); break; case DhcpClient.DHCP_FAILURE: handleIPv4Failure(); Loading @@ -1213,7 +1220,6 @@ public class IpManager extends StateMachine { Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1); } break; } case DhcpClient.CMD_ON_QUIT: // DHCPv4 quit early for some reason. Loading Loading
services/net/java/android/net/dhcp/DhcpClient.java +122 −55 Original line number Diff line number Diff line Loading @@ -125,17 +125,18 @@ public class DhcpClient extends StateMachine { public static final int CMD_CONFIGURE_LINKADDRESS = PUBLIC_BASE + 8; public static final int EVENT_LINKADDRESS_CONFIGURED = PUBLIC_BASE + 9; /* Message.arg1 arguments to CMD_POST_DHCP notification */ /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */ public static final int DHCP_SUCCESS = 1; public static final int DHCP_FAILURE = 2; // Messages. // Internal messages. private static final int PRIVATE_BASE = Protocol.BASE_DHCP + 100; private static final int CMD_KICK = PRIVATE_BASE + 1; private static final int CMD_RECEIVED_PACKET = PRIVATE_BASE + 2; private static final int CMD_TIMEOUT = PRIVATE_BASE + 3; private static final int CMD_RENEW_DHCP = PRIVATE_BASE + 4; private static final int CMD_EXPIRE_DHCP = PRIVATE_BASE + 5; private static final int CMD_REBIND_DHCP = PRIVATE_BASE + 5; private static final int CMD_EXPIRE_DHCP = PRIVATE_BASE + 6; // For message logging. private static final Class[] sMessageClasses = { DhcpClient.class }; Loading Loading @@ -177,6 +178,7 @@ public class DhcpClient extends StateMachine { private final WakeupMessage mKickAlarm; private final WakeupMessage mTimeoutAlarm; private final WakeupMessage mRenewAlarm; private final WakeupMessage mRebindAlarm; private final WakeupMessage mExpiryAlarm; private final String mIfaceName; Loading Loading @@ -241,8 +243,9 @@ public class DhcpClient extends StateMachine { mKickAlarm = makeWakeupMessage("KICK", CMD_KICK); // Used to time out PacketRetransmittingStates. mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT); // Used to schedule DHCP renews. // Used to schedule DHCP reacquisition. mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP); mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP); mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP); } Loading Loading @@ -276,6 +279,10 @@ public class DhcpClient extends StateMachine { } private boolean initSockets() { return initPacketSocket() && initUdpSocket(); } private boolean initPacketSocket() { try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP); PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex()); Loading @@ -285,6 +292,10 @@ public class DhcpClient extends StateMachine { Log.e(TAG, "Error creating packet socket", e); return false; } return true; } private boolean initUdpSocket() { try { mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1); Loading Loading @@ -363,16 +374,25 @@ public class DhcpClient extends StateMachine { return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000); } private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) { private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) { try { if (to.equals(INADDR_BROADCAST)) { if (encap == DhcpPacket.ENCAP_L2) { if (DBG) Log.d(TAG, "Broadcasting " + description); Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr); } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) { if (DBG) Log.d(TAG, "Broadcasting " + description); // We only send L3-encapped broadcasts in DhcpRebindingState, // where we have an IP address and an unconnected UDP socket. // // N.B.: We only need this codepath because DhcpRequestPacket // hardcodes the source IP address to 0.0.0.0. We could reuse // the packet socket if this ever changes. Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER); } else { // It's safe to call getpeername here, because we only send unicast packets if we // have an IP address, and we connect the UDP socket before // ConfiguringInterfaceState#exit. if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock)); // have an IP address, and we connect the UDP socket in DhcpBoundState#enter. if (DBG) Log.d(TAG, String.format("Unicasting %s to %s", description, Os.getpeername(mUdpSock))); Os.write(mUdpSock, buf); } } catch(ErrnoException|IOException e) { Loading @@ -386,14 +406,15 @@ public class DhcpClient extends StateMachine { ByteBuffer packet = DhcpPacket.buildDiscoverPacket( DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr, DO_UNICAST, REQUESTED_PARAMS); return transmitPacket(packet, "DHCPDISCOVER", INADDR_BROADCAST); return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST); } private boolean sendRequestPacket( Inet4Address clientAddress, Inet4Address requestedAddress, Inet4Address serverAddress, Inet4Address to) { // TODO: should we use the transaction ID from the server? int encap = to.equals(INADDR_BROADCAST) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP; final int encap = INADDR_ANY.equals(clientAddress) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP; ByteBuffer packet = DhcpPacket.buildRequestPacket( encap, mTransactionId, getSecs(), clientAddress, Loading @@ -403,7 +424,7 @@ public class DhcpClient extends StateMachine { String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() + " request=" + requestedAddress.getHostAddress() + " serverid=" + serverStr; return transmitPacket(packet, description, to); return transmitPacket(packet, description, encap, to); } private void scheduleLeaseTimers() { Loading @@ -413,14 +434,21 @@ public class DhcpClient extends StateMachine { } final long now = SystemClock.elapsedRealtime(); long renewTime = (now + mDhcpLeaseExpiry) / 2; mRenewAlarm.schedule(renewTime); long secondsHence = (renewTime - now) / 1000; Log.d(TAG, "Scheduling renewal in " + secondsHence + "s"); mExpiryAlarm.schedule(mDhcpLeaseExpiry); secondsHence = (mDhcpLeaseExpiry - now) / 1000; Log.d(TAG, "Scheduling expiry in " + secondsHence + "s"); // TODO: consider getting the renew and rebind timers from T1 and T2. // See also: // https://tools.ietf.org/html/rfc2131#section-4.4.5 // https://tools.ietf.org/html/rfc1533#section-9.9 // https://tools.ietf.org/html/rfc1533#section-9.10 final long remainingDelay = mDhcpLeaseExpiry - now; final long renewDelay = remainingDelay / 2; final long rebindDelay = remainingDelay * 7 / 8; mRenewAlarm.schedule(now + renewDelay); mRebindAlarm.schedule(now + rebindDelay); mExpiryAlarm.schedule(now + remainingDelay); Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s"); Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s"); Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s"); } private void notifySuccess() { Loading Loading @@ -719,7 +747,6 @@ public class DhcpClient extends StateMachine { class DhcpRequestingState extends PacketRetransmittingState { public DhcpRequestingState() { super(); mTimeout = DHCP_TIMEOUT_MS / 2; } Loading Loading @@ -777,7 +804,11 @@ public class DhcpClient extends StateMachine { @Override public void exit() { // Clear any extant alarms. mRenewAlarm.cancel(); mRebindAlarm.cancel(); mExpiryAlarm.cancel(); clearDhcpState(); // Tell IpManager to clear the IPv4 address. There is no need to // wait for confirmation since any subsequent packets are sent from // INADDR_ANY anyway (DISCOVER, REQUEST). Loading @@ -797,21 +828,7 @@ public class DhcpClient extends StateMachine { super.processMessage(message); switch (message.what) { case EVENT_LINKADDRESS_CONFIGURED: if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) { // There's likely no point in going into DhcpInitState here, we'll probably // just repeat the transaction, get the same IP address as before, and fail. // // NOTE: It is observed that connectUdpSock() basically never fails, due to // SO_BINDTODEVICE. Examining the local socket address shows it will happily // return an IPv4 address from another interface, or even return "0.0.0.0". // // TODO: Consider deleting this check, following testing on several kernels. notifyFailure(); transitionTo(mStoppedState); } else { transitionTo(mDhcpBoundState); } return HANDLED; default: return NOT_HANDLED; Loading @@ -823,8 +840,19 @@ public class DhcpClient extends StateMachine { @Override public void enter() { super.enter(); // TODO: DhcpStateMachine only supported renewing at 50% of the lease time, // and did not support rebinding. Now that the legacy DHCP client is gone, fix this. if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) { // There's likely no point in going into DhcpInitState here, we'll probably // just repeat the transaction, get the same IP address as before, and fail. // // NOTE: It is observed that connectUdpSock() basically never fails, due to // SO_BINDTODEVICE. Examining the local socket address shows it will happily // return an IPv4 address from another interface, or even return "0.0.0.0". // // TODO: Consider deleting this check, following testing on several kernels. notifyFailure(); transitionTo(mStoppedState); } scheduleLeaseTimers(); } Loading @@ -843,18 +871,10 @@ public class DhcpClient extends StateMachine { return NOT_HANDLED; } } @Override public void exit() { mRenewAlarm.cancel(); } } class DhcpRenewingState extends PacketRetransmittingState { public DhcpRenewingState() { super(); mTimeout = DHCP_TIMEOUT_MS; } abstract class DhcpReacquiringState extends PacketRetransmittingState { protected String mLeaseMsg; @Override public void enter() { Loading @@ -862,16 +882,14 @@ public class DhcpClient extends StateMachine { startNewTransaction(); } abstract protected Inet4Address packetDestination(); protected boolean sendPacket() { // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but... // http://b/25343517 . Try to make things work anyway by using broadcast renews. Inet4Address to = (mDhcpLease.serverAddress != null) ? mDhcpLease.serverAddress : INADDR_BROADCAST; return sendRequestPacket( (Inet4Address) mDhcpLease.ipAddress.getAddress(), // ciaddr INADDR_ANY, // DHCP_REQUESTED_IP null, // DHCP_SERVER_IDENTIFIER to); // packet destination address packetDestination()); // packet destination address } protected void receivePacket(DhcpPacket packet) { Loading @@ -890,7 +908,7 @@ public class DhcpClient extends StateMachine { // in IpManager and by any overridden relevant handlers of // the registered IpManager.Callback. IP address changes // are not supported here. acceptDhcpResults(results, "Renewed"); acceptDhcpResults(results, mLeaseMsg); transitionTo(mDhcpBoundState); } } else if (packet instanceof DhcpNakPacket) { Loading @@ -901,8 +919,57 @@ public class DhcpClient extends StateMachine { } } // Not implemented--yet. DhcpStateMachine did not implement it either. class DhcpRebindingState extends LoggingState { class DhcpRenewingState extends DhcpReacquiringState { public DhcpRenewingState() { mLeaseMsg = "Renewed"; } @Override public boolean processMessage(Message message) { if (super.processMessage(message) == HANDLED) { return HANDLED; } switch (message.what) { case CMD_REBIND_DHCP: transitionTo(mDhcpRebindingState); return HANDLED; default: return NOT_HANDLED; } } @Override protected Inet4Address packetDestination() { // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but... // http://b/25343517 . Try to make things work anyway by using broadcast renews. return (mDhcpLease.serverAddress != null) ? mDhcpLease.serverAddress : INADDR_BROADCAST; } } class DhcpRebindingState extends DhcpReacquiringState { public DhcpRebindingState() { mLeaseMsg = "Rebound"; } @Override public void enter() { super.enter(); // We need to broadcast and possibly reconnect the socket to a // completely different server. closeQuietly(mUdpSock); if (!initUdpSocket()) { Log.e(TAG, "Failed to recreate UDP socket"); transitionTo(mDhcpInitState); } } @Override protected Inet4Address packetDestination() { return INADDR_BROADCAST; } } class DhcpInitRebootState extends LoggingState { Loading
services/net/java/android/net/ip/IpManager.java +21 −15 Original line number Diff line number Diff line Loading @@ -1027,6 +1027,8 @@ public class IpManager extends StateMachine { } class StartedState extends State { private boolean mDhcpActionInFlight; @Override public void enter() { mStartTimeMillis = SystemClock.elapsedRealtime(); Loading Loading @@ -1066,7 +1068,7 @@ public class IpManager extends StateMachine { @Override public void exit() { mProvisioningTimeoutAlarm.cancel(); mDhcpActionTimeoutAlarm.cancel(); stopDhcpAction(); if (mIpReachabilityMonitor != null) { mIpReachabilityMonitor.stop(); Loading @@ -1086,16 +1088,22 @@ public class IpManager extends StateMachine { resetLinkProperties(); } private void startDhcpAction() { private void ensureDhcpAction() { if (!mDhcpActionInFlight) { mCallback.onPreDhcpAction(); mDhcpActionInFlight = true; final long alarmTime = SystemClock.elapsedRealtime() + mConfiguration.mRequestedPreDhcpActionMs; mDhcpActionTimeoutAlarm.schedule(alarmTime); } } private void stopDhcpAction() { mDhcpActionTimeoutAlarm.cancel(); if (mDhcpActionInFlight) { mCallback.onPostDhcpAction(); mDhcpActionInFlight = false; } } @Override Loading Loading @@ -1165,9 +1173,8 @@ public class IpManager extends StateMachine { break; case DhcpClient.CMD_PRE_DHCP_ACTION: if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); } if (mConfiguration.mRequestedPreDhcpActionMs > 0) { startDhcpAction(); ensureDhcpAction(); } else { sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); } Loading @@ -1193,18 +1200,18 @@ public class IpManager extends StateMachine { // This message is only received when: // // a) initial address acquisition succeeds, // b) renew succeeds, // c) renew fails, // b) renew succeeds or is NAK'd, // c) rebind succeeds or is NAK'd, or // c) the lease expires, // // but never when initial address acquisition fails. The latter // condition is now governed by the provisioning timeout. case DhcpClient.CMD_POST_DHCP_ACTION: { case DhcpClient.CMD_POST_DHCP_ACTION: stopDhcpAction(); final DhcpResults dhcpResults = (DhcpResults) msg.obj; switch (msg.arg1) { case DhcpClient.DHCP_SUCCESS: handleIPv4Success(dhcpResults); handleIPv4Success((DhcpResults) msg.obj); break; case DhcpClient.DHCP_FAILURE: handleIPv4Failure(); Loading @@ -1213,7 +1220,6 @@ public class IpManager extends StateMachine { Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1); } break; } case DhcpClient.CMD_ON_QUIT: // DHCPv4 quit early for some reason. Loading