From 5b76623a0e3fdaa792967375bb4e1e143de1ff03 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 6 Apr 2016 11:18:10 +0900 Subject: [PATCH] Move IPv4 address setting to IpManager Bug: 24837343 Bug: 27605330 Change-Id: I19ac80e45b3e9200f81d1166ac6094fd19aee963 --- .../net/java/android/net/dhcp/DhcpClient.java | 99 +++++++++++-------- .../net/java/android/net/ip/IpManager.java | 46 +++++---- 2 files changed, 89 insertions(+), 56 deletions(-) diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index 6d0808f781fec..2b6c916f2c470 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -32,8 +32,6 @@ import android.net.LinkAddress; import android.net.NetworkUtils; import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpErrorEvent; -import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -121,6 +119,13 @@ public class DhcpClient extends StateMachine { * after pre DHCP action is complete */ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = PUBLIC_BASE + 7; + /* Command and event notification to/from IpManager requesting the setting + * (or clearing) of an IPv4 LinkAddress. + */ + public static final int CMD_CLEAR_LINKADDRESS = PUBLIC_BASE + 8; + public static final int CMD_CONFIGURE_LINKADDRESS = PUBLIC_BASE + 9; + public static final int EVENT_LINKADDRESS_CONFIGURED = PUBLIC_BASE + 10; + /* Message.arg1 arguments to CMD_POST_DHCP notification */ public static final int DHCP_SUCCESS = 1; public static final int DHCP_FAILURE = 2; @@ -157,7 +162,6 @@ public class DhcpClient extends StateMachine { // System services / libraries we use. private final Context mContext; private final Random mRandom; - private final INetworkManagementService mNMService; // Sockets. // - We use a packet socket to receive, because servers send us packets bound for IP addresses @@ -192,7 +196,8 @@ public class DhcpClient extends StateMachine { private State mDhcpInitState = new DhcpInitState(); private State mDhcpSelectingState = new DhcpSelectingState(); private State mDhcpRequestingState = new DhcpRequestingState(); - private State mDhcpHaveAddressState = new DhcpHaveAddressState(); + private State mDhcpHaveLeaseState = new DhcpHaveLeaseState(); + private State mConfiguringInterfaceState = new ConfiguringInterfaceState(); private State mDhcpBoundState = new DhcpBoundState(); private State mDhcpRenewingState = new DhcpRenewingState(); private State mDhcpRebindingState = new DhcpRebindingState(); @@ -219,19 +224,17 @@ public class DhcpClient extends StateMachine { addState(mWaitBeforeStartState, mDhcpState); addState(mDhcpSelectingState, mDhcpState); addState(mDhcpRequestingState, mDhcpState); - addState(mDhcpHaveAddressState, mDhcpState); - addState(mDhcpBoundState, mDhcpHaveAddressState); - addState(mWaitBeforeRenewalState, mDhcpHaveAddressState); - addState(mDhcpRenewingState, mDhcpHaveAddressState); - addState(mDhcpRebindingState, mDhcpHaveAddressState); + addState(mDhcpHaveLeaseState, mDhcpState); + addState(mConfiguringInterfaceState, mDhcpHaveLeaseState); + addState(mDhcpBoundState, mDhcpHaveLeaseState); + addState(mWaitBeforeRenewalState, mDhcpHaveLeaseState); + addState(mDhcpRenewingState, mDhcpHaveLeaseState); + addState(mDhcpRebindingState, mDhcpHaveLeaseState); addState(mDhcpInitRebootState, mDhcpState); addState(mDhcpRebootingState, mDhcpState); setInitialState(mStoppedState); - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNMService = INetworkManagementService.Stub.asInterface(b); - mRandom = new Random(); // Used to schedule packet retransmissions. @@ -321,18 +324,6 @@ public class DhcpClient extends StateMachine { closeQuietly(mPacketSock); } - private boolean setIpAddress(LinkAddress address) { - InterfaceConfiguration ifcg = new InterfaceConfiguration(); - ifcg.setLinkAddress(address); - try { - mNMService.setInterfaceConfig(mIfaceName, ifcg); - } catch (RemoteException|IllegalStateException e) { - Log.e(TAG, "Error configuring IP address " + address + ": ", e); - return false; - } - return true; - } - class ReceiveThread extends Thread { private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH]; @@ -382,7 +373,8 @@ public class DhcpClient extends StateMachine { Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr); } 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 in DhcpHaveAddressState#enter. + // have an IP address, and we connect the UDP socket before + // ConfiguringInterfaceState#exit. if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock)); Os.write(mUdpSock, buf); } @@ -460,6 +452,7 @@ public class DhcpClient extends StateMachine { } abstract class LoggingState extends State { + @Override public void enter() { if (STATE_DBG) Log.d(TAG, "Entering state " + getName()); DhcpClientEvent.logStateEvent(mIfaceName, getName()); @@ -759,7 +752,7 @@ public class DhcpClient extends StateMachine { mOffer = null; Log.d(TAG, "Confirmed lease: " + mDhcpLease); setDhcpLeaseExpiry(packet); - transitionTo(mDhcpBoundState); + transitionTo(mConfiguringInterfaceState); } } else if (packet instanceof DhcpNakPacket) { // TODO: Wait a while before returning into INIT state. @@ -776,24 +769,52 @@ public class DhcpClient extends StateMachine { } } - class DhcpHaveAddressState extends LoggingState { + class DhcpHaveLeaseState extends LoggingState { @Override public void enter() { super.enter(); - if (!setIpAddress(mDhcpLease.ipAddress) || - (mDhcpLease.serverAddress != null && - !connectUdpSock((mDhcpLease.serverAddress)))) { - notifyFailure(); - // 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. - transitionTo(mStoppedState); - } } @Override public void exit() { - if (DBG) Log.d(TAG, "Clearing IP address"); - setIpAddress(new LinkAddress("0.0.0.0/0")); + // 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). + mController.sendMessage(CMD_CLEAR_LINKADDRESS); + } + } + + class ConfiguringInterfaceState extends LoggingState { + @Override + public void enter() { + super.enter(); + mController.sendMessage(CMD_CONFIGURE_LINKADDRESS, mDhcpLease.ipAddress); + } + + @Override + public boolean processMessage(Message message) { + 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; + } } } @@ -803,8 +824,8 @@ public class DhcpClient extends StateMachine { super.enter(); mOneshotTimeoutAlarm.cancel(); notifySuccess(); - // TODO: DhcpStateMachine only supported renewing at 50% of the lease time, and did not - // support rebinding. Once the legacy DHCP client is gone, fix this. + // 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. scheduleRenew(); } diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index e39f1bc0fae3b..fd98f4635618c 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -770,6 +770,19 @@ public class IpManager extends StateMachine { return (delta != ProvisioningChange.LOST_PROVISIONING); } + private boolean setIPv4Address(LinkAddress address) { + final InterfaceConfiguration ifcg = new InterfaceConfiguration(); + ifcg.setLinkAddress(address); + try { + mNwService.setInterfaceConfig(mInterfaceName, ifcg); + if (VDBG) Log.d(mTag, "IPv4 configuration succeeded"); + } catch (IllegalStateException | RemoteException e) { + Log.e(mTag, "IPv4 configuration failed: ", e); + return false; + } + return true; + } + private void clearIPv4Address() { try { final InterfaceConfiguration ifcg = new InterfaceConfiguration(); @@ -794,7 +807,6 @@ public class IpManager extends StateMachine { } private void handleIPv4Failure() { - // TODO: Figure out to de-dup this and the same code in DhcpClient. clearIPv4Address(); mDhcpResults = null; final LinkProperties newLp = assembleLinkProperties(); @@ -944,7 +956,7 @@ public class IpManager extends StateMachine { // If we have a StaticIpConfiguration attempt to apply it and // handle the result accordingly. if (mConfiguration.mStaticIpConfig != null) { - if (applyStaticIpConfig()) { + if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) { handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); } else { if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); } @@ -1050,6 +1062,21 @@ public class IpManager extends StateMachine { } break; + case DhcpClient.CMD_CLEAR_LINKADDRESS: + clearIPv4Address(); + break; + + case DhcpClient.CMD_CONFIGURE_LINKADDRESS: { + final LinkAddress ipAddress = (LinkAddress) msg.obj; + if (setIPv4Address(ipAddress)) { + mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED); + } else { + Log.e(mTag, "Failed to set IPv4 address!"); + transitionTo(mStoppingState); + } + break; + } + case DhcpClient.CMD_POST_DHCP_ACTION: { // Note that onPostDhcpAction() is likely to be // asynchronous, and thus there is no guarantee that we @@ -1082,20 +1109,5 @@ public class IpManager extends StateMachine { } return HANDLED; } - - private boolean applyStaticIpConfig() { - final InterfaceConfiguration ifcg = new InterfaceConfiguration(); - ifcg.setLinkAddress(mConfiguration.mStaticIpConfig.ipAddress); - ifcg.setInterfaceUp(); - try { - mNwService.setInterfaceConfig(mInterfaceName, ifcg); - if (DBG) Log.d(mTag, "Static IP configuration succeeded"); - } catch (IllegalStateException | RemoteException e) { - Log.e(mTag, "Static IP configuration failed: ", e); - return false; - } - - return true; - } } }