Merge "Move IPv4 address setting to IpManager" into nyc-dev

This commit is contained in:
Erik Kline
2016-04-26 23:27:46 +00:00
committed by Android (Google) Code Review
2 changed files with 89 additions and 56 deletions

View File

@@ -32,8 +32,6 @@ import android.net.LinkAddress;
import android.net.NetworkUtils; import android.net.NetworkUtils;
import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent; import android.net.metrics.DhcpErrorEvent;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
@@ -121,6 +119,13 @@ public class DhcpClient extends StateMachine {
* after pre DHCP action is complete */ * after pre DHCP action is complete */
public static final int CMD_PRE_DHCP_ACTION_COMPLETE = PUBLIC_BASE + 7; 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 */ /* Message.arg1 arguments to CMD_POST_DHCP notification */
public static final int DHCP_SUCCESS = 1; public static final int DHCP_SUCCESS = 1;
public static final int DHCP_FAILURE = 2; public static final int DHCP_FAILURE = 2;
@@ -157,7 +162,6 @@ public class DhcpClient extends StateMachine {
// System services / libraries we use. // System services / libraries we use.
private final Context mContext; private final Context mContext;
private final Random mRandom; private final Random mRandom;
private final INetworkManagementService mNMService;
// Sockets. // Sockets.
// - We use a packet socket to receive, because servers send us packets bound for IP addresses // - 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 mDhcpInitState = new DhcpInitState();
private State mDhcpSelectingState = new DhcpSelectingState(); private State mDhcpSelectingState = new DhcpSelectingState();
private State mDhcpRequestingState = new DhcpRequestingState(); 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 mDhcpBoundState = new DhcpBoundState();
private State mDhcpRenewingState = new DhcpRenewingState(); private State mDhcpRenewingState = new DhcpRenewingState();
private State mDhcpRebindingState = new DhcpRebindingState(); private State mDhcpRebindingState = new DhcpRebindingState();
@@ -219,19 +224,17 @@ public class DhcpClient extends StateMachine {
addState(mWaitBeforeStartState, mDhcpState); addState(mWaitBeforeStartState, mDhcpState);
addState(mDhcpSelectingState, mDhcpState); addState(mDhcpSelectingState, mDhcpState);
addState(mDhcpRequestingState, mDhcpState); addState(mDhcpRequestingState, mDhcpState);
addState(mDhcpHaveAddressState, mDhcpState); addState(mDhcpHaveLeaseState, mDhcpState);
addState(mDhcpBoundState, mDhcpHaveAddressState); addState(mConfiguringInterfaceState, mDhcpHaveLeaseState);
addState(mWaitBeforeRenewalState, mDhcpHaveAddressState); addState(mDhcpBoundState, mDhcpHaveLeaseState);
addState(mDhcpRenewingState, mDhcpHaveAddressState); addState(mWaitBeforeRenewalState, mDhcpHaveLeaseState);
addState(mDhcpRebindingState, mDhcpHaveAddressState); addState(mDhcpRenewingState, mDhcpHaveLeaseState);
addState(mDhcpRebindingState, mDhcpHaveLeaseState);
addState(mDhcpInitRebootState, mDhcpState); addState(mDhcpInitRebootState, mDhcpState);
addState(mDhcpRebootingState, mDhcpState); addState(mDhcpRebootingState, mDhcpState);
setInitialState(mStoppedState); setInitialState(mStoppedState);
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNMService = INetworkManagementService.Stub.asInterface(b);
mRandom = new Random(); mRandom = new Random();
// Used to schedule packet retransmissions. // Used to schedule packet retransmissions.
@@ -321,18 +324,6 @@ public class DhcpClient extends StateMachine {
closeQuietly(mPacketSock); 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 { class ReceiveThread extends Thread {
private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH]; 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); Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
} else { } else {
// It's safe to call getpeername here, because we only send unicast packets if we // 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)); if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock));
Os.write(mUdpSock, buf); Os.write(mUdpSock, buf);
} }
@@ -460,6 +452,7 @@ public class DhcpClient extends StateMachine {
} }
abstract class LoggingState extends State { abstract class LoggingState extends State {
@Override
public void enter() { public void enter() {
if (STATE_DBG) Log.d(TAG, "Entering state " + getName()); if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
DhcpClientEvent.logStateEvent(mIfaceName, getName()); DhcpClientEvent.logStateEvent(mIfaceName, getName());
@@ -759,7 +752,7 @@ public class DhcpClient extends StateMachine {
mOffer = null; mOffer = null;
Log.d(TAG, "Confirmed lease: " + mDhcpLease); Log.d(TAG, "Confirmed lease: " + mDhcpLease);
setDhcpLeaseExpiry(packet); setDhcpLeaseExpiry(packet);
transitionTo(mDhcpBoundState); transitionTo(mConfiguringInterfaceState);
} }
} else if (packet instanceof DhcpNakPacket) { } else if (packet instanceof DhcpNakPacket) {
// TODO: Wait a while before returning into INIT state. // 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 @Override
public void enter() { public void enter() {
super.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 @Override
public void exit() { public void exit() {
if (DBG) Log.d(TAG, "Clearing IP address"); // Tell IpManager to clear the IPv4 address. There is no need to
setIpAddress(new LinkAddress("0.0.0.0/0")); // 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(); super.enter();
mOneshotTimeoutAlarm.cancel(); mOneshotTimeoutAlarm.cancel();
notifySuccess(); notifySuccess();
// TODO: DhcpStateMachine only supported renewing at 50% of the lease time, and did not // TODO: DhcpStateMachine only supported renewing at 50% of the lease time,
// support rebinding. Once the legacy DHCP client is gone, fix this. // and did not support rebinding. Now that the legacy DHCP client is gone, fix this.
scheduleRenew(); scheduleRenew();
} }

View File

@@ -770,6 +770,19 @@ public class IpManager extends StateMachine {
return (delta != ProvisioningChange.LOST_PROVISIONING); 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() { private void clearIPv4Address() {
try { try {
final InterfaceConfiguration ifcg = new InterfaceConfiguration(); final InterfaceConfiguration ifcg = new InterfaceConfiguration();
@@ -794,7 +807,6 @@ public class IpManager extends StateMachine {
} }
private void handleIPv4Failure() { private void handleIPv4Failure() {
// TODO: Figure out to de-dup this and the same code in DhcpClient.
clearIPv4Address(); clearIPv4Address();
mDhcpResults = null; mDhcpResults = null;
final LinkProperties newLp = assembleLinkProperties(); final LinkProperties newLp = assembleLinkProperties();
@@ -944,7 +956,7 @@ public class IpManager extends StateMachine {
// If we have a StaticIpConfiguration attempt to apply it and // If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly. // handle the result accordingly.
if (mConfiguration.mStaticIpConfig != null) { if (mConfiguration.mStaticIpConfig != null) {
if (applyStaticIpConfig()) { if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else { } else {
if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); } if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
@@ -1050,6 +1062,21 @@ public class IpManager extends StateMachine {
} }
break; 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: { case DhcpClient.CMD_POST_DHCP_ACTION: {
// Note that onPostDhcpAction() is likely to be // Note that onPostDhcpAction() is likely to be
// asynchronous, and thus there is no guarantee that we // asynchronous, and thus there is no guarantee that we
@@ -1082,20 +1109,5 @@ public class IpManager extends StateMachine {
} }
return HANDLED; 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;
}
} }
} }