Merge "Program offload-exempt local prefixes into the HAL"
This commit is contained in:
@@ -57,6 +57,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.util.PrefixUtils;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -213,10 +214,10 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
mContext.getContentResolver(),
|
mContext.getContentResolver(),
|
||||||
mLog);
|
mLog);
|
||||||
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
|
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
|
||||||
mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK );
|
mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
|
||||||
mForwardedDownstreams = new HashSet<>();
|
mForwardedDownstreams = new HashSet<>();
|
||||||
mSimChange = new SimChangeListener(
|
mSimChange = new SimChangeListener(
|
||||||
mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
|
mContext, smHandler, () -> reevaluateSimCardProvisioning());
|
||||||
|
|
||||||
mStateReceiver = new StateReceiver();
|
mStateReceiver = new StateReceiver();
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
@@ -224,13 +225,13 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
||||||
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||||
mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
|
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
|
||||||
|
|
||||||
filter = new IntentFilter();
|
filter = new IntentFilter();
|
||||||
filter.addAction(Intent.ACTION_MEDIA_SHARED);
|
filter.addAction(Intent.ACTION_MEDIA_SHARED);
|
||||||
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
|
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
|
||||||
filter.addDataScheme("file");
|
filter.addDataScheme("file");
|
||||||
mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
|
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
|
||||||
|
|
||||||
// load device config info
|
// load device config info
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
@@ -1132,12 +1133,6 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startOffloadController() {
|
|
||||||
mOffloadController.start();
|
|
||||||
mOffloadController.updateExemptPrefixes(
|
|
||||||
mUpstreamNetworkMonitor.getOffloadExemptPrefixes());
|
|
||||||
}
|
|
||||||
|
|
||||||
class TetherMasterSM extends StateMachine {
|
class TetherMasterSM extends StateMachine {
|
||||||
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
|
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
|
||||||
// an interface SM has requested Tethering/Local Hotspot
|
// an interface SM has requested Tethering/Local Hotspot
|
||||||
@@ -1155,14 +1150,14 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
|
static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
|
||||||
static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
|
static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
|
||||||
|
|
||||||
private State mInitialState;
|
private final State mInitialState;
|
||||||
private State mTetherModeAliveState;
|
private final State mTetherModeAliveState;
|
||||||
|
|
||||||
private State mSetIpForwardingEnabledErrorState;
|
private final State mSetIpForwardingEnabledErrorState;
|
||||||
private State mSetIpForwardingDisabledErrorState;
|
private final State mSetIpForwardingDisabledErrorState;
|
||||||
private State mStartTetheringErrorState;
|
private final State mStartTetheringErrorState;
|
||||||
private State mStopTetheringErrorState;
|
private final State mStopTetheringErrorState;
|
||||||
private State mSetDnsForwardersErrorState;
|
private final State mSetDnsForwardersErrorState;
|
||||||
|
|
||||||
// This list is a little subtle. It contains all the interfaces that currently are
|
// This list is a little subtle. It contains all the interfaces that currently are
|
||||||
// requesting tethering, regardless of whether these interfaces are still members of
|
// requesting tethering, regardless of whether these interfaces are still members of
|
||||||
@@ -1202,22 +1197,46 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
|
|
||||||
mNotifyList = new ArrayList<>();
|
mNotifyList = new ArrayList<>();
|
||||||
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
|
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
|
||||||
|
|
||||||
setInitialState(mInitialState);
|
setInitialState(mInitialState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startOffloadController() {
|
||||||
|
mOffloadController.start();
|
||||||
|
sendOffloadExemptPrefixes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendOffloadExemptPrefixes() {
|
||||||
|
sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendOffloadExemptPrefixes(Set<IpPrefix> localPrefixes) {
|
||||||
|
// Add in well-known minimum set.
|
||||||
|
PrefixUtils.addNonForwardablePrefixes(localPrefixes);
|
||||||
|
// Add tragically hardcoded prefixes.
|
||||||
|
localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
|
||||||
|
|
||||||
|
// Add prefixes for all downstreams, regardless of IP serving mode.
|
||||||
|
for (TetherInterfaceStateMachine tism : mNotifyList) {
|
||||||
|
localPrefixes.addAll(PrefixUtils.localPrefixesFrom(tism.linkProperties()));
|
||||||
|
}
|
||||||
|
|
||||||
|
mOffloadController.setLocalPrefixes(localPrefixes);
|
||||||
|
}
|
||||||
|
|
||||||
class InitialState extends State {
|
class InitialState extends State {
|
||||||
@Override
|
@Override
|
||||||
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;
|
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) 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:
|
case EVENT_IFACE_SERVING_STATE_INACTIVE:
|
||||||
who = (TetherInterfaceStateMachine)message.obj;
|
who = (TetherInterfaceStateMachine) 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;
|
||||||
@@ -1412,8 +1431,8 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
|
private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
|
||||||
if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) {
|
if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
|
||||||
mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o);
|
sendOffloadExemptPrefixes((Set<IpPrefix>) o);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1517,7 +1536,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;
|
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) 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(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
|
||||||
@@ -1531,7 +1550,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;
|
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) 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);
|
||||||
|
|
||||||
@@ -1563,6 +1582,9 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
mOffloadController.notifyDownstreamLinkProperties(newLp);
|
mOffloadController.notifyDownstreamLinkProperties(newLp);
|
||||||
} else {
|
} else {
|
||||||
mOffloadController.removeDownstreamInterface(newLp.getInterfaceName());
|
mOffloadController.removeDownstreamInterface(newLp.getInterfaceName());
|
||||||
|
// Another interface might be in local-only hotspot mode;
|
||||||
|
// resend all local prefixes to the OffloadController.
|
||||||
|
sendOffloadExemptPrefixes();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1604,7 +1626,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;
|
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
|
||||||
who.sendMessage(mErrorNotification);
|
who.sendMessage(mErrorNotification);
|
||||||
break;
|
break;
|
||||||
case CMD_CLEAR_ERROR:
|
case CMD_CLEAR_ERROR:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
|
|||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.net.IpPrefix;
|
import android.net.IpPrefix;
|
||||||
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.RouteInfo;
|
import android.net.RouteInfo;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
@@ -27,8 +28,11 @@ import android.os.Handler;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,7 +51,13 @@ public class OffloadController {
|
|||||||
private boolean mConfigInitialized;
|
private boolean mConfigInitialized;
|
||||||
private boolean mControlInitialized;
|
private boolean mControlInitialized;
|
||||||
private LinkProperties mUpstreamLinkProperties;
|
private LinkProperties mUpstreamLinkProperties;
|
||||||
|
// The complete set of offload-exempt prefixes passed in via Tethering from
|
||||||
|
// all upstream and downstream sources.
|
||||||
private Set<IpPrefix> mExemptPrefixes;
|
private Set<IpPrefix> mExemptPrefixes;
|
||||||
|
// A strictly "smaller" set of prefixes, wherein offload-approved prefixes
|
||||||
|
// (e.g. downstream on-link prefixes) have been removed and replaced with
|
||||||
|
// prefixes representing only the locally-assigned IP addresses.
|
||||||
|
private Set<String> mLastLocalPrefixStrs;
|
||||||
|
|
||||||
public OffloadController(Handler h, OffloadHardwareInterface hwi,
|
public OffloadController(Handler h, OffloadHardwareInterface hwi,
|
||||||
ContentResolver contentResolver, SharedLog log) {
|
ContentResolver contentResolver, SharedLog log) {
|
||||||
@@ -55,6 +65,8 @@ public class OffloadController {
|
|||||||
mHwInterface = hwi;
|
mHwInterface = hwi;
|
||||||
mContentResolver = contentResolver;
|
mContentResolver = contentResolver;
|
||||||
mLog = log.forSubComponent(TAG);
|
mLog = log.forSubComponent(TAG);
|
||||||
|
mExemptPrefixes = new HashSet<>();
|
||||||
|
mLastLocalPrefixStrs = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
@@ -134,25 +146,22 @@ public class OffloadController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setUpstreamLinkProperties(LinkProperties lp) {
|
public void setUpstreamLinkProperties(LinkProperties lp) {
|
||||||
if (!started()) return;
|
if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
|
||||||
|
|
||||||
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
|
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
|
||||||
// TODO: examine return code and decide what to do if programming
|
// TODO: examine return code and decide what to do if programming
|
||||||
// upstream parameters fails (probably just wait for a subsequent
|
// upstream parameters fails (probably just wait for a subsequent
|
||||||
// onOffloadEvent() callback to tell us offload is available again and
|
// onOffloadEvent() callback to tell us offload is available again and
|
||||||
// then reapply all state).
|
// then reapply all state).
|
||||||
|
computeAndPushLocalPrefixes();
|
||||||
pushUpstreamParameters();
|
pushUpstreamParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) {
|
public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
|
||||||
if (!started()) return;
|
if (!started()) return;
|
||||||
|
|
||||||
mExemptPrefixes = exemptPrefixes;
|
mExemptPrefixes = localPrefixes;
|
||||||
// TODO:
|
computeAndPushLocalPrefixes();
|
||||||
// - add IP addresses from all downstream link properties
|
|
||||||
// - add routes from all non-tethering downstream link properties
|
|
||||||
// - remove any 64share prefixes
|
|
||||||
// - push this to the HAL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyDownstreamLinkProperties(LinkProperties lp) {
|
public void notifyDownstreamLinkProperties(LinkProperties lp) {
|
||||||
@@ -215,4 +224,42 @@ public class OffloadController {
|
|||||||
return mHwInterface.setUpstreamParameters(
|
return mHwInterface.setUpstreamParameters(
|
||||||
iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
|
iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean computeAndPushLocalPrefixes() {
|
||||||
|
final Set<String> localPrefixStrs = computeLocalPrefixStrings(
|
||||||
|
mExemptPrefixes, mUpstreamLinkProperties);
|
||||||
|
if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true;
|
||||||
|
|
||||||
|
mLastLocalPrefixStrs = localPrefixStrs;
|
||||||
|
return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Factor in downstream LinkProperties once that information is available.
|
||||||
|
private static Set<String> computeLocalPrefixStrings(
|
||||||
|
Set<IpPrefix> localPrefixes, LinkProperties upstreamLinkProperties) {
|
||||||
|
// Create an editable copy.
|
||||||
|
final Set<IpPrefix> prefixSet = new HashSet<>(localPrefixes);
|
||||||
|
|
||||||
|
// TODO: If a downstream interface (not currently passed in) is reusing
|
||||||
|
// the /64 of the upstream (64share) then:
|
||||||
|
//
|
||||||
|
// [a] remove that /64 from the local prefixes
|
||||||
|
// [b] add in /128s for IP addresses on the downstream interface
|
||||||
|
// [c] add in /128s for IP addresses on the upstream interface
|
||||||
|
//
|
||||||
|
// Until downstream information is available here, simply add /128s from
|
||||||
|
// the upstream network; they'll just be redundant with their /64.
|
||||||
|
if (upstreamLinkProperties != null) {
|
||||||
|
for (LinkAddress linkAddr : upstreamLinkProperties.getLinkAddresses()) {
|
||||||
|
if (!linkAddr.isGlobalPreferred()) continue;
|
||||||
|
final InetAddress ip = linkAddr.getAddress();
|
||||||
|
if (!(ip instanceof Inet6Address)) continue;
|
||||||
|
prefixSet.add(new IpPrefix(ip, 128));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final HashSet<String> localPrefixStrs = new HashSet<>();
|
||||||
|
for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString());
|
||||||
|
return localPrefixStrs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,26 @@ public class OffloadHardwareInterface {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
|
||||||
|
final String logmsg = String.format("setLocalPrefixes([%s])",
|
||||||
|
String.join(",", localPrefixes));
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mOffloadControl.setLocalPrefixes(localPrefixes,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.success = success;
|
||||||
|
results.errMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.success;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean setUpstreamParameters(
|
public boolean setUpstreamParameters(
|
||||||
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
|
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
|
||||||
iface = (iface != null) ? iface : NO_INTERFACE_NAME;
|
iface = (iface != null) ? iface : NO_INTERFACE_NAME;
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
|
|
||||||
public int lastError() { return mLastError; }
|
public int lastError() { return mLastError; }
|
||||||
|
|
||||||
|
public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
|
||||||
|
|
||||||
public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
|
public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
|
||||||
|
|
||||||
public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
|
public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.net.NetworkCapabilities;
|
|||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.NetworkState;
|
import android.net.NetworkState;
|
||||||
import android.net.util.NetworkConstants;
|
import android.net.util.NetworkConstants;
|
||||||
|
import android.net.util.PrefixUtils;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -72,16 +73,11 @@ public class UpstreamNetworkMonitor {
|
|||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
private static final boolean VDBG = false;
|
private static final boolean VDBG = false;
|
||||||
|
|
||||||
private static final IpPrefix[] MINIMUM_LOCAL_PREFIXES_SET = {
|
|
||||||
prefix("127.0.0.0/8"), prefix("169.254.0.0/16"),
|
|
||||||
prefix("::/3"), prefix("fe80::/64"), prefix("fc00::/7"), prefix("ff00::/8"),
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final int EVENT_ON_AVAILABLE = 1;
|
public static final int EVENT_ON_AVAILABLE = 1;
|
||||||
public static final int EVENT_ON_CAPABILITIES = 2;
|
public static final int EVENT_ON_CAPABILITIES = 2;
|
||||||
public static final int EVENT_ON_LINKPROPERTIES = 3;
|
public static final int EVENT_ON_LINKPROPERTIES = 3;
|
||||||
public static final int EVENT_ON_LOST = 4;
|
public static final int EVENT_ON_LOST = 4;
|
||||||
public static final int NOTIFY_EXEMPT_PREFIXES = 10;
|
public static final int NOTIFY_LOCAL_PREFIXES = 10;
|
||||||
|
|
||||||
private static final int CALLBACK_LISTEN_ALL = 1;
|
private static final int CALLBACK_LISTEN_ALL = 1;
|
||||||
private static final int CALLBACK_TRACK_DEFAULT = 2;
|
private static final int CALLBACK_TRACK_DEFAULT = 2;
|
||||||
@@ -93,7 +89,7 @@ public class UpstreamNetworkMonitor {
|
|||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
private final int mWhat;
|
private final int mWhat;
|
||||||
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
|
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
|
||||||
private HashSet<IpPrefix> mOffloadExemptPrefixes;
|
private HashSet<IpPrefix> mLocalPrefixes;
|
||||||
private ConnectivityManager mCM;
|
private ConnectivityManager mCM;
|
||||||
private NetworkCallback mListenAllCallback;
|
private NetworkCallback mListenAllCallback;
|
||||||
private NetworkCallback mDefaultNetworkCallback;
|
private NetworkCallback mDefaultNetworkCallback;
|
||||||
@@ -107,7 +103,7 @@ public class UpstreamNetworkMonitor {
|
|||||||
mHandler = mTarget.getHandler();
|
mHandler = mTarget.getHandler();
|
||||||
mLog = log.forSubComponent(TAG);
|
mLog = log.forSubComponent(TAG);
|
||||||
mWhat = what;
|
mWhat = what;
|
||||||
mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
|
mLocalPrefixes = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -223,8 +219,8 @@ public class UpstreamNetworkMonitor {
|
|||||||
return typeStatePair.ns;
|
return typeStatePair.ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<IpPrefix> getOffloadExemptPrefixes() {
|
public Set<IpPrefix> getLocalPrefixes() {
|
||||||
return (Set<IpPrefix>) mOffloadExemptPrefixes.clone();
|
return (Set<IpPrefix>) mLocalPrefixes.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAvailable(int callbackType, Network network) {
|
private void handleAvailable(int callbackType, Network network) {
|
||||||
@@ -360,11 +356,11 @@ public class UpstreamNetworkMonitor {
|
|||||||
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
|
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recomputeOffloadExemptPrefixes() {
|
private void recomputeLocalPrefixes() {
|
||||||
final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
|
final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
|
||||||
if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) {
|
if (!mLocalPrefixes.equals(localPrefixes)) {
|
||||||
mOffloadExemptPrefixes = exemptPrefixes;
|
mLocalPrefixes = localPrefixes;
|
||||||
notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone());
|
notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +398,7 @@ public class UpstreamNetworkMonitor {
|
|||||||
@Override
|
@Override
|
||||||
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
|
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
|
||||||
handleLinkProp(network, newLp);
|
handleLinkProp(network, newLp);
|
||||||
recomputeOffloadExemptPrefixes();
|
recomputeLocalPrefixes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle onNetworkSuspended();
|
// TODO: Handle onNetworkSuspended();
|
||||||
@@ -411,7 +407,7 @@ public class UpstreamNetworkMonitor {
|
|||||||
@Override
|
@Override
|
||||||
public void onLost(Network network) {
|
public void onLost(Network network) {
|
||||||
handleLost(mCallbackType, network);
|
handleLost(mCallbackType, network);
|
||||||
recomputeOffloadExemptPrefixes();
|
recomputeLocalPrefixes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,35 +456,15 @@ public class UpstreamNetworkMonitor {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) {
|
private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
|
||||||
final HashSet<IpPrefix> prefixSet = new HashSet<>();
|
final HashSet<IpPrefix> prefixSet = new HashSet<>();
|
||||||
|
|
||||||
addDefaultLocalPrefixes(prefixSet);
|
|
||||||
|
|
||||||
for (NetworkState ns : netStates) {
|
for (NetworkState ns : netStates) {
|
||||||
addOffloadExemptPrefixes(prefixSet, ns.linkProperties);
|
final LinkProperties lp = ns.linkProperties;
|
||||||
|
if (lp == null) continue;
|
||||||
|
prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefixSet;
|
return prefixSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addDefaultLocalPrefixes(Set<IpPrefix> prefixSet) {
|
|
||||||
Collections.addAll(prefixSet, MINIMUM_LOCAL_PREFIXES_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addOffloadExemptPrefixes(Set<IpPrefix> prefixSet, LinkProperties lp) {
|
|
||||||
if (lp == null) return;
|
|
||||||
|
|
||||||
for (LinkAddress linkAddr : lp.getAllLinkAddresses()) {
|
|
||||||
prefixSet.add(new IpPrefix(linkAddr.getAddress(), linkAddr.getPrefixLength()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Consider adding other non-default routes associated with this
|
|
||||||
// network. Traffic to these destinations should perhaps not go through
|
|
||||||
// the Internet (upstream).
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IpPrefix prefix(String prefixStr) {
|
|
||||||
return new IpPrefix(prefixStr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
74
services/net/java/android/net/util/PrefixUtils.java
Normal file
74
services/net/java/android/net/util/PrefixUtils.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net.util;
|
||||||
|
|
||||||
|
import android.net.IpPrefix;
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.LinkProperties;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class PrefixUtils {
|
||||||
|
private static final IpPrefix[] MIN_NON_FORWARDABLE_PREFIXES = {
|
||||||
|
pfx("127.0.0.0/8"), // IPv4 loopback
|
||||||
|
pfx("169.254.0.0/16"), // IPv4 link-local, RFC3927#section-8
|
||||||
|
pfx("::/3"),
|
||||||
|
pfx("fe80::/64"), // IPv6 link-local
|
||||||
|
pfx("fc00::/7"), // IPv6 ULA
|
||||||
|
pfx("ff02::/8"), // IPv6 link-local multicast
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final IpPrefix DEFAULT_WIFI_P2P_PREFIX = pfx("192.168.49.0/24");
|
||||||
|
|
||||||
|
public static Set<IpPrefix> getNonForwardablePrefixes() {
|
||||||
|
final HashSet<IpPrefix> prefixes = new HashSet<>();
|
||||||
|
addNonForwardablePrefixes(prefixes);
|
||||||
|
return prefixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addNonForwardablePrefixes(Set<IpPrefix> prefixes) {
|
||||||
|
Collections.addAll(prefixes, MIN_NON_FORWARDABLE_PREFIXES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<IpPrefix> localPrefixesFrom(LinkProperties lp) {
|
||||||
|
final HashSet<IpPrefix> localPrefixes = new HashSet<>();
|
||||||
|
if (lp == null) return localPrefixes;
|
||||||
|
|
||||||
|
for (LinkAddress addr : lp.getAllLinkAddresses()) {
|
||||||
|
if (addr.getAddress().isLinkLocalAddress()) continue;
|
||||||
|
localPrefixes.add(asIpPrefix(addr));
|
||||||
|
}
|
||||||
|
// TODO: Add directly-connected routes as well (ones from which we did
|
||||||
|
// not also form a LinkAddress)?
|
||||||
|
|
||||||
|
return localPrefixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IpPrefix asIpPrefix(LinkAddress addr) {
|
||||||
|
return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IpPrefix pfx(String prefixStr) {
|
||||||
|
return new IpPrefix(prefixStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.RouteInfo;
|
import android.net.RouteInfo;
|
||||||
@@ -45,6 +46,8 @@ import com.android.internal.util.test.FakeSettingsProvider;
|
|||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -186,17 +189,43 @@ public class OffloadControllerTest {
|
|||||||
any(OffloadHardwareInterface.ControlCallback.class));
|
any(OffloadHardwareInterface.ControlCallback.class));
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
offload.setUpstreamLinkProperties(null);
|
// In reality, the UpstreamNetworkMonitor would have passed down to us
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
// a covering set of local prefixes representing a minimum essential
|
||||||
eq(null), eq(null), eq(null), eq(null));
|
// set plus all the prefixes on networks with network agents.
|
||||||
|
//
|
||||||
|
// We simulate that there, and then add upstream elements one by one
|
||||||
|
// and watch what happens.
|
||||||
|
final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
|
||||||
|
for (String s : new String[]{
|
||||||
|
"127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
|
||||||
|
minimumLocalPrefixes.add(new IpPrefix(s));
|
||||||
|
}
|
||||||
|
offload.setLocalPrefixes(minimumLocalPrefixes);
|
||||||
|
inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
|
ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
|
||||||
|
assertEquals(4, localPrefixes.size());
|
||||||
|
assertTrue(localPrefixes.contains("127.0.0.0/8"));
|
||||||
|
assertTrue(localPrefixes.contains("192.0.2.0/24"));
|
||||||
|
assertTrue(localPrefixes.contains("fe80::/64"));
|
||||||
|
assertTrue(localPrefixes.contains("2001:db8::/64"));
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
offload.setUpstreamLinkProperties(null);
|
||||||
|
// No change in local addresses means no call to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
|
// This LinkProperties value does not differ from the default upstream.
|
||||||
|
// There should be no extraneous call to setUpstreamParameters().
|
||||||
|
inOrder.verify(mHardware, never()).setUpstreamParameters(
|
||||||
|
anyObject(), anyObject(), anyObject(), anyObject());
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
reset(mHardware);
|
|
||||||
|
|
||||||
final LinkProperties lp = new LinkProperties();
|
final LinkProperties lp = new LinkProperties();
|
||||||
|
|
||||||
final String testIfName = "rmnet_data17";
|
final String testIfName = "rmnet_data17";
|
||||||
lp.setInterfaceName(testIfName);
|
lp.setInterfaceName(testIfName);
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// No change in local addresses means no call to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
eq(testIfName), eq(null), eq(null), eq(null));
|
eq(testIfName), eq(null), eq(null), eq(null));
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
@@ -204,7 +233,15 @@ public class OffloadControllerTest {
|
|||||||
final String ipv4Addr = "192.0.2.5";
|
final String ipv4Addr = "192.0.2.5";
|
||||||
final String linkAddr = ipv4Addr + "/24";
|
final String linkAddr = ipv4Addr + "/24";
|
||||||
lp.addLinkAddress(new LinkAddress(linkAddr));
|
lp.addLinkAddress(new LinkAddress(linkAddr));
|
||||||
|
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// IPv4 prefixes and addresses on the upstream are simply left as whole
|
||||||
|
// prefixes (already passed in from UpstreamNetworkMonitor code). If a
|
||||||
|
// tethering client sends traffic to the IPv4 default router or other
|
||||||
|
// clients on the upstream this will not be hardware-forwarded, and that
|
||||||
|
// should be fine for now. Ergo: no change in local addresses, no call
|
||||||
|
// to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
|
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
@@ -212,6 +249,8 @@ public class OffloadControllerTest {
|
|||||||
final String ipv4Gateway = "192.0.2.1";
|
final String ipv4Gateway = "192.0.2.1";
|
||||||
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
|
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// No change in local addresses means no call to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
|
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
@@ -219,6 +258,8 @@ public class OffloadControllerTest {
|
|||||||
final String ipv6Gw1 = "fe80::cafe";
|
final String ipv6Gw1 = "fe80::cafe";
|
||||||
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
|
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// No change in local addresses means no call to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||||
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
|
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
|
||||||
@@ -229,6 +270,8 @@ public class OffloadControllerTest {
|
|||||||
final String ipv6Gw2 = "fe80::d00d";
|
final String ipv6Gw2 = "fe80::d00d";
|
||||||
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
|
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// No change in local addresses means no call to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||||
v6gws = mStringArrayCaptor.getValue();
|
v6gws = mStringArrayCaptor.getValue();
|
||||||
@@ -244,6 +287,8 @@ public class OffloadControllerTest {
|
|||||||
stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
|
stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
|
||||||
assertTrue(lp.addStackedLink(stacked));
|
assertTrue(lp.addStackedLink(stacked));
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// No change in local addresses means no call to setLocalPrefixes().
|
||||||
|
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||||
v6gws = mStringArrayCaptor.getValue();
|
v6gws = mStringArrayCaptor.getValue();
|
||||||
@@ -251,5 +296,43 @@ public class OffloadControllerTest {
|
|||||||
assertTrue(v6gws.contains(ipv6Gw1));
|
assertTrue(v6gws.contains(ipv6Gw1));
|
||||||
assertTrue(v6gws.contains(ipv6Gw2));
|
assertTrue(v6gws.contains(ipv6Gw2));
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
// Add in some IPv6 upstream info. When there is a tethered downstream
|
||||||
|
// making use of the IPv6 prefix we would expect to see the /64 route
|
||||||
|
// removed from "local prefixes" and /128s added for the upstream IPv6
|
||||||
|
// addresses. This is not yet implemented, and for now we simply
|
||||||
|
// expect to see these /128s.
|
||||||
|
lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64")));
|
||||||
|
// "2001:db8::/64" plus "assigned" ASCII in hex
|
||||||
|
lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64"));
|
||||||
|
// "2001:db8::/64" plus "random" ASCII in hex
|
||||||
|
lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64"));
|
||||||
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
|
||||||
|
localPrefixes = mStringArrayCaptor.getValue();
|
||||||
|
assertEquals(6, localPrefixes.size());
|
||||||
|
assertTrue(localPrefixes.contains("127.0.0.0/8"));
|
||||||
|
assertTrue(localPrefixes.contains("192.0.2.0/24"));
|
||||||
|
assertTrue(localPrefixes.contains("fe80::/64"));
|
||||||
|
assertTrue(localPrefixes.contains("2001:db8::/64"));
|
||||||
|
assertTrue(localPrefixes.contains("2001:db8::6173:7369:676e:6564/128"));
|
||||||
|
assertTrue(localPrefixes.contains("2001:db8::7261:6e64:6f6d/128"));
|
||||||
|
// The relevant parts of the LinkProperties have not changed, but at the
|
||||||
|
// moment we do not de-dup upstream LinkProperties this carefully.
|
||||||
|
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
|
||||||
|
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
|
||||||
|
v6gws = mStringArrayCaptor.getValue();
|
||||||
|
assertEquals(2, v6gws.size());
|
||||||
|
assertTrue(v6gws.contains(ipv6Gw1));
|
||||||
|
assertTrue(v6gws.contains(ipv6Gw2));
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
// Completely identical LinkProperties updates are de-duped.
|
||||||
|
offload.setUpstreamLinkProperties(lp);
|
||||||
|
// This LinkProperties value does not differ from the default upstream.
|
||||||
|
// There should be no extraneous call to setUpstreamParameters().
|
||||||
|
inOrder.verify(mHardware, never()).setUpstreamParameters(
|
||||||
|
anyObject(), anyObject(), anyObject(), anyObject());
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -324,19 +324,14 @@ public class UpstreamNetworkMonitorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOffloadExemptPrefixes() throws Exception {
|
public void testLocalPrefixes() throws Exception {
|
||||||
mUNM.start();
|
mUNM.start();
|
||||||
|
|
||||||
// [0] Test minimum set of exempt prefixes.
|
// [0] Test minimum set of local prefixes.
|
||||||
Set<IpPrefix> exempt = mUNM.getOffloadExemptPrefixes();
|
Set<IpPrefix> local = mUNM.getLocalPrefixes();
|
||||||
final String[] MINSET = {
|
assertTrue(local.isEmpty());
|
||||||
"127.0.0.0/8", "169.254.0.0/16",
|
|
||||||
"::/3", "fe80::/64", "fc00::/7", "ff00::/8",
|
|
||||||
};
|
|
||||||
assertPrefixSet(exempt, INCLUDES, MINSET);
|
|
||||||
final Set<String> alreadySeen = new HashSet<>();
|
final Set<String> alreadySeen = new HashSet<>();
|
||||||
Collections.addAll(alreadySeen, MINSET);
|
|
||||||
assertEquals(alreadySeen.size(), exempt.size());
|
|
||||||
|
|
||||||
// [1] Pretend Wi-Fi connects.
|
// [1] Pretend Wi-Fi connects.
|
||||||
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
|
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
|
||||||
@@ -355,15 +350,15 @@ public class UpstreamNetworkMonitorTest {
|
|||||||
wifiAgent.fakeConnect();
|
wifiAgent.fakeConnect();
|
||||||
wifiAgent.sendLinkProperties(wifiLp);
|
wifiAgent.sendLinkProperties(wifiLp);
|
||||||
|
|
||||||
exempt = mUNM.getOffloadExemptPrefixes();
|
local = mUNM.getLocalPrefixes();
|
||||||
assertPrefixSet(exempt, INCLUDES, alreadySeen);
|
assertPrefixSet(local, INCLUDES, alreadySeen);
|
||||||
final String[] wifiLinkPrefixes = {
|
final String[] wifiLinkPrefixes = {
|
||||||
// Excludes link-local as that's already tested within MINSET.
|
// Link-local prefixes are excluded and dealt with elsewhere.
|
||||||
"100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64",
|
"100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64",
|
||||||
};
|
};
|
||||||
assertPrefixSet(exempt, INCLUDES, wifiLinkPrefixes);
|
assertPrefixSet(local, INCLUDES, wifiLinkPrefixes);
|
||||||
Collections.addAll(alreadySeen, wifiLinkPrefixes);
|
Collections.addAll(alreadySeen, wifiLinkPrefixes);
|
||||||
assertEquals(alreadySeen.size(), exempt.size());
|
assertEquals(alreadySeen.size(), local.size());
|
||||||
|
|
||||||
// [2] Pretend mobile connects.
|
// [2] Pretend mobile connects.
|
||||||
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
|
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
|
||||||
@@ -379,12 +374,12 @@ public class UpstreamNetworkMonitorTest {
|
|||||||
cellAgent.fakeConnect();
|
cellAgent.fakeConnect();
|
||||||
cellAgent.sendLinkProperties(cellLp);
|
cellAgent.sendLinkProperties(cellLp);
|
||||||
|
|
||||||
exempt = mUNM.getOffloadExemptPrefixes();
|
local = mUNM.getLocalPrefixes();
|
||||||
assertPrefixSet(exempt, INCLUDES, alreadySeen);
|
assertPrefixSet(local, INCLUDES, alreadySeen);
|
||||||
final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" };
|
final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" };
|
||||||
assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
|
assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
|
||||||
Collections.addAll(alreadySeen, cellLinkPrefixes);
|
Collections.addAll(alreadySeen, cellLinkPrefixes);
|
||||||
assertEquals(alreadySeen.size(), exempt.size());
|
assertEquals(alreadySeen.size(), local.size());
|
||||||
|
|
||||||
// [3] Pretend DUN connects.
|
// [3] Pretend DUN connects.
|
||||||
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
|
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
|
||||||
@@ -401,21 +396,20 @@ public class UpstreamNetworkMonitorTest {
|
|||||||
dunAgent.fakeConnect();
|
dunAgent.fakeConnect();
|
||||||
dunAgent.sendLinkProperties(dunLp);
|
dunAgent.sendLinkProperties(dunLp);
|
||||||
|
|
||||||
exempt = mUNM.getOffloadExemptPrefixes();
|
local = mUNM.getLocalPrefixes();
|
||||||
assertPrefixSet(exempt, INCLUDES, alreadySeen);
|
assertPrefixSet(local, INCLUDES, alreadySeen);
|
||||||
final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" };
|
final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" };
|
||||||
assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
|
assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
|
||||||
Collections.addAll(alreadySeen, dunLinkPrefixes);
|
Collections.addAll(alreadySeen, dunLinkPrefixes);
|
||||||
assertEquals(alreadySeen.size(), exempt.size());
|
assertEquals(alreadySeen.size(), local.size());
|
||||||
|
|
||||||
// [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
|
// [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
|
||||||
// longer be included (should be properly removed).
|
// longer be included (should be properly removed).
|
||||||
wifiAgent.fakeDisconnect();
|
wifiAgent.fakeDisconnect();
|
||||||
exempt = mUNM.getOffloadExemptPrefixes();
|
local = mUNM.getLocalPrefixes();
|
||||||
assertPrefixSet(exempt, INCLUDES, MINSET);
|
assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes);
|
||||||
assertPrefixSet(exempt, EXCLUDES, wifiLinkPrefixes);
|
assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
|
||||||
assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
|
assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
|
||||||
assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {
|
private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {
|
||||||
|
|||||||
Reference in New Issue
Block a user