Merge "Initial rename to IpServer"

This commit is contained in:
Erik Kline
2018-09-13 10:28:27 +00:00
committed by Gerrit Code Review
7 changed files with 321 additions and 375 deletions

View File

@@ -68,6 +68,7 @@ import android.content.res.Resources;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.net.INetworkPolicyManager; import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService; import android.net.INetworkStatsService;
import android.net.ip.IpServer;
import android.net.IpPrefix; import android.net.IpPrefix;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -112,10 +113,8 @@ import com.android.internal.util.Protocol;
import com.android.internal.util.State; import com.android.internal.util.State;
import com.android.internal.util.StateMachine; import com.android.internal.util.StateMachine;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadController; import com.android.server.connectivity.tethering.OffloadController;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringConfiguration; import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.TetheringInterfaceUtils; import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
@@ -149,7 +148,7 @@ public class Tethering extends BaseNetworkObserver {
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
private static final Class[] messageClasses = { private static final Class[] messageClasses = {
Tethering.class, TetherMasterSM.class, TetherInterfaceStateMachine.class Tethering.class, TetherMasterSM.class, IpServer.class
}; };
private static final SparseArray<String> sMagicDecoderRing = private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(messageClasses); MessageUtils.findMessageNames(messageClasses);
@@ -159,21 +158,21 @@ public class Tethering extends BaseNetworkObserver {
.getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable)); .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
private static class TetherState { private static class TetherState {
public final TetherInterfaceStateMachine stateMachine; public final IpServer ipServer;
public int lastState; public int lastState;
public int lastError; public int lastError;
public TetherState(TetherInterfaceStateMachine sm) { public TetherState(IpServer ipServer) {
stateMachine = sm; this.ipServer = ipServer;
// Assume all state machines start out available and with no errors. // Assume all state machines start out available and with no errors.
lastState = IControlsTethering.STATE_AVAILABLE; lastState = IpServer.STATE_AVAILABLE;
lastError = TETHER_ERROR_NO_ERROR; lastError = TETHER_ERROR_NO_ERROR;
} }
public boolean isCurrentlyServing() { public boolean isCurrentlyServing() {
switch (lastState) { switch (lastState) {
case IControlsTethering.STATE_TETHERED: case IpServer.STATE_TETHERED:
case IControlsTethering.STATE_LOCAL_ONLY: case IpServer.STATE_LOCAL_ONLY:
return true; return true;
default: default:
return false; return false;
@@ -198,7 +197,7 @@ public class Tethering extends BaseNetworkObserver {
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor; private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
// TODO: Figure out how to merge this and other downstream-tracking objects // TODO: Figure out how to merge this and other downstream-tracking objects
// into a single coherent structure. // into a single coherent structure.
private final HashSet<TetherInterfaceStateMachine> mForwardedDownstreams; private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange; private final VersionedBroadcastListener mCarrierConfigChange;
private final TetheringDependencies mDeps; private final TetheringDependencies mDeps;
@@ -604,7 +603,7 @@ public class Tethering extends BaseNetworkObserver {
} }
public int tether(String iface) { public int tether(String iface) {
return tether(iface, IControlsTethering.STATE_TETHERED); return tether(iface, IpServer.STATE_TETHERED);
} }
private int tether(String iface, int requestedState) { private int tether(String iface, int requestedState) {
@@ -617,7 +616,7 @@ public class Tethering extends BaseNetworkObserver {
} }
// Ignore the error status of the interface. If the interface is available, // Ignore the error status of the interface. If the interface is available,
// the errors are referring to past tethering attempts anyway. // the errors are referring to past tethering attempts anyway.
if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) { if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring"); Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
return TETHER_ERROR_UNAVAIL_IFACE; return TETHER_ERROR_UNAVAIL_IFACE;
} }
@@ -626,8 +625,7 @@ public class Tethering extends BaseNetworkObserver {
// return an error. // return an error.
// //
// TODO: reexamine the threading and messaging model. // TODO: reexamine the threading and messaging model.
tetherState.stateMachine.sendMessage( tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
return TETHER_ERROR_NO_ERROR; return TETHER_ERROR_NO_ERROR;
} }
} }
@@ -644,8 +642,7 @@ public class Tethering extends BaseNetworkObserver {
Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring"); Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
return TETHER_ERROR_UNAVAIL_IFACE; return TETHER_ERROR_UNAVAIL_IFACE;
} }
tetherState.stateMachine.sendMessage( tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
return TETHER_ERROR_NO_ERROR; return TETHER_ERROR_NO_ERROR;
} }
} }
@@ -689,11 +686,11 @@ public class Tethering extends BaseNetworkObserver {
String iface = mTetherStates.keyAt(i); String iface = mTetherStates.keyAt(i);
if (tetherState.lastError != TETHER_ERROR_NO_ERROR) { if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
erroredList.add(iface); erroredList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) { } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
availableList.add(iface); availableList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) { } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
localOnlyList.add(iface); localOnlyList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) { } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
if (cfg.isUsb(iface)) { if (cfg.isUsb(iface)) {
usbTethered = true; usbTethered = true;
} else if (cfg.isWifi(iface)) { } else if (cfg.isWifi(iface)) {
@@ -882,10 +879,10 @@ public class Tethering extends BaseNetworkObserver {
synchronized (Tethering.this.mPublicSync) { synchronized (Tethering.this.mPublicSync) {
if (!usbConnected && mRndisEnabled) { if (!usbConnected && mRndisEnabled) {
// Turn off tethering if it was enabled and there is a disconnect. // Turn off tethering if it was enabled and there is a disconnect.
tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB); tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
} else if (usbConfigured && rndisEnabled) { } else if (usbConfigured && rndisEnabled) {
// Tether if rndis is enabled and usb is configured. // Tether if rndis is enabled and usb is configured.
tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB); tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
} }
mRndisEnabled = usbConfigured && rndisEnabled; mRndisEnabled = usbConfigured && rndisEnabled;
} }
@@ -959,15 +956,15 @@ public class Tethering extends BaseNetworkObserver {
if (!TextUtils.isEmpty(ifname)) { if (!TextUtils.isEmpty(ifname)) {
final TetherState ts = mTetherStates.get(ifname); final TetherState ts = mTetherStates.get(ifname);
if (ts != null) { if (ts != null) {
ts.stateMachine.unwanted(); ts.ipServer.unwanted();
return; return;
} }
} }
for (int i = 0; i < mTetherStates.size(); i++) { for (int i = 0; i < mTetherStates.size(); i++) {
TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine; final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
if (tism.interfaceType() == TETHERING_WIFI) { if (ipServer.interfaceType() == TETHERING_WIFI) {
tism.unwanted(); ipServer.unwanted();
return; return;
} }
} }
@@ -978,15 +975,15 @@ public class Tethering extends BaseNetworkObserver {
} }
private void enableWifiIpServingLocked(String ifname, int wifiIpMode) { private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
// Map wifiIpMode values to IControlsTethering serving states, inferring // Map wifiIpMode values to IpServer.Callback serving states, inferring
// from mWifiTetherRequested as a final "best guess". // from mWifiTetherRequested as a final "best guess".
final int ipServingMode; final int ipServingMode;
switch (wifiIpMode) { switch (wifiIpMode) {
case IFACE_IP_MODE_TETHERED: case IFACE_IP_MODE_TETHERED:
ipServingMode = IControlsTethering.STATE_TETHERED; ipServingMode = IpServer.STATE_TETHERED;
break; break;
case IFACE_IP_MODE_LOCAL_ONLY: case IFACE_IP_MODE_LOCAL_ONLY:
ipServingMode = IControlsTethering.STATE_LOCAL_ONLY; ipServingMode = IpServer.STATE_LOCAL_ONLY;
break; break;
default: default:
mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode); mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
@@ -1041,12 +1038,12 @@ public class Tethering extends BaseNetworkObserver {
private void changeInterfaceState(String ifname, int requestedState) { private void changeInterfaceState(String ifname, int requestedState) {
final int result; final int result;
switch (requestedState) { switch (requestedState) {
case IControlsTethering.STATE_UNAVAILABLE: case IpServer.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE: case IpServer.STATE_AVAILABLE:
result = untether(ifname); result = untether(ifname);
break; break;
case IControlsTethering.STATE_TETHERED: case IpServer.STATE_TETHERED:
case IControlsTethering.STATE_LOCAL_ONLY: case IpServer.STATE_LOCAL_ONLY:
result = tether(ifname, requestedState); result = tether(ifname, requestedState);
break; break;
default: default:
@@ -1104,7 +1101,7 @@ public class Tethering extends BaseNetworkObserver {
synchronized (mPublicSync) { synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) { for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i); TetherState tetherState = mTetherStates.valueAt(i);
if (tetherState.lastState == IControlsTethering.STATE_TETHERED) { if (tetherState.lastState == IpServer.STATE_TETHERED) {
list.add(mTetherStates.keyAt(i)); list.add(mTetherStates.keyAt(i));
} }
} }
@@ -1117,7 +1114,7 @@ public class Tethering extends BaseNetworkObserver {
synchronized (mPublicSync) { synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) { for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i); TetherState tetherState = mTetherStates.valueAt(i);
if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) { if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
list.add(mTetherStates.keyAt(i)); list.add(mTetherStates.keyAt(i));
} }
} }
@@ -1177,7 +1174,7 @@ public class Tethering extends BaseNetworkObserver {
synchronized (mPublicSync) { synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) { for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i); TetherState tetherState = mTetherStates.valueAt(i);
if (tetherState.lastState != IControlsTethering.STATE_TETHERED) { if (tetherState.lastState != IpServer.STATE_TETHERED) {
continue; // Skip interfaces that aren't tethered. continue; // Skip interfaces that aren't tethered.
} }
String iface = mTetherStates.keyAt(i); String iface = mTetherStates.keyAt(i);
@@ -1231,7 +1228,7 @@ public class Tethering extends BaseNetworkObserver {
// Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
// so that the garbage collector does not clean up the state machine before it has a chance // so that the garbage collector does not clean up the state machine before it has a chance
// to tear itself down. // to tear itself down.
private final ArrayList<TetherInterfaceStateMachine> mNotifyList; private final ArrayList<IpServer> mNotifyList;
private final IPv6TetheringCoordinator mIPv6TetheringCoordinator; private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
private final OffloadWrapper mOffload; private final OffloadWrapper mOffload;
@@ -1268,17 +1265,19 @@ public class Tethering extends BaseNetworkObserver {
public boolean processMessage(Message message) { public boolean processMessage(Message message) {
logMessage(this, message.what); logMessage(this, message.what);
switch (message.what) { switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE: case EVENT_IFACE_SERVING_STATE_ACTIVE: {
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj; final IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who); if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who); handleInterfaceServingStateActive(message.arg1, who);
transitionTo(mTetherModeAliveState); transitionTo(mTetherModeAliveState);
break; break;
case EVENT_IFACE_SERVING_STATE_INACTIVE: }
who = (TetherInterfaceStateMachine) message.obj; case EVENT_IFACE_SERVING_STATE_INACTIVE: {
final IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who); if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who); handleInterfaceServingStateInactive(who);
break; break;
}
case EVENT_IFACE_UPDATE_LINKPROPERTIES: case EVENT_IFACE_UPDATE_LINKPROPERTIES:
// Silently ignore these for now. // Silently ignore these for now.
break; break;
@@ -1410,8 +1409,8 @@ public class Tethering extends BaseNetworkObserver {
protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) { protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
mCurrentUpstreamIfaceSet = ifaces; mCurrentUpstreamIfaceSet = ifaces;
for (TetherInterfaceStateMachine sm : mNotifyList) { for (IpServer ipServer : mNotifyList) {
sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces); ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
} }
} }
@@ -1420,13 +1419,13 @@ public class Tethering extends BaseNetworkObserver {
mOffload.updateUpstreamNetworkState(ns); mOffload.updateUpstreamNetworkState(ns);
} }
private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) { private void handleInterfaceServingStateActive(int mode, IpServer who) {
if (mNotifyList.indexOf(who) < 0) { if (mNotifyList.indexOf(who) < 0) {
mNotifyList.add(who); mNotifyList.add(who);
mIPv6TetheringCoordinator.addActiveDownstream(who, mode); mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
} }
if (mode == IControlsTethering.STATE_TETHERED) { if (mode == IpServer.STATE_TETHERED) {
// No need to notify OffloadController just yet as there are no // No need to notify OffloadController just yet as there are no
// "offload-able" prefixes to pass along. This will handled // "offload-able" prefixes to pass along. This will handled
// when the TISM informs Tethering of its LinkProperties. // when the TISM informs Tethering of its LinkProperties.
@@ -1441,10 +1440,10 @@ public class Tethering extends BaseNetworkObserver {
final WifiManager mgr = getWifiManager(); final WifiManager mgr = getWifiManager();
final String iface = who.interfaceName(); final String iface = who.interfaceName();
switch (mode) { switch (mode) {
case IControlsTethering.STATE_TETHERED: case IpServer.STATE_TETHERED:
mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED); mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
break; break;
case IControlsTethering.STATE_LOCAL_ONLY: case IpServer.STATE_LOCAL_ONLY:
mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY); mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
break; break;
default: default:
@@ -1454,7 +1453,7 @@ public class Tethering extends BaseNetworkObserver {
} }
} }
private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) { private void handleInterfaceServingStateInactive(IpServer who) {
mNotifyList.remove(who); mNotifyList.remove(who);
mIPv6TetheringCoordinator.removeActiveDownstream(who); mIPv6TetheringCoordinator.removeActiveDownstream(who);
mOffload.excludeDownstreamInterface(who.interfaceName()); mOffload.excludeDownstreamInterface(who.interfaceName());
@@ -1563,10 +1562,10 @@ public class Tethering extends BaseNetworkObserver {
boolean retValue = true; boolean retValue = true;
switch (message.what) { switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE: { case EVENT_IFACE_SERVING_STATE_ACTIVE: {
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj; IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who); if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who); handleInterfaceServingStateActive(message.arg1, who);
who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
mCurrentUpstreamIfaceSet); mCurrentUpstreamIfaceSet);
// If there has been a change and an upstream is now // If there has been a change and an upstream is now
// desired, kick off the selection process. // desired, kick off the selection process.
@@ -1577,7 +1576,7 @@ public class Tethering extends BaseNetworkObserver {
break; break;
} }
case EVENT_IFACE_SERVING_STATE_INACTIVE: { case EVENT_IFACE_SERVING_STATE_INACTIVE: {
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj; IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who); if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who); handleInterfaceServingStateInactive(who);
@@ -1591,7 +1590,7 @@ public class Tethering extends BaseNetworkObserver {
if (DBG) { if (DBG) {
Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() + Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
" live requests:"); " live requests:");
for (TetherInterfaceStateMachine o : mNotifyList) { for (IpServer o : mNotifyList) {
Log.d(TAG, " " + o); Log.d(TAG, " " + o);
} }
} }
@@ -1605,7 +1604,7 @@ public class Tethering extends BaseNetworkObserver {
} }
case EVENT_IFACE_UPDATE_LINKPROPERTIES: { case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
final LinkProperties newLp = (LinkProperties) message.obj; final LinkProperties newLp = (LinkProperties) message.obj;
if (message.arg1 == IControlsTethering.STATE_TETHERED) { if (message.arg1 == IpServer.STATE_TETHERED) {
mOffload.updateDownstreamLinkProperties(newLp); mOffload.updateDownstreamLinkProperties(newLp);
} else { } else {
mOffload.excludeDownstreamInterface(newLp.getInterfaceName()); mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
@@ -1650,7 +1649,7 @@ public class Tethering extends BaseNetworkObserver {
boolean retValue = true; boolean retValue = true;
switch (message.what) { switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE: case EVENT_IFACE_SERVING_STATE_ACTIVE:
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj; IpServer who = (IpServer) message.obj;
who.sendMessage(mErrorNotification); who.sendMessage(mErrorNotification);
break; break;
case CMD_CLEAR_ERROR: case CMD_CLEAR_ERROR:
@@ -1665,8 +1664,8 @@ public class Tethering extends BaseNetworkObserver {
void notify(int msgType) { void notify(int msgType) {
mErrorNotification = msgType; mErrorNotification = msgType;
for (TetherInterfaceStateMachine sm : mNotifyList) { for (IpServer ipServer : mNotifyList) {
sm.sendMessage(msgType); ipServer.sendMessage(msgType);
} }
} }
@@ -1676,7 +1675,7 @@ public class Tethering extends BaseNetworkObserver {
@Override @Override
public void enter() { public void enter() {
Log.e(TAG, "Error in setIpForwardingEnabled"); Log.e(TAG, "Error in setIpForwardingEnabled");
notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR); notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
} }
} }
@@ -1684,7 +1683,7 @@ public class Tethering extends BaseNetworkObserver {
@Override @Override
public void enter() { public void enter() {
Log.e(TAG, "Error in setIpForwardingDisabled"); Log.e(TAG, "Error in setIpForwardingDisabled");
notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR); notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
} }
} }
@@ -1692,7 +1691,7 @@ public class Tethering extends BaseNetworkObserver {
@Override @Override
public void enter() { public void enter() {
Log.e(TAG, "Error in startTethering"); Log.e(TAG, "Error in startTethering");
notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR); notify(IpServer.CMD_START_TETHERING_ERROR);
try { try {
mNMService.setIpForwardingEnabled(false); mNMService.setIpForwardingEnabled(false);
} catch (Exception e) {} } catch (Exception e) {}
@@ -1703,7 +1702,7 @@ public class Tethering extends BaseNetworkObserver {
@Override @Override
public void enter() { public void enter() {
Log.e(TAG, "Error in stopTethering"); Log.e(TAG, "Error in stopTethering");
notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR); notify(IpServer.CMD_STOP_TETHERING_ERROR);
try { try {
mNMService.setIpForwardingEnabled(false); mNMService.setIpForwardingEnabled(false);
} catch (Exception e) {} } catch (Exception e) {}
@@ -1714,7 +1713,7 @@ public class Tethering extends BaseNetworkObserver {
@Override @Override
public void enter() { public void enter() {
Log.e(TAG, "Error in setDnsForwarders"); Log.e(TAG, "Error in setDnsForwarders");
notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR); notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
try { try {
mNMService.stopTethering(); mNMService.stopTethering();
} catch (Exception e) {} } catch (Exception e) {}
@@ -1771,15 +1770,15 @@ public class Tethering extends BaseNetworkObserver {
// Maybe add prefixes or addresses for downstreams, depending on // Maybe add prefixes or addresses for downstreams, depending on
// the IP serving mode of each. // the IP serving mode of each.
for (TetherInterfaceStateMachine tism : mNotifyList) { for (IpServer ipServer : mNotifyList) {
final LinkProperties lp = tism.linkProperties(); final LinkProperties lp = ipServer.linkProperties();
switch (tism.servingMode()) { switch (ipServer.servingMode()) {
case IControlsTethering.STATE_UNAVAILABLE: case IpServer.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE: case IpServer.STATE_AVAILABLE:
// No usable LinkProperties in these states. // No usable LinkProperties in these states.
continue; continue;
case IControlsTethering.STATE_TETHERED: case IpServer.STATE_TETHERED:
// Only add IPv4 /32 and IPv6 /128 prefixes. The // Only add IPv4 /32 and IPv6 /128 prefixes. The
// directly-connected prefixes will be sent as // directly-connected prefixes will be sent as
// downstream "offload-able" prefixes. // downstream "offload-able" prefixes.
@@ -1789,7 +1788,7 @@ public class Tethering extends BaseNetworkObserver {
localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip)); localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
} }
break; break;
case IControlsTethering.STATE_LOCAL_ONLY: case IpServer.STATE_LOCAL_ONLY:
// Add prefixes covering all local IPs. // Add prefixes covering all local IPs.
localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp)); localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
break; break;
@@ -1826,16 +1825,16 @@ public class Tethering extends BaseNetworkObserver {
pw.print(iface + " - "); pw.print(iface + " - ");
switch (tetherState.lastState) { switch (tetherState.lastState) {
case IControlsTethering.STATE_UNAVAILABLE: case IpServer.STATE_UNAVAILABLE:
pw.print("UnavailableState"); pw.print("UnavailableState");
break; break;
case IControlsTethering.STATE_AVAILABLE: case IpServer.STATE_AVAILABLE:
pw.print("AvailableState"); pw.print("AvailableState");
break; break;
case IControlsTethering.STATE_TETHERED: case IpServer.STATE_TETHERED:
pw.print("TetheredState"); pw.print("TetheredState");
break; break;
case IControlsTethering.STATE_LOCAL_ONLY: case IpServer.STATE_LOCAL_ONLY:
pw.print("LocalHotspotState"); pw.print("LocalHotspotState");
break; break;
default: default:
@@ -1873,28 +1872,26 @@ public class Tethering extends BaseNetworkObserver {
return false; return false;
} }
private IControlsTethering makeControlCallback(String ifname) { private IpServer.Callback makeControlCallback() {
return new IControlsTethering() { return new IpServer.Callback() {
@Override @Override
public void updateInterfaceState( public void updateInterfaceState(IpServer who, int state, int lastError) {
TetherInterfaceStateMachine who, int state, int lastError) { notifyInterfaceStateChange(who, state, lastError);
notifyInterfaceStateChange(ifname, who, state, lastError);
} }
@Override @Override
public void updateLinkProperties( public void updateLinkProperties(IpServer who, LinkProperties newLp) {
TetherInterfaceStateMachine who, LinkProperties newLp) { notifyLinkPropertiesChanged(who, newLp);
notifyLinkPropertiesChanged(ifname, who, newLp);
} }
}; };
} }
// TODO: Move into TetherMasterSM. // TODO: Move into TetherMasterSM.
private void notifyInterfaceStateChange( private void notifyInterfaceStateChange(IpServer who, int state, int error) {
String iface, TetherInterfaceStateMachine who, int state, int error) { final String iface = who.interfaceName();
synchronized (mPublicSync) { synchronized (mPublicSync) {
final TetherState tetherState = mTetherStates.get(iface); final TetherState tetherState = mTetherStates.get(iface);
if (tetherState != null && tetherState.stateMachine.equals(who)) { if (tetherState != null && tetherState.ipServer.equals(who)) {
tetherState.lastState = state; tetherState.lastState = state;
tetherState.lastError = error; tetherState.lastError = error;
} else { } else {
@@ -1908,7 +1905,7 @@ public class Tethering extends BaseNetworkObserver {
// Notify that we're tethering (or not) this interface. // Notify that we're tethering (or not) this interface.
// This is how data saver for instance knows if the user explicitly // This is how data saver for instance knows if the user explicitly
// turned on tethering (thus keeping us from being in data saver mode). // turned on tethering (thus keeping us from being in data saver mode).
mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED); mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
} catch (RemoteException e) { } catch (RemoteException e) {
// Not really very much we can do here. // Not really very much we can do here.
} }
@@ -1921,12 +1918,12 @@ public class Tethering extends BaseNetworkObserver {
} }
int which; int which;
switch (state) { switch (state) {
case IControlsTethering.STATE_UNAVAILABLE: case IpServer.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE: case IpServer.STATE_AVAILABLE:
which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE; which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
break; break;
case IControlsTethering.STATE_TETHERED: case IpServer.STATE_TETHERED:
case IControlsTethering.STATE_LOCAL_ONLY: case IpServer.STATE_LOCAL_ONLY:
which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE; which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
break; break;
default: default:
@@ -1937,12 +1934,12 @@ public class Tethering extends BaseNetworkObserver {
sendTetherStateChangedBroadcast(); sendTetherStateChangedBroadcast();
} }
private void notifyLinkPropertiesChanged(String iface, TetherInterfaceStateMachine who, private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
LinkProperties newLp) { final String iface = who.interfaceName();
final int state; final int state;
synchronized (mPublicSync) { synchronized (mPublicSync) {
final TetherState tetherState = mTetherStates.get(iface); final TetherState tetherState = mTetherStates.get(iface);
if (tetherState != null && tetherState.stateMachine.equals(who)) { if (tetherState != null && tetherState.ipServer.equals(who)) {
state = tetherState.lastState; state = tetherState.lastState;
} else { } else {
mLog.log("got notification from stale iface " + iface); mLog.log("got notification from stale iface " + iface);
@@ -1952,7 +1949,7 @@ public class Tethering extends BaseNetworkObserver {
mLog.log(String.format( mLog.log(String.format(
"OBSERVED LinkProperties update iface=%s state=%s lp=%s", "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
iface, IControlsTethering.getStateString(state), newLp)); iface, IpServer.getStateString(state), newLp));
final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES; final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
mTetherMasterSM.sendMessage(which, state, 0, newLp); mTetherMasterSM.sendMessage(which, state, 0, newLp);
} }
@@ -1976,11 +1973,11 @@ public class Tethering extends BaseNetworkObserver {
mLog.log("adding TetheringInterfaceStateMachine for: " + iface); mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState( final TetherState tetherState = new TetherState(
new TetherInterfaceStateMachine( new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
iface, mLooper, interfaceType, mLog, mNMService, mStatsService, makeControlCallback(), mConfig.enableLegacyDhcpServer,
makeControlCallback(iface), mConfig.enableLegacyDhcpServer, mDeps)); mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState); mTetherStates.put(iface, tetherState);
tetherState.stateMachine.start(); tetherState.ipServer.start();
} }
private void stopTrackingInterfaceLocked(final String iface) { private void stopTrackingInterfaceLocked(final String iface) {
@@ -1989,36 +1986,11 @@ public class Tethering extends BaseNetworkObserver {
mLog.log("attempting to remove unknown iface (" + iface + "), ignoring"); mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
return; return;
} }
tetherState.stateMachine.stop(); tetherState.ipServer.stop();
mLog.log("removing TetheringInterfaceStateMachine for: " + iface); mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
mTetherStates.remove(iface); mTetherStates.remove(iface);
} }
private static String getIPv4DefaultRouteInterface(NetworkState ns) {
if (ns == null) return null;
return getInterfaceForDestination(ns.linkProperties, Inet4Address.ANY);
}
private static String getIPv6DefaultRouteInterface(NetworkState ns) {
if (ns == null) return null;
// An upstream network's IPv6 capability is currently only useful if it
// can be 64share'd downstream (RFC 7278). For now, that means mobile
// upstream networks only.
if (ns.networkCapabilities == null ||
!ns.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
return null;
}
return getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY);
}
private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
final RouteInfo ri = (lp != null)
? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
: null;
return (ri != null) ? ri.getInterface() : null;
}
private static String[] copy(String[] strarray) { private static String[] copy(String[] strarray) {
return Arrays.copyOf(strarray, strarray.length); return Arrays.copyOf(strarray, strarray.length);
} }

View File

@@ -1,66 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.connectivity.tethering;
import android.net.LinkProperties;
/**
* @hide
*
* Interface with methods necessary to notify that a given interface is ready for tethering.
*
* Rename to something more representative, e.g. IpServingControlCallback.
*
* All methods MUST be called on the TetherMasterSM main Looper's thread.
*/
public class IControlsTethering {
public static final int STATE_UNAVAILABLE = 0;
public static final int STATE_AVAILABLE = 1;
public static final int STATE_TETHERED = 2;
public static final int STATE_LOCAL_ONLY = 3;
public static String getStateString(int state) {
switch (state) {
case STATE_UNAVAILABLE: return "UNAVAILABLE";
case STATE_AVAILABLE: return "AVAILABLE";
case STATE_TETHERED: return "TETHERED";
case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
}
return "UNKNOWN: " + state;
}
/**
* Notify that |who| has changed its tethering state.
*
* TODO: Remove the need for the |who| argument.
*
* @param who corresponding instance of a TetherInterfaceStateMachine
* @param state one of IControlsTethering.STATE_*
* @param lastError one of ConnectivityManager.TETHER_ERROR_*
*/
public void updateInterfaceState(TetherInterfaceStateMachine who, int state, int lastError) {}
/**
* Notify that |who| has new LinkProperties.
*
* TODO: Remove the need for the |who| argument.
*
* @param who corresponding instance of a TetherInterfaceStateMachine
* @param newLp the new LinkProperties to report
*/
public void updateLinkProperties(TetherInterfaceStateMachine who, LinkProperties newLp) {}
}

View File

@@ -17,6 +17,7 @@
package com.android.server.connectivity.tethering; package com.android.server.connectivity.tethering;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.ip.IpServer;
import android.net.IpPrefix; import android.net.IpPrefix;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -50,19 +51,19 @@ public class IPv6TetheringCoordinator {
private static final boolean VDBG = false; private static final boolean VDBG = false;
private static class Downstream { private static class Downstream {
public final TetherInterfaceStateMachine tism; public final IpServer ipServer;
public final int mode; // IControlsTethering.STATE_* public final int mode; // IpServer.STATE_*
// Used to append to a ULA /48, constructing a ULA /64 for local use. // Used to append to a ULA /48, constructing a ULA /64 for local use.
public final short subnetId; public final short subnetId;
Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) { Downstream(IpServer ipServer, int mode, short subnetId) {
this.tism = tism; this.ipServer = ipServer;
this.mode = mode; this.mode = mode;
this.subnetId = subnetId; this.subnetId = subnetId;
} }
} }
private final ArrayList<TetherInterfaceStateMachine> mNotifyList; private final ArrayList<IpServer> mNotifyList;
private final SharedLog mLog; private final SharedLog mLog;
// NOTE: mActiveDownstreams is a list and not a hash data structure because // NOTE: mActiveDownstreams is a list and not a hash data structure because
// we keep active downstreams in arrival order. This is done so /64s can // we keep active downstreams in arrival order. This is done so /64s can
@@ -74,8 +75,7 @@ public class IPv6TetheringCoordinator {
private short mNextSubnetId; private short mNextSubnetId;
private NetworkState mUpstreamNetworkState; private NetworkState mUpstreamNetworkState;
public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList, public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
SharedLog log) {
mNotifyList = notifyList; mNotifyList = notifyList;
mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG);
mActiveDownstreams = new LinkedList<>(); mActiveDownstreams = new LinkedList<>();
@@ -83,7 +83,7 @@ public class IPv6TetheringCoordinator {
mNextSubnetId = 0; mNextSubnetId = 0;
} }
public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) { public void addActiveDownstream(IpServer downstream, int mode) {
if (findDownstream(downstream) == null) { if (findDownstream(downstream) == null) {
// Adding a new downstream appends it to the list. Adding a // Adding a new downstream appends it to the list. Adding a
// downstream a second time without first removing it has no effect. // downstream a second time without first removing it has no effect.
@@ -98,7 +98,7 @@ public class IPv6TetheringCoordinator {
} }
} }
public void removeActiveDownstream(TetherInterfaceStateMachine downstream) { public void removeActiveDownstream(IpServer downstream) {
stopIPv6TetheringOn(downstream); stopIPv6TetheringOn(downstream);
if (mActiveDownstreams.remove(findDownstream(downstream))) { if (mActiveDownstreams.remove(findDownstream(downstream))) {
updateIPv6TetheringInterfaces(); updateIPv6TetheringInterfaces();
@@ -133,8 +133,8 @@ public class IPv6TetheringCoordinator {
} }
private void stopIPv6TetheringOnAllInterfaces() { private void stopIPv6TetheringOnAllInterfaces() {
for (TetherInterfaceStateMachine sm : mNotifyList) { for (IpServer ipServer : mNotifyList) {
stopIPv6TetheringOn(sm); stopIPv6TetheringOn(ipServer);
} }
} }
@@ -156,28 +156,28 @@ public class IPv6TetheringCoordinator {
} }
private void updateIPv6TetheringInterfaces() { private void updateIPv6TetheringInterfaces() {
for (TetherInterfaceStateMachine sm : mNotifyList) { for (IpServer ipServer : mNotifyList) {
final LinkProperties lp = getInterfaceIPv6LinkProperties(sm); final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
break; break;
} }
} }
private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) { private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) { if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
// TODO: Figure out IPv6 support on PAN interfaces. // TODO: Figure out IPv6 support on PAN interfaces.
return null; return null;
} }
final Downstream ds = findDownstream(sm); final Downstream ds = findDownstream(ipServer);
if (ds == null) return null; if (ds == null) return null;
if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) { if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
// Build a Unique Locally-assigned Prefix configuration. // Build a Unique Locally-assigned Prefix configuration.
return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId); return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
} }
// This downstream is in IControlsTethering.STATE_TETHERED mode. // This downstream is in IpServer.STATE_TETHERED mode.
if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) { if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
return null; return null;
} }
@@ -188,7 +188,7 @@ public class IPv6TetheringCoordinator {
// IPv6 toward the oldest (first requested) active downstream. // IPv6 toward the oldest (first requested) active downstream.
final Downstream currentActive = mActiveDownstreams.peek(); final Downstream currentActive = mActiveDownstreams.peek();
if (currentActive != null && currentActive.tism == sm) { if (currentActive != null && currentActive.ipServer == ipServer) {
final LinkProperties lp = getIPv6OnlyLinkProperties( final LinkProperties lp = getIPv6OnlyLinkProperties(
mUpstreamNetworkState.linkProperties); mUpstreamNetworkState.linkProperties);
if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) { if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
@@ -199,9 +199,9 @@ public class IPv6TetheringCoordinator {
return null; return null;
} }
Downstream findDownstream(TetherInterfaceStateMachine tism) { Downstream findDownstream(IpServer ipServer) {
for (Downstream ds : mActiveDownstreams) { for (Downstream ds : mActiveDownstreams) {
if (ds.tism == tism) return ds; if (ds.ipServer == ipServer) return ds;
} }
return null; return null;
} }
@@ -304,7 +304,7 @@ public class IPv6TetheringCoordinator {
ns.linkProperties); ns.linkProperties);
} }
private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) { private static void stopIPv6TetheringOn(IpServer ipServer) {
sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null); ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
} }
} }

View File

@@ -21,6 +21,7 @@ import android.net.INetd;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.dhcp.DhcpServer; import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams; import android.net.dhcp.DhcpServingParams;
import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon; import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams; import android.net.util.InterfaceParams;
import android.net.util.NetdService; import android.net.util.NetdService;
@@ -49,20 +50,12 @@ public class TetheringDependencies {
} }
public IPv6TetheringCoordinator getIPv6TetheringCoordinator( public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) { ArrayList<IpServer> notifyList, SharedLog log) {
return new IPv6TetheringCoordinator(notifyList, log); return new IPv6TetheringCoordinator(notifyList, log);
} }
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { public IpServer.Dependencies getIpServerDependencies() {
return new RouterAdvertisementDaemon(ifParams); return new IpServer.Dependencies();
}
public InterfaceParams getInterfaceParams(String ifName) {
return InterfaceParams.getByName(ifName);
}
public INetd getNetdService() {
return NetdService.getInstance();
} }
public boolean isTetheringSupported() { public boolean isTetheringSupported() {
@@ -72,9 +65,4 @@ public class TetheringDependencies {
public NetworkRequest getDefaultNetworkRequest() { public NetworkRequest getDefaultNetworkRequest() {
return null; return null;
} }
public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, DhcpServingParams params,
SharedLog log) {
return new DhcpServer(looper, iface, params, log);
}
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.server.connectivity.tethering; package android.net.ip;
import static android.net.NetworkUtils.numericToInetAddress; import static android.net.NetworkUtils.numericToInetAddress;
import static android.net.util.NetworkConstants.asByte; import static android.net.util.NetworkConstants.asByte;
@@ -31,11 +31,10 @@ import android.net.LinkProperties;
import android.net.RouteInfo; import android.net.RouteInfo;
import android.net.dhcp.DhcpServer; import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams; import android.net.dhcp.DhcpServingParams;
import android.net.ip.InterfaceController;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.InterfaceParams; import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet; import android.net.util.InterfaceSet;
import android.net.util.NetdService;
import android.net.util.SharedLog; import android.net.util.SharedLog;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.Looper; import android.os.Looper;
@@ -67,7 +66,22 @@ import java.util.Set;
* *
* @hide * @hide
*/ */
public class TetherInterfaceStateMachine extends StateMachine { public class IpServer extends StateMachine {
public static final int STATE_UNAVAILABLE = 0;
public static final int STATE_AVAILABLE = 1;
public static final int STATE_TETHERED = 2;
public static final int STATE_LOCAL_ONLY = 3;
public static String getStateString(int state) {
switch (state) {
case STATE_UNAVAILABLE: return "UNAVAILABLE";
case STATE_AVAILABLE: return "AVAILABLE";
case STATE_TETHERED: return "TETHERED";
case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
}
return "UNKNOWN: " + state;
}
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
private static final byte DOUG_ADAMS = (byte) 42; private static final byte DOUG_ADAMS = (byte) 42;
@@ -83,15 +97,53 @@ public class TetherInterfaceStateMachine extends StateMachine {
// TODO: have this configurable // TODO: have this configurable
private static final int DHCP_LEASE_TIME_SECS = 3600; private static final int DHCP_LEASE_TIME_SECS = 3600;
private final static String TAG = "TetherInterfaceSM"; private final static String TAG = "IpServer";
private final static boolean DBG = false; private final static boolean DBG = false;
private final static boolean VDBG = false; private final static boolean VDBG = false;
private static final Class[] messageClasses = { private static final Class[] messageClasses = {
TetherInterfaceStateMachine.class IpServer.class
}; };
private static final SparseArray<String> sMagicDecoderRing = private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(messageClasses); MessageUtils.findMessageNames(messageClasses);
public static class Callback {
/**
* Notify that |who| has changed its tethering state.
*
* @param who the calling instance of IpServer
* @param state one of STATE_*
* @param lastError one of ConnectivityManager.TETHER_ERROR_*
*/
public void updateInterfaceState(IpServer who, int state, int lastError) {}
/**
* Notify that |who| has new LinkProperties.
*
* @param who the calling instance of IpServer
* @param newLp the new LinkProperties to report
*/
public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
}
public static class Dependencies {
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
return new RouterAdvertisementDaemon(ifParams);
}
public InterfaceParams getInterfaceParams(String ifName) {
return InterfaceParams.getByName(ifName);
}
public INetd getNetdService() {
return NetdService.getInstance();
}
public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
DhcpServingParams params, SharedLog log) {
return new DhcpServer(looper, iface, params, log);
}
}
private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100;
// request from the user that it wants to tether // request from the user that it wants to tether
public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2; public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2;
@@ -123,7 +175,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
private final INetworkManagementService mNMService; private final INetworkManagementService mNMService;
private final INetd mNetd; private final INetd mNetd;
private final INetworkStatsService mStatsService; private final INetworkStatsService mStatsService;
private final IControlsTethering mTetherController; private final Callback mCallback;
private final InterfaceController mInterfaceCtrl; private final InterfaceController mInterfaceCtrl;
private final String mIfaceName; private final String mIfaceName;
@@ -131,7 +183,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
private final LinkProperties mLinkProperties; private final LinkProperties mLinkProperties;
private final boolean mUsingLegacyDhcp; private final boolean mUsingLegacyDhcp;
private final TetheringDependencies mDeps; private final Dependencies mDeps;
private int mLastError; private int mLastError;
private int mServingMode; private int mServingMode;
@@ -148,17 +200,16 @@ public class TetherInterfaceStateMachine extends StateMachine {
private DhcpServer mDhcpServer; private DhcpServer mDhcpServer;
private RaParams mLastRaParams; private RaParams mLastRaParams;
public TetherInterfaceStateMachine( public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log, String ifaceName, Looper looper, int interfaceType, SharedLog log,
INetworkManagementService nMService, INetworkStatsService statsService, INetworkManagementService nMService, INetworkStatsService statsService,
IControlsTethering tetherController, boolean usingLegacyDhcp, Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
TetheringDependencies deps) {
super(ifaceName, looper); super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName); mLog = log.forSubComponent(ifaceName);
mNMService = nMService; mNMService = nMService;
mNetd = deps.getNetdService(); mNetd = deps.getNetdService();
mStatsService = statsService; mStatsService = statsService;
mTetherController = tetherController; mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog); mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
mIfaceName = ifaceName; mIfaceName = ifaceName;
mInterfaceType = interfaceType; mInterfaceType = interfaceType;
@@ -167,7 +218,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
mDeps = deps; mDeps = deps;
resetLinkProperties(); resetLinkProperties();
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
mServingMode = IControlsTethering.STATE_AVAILABLE; mServingMode = STATE_AVAILABLE;
mInitialState = new InitialState(); mInitialState = new InitialState();
mLocalHotspotState = new LocalHotspotState(); mLocalHotspotState = new LocalHotspotState();
@@ -521,14 +572,12 @@ public class TetherInterfaceStateMachine extends StateMachine {
private void sendInterfaceState(int newInterfaceState) { private void sendInterfaceState(int newInterfaceState) {
mServingMode = newInterfaceState; mServingMode = newInterfaceState;
mTetherController.updateInterfaceState( mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
sendLinkProperties(); sendLinkProperties();
} }
private void sendLinkProperties() { private void sendLinkProperties() {
mTetherController.updateLinkProperties( mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
} }
private void resetLinkProperties() { private void resetLinkProperties() {
@@ -539,7 +588,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
class InitialState extends State { class InitialState extends State {
@Override @Override
public void enter() { public void enter() {
sendInterfaceState(IControlsTethering.STATE_AVAILABLE); sendInterfaceState(STATE_AVAILABLE);
} }
@Override @Override
@@ -549,10 +598,10 @@ public class TetherInterfaceStateMachine extends StateMachine {
case CMD_TETHER_REQUESTED: case CMD_TETHER_REQUESTED:
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
switch (message.arg1) { switch (message.arg1) {
case IControlsTethering.STATE_LOCAL_ONLY: case STATE_LOCAL_ONLY:
transitionTo(mLocalHotspotState); transitionTo(mLocalHotspotState);
break; break;
case IControlsTethering.STATE_TETHERED: case STATE_TETHERED:
transitionTo(mTetheredState); transitionTo(mTetheredState);
break; break;
default: default:
@@ -649,7 +698,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
// problematic because transitioning during a multi-state jump yields // problematic because transitioning during a multi-state jump yields
// a Log.wtf(). Ultimately, there should be only one ServingState, // a Log.wtf(). Ultimately, there should be only one ServingState,
// and forwarding and NAT rules should be handled by a coordinating // and forwarding and NAT rules should be handled by a coordinating
// functional element outside of TetherInterfaceStateMachine. // functional element outside of IpServer.
class LocalHotspotState extends BaseServingState { class LocalHotspotState extends BaseServingState {
@Override @Override
public void enter() { public void enter() {
@@ -659,7 +708,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
} }
if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName); if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY); sendInterfaceState(STATE_LOCAL_ONLY);
} }
@Override @Override
@@ -685,7 +734,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
// problematic because transitioning during a multi-state jump yields // problematic because transitioning during a multi-state jump yields
// a Log.wtf(). Ultimately, there should be only one ServingState, // a Log.wtf(). Ultimately, there should be only one ServingState,
// and forwarding and NAT rules should be handled by a coordinating // and forwarding and NAT rules should be handled by a coordinating
// functional element outside of TetherInterfaceStateMachine. // functional element outside of IpServer.
class TetheredState extends BaseServingState { class TetheredState extends BaseServingState {
@Override @Override
public void enter() { public void enter() {
@@ -695,7 +744,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
} }
if (DBG) Log.d(TAG, "Tethered " + mIfaceName); if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
sendInterfaceState(IControlsTethering.STATE_TETHERED); sendInterfaceState(STATE_TETHERED);
} }
@Override @Override
@@ -817,7 +866,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
@Override @Override
public void enter() { public void enter() {
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE); sendInterfaceState(STATE_UNAVAILABLE);
} }
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.server.connectivity.tethering; package android.net.ip;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@@ -37,9 +37,9 @@ import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_USB; import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHERING_WIFI;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE; import static android.net.ip.IpServer.STATE_AVAILABLE;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED; import static android.net.ip.IpServer.STATE_TETHERED;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE; import static android.net.ip.IpServer.STATE_UNAVAILABLE;
import android.net.INetworkStatsService; import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration; import android.net.InterfaceConfiguration;
@@ -50,7 +50,6 @@ import android.net.MacAddress;
import android.net.RouteInfo; import android.net.RouteInfo;
import android.net.dhcp.DhcpServer; import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams; import android.net.dhcp.DhcpServingParams;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams; import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet; import android.net.util.InterfaceSet;
import android.net.util.SharedLog; import android.net.util.SharedLog;
@@ -74,7 +73,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class TetherInterfaceStateMachineTest { public class IpServerTest {
private static final String IFACE_NAME = "testnet1"; private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0"; private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1"; private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -85,39 +84,38 @@ public class TetherInterfaceStateMachineTest {
@Mock private INetworkManagementService mNMService; @Mock private INetworkManagementService mNMService;
@Mock private INetworkStatsService mStatsService; @Mock private INetworkStatsService mStatsService;
@Mock private IControlsTethering mTetherHelper; @Mock private IpServer.Callback mCallback;
@Mock private InterfaceConfiguration mInterfaceConfiguration; @Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private SharedLog mSharedLog; @Mock private SharedLog mSharedLog;
@Mock private DhcpServer mDhcpServer; @Mock private DhcpServer mDhcpServer;
@Mock private RouterAdvertisementDaemon mRaDaemon; @Mock private RouterAdvertisementDaemon mRaDaemon;
@Mock private TetheringDependencies mTetheringDependencies; @Mock private IpServer.Dependencies mDependencies;
@Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor; @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;
private final TestLooper mLooper = new TestLooper(); private final TestLooper mLooper = new TestLooper();
private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor = private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
ArgumentCaptor.forClass(LinkProperties.class); ArgumentCaptor.forClass(LinkProperties.class);
private TetherInterfaceStateMachine mTestedSm; private IpServer mIpServer;
private void initStateMachine(int interfaceType) throws Exception { private void initStateMachine(int interfaceType) throws Exception {
initStateMachine(interfaceType, false /* usingLegacyDhcp */); initStateMachine(interfaceType, false /* usingLegacyDhcp */);
} }
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception { private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
mTestedSm = new TetherInterfaceStateMachine( mIpServer = new IpServer(
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
mNMService, mStatsService, mTetherHelper, usingLegacyDhcp, mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
mTetheringDependencies); mIpServer.start();
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies // Starting the state machine always puts us in a consistent state and notifies
// the rest of the world that we've changed from an unknown to available state. // the rest of the world that we've changed from an unknown to available state.
mLooper.dispatchAll(); mLooper.dispatchAll();
reset(mNMService, mStatsService, mTetherHelper); reset(mNMService, mStatsService, mCallback);
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
when(mTetheringDependencies.makeDhcpServer( when(mDependencies.makeDhcpServer(
any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer); any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
when(mTetheringDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mTetheringDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
when(mRaDaemon.start()).thenReturn(true); when(mRaDaemon.start()).thenReturn(true);
} }
@@ -130,11 +128,11 @@ public class TetherInterfaceStateMachineTest {
private void initTetheredStateMachine(int interfaceType, String upstreamIface, private void initTetheredStateMachine(int interfaceType, String upstreamIface,
boolean usingLegacyDhcp) throws Exception { boolean usingLegacyDhcp) throws Exception {
initStateMachine(interfaceType, usingLegacyDhcp); initStateMachine(interfaceType, usingLegacyDhcp);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
if (upstreamIface != null) { if (upstreamIface != null) {
dispatchTetherConnectionChanged(upstreamIface); dispatchTetherConnectionChanged(upstreamIface);
} }
reset(mNMService, mStatsService, mTetherHelper); reset(mNMService, mStatsService, mCallback);
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
} }
@@ -145,34 +143,34 @@ public class TetherInterfaceStateMachineTest {
@Test @Test
public void startsOutAvailable() { public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper, TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
false /* usingLegacyDhcp */, mTetheringDependencies); false /* usingLegacyDhcp */, mDependencies);
mTestedSm.start(); mIpServer.start();
mLooper.dispatchAll(); mLooper.dispatchAll();
verify(mTetherHelper).updateInterfaceState( verify(mCallback).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class)); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService); verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
} }
@Test @Test
public void shouldDoNothingUntilRequested() throws Exception { public void shouldDoNothingUntilRequested() throws Exception {
initStateMachine(TETHERING_BLUETOOTH); initStateMachine(TETHERING_BLUETOOTH);
final int [] NOOP_COMMANDS = { final int [] NOOP_COMMANDS = {
TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED, IpServer.CMD_TETHER_UNREQUESTED,
TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR, IpServer.CMD_IP_FORWARDING_ENABLE_ERROR,
TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR, IpServer.CMD_IP_FORWARDING_DISABLE_ERROR,
TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR, IpServer.CMD_START_TETHERING_ERROR,
TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR, IpServer.CMD_STOP_TETHERING_ERROR,
TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR, IpServer.CMD_SET_DNS_FORWARDERS_ERROR,
TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED IpServer.CMD_TETHER_CONNECTION_CHANGED
}; };
for (int command : NOOP_COMMANDS) { for (int command : NOOP_COMMANDS) {
// None of these commands should trigger us to request action from // None of these commands should trigger us to request action from
// the rest of the system. // the rest of the system.
dispatchCommand(command); dispatchCommand(command);
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
} }
@@ -180,57 +178,57 @@ public class TetherInterfaceStateMachineTest {
public void handlesImmediateInterfaceDown() throws Exception { public void handlesImmediateInterfaceDown() throws Exception {
initStateMachine(TETHERING_BLUETOOTH); initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN); dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
verify(mTetherHelper).updateInterfaceState( verify(mCallback).updateInterfaceState(
mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class)); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
public void canBeTethered() throws Exception { public void canBeTethered() throws Exception {
initStateMachine(TETHERING_BLUETOOTH); initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder inOrder = inOrder(mTetherHelper, mNMService); InOrder inOrder = inOrder(mCallback, mNMService);
inOrder.verify(mNMService).tetherInterface(IFACE_NAME); inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
inOrder.verify(mTetherHelper).updateInterfaceState( inOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR); mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mTetherHelper).updateLinkProperties( inOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), any(LinkProperties.class)); eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
public void canUnrequestTethering() throws Exception { public void canUnrequestTethering() throws Exception {
initTetheredStateMachine(TETHERING_BLUETOOTH, null); initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
inOrder.verify(mNMService).untetherInterface(IFACE_NAME); inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any()); inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
inOrder.verify(mTetherHelper).updateInterfaceState( inOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mTetherHelper).updateLinkProperties( inOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), any(LinkProperties.class)); eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
public void canBeTetheredAsUsb() throws Exception { public void canBeTetheredAsUsb() throws Exception {
initStateMachine(TETHERING_USB); initStateMachine(TETHERING_USB);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder inOrder = inOrder(mTetherHelper, mNMService); InOrder inOrder = inOrder(mCallback, mNMService);
inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME); inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
inOrder.verify(mNMService).tetherInterface(IFACE_NAME); inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
inOrder.verify(mTetherHelper).updateInterfaceState( inOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR); mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mTetherHelper).updateLinkProperties( inOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), mLinkPropertiesCaptor.capture()); eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
@@ -243,7 +241,7 @@ public class TetherInterfaceStateMachineTest {
InOrder inOrder = inOrder(mNMService); InOrder inOrder = inOrder(mNMService);
inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
@@ -257,7 +255,7 @@ public class TetherInterfaceStateMachineTest {
inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
@@ -300,18 +298,18 @@ public class TetherInterfaceStateMachineTest {
public void canUnrequestTetheringWithUpstream() throws Exception { public void canUnrequestTetheringWithUpstream() throws Exception {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
inOrder.verify(mStatsService).forceUpdate(); inOrder.verify(mStatsService).forceUpdate();
inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).untetherInterface(IFACE_NAME); inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any()); inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
inOrder.verify(mTetherHelper).updateInterfaceState( inOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mTetherHelper).updateLinkProperties( inOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), any(LinkProperties.class)); eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
@Test @Test
@@ -322,15 +320,15 @@ public class TetherInterfaceStateMachineTest {
if (shouldThrow) { if (shouldThrow) {
doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME); doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
} }
dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN); dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper); InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
usbTeardownOrder.verify(mNMService).setInterfaceConfig( usbTeardownOrder.verify(mNMService).setInterfaceConfig(
IFACE_NAME, mInterfaceConfiguration); IFACE_NAME, mInterfaceConfiguration);
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState( usbTeardownOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties( usbTeardownOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), mLinkPropertiesCaptor.capture()); eq(mIpServer), mLinkPropertiesCaptor.capture());
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue()); assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
} }
} }
@@ -340,15 +338,15 @@ public class TetherInterfaceStateMachineTest {
initStateMachine(TETHERING_USB); initStateMachine(TETHERING_USB);
doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME); doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper); InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
usbTeardownOrder.verify(mNMService).setInterfaceConfig( usbTeardownOrder.verify(mNMService).setInterfaceConfig(
IFACE_NAME, mInterfaceConfiguration); IFACE_NAME, mInterfaceConfiguration);
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState( usbTeardownOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR); mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties( usbTeardownOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), mLinkPropertiesCaptor.capture()); eq(mIpServer), mLinkPropertiesCaptor.capture());
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue()); assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
} }
@@ -358,13 +356,13 @@ public class TetherInterfaceStateMachineTest {
doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString()); doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
dispatchTetherConnectionChanged(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE);
InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper); InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState( usbTeardownOrder.verify(mCallback).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR); mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties( usbTeardownOrder.verify(mCallback).updateLinkProperties(
eq(mTestedSm), mLinkPropertiesCaptor.capture()); eq(mIpServer), mLinkPropertiesCaptor.capture());
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue()); assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
} }
@@ -372,11 +370,11 @@ public class TetherInterfaceStateMachineTest {
public void ignoresDuplicateUpstreamNotifications() throws Exception { public void ignoresDuplicateUpstreamNotifications() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
dispatchTetherConnectionChanged(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE);
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
} }
} }
@@ -401,11 +399,11 @@ public class TetherInterfaceStateMachineTest {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */); initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
dispatchTetherConnectionChanged(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE);
verify(mTetheringDependencies, never()).makeDhcpServer(any(), any(), any(), any()); verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any());
} }
private void assertDhcpStarted(IpPrefix expectedPrefix) { private void assertDhcpStarted(IpPrefix expectedPrefix) {
verify(mTetheringDependencies, times(1)).makeDhcpServer( verify(mDependencies, times(1)).makeDhcpServer(
eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog)); eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
verify(mDhcpServer, times(1)).start(); verify(mDhcpServer, times(1)).start();
final DhcpServingParams params = mDhcpParamsCaptor.getValue(); final DhcpServingParams params = mDhcpParamsCaptor.getValue();
@@ -422,21 +420,21 @@ public class TetherInterfaceStateMachineTest {
/** /**
* Send a command to the state machine under test, and run the event loop to idle. * Send a command to the state machine under test, and run the event loop to idle.
* *
* @param command One of the TetherInterfaceStateMachine.CMD_* constants. * @param command One of the IpServer.CMD_* constants.
* @param arg1 An additional argument to pass. * @param arg1 An additional argument to pass.
*/ */
private void dispatchCommand(int command, int arg1) { private void dispatchCommand(int command, int arg1) {
mTestedSm.sendMessage(command, arg1); mIpServer.sendMessage(command, arg1);
mLooper.dispatchAll(); mLooper.dispatchAll();
} }
/** /**
* Send a command to the state machine under test, and run the event loop to idle. * Send a command to the state machine under test, and run the event loop to idle.
* *
* @param command One of the TetherInterfaceStateMachine.CMD_* constants. * @param command One of the IpServer.CMD_* constants.
*/ */
private void dispatchCommand(int command) { private void dispatchCommand(int command) {
mTestedSm.sendMessage(command); mIpServer.sendMessage(command);
mLooper.dispatchAll(); mLooper.dispatchAll();
} }
@@ -447,7 +445,7 @@ public class TetherInterfaceStateMachineTest {
* @param upstreamIface String name of upstream interface (or null) * @param upstreamIface String name of upstream interface (or null)
*/ */
private void dispatchTetherConnectionChanged(String upstreamIface) { private void dispatchTetherConnectionChanged(String upstreamIface) {
mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
new InterfaceSet(upstreamIface)); new InterfaceSet(upstreamIface));
mLooper.dispatchAll(); mLooper.dispatchAll();
} }

View File

@@ -75,6 +75,7 @@ import android.net.NetworkRequest;
import android.net.NetworkState; import android.net.NetworkState;
import android.net.NetworkUtils; import android.net.NetworkUtils;
import android.net.RouteInfo; import android.net.RouteInfo;
import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon; import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams; import android.net.util.InterfaceParams;
import android.net.util.NetworkConstants; import android.net.util.NetworkConstants;
@@ -99,10 +100,8 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.StateMachine; import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadHardwareInterface; import com.android.server.connectivity.tethering.OffloadHardwareInterface;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor; import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
@@ -190,7 +189,7 @@ public class TetheringTest {
public class MockTetheringDependencies extends TetheringDependencies { public class MockTetheringDependencies extends TetheringDependencies {
StateMachine upstreamNetworkMonitorMasterSM; StateMachine upstreamNetworkMonitorMasterSM;
ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList; ArrayList<IpServer> ipv6CoordinatorNotifyList;
int isTetheringSupportedCalls; int isTetheringSupportedCalls;
public void reset() { public void reset() {
@@ -213,29 +212,35 @@ public class TetheringTest {
@Override @Override
public IPv6TetheringCoordinator getIPv6TetheringCoordinator( public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) { ArrayList<IpServer> notifyList, SharedLog log) {
ipv6CoordinatorNotifyList = notifyList; ipv6CoordinatorNotifyList = notifyList;
return mIPv6TetheringCoordinator; return mIPv6TetheringCoordinator;
} }
@Override @Override
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { public IpServer.Dependencies getIpServerDependencies() {
return mRouterAdvertisementDaemon; return new IpServer.Dependencies() {
} @Override
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
InterfaceParams ifParams) {
return mRouterAdvertisementDaemon;
}
@Override @Override
public INetd getNetdService() { public InterfaceParams getInterfaceParams(String ifName) {
return mNetd; final String[] ifaces = new String[] {
} TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
final int index = ArrayUtils.indexOf(ifaces, ifName);
assertTrue("Non-mocked interface: " + ifName, index >= 0);
return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
MacAddress.ALL_ZEROS_ADDRESS);
}
@Override @Override
public InterfaceParams getInterfaceParams(String ifName) { public INetd getNetdService() {
final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME, return mNetd;
TEST_MOBILE_IFNAME }; }
final int index = ArrayUtils.indexOf(ifaces, ifName); };
assertTrue("Non-mocked interface: " + ifName, index >= 0);
return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
MacAddress.ALL_ZEROS_ADDRESS);
} }
@Override @Override
@@ -458,9 +463,9 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED); sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll(); mLooper.dispatchAll();
// If, and only if, Tethering received an interface status changed // If, and only if, Tethering received an interface status changed then
// then it creates a TetherInterfaceStateMachine and sends out a // it creates a IpServer and sends out a broadcast indicating that the
// broadcast indicating that the interface is "available". // interface is "available".
if (emulateInterfaceStatusChanged) { if (emulateInterfaceStatusChanged) {
assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls); assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
@@ -557,18 +562,18 @@ public class TetheringTest {
} }
/** /**
* Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator. * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
*/ */
private void sendIPv6TetherUpdates(NetworkState upstreamState) { private void sendIPv6TetherUpdates(NetworkState upstreamState) {
// IPv6TetheringCoordinator must have been notified of downstream // IPv6TetheringCoordinator must have been notified of downstream
verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream( verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)), argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
eq(IControlsTethering.STATE_TETHERED)); eq(IpServer.STATE_TETHERED));
for (TetherInterfaceStateMachine tism : for (IpServer ipSrv :
mTetheringDependencies.ipv6CoordinatorNotifyList) { mTetheringDependencies.ipv6CoordinatorNotifyList) {
NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false); NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
upstreamState.linkProperties.isIPv6Provisioned() upstreamState.linkProperties.isIPv6Provisioned()
? ipv6OnlyState.linkProperties ? ipv6OnlyState.linkProperties
: null); : null);
@@ -812,7 +817,7 @@ public class TetheringTest {
// We verify get/set called thrice here: once for setup and twice during // We verify get/set called thrice here: once for setup and twice during
// teardown because all events happen over the course of the single // teardown because all events happen over the course of the single
// dispatchAll() above. Note that once the TISM IPv4 address config // dispatchAll() above. Note that once the IpServer IPv4 address config
// code is refactored the two calls during shutdown will revert to one. // code is refactored the two calls during shutdown will revert to one.
verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME); verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, times(3)) verify(mNMService, times(3))